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 {
$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),
constructors: {
'': BridgeConstructorDef(
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),
)),
'outerHtml': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)),
'text': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)),
'children': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MElement.$type]), nullable: true),
returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$MElement.$type]),
nullable: true),
)),
},
methods: {
'select': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MElement.$type]), nullable: true),
params: [BridgeParameter('selector', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$MElement.$type]),
nullable: true),
params: [
BridgeParameter(
'selector',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'selectFirst': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation($MElement.$type, nullable: true),
params: [BridgeParameter('selector', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
params: [
BridgeParameter(
'selector',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'getElementsByClassName': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]), nullable: true),
params: [BridgeParameter('classNames', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$type]),
nullable: true),
params: [
BridgeParameter(
'classNames',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'getElementsByTagName': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]), nullable: true),
params: [BridgeParameter('localNames', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$type]),
nullable: true),
params: [
BridgeParameter(
'localNames',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'getElementById': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation($MElement.$type, nullable: true),
params: [BridgeParameter('id', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
params: [
BridgeParameter(
'id',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'xpath': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])),
params: [BridgeParameter('xpath', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
returns: BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])),
params: [
BridgeParameter(
'xpath',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'xpathFirst': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
params: [BridgeParameter('xpath', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
params: [
BridgeParameter(
'xpath',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'attr': BridgeMethodDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), params: [
BridgeParameter('attr', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), false)
]),
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
params: [
BridgeParameter(
'attr',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
false)
]),
),
'hasAttr': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)),
params: [BridgeParameter('attr', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
params: [
BridgeParameter(
'attr',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
},
wrap: true);
@ -125,7 +185,9 @@ class $MDocument implements MDocument, $Instance {
return res == null ? const $null() : $String(res);
case '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':
return __select;
case 'selectFirst':
@ -156,59 +218,79 @@ class $MDocument implements MDocument, $Instance {
void $setProperty(Runtime runtime, String identifier, $Value value) {}
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);
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 $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);
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));
}
static const $Function __getElementsByClassName = $Function(_getElementsByClassName);
static $Value? _getElementsByClassName(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 __getElementsByClassName =
$Function(_getElementsByClassName);
static $Value? _getElementsByClassName(
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 $Value? _getElementsByTagName(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 __getElementsByTagName =
$Function(_getElementsByTagName);
static $Value? _getElementsByTagName(
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 $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);
return res == null ? const $null() : $MElement.wrap(res);
}
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);
return $List.wrap(res.map((e) => $String(e)).toList());
}
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);
return res == null ? const $null() : $String(res);
}
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 ?? "");
return res == null ? const $null() : $String(res);
}
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 ?? "");
return res == null ? const $null() : $String(res);
}
@ -226,10 +308,12 @@ class $MDocument implements MDocument, $Instance {
String? xpathFirst(String xpath) => $value.xpathFirst(xpath);
@override
List<MElement>? getElementsByClassName(String classNames) => $value.getElementsByClassName(classNames);
List<MElement>? getElementsByClassName(String classNames) =>
$value.getElementsByClassName(classNames);
@override
List<MElement>? getElementsByTagName(String localNames) => $value.getElementsByTagName(localNames);
List<MElement>? getElementsByTagName(String localNames) =>
$value.getElementsByTagName(localNames);
@override
String? attr(String attr) => $value.attr(attr);
@ -265,11 +349,15 @@ class $MDocument implements MDocument, $Instance {
class $Document implements $Instance {
$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(
BridgeClassType($type),
constructors: {'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type, nullable: true)))},
constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation($type, nullable: true)))
},
wrap: true,
);

View file

@ -5,13 +5,15 @@ import 'package:mangayomi/eval/model/element.dart';
class $MElement implements MElement, $Instance {
$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),
constructors: {
'': BridgeConstructorDef(
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: {
'outerHtml': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)),
'innerHtml': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)),
'text': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)),
'className': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)),
'localName': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)),
'namespaceUri': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)),
'getSrc': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)),
'getImg': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)),
'getHref': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)),
'getDataSrc': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)),
'children': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]), nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]),
nullable: true),
)),
'parent': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation($type, nullable: true),
@ -64,48 +77,100 @@ class $MElement implements MElement, $Instance {
},
methods: {
'attr': BridgeMethodDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), params: [
BridgeParameter('attr', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), false)
]),
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
params: [
BridgeParameter(
'attr',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
false)
]),
),
'text': BridgeMethodDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true)),
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true)),
),
'select': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]), nullable: true),
params: [BridgeParameter('selector', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$type]),
nullable: true),
params: [
BridgeParameter(
'selector',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'selectFirst': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation($type, nullable: true),
params: [BridgeParameter('selector', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
params: [
BridgeParameter(
'selector',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'getElementsByClassName': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]), nullable: true),
params: [BridgeParameter('classNames', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$type]),
nullable: true),
params: [
BridgeParameter(
'classNames',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'getElementsByTagName': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]), nullable: true),
params: [BridgeParameter('localNames', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$type]),
nullable: true),
params: [
BridgeParameter(
'localNames',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'xpath': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]),
returns: BridgeTypeAnnotation(
BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]),
nullable: true),
params: [BridgeParameter('xpath', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
params: [
BridgeParameter(
'xpath',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'xpathFirst': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true),
params: [BridgeParameter('xpath', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
params: [
BridgeParameter(
'xpath',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
'hasAttr': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)),
params: [BridgeParameter('attr', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]),
params: [
BridgeParameter(
'attr',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
},
wrap: true);
@ -129,28 +194,44 @@ class $MElement implements MElement, $Instance {
return res == null ? const $null() : $String(res);
case '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':
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':
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':
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':
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':
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':
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':
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':
final res = $value.parent;
return res == null ? const $null() : $MElement.wrap(res);
@ -187,62 +268,83 @@ class $MElement implements MElement, $Instance {
@override
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));
}
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 ?? "");
return res == null ? const $null() : $String(res);
}
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);
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 $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);
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) {
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 $Value? _getElementsByClassName(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
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) {
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 $Value? _getElementsByTagName(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
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 $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);
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 $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);
return res == null ? const $null() : $String(res);
}
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 ?? "");
return res == null ? const $null() : $String(res);
}
@ -266,10 +368,12 @@ class $MElement implements MElement, $Instance {
List<MElement>? get children => $value.children;
@override
List<MElement>? getElementsByClassName(String classNames) => $value.getElementsByClassName(classNames);
List<MElement>? getElementsByClassName(String classNames) =>
$value.getElementsByClassName(classNames);
@override
List<MElement>? getElementsByTagName(String localNames) => $value.getElementsByTagName(localNames);
List<MElement>? getElementsByTagName(String localNames) =>
$value.getElementsByTagName(localNames);
@override
bool hasAttr(String attr) => $value.hasAttr(attr);
@ -317,11 +421,15 @@ class $MElement implements MElement, $Instance {
class $Element implements $Instance {
$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(
BridgeClassType($type),
constructors: {'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type, nullable: true)))},
constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation($type, nullable: true)))
},
wrap: true,
);

View file

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

View file

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

View file

@ -5,23 +5,35 @@ import 'package:mangayomi/eval/model/m_chapter.dart';
class $MChapter implements MChapter, $Instance {
$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),
constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [], namedParams: [
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),
]))
'': BridgeConstructorDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation($type),
params: [],
namedParams: [
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
fields: {
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'url': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'dateUpload': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'scanlator': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'name': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'url': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'dateUpload': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'scanlator': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
},
wrap: true);
@ -102,5 +114,10 @@ class $MChapter implements MChapter, $Instance {
set scanlator(String? scanlator) {}
@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 {
$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),
constructors: {'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: []))},
constructors: {
'': BridgeConstructorDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: []))
},
// Specify class fields
fields: {
'author': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'artist': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'author': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'artist': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'status': BridgeFieldDef(BridgeTypeAnnotation($MStatus.$type)),
'genre': BridgeFieldDef(
BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]),
),
),
'imageUrl': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'link': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'description': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'chapters': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MChapter.$type]))),
'imageUrl': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'name': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'link': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'description': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'chapters': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$MChapter.$type]))),
},
wrap: true);
@ -65,7 +76,8 @@ class $MManga implements MManga, $Instance {
case 'description':
return $String($value.description!);
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:
return _superclass.$getProperty(runtime, identifier);
@ -85,7 +97,8 @@ class $MManga implements MManga, $Instance {
case 'status':
$value.status = value.$reified;
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':
$value.imageUrl = value.$reified;
case 'name':
@ -96,7 +109,11 @@ class $MManga implements MManga, $Instance {
$value.description = value.$reified;
case 'chapters':
$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();
default:

View file

@ -7,26 +7,40 @@ import 'package:mangayomi/eval/model/m_pages.dart';
class $MPages implements MPages, $Instance {
$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),
constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('list', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MManga.$type])), false),
BridgeParameter('hasNextPage', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool), nullable: true), true),
'': BridgeConstructorDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter(
'list',
BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$MManga.$type])),
false),
BridgeParameter(
'hasNextPage',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool),
nullable: true),
true),
]))
},
fields: {
'list': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MManga.$type])),
),
'hasNextPage': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool), nullable: true)),
'hasNextPage': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.bool),
nullable: true)),
},
wrap: true);
static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) {
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

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 {
$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),
constructors: {'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: []))},
constructors: {
'': BridgeConstructorDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: []))
},
fields: {
'id': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int))),
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'baseUrl': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'lang': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'isFullData': 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))),
'id':
BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int))),
'name': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'baseUrl': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'lang': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'isFullData':
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);

View file

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

View file

@ -5,7 +5,8 @@ import 'package:mangayomi/models/video.dart';
class $MTrack implements Track, $Instance {
$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),
constructors: {
@ -15,8 +16,10 @@ class $MTrack implements Track, $Instance {
},
// Specify class fields
fields: {
'file': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'label': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'file': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'label': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
},
wrap: true);

View file

@ -6,7 +6,8 @@ import 'package:mangayomi/models/video.dart';
class $MVideo implements Video, $Instance {
$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),
constructors: {
@ -16,14 +17,22 @@ class $MVideo implements Video, $Instance {
},
// Specify class fields
fields: {
'url': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'quality': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'originalUrl': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'url': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'quality': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'originalUrl': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'headers': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.map, [BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string)]),
BridgeTypeRef(CoreTypes.map, [
BridgeTypeRef(CoreTypes.string),
BridgeTypeRef(CoreTypes.string)
]),
nullable: true)),
'subtitles': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MTrack.$type]))),
'audios': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MTrack.$type]))),
'subtitles': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$MTrack.$type]))),
'audios': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$MTrack.$type]))),
},
wrap: true);
@ -51,9 +60,13 @@ class $MVideo implements Video, $Instance {
case 'headers':
return $Map.wrap($value.headers ?? {});
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':
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:
return _superclass.$getProperty(runtime, identifier);
@ -73,12 +86,17 @@ class $MVideo implements Video, $Instance {
case 'originalUrl':
$value.originalUrl = value.$reified;
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':
$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':
$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:
_superclass.$setProperty(runtime, identifier, value);

View file

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

View file

@ -61,39 +61,64 @@ class MEvalPlugin extends EvalPlugin {
@override
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);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MChapter.', $MChapter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MManga.', $MManga.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MPages.', $MPages.$new);
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);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'MChapter.', $MChapter.$new);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'MManga.', $MManga.$new);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'MPages.', $MPages.$new);
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
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'FilterList.', $FilterList.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'SelectFilter.', $SelectFilter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'SeparatorFilter.', $SeparatorFilter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'HeaderFilter.', $HeaderFilter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'TextFilter.', $TextFilter.$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);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'FilterList.', $FilterList.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'SelectFilter.', $SelectFilter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'SeparatorFilter.', $SeparatorFilter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'HeaderFilter.', $HeaderFilter.$new);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'TextFilter.', $TextFilter.$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
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'CheckBoxPreference.', $CheckBoxPreference.$new);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'SwitchPreferenceCompat.', $SwitchPreferenceCompat.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'ListPreference.', $ListPreference.$new);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'MultiSelectListPreference.', $MultiSelectListPreference.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'EditTextPreference.', $EditTextPreference.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'CheckBoxPreference.', $CheckBoxPreference.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'SwitchPreferenceCompat.', $SwitchPreferenceCompat.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'ListPreference.', $ListPreference.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'MultiSelectListPreference.', $MultiSelectListPreference.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'EditTextPreference.', $EditTextPreference.$new);
//DOM HTML
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MElement.', $MElement.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MDocument.', $MDocument.$new);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'MElement.', $MElement.$new);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'MDocument.', $MDocument.$new);
//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);
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
@ -103,7 +104,9 @@ class DartExtensionService implements ExtensionService {
@override
Future<List<PageUrl>> getPageList(String url) async {
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();
}
@ -117,7 +120,10 @@ class DartExtensionService implements ExtensionService {
List<dynamic> list;
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 (_) {
list = [];
}

View file

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

View file

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

View file

@ -11,7 +11,8 @@ class JsHttpClient {
void init() {
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 {
@ -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;
var request = http.Request(method, Uri.parse(url));
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.headers.addAll(headers ?? {});
http.StreamedResponse response = await client.send(request);
@ -136,6 +139,7 @@ extension ToMapExtension on Map? {
}
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
Map<String, String> getHeaders() {
return _extensionCall<Map>('getHeaders(`${source.baseUrl ?? ''}`)', {}).toMapStringString!;
return _extensionCall<Map>('getHeaders(`${source.baseUrl ?? ''}`)', {})
.toMapStringString!;
}
@override
@ -98,13 +99,15 @@ var extention = new DefaultExtension();
@override
Future<MPages> getLatestUpdates(int page) async {
return MPages.fromJson(await _extensionCallAsync('getLatestUpdates($page)', {}));
return MPages.fromJson(
await _extensionCallAsync('getLatestUpdates($page)', {}));
}
@override
Future<MPages> search(String query, int page, List<dynamic> filters) async {
return MPages.fromJson(
await _extensionCallAsync('search("$query",$page,${jsonEncode(filterValuesListToJson(filters))})', {}));
return MPages.fromJson(await _extensionCallAsync(
'search("$query",$page,${jsonEncode(filterValuesListToJson(filters))})',
{}));
}
@override
@ -115,14 +118,17 @@ var extention = new DefaultExtension();
@override
Future<List<PageUrl>> getPageList(String url) async {
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();
}
@override
Future<List<Video>> getVideoList(String url) async {
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))
.toList()
.toSet()
@ -149,12 +155,11 @@ var extention = new DefaultExtension();
.toList();
}
T _extensionCall<T>(String call, T def) {
_init();
try {
final res = runtime.evaluate('JSON.stringify(extention.`$call`)');
final res = runtime.evaluate('JSON.stringify(extention.$call)');
return jsonDecode(res.stringResult) as T;
} catch (_) {
@ -170,7 +175,8 @@ var extention = new DefaultExtension();
_init();
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;
} catch (_) {

View file

@ -19,7 +19,8 @@ class MDocument {
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) {
return _document?.select(selector)?.map((e) => MElement(e)).toList();
@ -34,11 +35,17 @@ class MDocument {
}
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) {
return _document?.getElementsByTagName(localNames).map((e) => MElement(e)).toList();
return _document
?.getElementsByTagName(localNames)
.map((e) => MElement(e))
.toList();
}
MElement? getElementById(String id) {

View file

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

View file

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

View file

@ -44,15 +44,18 @@ class WordSet {
WordSet(this.words);
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) {
return words.any((word) => dateString.toLowerCase().startsWith(word.toLowerCase()));
return words
.any((word) => dateString.toLowerCase().startsWith(word.toLowerCase()));
}
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
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) {
attrs = [attr];
}
@ -102,7 +106,10 @@ class MBridge {
statusMap = element;
}
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) {
0 => Status.ongoing,
1 => Status.completed,
@ -259,7 +266,8 @@ class MBridge {
}
//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 = [];
for (var element in value) {
if (element is $Value) {
@ -304,7 +312,8 @@ class MBridge {
}
//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) {
return expression.replaceAll(RegExp(source), replace);
}
@ -319,48 +328,58 @@ class MBridge {
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);
}
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);
}
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 = {};
if (headers != null) {
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();
await quark.initCloudDrive(cookie, CloudDriveType.quark);
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();
await uc.initCloudDrive(cookie, CloudDriveType.uc);
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();
await quark.initCloudDrive(cookie, CloudDriveType.quark);
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();
await uc.initCloudDrive(cookie, CloudDriveType.uc);
return await uc.videosFromUrl(url);
}
static Future<List<Video>> streamTapeExtractor(String url, String? quality) async {
return await StreamTapeExtractor().videosFromUrl(url, quality: quality ?? "StreamTape");
static Future<List<Video>> streamTapeExtractor(
String url, String? quality) async {
return await StreamTapeExtractor()
.videosFromUrl(url, quality: quality ?? "StreamTape");
}
//Utility to use substring
@ -383,28 +402,55 @@ class MBridge {
}
//Parse a chapter date to millisecondsSinceEpoch
static String parseChapterDate(
String date, String dateFormat, String dateFormatLocale, Function((String, String, bool)) newLocale) {
static String parseChapterDate(String date, String dateFormat,
String dateFormatLocale, Function((String, String, bool)) newLocale) {
int parseRelativeDate(String date) {
final number = int.tryParse(RegExp(r"(\d+)").firstMatch(date)!.group(0)!);
if (number == null) return 0;
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;
} else if (WordSet(["jam", "saat", "heure", "hora", "hour", "ชั่วโมง", "giờ", "ore", "ساعة", "小时"])
.anyWordIn(date)) {
} else if (WordSet([
"jam",
"saat",
"heure",
"hora",
"hour",
"ชั่วโมง",
"giờ",
"ore",
"ساعة",
"小时"
]).anyWordIn(date)) {
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;
} 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;
} else if (WordSet(["week", "semana"]).anyWordIn(date)) {
return cal.subtract(Duration(days: number * 7)).millisecondsSinceEpoch;
} else if (WordSet(["month", "mes"]).anyWordIn(date)) {
return cal.subtract(Duration(days: number * 30)).millisecondsSinceEpoch;
} 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 {
return 0;
}
@ -430,11 +476,19 @@ class MBridge {
} else if (date.contains(RegExp(r"\d(st|nd|rd|th)"))) {
final cleanedDate = date
.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(" ");
return DateFormat(dateFormat, dateFormatLocale).parse(cleanedDate).millisecondsSinceEpoch.toString();
return DateFormat(dateFormat, dateFormatLocale)
.parse(cleanedDate)
.millisecondsSinceEpoch
.toString();
} else {
return DateFormat(dateFormat, dateFormatLocale).parse(date).millisecondsSinceEpoch.toString();
return DateFormat(dateFormat, dateFormatLocale)
.parse(date)
.millisecondsSinceEpoch
.toString();
}
} catch (e) {
final supportedLocales = DateFormat.allLocalesWithSymbols();
@ -456,18 +510,27 @@ class MBridge {
DateTime cal = DateTime.now().subtract(const Duration(days: 2));
cal = DateTime(cal.year, cal.month, cal.day);
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();
} else if (WordSet(["hace"]).startsWith(date)) {
return parseRelativeDate(date).toString();
} else if (date.contains(RegExp(r"\d(st|nd|rd|th)"))) {
final cleanedDate = date
.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(" ");
return DateFormat(dateFormat, locale).parse(cleanedDate).millisecondsSinceEpoch.toString();
return DateFormat(dateFormat, locale)
.parse(cleanedDate)
.millisecondsSinceEpoch
.toString();
} else {
return DateFormat(dateFormat, locale).parse(date).millisecondsSinceEpoch.toString();
return DateFormat(dateFormat, locale)
.parse(date)
.millisecondsSinceEpoch
.toString();
}
} catch (_) {}
}
@ -485,13 +548,15 @@ class MBridge {
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 = {};
if (headers != null) {
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 {
@ -502,12 +567,14 @@ class MBridge {
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 = {};
if (headers != null) {
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 {
@ -518,8 +585,10 @@ class MBridge {
return await VidBomExtractor().videosFromUrl(url);
}
static Future<List<Video>> streamlareExtractor(String url, String prefix, String suffix) async {
return await StreamlareExtractor().videosFromUrl(url, prefix: prefix, suffix: suffix);
static Future<List<Video>> streamlareExtractor(
String url, String prefix, String suffix) async {
return await StreamlareExtractor()
.videosFromUrl(url, prefix: prefix, suffix: suffix);
}
static String encryptAESCryptoJS(String plainText, String passphrase) {
@ -530,16 +599,18 @@ class MBridge {
return CryptoAES.decryptAESCryptoJS(encrypted, passphrase);
}
static Video toVideo(
String url, String quality, String originalUrl, String? headers, List<Track>? subtitles, List<Track>? audios) {
static Video toVideo(String url, String quality, String originalUrl,
String? headers, List<Track>? subtitles, List<Track>? audios) {
Map<String, String> newHeaders = {};
if (headers != null) {
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 {
if (encrypt) {
final encryptt = _encrypt(secretKeyString, iv);
@ -603,7 +674,10 @@ void botToast(String title,
bool hasCloudFlare = false,
String? url}) {
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(
onlyOne: true,
dismissDirections: [DismissDirection.horizontal, DismissDirection.down],
@ -617,9 +691,11 @@ void botToast(String title,
? (_) => OutlinedButton.icon(
style: OutlinedButton.styleFrom(elevation: 10),
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),
)
: null,
@ -629,6 +705,7 @@ void botToast(String title,
(encrypt.Encrypter, encrypt.IV) _encrypt(String keyy, String ivv) {
final key = encrypt.Key.fromUtf8(keyy);
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);
}

View file

@ -8,7 +8,16 @@ class MChapter {
String? scanlator;
MChapter({this.name, this.url, this.dateUpload, this.scanlator});
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,
_ => 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
? (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'] as List).map((e) => MChapter.fromJson(e)).toList()
? (json['episodes'] as List)
.map((e) => MChapter.fromJson(e))
.toList()
: []);
}
Map<String, dynamic> toJson() => {

View file

@ -7,7 +7,9 @@ class MPages {
factory MPages.fromJson(Map<String, dynamic> json) {
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']);
}

View file

@ -6,7 +6,8 @@ class MVideo {
List<MTrack>? subtitles;
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 {

View file

@ -27,11 +27,15 @@ class SourcePreference {
'id': id,
'sourceId': sourceId,
'key': key,
if (checkBoxPreference != null) 'checkBoxPreference': checkBoxPreference!.toJson(),
if (switchPreferenceCompat != null) 'switchPreferenceCompat': switchPreferenceCompat!.toJson(),
if (checkBoxPreference != null)
'checkBoxPreference': checkBoxPreference!.toJson(),
if (switchPreferenceCompat != null)
'switchPreferenceCompat': switchPreferenceCompat!.toJson(),
if (listPreference != null) 'listPreference': listPreference!.toJson(),
if (multiSelectListPreference != null) 'multiSelectListPreference': multiSelectListPreference!.toJson(),
if (editTextPreference != null) 'editTextPreference': editTextPreference!.toJson()
if (multiSelectListPreference != null)
'multiSelectListPreference': multiSelectListPreference!.toJson(),
if (editTextPreference != null)
'editTextPreference': editTextPreference!.toJson()
};
factory SourcePreference.fromJson(Map<String, dynamic> json) {
@ -39,17 +43,22 @@ class SourcePreference {
id: json['id'] ?? Isar.autoIncrement,
sourceId: json['sourceId'],
key: json['key'],
checkBoxPreference:
json['checkBoxPreference'] != null ? CheckBoxPreference.fromJson(json['checkBoxPreference']) : null,
checkBoxPreference: json['checkBoxPreference'] != null
? CheckBoxPreference.fromJson(json['checkBoxPreference'])
: null,
switchPreferenceCompat: json['switchPreferenceCompat'] != null
? SwitchPreferenceCompat.fromJson(json['switchPreferenceCompat'])
: null,
listPreference: json['listPreference'] != null ? ListPreference.fromJson(json['listPreference']) : null,
multiSelectListPreference: json['multiSelectListPreference'] != null
? MultiSelectListPreference.fromJson(json['multiSelectListPreference'])
listPreference: json['listPreference'] != null
? ListPreference.fromJson(json['listPreference'])
: null,
editTextPreference:
json['editTextPreference'] != null ? EditTextPreference.fromJson(json['editTextPreference']) : null);
multiSelectListPreference: json['multiSelectListPreference'] != 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});
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) {
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});
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) {
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>? 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() =>
{'title': title, 'summary': summary, 'valueIndex': valueIndex, 'entries': entries, 'entryValues': entryValues};
Map<String, dynamic> toJson() => {
'title': title,
'summary': summary,
'valueIndex': valueIndex,
'entries': entries,
'entryValues': entryValues
};
factory ListPreference.fromJson(Map<String, dynamic> json) {
return ListPreference(
@ -114,7 +137,8 @@ class MultiSelectListPreference {
List<String>? entryValues;
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() => {
'title': title,
@ -143,7 +167,13 @@ class EditTextPreference {
String? dialogMessage;
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() => {
'title': title,
@ -173,5 +203,6 @@ class SourcePreferenceStringValue {
String? key;
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`.
class TorrentLibrary {
/// 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].
TorrentLibrary(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup;
TorrentLibrary(ffi.DynamicLibrary dynamicLibrary)
: _lookup = dynamicLibrary.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;
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_start = ___va_startPtr.asFunction<void Function(ffi.Pointer<va_list>)>();
late final ___va_startPtr =
_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() {
return ___security_init_cookie();
}
late final ___security_init_cookiePtr = _lookup<ffi.NativeFunction<ffi.Void Function()>>('__security_init_cookie');
late final ___security_init_cookie = ___security_init_cookiePtr.asFunction<void Function()>();
late final ___security_init_cookiePtr =
_lookup<ffi.NativeFunction<ffi.Void Function()>>(
'__security_init_cookie');
late final ___security_init_cookie =
___security_init_cookiePtr.asFunction<void Function()>();
void __security_check_cookie(
int _StackCookie,
@ -49,8 +59,10 @@ class TorrentLibrary {
}
late final ___security_check_cookiePtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.UintPtr)>>('__security_check_cookie');
late final ___security_check_cookie = ___security_check_cookiePtr.asFunction<void Function(int)>();
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.UintPtr)>>(
'__security_check_cookie');
late final ___security_check_cookie =
___security_check_cookiePtr.asFunction<void Function(int)>();
void __report_gsfailure(
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_gsfailure = ___report_gsfailurePtr.asFunction<void Function(int)>();
late final ___report_gsfailurePtr =
_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;
@ -74,16 +90,20 @@ class TorrentLibrary {
}
late final __invalid_parameter_noinfoPtr =
_lookup<ffi.NativeFunction<ffi.Void Function()>>('_invalid_parameter_noinfo');
late final __invalid_parameter_noinfo = __invalid_parameter_noinfoPtr.asFunction<void Function()>();
_lookup<ffi.NativeFunction<ffi.Void Function()>>(
'_invalid_parameter_noinfo');
late final __invalid_parameter_noinfo =
__invalid_parameter_noinfoPtr.asFunction<void Function()>();
void _invalid_parameter_noinfo_noreturn() {
return __invalid_parameter_noinfo_noreturn();
}
late final __invalid_parameter_noinfo_noreturnPtr =
_lookup<ffi.NativeFunction<ffi.Void Function()>>('_invalid_parameter_noinfo_noreturn');
late final __invalid_parameter_noinfo_noreturn = __invalid_parameter_noinfo_noreturnPtr.asFunction<void Function()>();
_lookup<ffi.NativeFunction<ffi.Void Function()>>(
'_invalid_parameter_noinfo_noreturn');
late final __invalid_parameter_noinfo_noreturn =
__invalid_parameter_noinfo_noreturnPtr.asFunction<void Function()>();
void _invoke_watson(
ffi.Pointer<ffi.WChar> _Expression,
@ -103,16 +123,22 @@ class TorrentLibrary {
late final __invoke_watsonPtr = _lookup<
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');
late final __invoke_watson = __invoke_watsonPtr
.asFunction<void Function(ffi.Pointer<ffi.WChar>, ffi.Pointer<ffi.WChar>, ffi.Pointer<ffi.WChar>, int, int)>();
late final __invoke_watson = __invoke_watsonPtr.asFunction<
void Function(ffi.Pointer<ffi.WChar>, ffi.Pointer<ffi.WChar>,
ffi.Pointer<ffi.WChar>, int, int)>();
ffi.Pointer<ffi.Int> _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()>();
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)>();
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_errno = __get_errnoPtr.asFunction<int Function(ffi.Pointer<ffi.Int>)>();
late final __get_errnoPtr =
_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() {
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()>();
int __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()>();
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)>();
_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)>();
_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)>();
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)>();
_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)>();
_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)>();
_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)>();
_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)>();
_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)>();
_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)>();
_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)>();
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)>();
_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)>();
_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)>();
_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)>();
_Dcomplex cpow(
@ -326,8 +373,11 @@ class TorrentLibrary {
);
}
late final _cpowPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>>('cpow');
late final _cpow = _cpowPtr.asFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>();
late final _cpowPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>>(
'cpow');
late final _cpow =
_cpowPtr.asFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>();
_Dcomplex cproj(
_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)>();
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)>();
_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)>();
_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)>();
_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)>();
_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)>();
_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)>();
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)>();
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)>();
_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)>();
_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)>();
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)>();
_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)>();
_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)>();
_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)>();
_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)>();
_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)>();
_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)>();
_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)>();
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)>();
_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)>();
_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)>();
_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)>();
_Fcomplex cpowf(
@ -592,8 +665,11 @@ class TorrentLibrary {
);
}
late final _cpowfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>>('cpowf');
late final _cpowf = _cpowfPtr.asFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>();
late final _cpowfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>>(
'cpowf');
late final _cpowf =
_cpowfPtr.asFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>();
_Fcomplex cprojf(
_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)>();
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)>();
_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)>();
_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)>();
_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)>();
_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)>();
_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)>();
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)>();
_Dcomplex _Cbuild(
@ -693,8 +777,11 @@ class TorrentLibrary {
);
}
late final __CbuildPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(ffi.Double, ffi.Double)>>('_Cbuild');
late final __Cbuild = __CbuildPtr.asFunction<_Dcomplex Function(double, double)>();
late final __CbuildPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(ffi.Double, ffi.Double)>>(
'_Cbuild');
late final __Cbuild =
__CbuildPtr.asFunction<_Dcomplex Function(double, double)>();
_Dcomplex _Cmulcc(
_Dcomplex _X,
@ -706,8 +793,11 @@ class TorrentLibrary {
);
}
late final __CmulccPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>>('_Cmulcc');
late final __Cmulcc = __CmulccPtr.asFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>();
late final __CmulccPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>>(
'_Cmulcc');
late final __Cmulcc =
__CmulccPtr.asFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>();
_Dcomplex _Cmulcr(
_Dcomplex _X,
@ -719,8 +809,11 @@ class TorrentLibrary {
);
}
late final __CmulcrPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex, ffi.Double)>>('_Cmulcr');
late final __Cmulcr = __CmulcrPtr.asFunction<_Dcomplex Function(_Dcomplex, double)>();
late final __CmulcrPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex, ffi.Double)>>(
'_Cmulcr');
late final __Cmulcr =
__CmulcrPtr.asFunction<_Dcomplex Function(_Dcomplex, double)>();
_Fcomplex _FCbuild(
double _Re,
@ -732,8 +825,11 @@ class TorrentLibrary {
);
}
late final __FCbuildPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(ffi.Float, ffi.Float)>>('_FCbuild');
late final __FCbuild = __FCbuildPtr.asFunction<_Fcomplex Function(double, double)>();
late final __FCbuildPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(ffi.Float, ffi.Float)>>(
'_FCbuild');
late final __FCbuild =
__FCbuildPtr.asFunction<_Fcomplex Function(double, double)>();
_Fcomplex _FCmulcc(
_Fcomplex _X,
@ -745,8 +841,11 @@ class TorrentLibrary {
);
}
late final __FCmulccPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>>('_FCmulcc');
late final __FCmulcc = __FCmulccPtr.asFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>();
late final __FCmulccPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>>(
'_FCmulcc');
late final __FCmulcc =
__FCmulccPtr.asFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>();
_Fcomplex _FCmulcr(
_Fcomplex _X,
@ -758,8 +857,11 @@ class TorrentLibrary {
);
}
late final __FCmulcrPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex, ffi.Float)>>('_FCmulcr');
late final __FCmulcr = __FCmulcrPtr.asFunction<_Fcomplex Function(_Fcomplex, double)>();
late final __FCmulcrPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex, ffi.Float)>>(
'_FCmulcr');
late final __FCmulcr =
__FCmulcrPtr.asFunction<_Fcomplex Function(_Fcomplex, double)>();
Start_return Start(
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 _Start = _StartPtr.asFunction<Start_return Function(ffi.Pointer<ffi.Char>)>();
late final _StartPtr =
_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>;

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.');
final document = await getApplicationDocumentsDirectory();
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);
await StorageProvider().requestPermission();

View file

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

View file

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

View file

@ -115,7 +115,8 @@ class Source {
additionalParams = json['additionalParams'] ?? "";
isObsolete = json['isObsolete'];
isLocal = json['isLocal'];
sourceCodeLanguage = SourceCodeLanguage.values[json['sourceCodeLanguage'] ?? 0];
sourceCodeLanguage =
SourceCodeLanguage.values[json['sourceCodeLanguage'] ?? 0];
}
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'];
}
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>? 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) {
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,
subtitles: json['subtitles'] != null ? (json['subtitles'] as List).map((e) => Track.fromJson(e)).toList() : [],
audios: json['audios'] != null ? (json['audios'] as List).map((e) => Track.fromJson(e)).toList() : []);
subtitles: json['subtitles'] != null
? (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() => {
'url': url,

View file

@ -50,7 +50,8 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
for (var infoHash in _infoHashList) {
MTorrentServer().removeTorrent(infoHash);
}
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
super.dispose();
}
@ -64,13 +65,15 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
@override
Widget build(BuildContext context) {
final serversData = ref.watch(getVideoListProvider(episode: widget.episode));
final serversData =
ref.watch(getVideoListProvider(episode: widget.episode));
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
return serversData.when(
data: (data) {
final (videos, isLocal, infoHashList) = data;
_infoHashList = infoHashList;
if (videos.isEmpty && !(widget.episode.manga.value!.isLocalArchive ?? false)) {
if (videos.isEmpty &&
!(widget.episode.manga.value!.isLocalArchive ?? false)) {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(
@ -102,7 +105,8 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
title: const Text(''),
leading: BackButton(
onPressed: () {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context);
},
),
@ -120,7 +124,8 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
leading: BackButton(
color: Colors.white,
onPressed: () {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context);
},
),
@ -150,18 +155,24 @@ class AnimeStreamPage extends riv.ConsumerStatefulWidget {
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 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 _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 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<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<bool> _showFitLabel = ValueNotifier(false);
final ValueNotifier<bool> _isCompleted = ValueNotifier(false);
@ -175,9 +186,12 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
bool _hasEndingSkip = false;
bool _initSubtitleAndAudio = true;
late final StreamSubscription<Duration> _currentPositionSub = _player.stream.position.listen(
late final StreamSubscription<Duration> _currentPositionSub =
_player.stream.position.listen(
(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;
if (_firstVid.subtitles?.isNotEmpty ?? false) {
@ -191,8 +205,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
} catch (_) {}
try {
if (_firstVid.audios?.isNotEmpty ?? false) {
_player.setAudioTrack(AudioTrack.uri(_firstVid.audios!.first.file ?? "",
title: _firstVid.audios!.first.label, language: _firstVid.audios!.first.label));
_player.setAudioTrack(AudioTrack.uri(
_firstVid.audios!.first.file ?? "",
title: _firstVid.audios!.first.label,
language: _firstVid.audios!.first.label));
}
} 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) {
_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 (mounted) {
pushToNewEpisode(context, _streamController.getNextEpisode());
@ -231,12 +249,14 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
_loadAndroidFont().then(
(_) {
_player.open(Media(_video.value!.videoTrack!.id,
httpHeaders: _video.value!.headers, start: _streamController.geTCurrentPosition()));
httpHeaders: _video.value!.headers,
start: _streamController.geTCurrentPosition()));
if (widget.isTorrent) {
Future.delayed(const Duration(seconds: 10)).then((_) {
if (mounted) {
_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 fontPath = path.join(subDir.path, '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);
await fontFile.writeAsBytes(bytes);
await (_player.platform as NativePlayer).setProperty('sub-fonts-dir', subDir.path);
await (_player.platform as NativePlayer).setProperty('sub-font', 'Droid Sans Fallback');
await (_player.platform as NativePlayer)
.setProperty('sub-fonts-dir', subDir.path);
await (_player.platform as NativePlayer)
.setProperty('sub-font', 'Droid Sans Fallback');
} catch (_) {}
}
}
@ -265,12 +288,14 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
void _initAniSkip() async {
await _player.stream.buffer.first;
_streamController.getAniSkipResults((result) {
final openingRes = result.where((element) => element.skipType == "op").toList();
final openingRes =
result.where((element) => element.skipType == "op").toList();
_hasOpeningSkip = openingRes.isNotEmpty;
if (_hasOpeningSkip) {
_openingResult = openingRes.first;
}
final endingRes = result.where((element) => element.skipType == "ed").toList();
final endingRes =
result.where((element) => element.skipType == "ed").toList();
_hasEndingSkip = endingRes.isNotEmpty;
if (_hasEndingSkip) {
_endingResult = endingRes.first;
@ -295,14 +320,17 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
}
void _setCurrentPosition(bool save) {
_streamController.setCurrentPosition(_currentPosition.value, _currentTotalDuration.value, save: save);
_streamController.setCurrentPosition(
_currentPosition.value, _currentTotalDuration.value,
save: save);
_streamController.setAnimeHistoryUpdate();
_streamController.checkAndSyncProgress();
}
void _setLandscapeMode(bool state) {
if (state) {
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
SystemChrome.setPreferredOrientations(
[DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
} else {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
@ -317,7 +345,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
children: [
Flexible(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: MediaQuery.of(context).padding.top),
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).padding.top),
child: Text(text,
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
fontSize: 16,
@ -331,7 +360,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
Widget _videoQualityWidget(BuildContext context) {
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()
.map((e) => VideoPrefs(videoTrack: e, isLocal: true))
.toList();
@ -339,7 +369,9 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
if (widget.videos.isNotEmpty && !widget.isLocal) {
for (var video in widget.videos) {
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),
child: Column(
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(
child: textWidget(widget.isLocal ? _firstVid.quality : quality.videoTrack!.title!, selected),
child: textWidget(
widget.isLocal ? _firstVid.quality : quality.videoTrack!.title!,
selected),
onTap: () async {
_video.value = quality;
if (quality.isLocal) {
if (widget.isLocal) {
_player.setVideoTrack(quality.videoTrack!);
} else {
_player
.open(Media(quality.videoTrack!.id, httpHeaders: quality.headers, start: _currentPosition.value));
_player.open(Media(quality.videoTrack!.id,
httpHeaders: quality.headers,
start: _currentPosition.value));
}
} else {
_player
.open(Media(quality.videoTrack!.id, httpHeaders: quality.headers, start: _currentPosition.value));
_player.open(Media(quality.videoTrack!.id,
httpHeaders: quality.headers,
start: _currentPosition.value));
}
Navigator.pop(context);
},
@ -419,8 +457,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
}
Widget _videoSubtitle(BuildContext context, Function(bool) hasSubtitleTrack) {
List<VideoPrefs> videoSubtitle =
_player.state.tracks.subtitle.toList().map((e) => VideoPrefs(isLocal: true, subtitle: e)).toList();
List<VideoPrefs> videoSubtitle = _player.state.tracks.subtitle
.toList()
.map((e) => VideoPrefs(isLocal: true, subtitle: e))
.toList();
List<String> subs = [];
if (widget.videos.isNotEmpty && !widget.isLocal) {
@ -443,7 +483,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
videoSubtitle = videoSubtitle
.map((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;
})
.toList()
@ -451,11 +494,16 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
.toList();
videoSubtitle.sort((a, b) => a.title!.compareTo(b.title!));
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 = [];
for (var element in videoSubtitle) {
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.subtitle?.title ??
element.subtitle?.language ??
@ -470,9 +518,17 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 12),
child: Column(
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");
return GestureDetector(
onTap: () {
@ -489,8 +545,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
}
Widget _videoAudios(BuildContext context) {
List<VideoPrefs> videoAudio =
_player.state.tracks.audio.toList().map((e) => VideoPrefs(isLocal: true, audio: e)).toList();
List<VideoPrefs> videoAudio = _player.state.tracks.audio
.toList()
.map((e) => VideoPrefs(isLocal: true, audio: e))
.toList();
List<String> audios = [];
if (widget.videos.isNotEmpty && !widget.isLocal) {
@ -498,7 +556,9 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
for (var audio in video.audios ?? []) {
if (!audios.contains(audio.file)) {
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!);
}
}
@ -508,7 +568,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
videoAudio = videoAudio
.map((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;
})
.toList()
@ -520,8 +583,13 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 12),
child: Column(
children: videoAudio.toSet().toList().map((aud) {
final title = aud.title ?? aud.audio?.title ?? aud.audio?.language ?? aud.audio?.channels ?? "None";
final selected = (aud.audio == audio) || (audio.id == "no" && title == "None");
final title = aud.title ??
aud.audio?.title ??
aud.audio?.language ??
aud.audio?.channels ??
"None";
final selected =
(aud.audio == audio) || (audio.id == "no" && title == "None");
return GestureDetector(
onTap: () {
Navigator.pop(context);
@ -542,8 +610,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
void _togglePlaybackSpeed() {
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) {
_setPlaybackSpeed(allowedSpeeds[allowedSpeeds.indexOf(_playbackSpeed.value) + 1]);
if (allowedSpeeds.indexOf(_playbackSpeed.value) <
allowedSpeeds.length - 1) {
_setPlaybackSpeed(
allowedSpeeds[allowedSpeeds.indexOf(_playbackSpeed.value) + 1]);
} else {
_setPlaybackSpeed(allowedSpeeds[0]);
}
@ -576,20 +646,26 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
}
Widget _seekToWidget() {
final defaultSkipIntroLength = ref.watch(defaultSkipIntroLengthStateProvider);
final defaultSkipIntroLength =
ref.watch(defaultSkipIntroLengthStateProvider);
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: SizedBox(
height: 35,
child: ElevatedButton(
onPressed: () async {
_tempPosition.value = Duration(seconds: defaultSkipIntroLength + _currentPosition.value.inSeconds);
await _player.seek(Duration(seconds: _currentPosition.value.inSeconds + defaultSkipIntroLength));
_tempPosition.value = Duration(
seconds: defaultSkipIntroLength +
_currentPosition.value.inSeconds);
await _player.seek(Duration(
seconds: _currentPosition.value.inSeconds +
defaultSkipIntroLength));
_tempPosition.value = null;
},
child: Padding(
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();
}),
IconButton(
icon: const Icon(Icons.fit_screen_outlined, color: Colors.white),
icon: const Icon(Icons.fit_screen_outlined,
color: Colors.white),
onPressed: () async {
_changeFitLabel(ref);
},
@ -644,7 +721,9 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
_setLandscapeMode(!snapshot);
_enterFullScreen.value = !snapshot;
},
icon: Icon(snapshot ? Icons.fullscreen_exit : Icons.fullscreen),
icon: Icon(snapshot
? Icons.fullscreen_exit
: Icons.fullscreen),
iconSize: 25,
color: Colors.white,
);
@ -661,7 +740,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
Widget _desktopBottomButtonBar(BuildContext context) {
bool hasPrevEpisode = _streamController.getEpisodeIndex().$1 + 1 !=
_streamController.getEpisodesLength(_streamController.getEpisodeIndex().$2);
_streamController
.getEpisodesLength(_streamController.getEpisodeIndex().$2);
bool hasNextEpisode = _streamController.getEpisodeIndex().$1 != 0;
final skipDuration = ref.watch(defaultDoubleTapToSkipLengthStateProvider);
return Column(
@ -675,7 +755,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
if (hasPrevEpisode)
IconButton(
onPressed: () {
pushToNewEpisode(context, _streamController.getPrevEpisode());
pushToNewEpisode(
context, _streamController.getPrevEpisode());
},
icon: const Icon(
Icons.skip_previous,
@ -688,7 +769,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
if (hasNextEpisode)
IconButton(
onPressed: () async {
pushToNewEpisode(context, _streamController.getNextEpisode());
pushToNewEpisode(
context, _streamController.getNextEpisode());
},
icon: const Icon(Icons.skip_next, color: Colors.white),
),
@ -697,8 +779,12 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
width: 50,
child: IconButton(
onPressed: () async {
_tempPosition.value = Duration(seconds: skipDuration - _currentPosition.value.inSeconds);
await _player.seek(Duration(seconds: _currentPosition.value.inSeconds - skipDuration));
_tempPosition.value = Duration(
seconds:
skipDuration - _currentPosition.value.inSeconds);
await _player.seek(Duration(
seconds:
_currentPosition.value.inSeconds - skipDuration));
_tempPosition.value = null;
},
icon: Stack(
@ -716,7 +802,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
padding: const EdgeInsets.only(top: 2),
child: Text(
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,
child: IconButton(
onPressed: () async {
_tempPosition.value = Duration(seconds: skipDuration + _currentPosition.value.inSeconds);
await _player.seek(Duration(seconds: _currentPosition.value.inSeconds + skipDuration));
_tempPosition.value = Duration(
seconds:
skipDuration + _currentPosition.value.inSeconds);
await _player.seek(Duration(
seconds:
_currentPosition.value.inSeconds + skipDuration));
_tempPosition.value = null;
},
icon: Stack(
@ -748,7 +839,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
padding: const EdgeInsets.only(top: 2),
child: Text(
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(
valueListenable: _tempPosition,
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();
}),
IconButton(
icon: const Icon(Icons.fit_screen_outlined, color: Colors.white),
icon: const Icon(Icons.fit_screen_outlined,
color: Colors.white),
onPressed: () async {
_changeFitLabel(ref);
},
@ -810,7 +904,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
valueListenable: _enterFullScreen,
builder: (context, fullScreen, _) {
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(
children: [
BackButton(
@ -825,7 +922,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
}
}
} else {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
if (mounted) {
Navigator.pop(context);
}
@ -839,7 +937,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
width: context.width(0.8),
child: Text(
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,
),
),
@ -848,7 +947,9 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
child: Text(
widget.episode.name!,
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,
),
),
@ -924,7 +1025,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
void _resize(BoxFit fit) async {
await Future.delayed(const Duration(milliseconds: 100));
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(
children: [
Video(
subtitleViewConfiguration: SubtitleViewConfiguration(visible: false, style: subtileTextStyle(ref)),
subtitleViewConfiguration: SubtitleViewConfiguration(
visible: false, style: subtileTextStyle(ref)),
fit: fit,
key: _key,
controls: (state) => _isDesktop
@ -976,8 +1079,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
builder: (context, value, child) {
if (_hasOpeningSkip || _hasEndingSkip) {
if (_hasOpeningSkip) {
if (_openingResult!.interval!.startTime!.ceil() <= value.inSeconds &&
_openingResult!.interval!.endTime!.toInt() > value.inSeconds) {
if (_openingResult!.interval!.startTime!.ceil() <=
value.inSeconds &&
_openingResult!.interval!.endTime!.toInt() >
value.inSeconds) {
_showAniSkipOpeningButton.value = true;
_showAniSkipEndingButton.value = false;
} else {
@ -985,8 +1090,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
}
}
if (_hasEndingSkip) {
if (_endingResult!.interval!.startTime!.ceil() <= value.inSeconds &&
_endingResult!.interval!.endTime!.toInt() > value.inSeconds) {
if (_endingResult!.interval!.startTime!.ceil() <=
value.inSeconds &&
_endingResult!.interval!.endTime!.toInt() >
value.inSeconds) {
_showAniSkipEndingButton.value = true;
_showAniSkipOpeningButton.value = false;
}
@ -995,9 +1102,12 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
}
}
return Consumer(builder: (context, ref, _) {
late final enableAniSkip = ref.watch(enableAniSkipStateProvider);
late final enableAutoSkip = ref.watch(enableAutoSkipStateProvider);
late final aniSkipTimeoutLength = ref.watch(aniSkipTimeoutLengthStateProvider);
late final enableAniSkip =
ref.watch(enableAniSkipStateProvider);
late final enableAutoSkip =
ref.watch(enableAutoSkipStateProvider);
late final aniSkipTimeoutLength =
ref.watch(aniSkipTimeoutLengthStateProvider);
return ValueListenableBuilder(
valueListenable: _showAniSkipOpeningButton,
builder: (context, showAniSkipOpENINGButton, child) {
@ -1055,11 +1165,13 @@ Widget seekIndicatorTextWidget(Duration duration, Duration currentPosition) {
children: [
Text(
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(
"[${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;
bool isLocal;
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) {
return isInFilterList ? getAnime().getFilteredChapterList().length : getAnime().chapters.length;
return isInFilterList
? getAnime().getFilteredChapterList().length
: getAnime().chapters.length;
}
Duration geTCurrentPosition() {
if (incognitoMode) return Duration.zero;
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() {
@ -122,7 +126,8 @@ class AnimeStreamController extends _$AnimeStreamController {
});
History? history;
final empty = isar.historys.filter().mangaIdEqualTo(getAnime().id).isEmptySync();
final empty =
isar.historys.filter().mangaIdEqualTo(getAnime().id).isEmptySync();
if (empty) {
history = History(
@ -132,7 +137,10 @@ class AnimeStreamController extends _$AnimeStreamController {
chapterId: episode.id)
..chapter.value = episode;
} else {
history = (isar.historys.filter().mangaIdEqualTo(getAnime().id).findFirstSync())!
history = (isar.historys
.filter()
.mangaIdEqualTo(getAnime().id)
.findFirstSync())!
..chapterId = episode.id
..chapter.value = episode
..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 (incognitoMode) return;
final markEpisodeAsSeenType = ref.watch(markEpisodeAsSeenTypeStateProvider);
final isWatch = totalDuration != null && totalDuration != Duration.zero && duration != Duration.zero
? duration.inSeconds >= ((totalDuration.inSeconds * markEpisodeAsSeenType) / 100).ceil()
final isWatch = totalDuration != null &&
totalDuration != Duration.zero &&
duration != Duration.zero
? duration.inSeconds >=
((totalDuration.inSeconds * markEpisodeAsSeenType) / 100).ceil()
: false;
if (isWatch || save) {
final ep = episode;
isar.writeTxnSync(() {
ep.isRead = isWatch;
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);
});
if (isWatch) {
@ -172,10 +186,18 @@ class AnimeStreamController extends _$AnimeStreamController {
}
(int, int)? _getTrackId() {
final malId =
isar.tracks.filter().syncIdEqualTo(1).mangaIdEqualTo(episode.manga.value!.id!).findFirstSync()?.mediaId;
final aniId =
isar.tracks.filter().syncIdEqualTo(2).mangaIdEqualTo(episode.manga.value!.id!).findFirstSync()?.mediaId;
final malId = isar.tracks
.filter()
.syncIdEqualTo(1)
.mangaIdEqualTo(episode.manga.value!.id!)
.findFirstSync()
?.mediaId;
final aniId = isar.tracks
.filter()
.syncIdEqualTo(2)
.mangaIdEqualTo(episode.manga.value!.id!)
.findFirstSync()
?.mediaId;
return switch (malId) {
!= null => (malId, 1),
== 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));
if (ref.watch(enableAniSkipStateProvider)) {
final id = _getTrackId();
if (id != null) {
final res = await ref
.read(aniSkipProvider.notifier)
.getResult(id, ChapterRecognition().parseChapterNumber(episode.manga.value!.name!, episode.name!), 0);
final res = await ref.read(aniSkipProvider.notifier).getResult(
id,
ChapterRecognition()
.parseChapterNumber(episode.manga.value!.name!, episode.name!),
0);
result.call(res ?? []);
return res;
}

View file

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

View file

@ -20,14 +20,18 @@ class AniSkipCountDownButton extends ConsumerStatefulWidget {
required this.timeoutLength});
@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;
@override
void initState() {
_controller = AnimationController(vsync: this, duration: Duration(seconds: widget.timeoutLength))..forward();
_controller = AnimationController(
vsync: this, duration: Duration(seconds: widget.timeoutLength))
..forward();
super.initState();
if (widget.active) {
if (widget.autoSkip) {
@ -50,7 +54,8 @@ class _AniSkipCountDownButtonState extends ConsumerState<AniSkipCountDownButton>
_isCompleted = true;
});
_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;
@ -72,7 +77,8 @@ class _AniSkipCountDownButtonState extends ConsumerState<AniSkipCountDownButton>
padding: const EdgeInsets.symmetric(horizontal: 40),
child: MaterialButton(
padding: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
onPressed: () {
_seekTo();
},
@ -103,15 +109,21 @@ class _AniSkipCountDownButtonState extends ConsumerState<AniSkipCountDownButton>
),
Positioned.fill(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
padding:
const EdgeInsets.symmetric(horizontal: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisAlignment:
MainAxisAlignment.spaceAround,
children: [
Text(
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()),
],
),

View file

@ -10,7 +10,12 @@ class CustomSeekBar extends StatefulWidget {
final Function(Duration)? onSeekStart;
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
CustomSeekBarState createState() => CustomSeekBarState();
@ -64,7 +69,8 @@ class CustomSeekBarState extends State<CustomSeekBar> {
width: 70,
child: Center(
child: Text(
(widget.delta ?? tempPosition ?? position).label(reference: duration),
(widget.delta ?? tempPosition ?? position)
.label(reference: duration),
style: const TextStyle(
height: 1.0,
fontSize: 12.0,
@ -79,10 +85,15 @@ class CustomSeekBarState extends State<CustomSeekBar> {
),
child: Slider(
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),
onChanged: (value) {
widget.onSeekStart?.call(Duration(milliseconds: value.toInt() - position.inMilliseconds));
widget.onSeekStart?.call(Duration(
milliseconds: value.toInt() - position.inMilliseconds));
if (mounted) {
setState(() {
tempPosition = Duration(milliseconds: value.toInt());
@ -90,7 +101,8 @@ class CustomSeekBarState extends State<CustomSeekBar> {
}
},
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()));
},
),

View file

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

View file

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

View file

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

View file

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

View file

@ -77,10 +77,12 @@ class _CustomSubtitleViewState extends ConsumerState<CustomSubtitleView> {
return LayoutBuilder(
builder: (context, constraints) {
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 textScaler = widget.configuration.textScaler ?? TextScaler.linear(textScaleFactor);
final textScaler = widget.configuration.textScaler ??
TextScaler.linear(textScaleFactor);
return Material(
color: Colors.transparent,
child: AnimatedContainer(
@ -105,19 +107,35 @@ class _CustomSubtitleViewState extends ConsumerState<CustomSubtitleView> {
TextStyle subtileTextStyle(WidgetRef ref) {
final subSets = ref.watch(subtitleSettingsStateProvider);
final borderColor =
Color.fromARGB(subSets.borderColorA!, subSets.borderColorR!, subSets.borderColorG!, subSets.borderColorB!);
final borderColor = Color.fromARGB(subSets.borderColorA!,
subSets.borderColorR!, subSets.borderColorG!, subSets.borderColorB!);
return TextStyle(
fontSize: subSets.fontSize!.toDouble(),
fontWeight: subSets.useBold! ? FontWeight.bold : 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: [
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),
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),
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(
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();
}
class _BrowseScreenState extends ConsumerState<BrowseScreen> with TickerProviderStateMixin {
class _BrowseScreenState extends ConsumerState<BrowseScreen>
with TickerProviderStateMixin {
late TabController _tabBarController;
@override
@ -74,26 +75,33 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen> with TickerProvider
)
: Row(
children: [
if (_tabBarController.index == 2 || _tabBarController.index == 3)
if (_tabBarController.index == 2 ||
_tabBarController.index == 3)
IconButton(
onPressed: () {
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
? IconButton(
splashRadius: 20,
onPressed: () {
if (_tabBarController.index != 1 && _tabBarController.index != 0) {
if (_tabBarController.index != 1 &&
_tabBarController.index != 0) {
setState(() {
_isSearch = true;
});
} else {
context.push('/globalSearch', extra: _tabBarController.index == 0 ? true : false);
context.push('/globalSearch',
extra: _tabBarController.index == 0
? true
: false);
}
},
icon: Icon(
_tabBarController.index == 0 || _tabBarController.index == 1
_tabBarController.index == 0 ||
_tabBarController.index == 1
? Icons.travel_explore_rounded
: Icons.search_rounded,
color: Theme.of(context).hintColor))
@ -118,7 +126,8 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen> with TickerProvider
icon: Icon(
_tabBarController.index == 0 || _tabBarController.index == 1
? Icons.filter_list_sharp
: _tabBarController.index == 2 || _tabBarController.index == 3
: _tabBarController.index == 2 ||
_tabBarController.index == 3
? Icons.translate_rounded
: Icons.help_outline_outlined,
color: Theme.of(context).hintColor)),
@ -132,7 +141,11 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen> with TickerProvider
Tab(text: l10n.anime_sources),
Tab(
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(
@ -187,18 +200,23 @@ Widget _extensionUpdateNumbers(WidgetRef ref, bool isManga) {
.watch(fireImmediately: true),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final entries =
snapshot.data!.where((element) => compareVersions(element.version!, element.versionLast!) < 0).toList();
final entries = snapshot.data!
.where((element) =>
compareVersions(element.version!, element.versionLast!) < 0)
.toList();
return entries.isEmpty
? Container()
: Container(
decoration:
BoxDecoration(borderRadius: BorderRadius.circular(20), color: Theme.of(context).focusColor),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Theme.of(context).focusColor),
child: Padding(
padding: const EdgeInsets.all(5),
child: Text(
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> {
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(
text: source?.sourceCode ?? "",
language: getSourceMode(source),
@ -59,7 +60,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
bool _isLoading = false;
String _errorText = "";
bool _error = false;
final _logsNotifier = ValueNotifier<List<(LoggerLevel, String, DateTime)>>([]);
final _logsNotifier =
ValueNotifier<List<(LoggerLevel, String, DateTime)>>([]);
late final _logStreamController = Logger.logStreamController;
final _scrollController = ScrollController();
@override
@ -96,13 +98,15 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
),
const Spacer(),
ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: context.primaryColor),
style: ElevatedButton.styleFrom(
backgroundColor: context.primaryColor),
onPressed: () {
Navigator.pop(context, 'filter');
},
child: Text(
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(
textStyle: TextStyle(
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,
),
@ -165,7 +170,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
source?.sourceCode = a;
});
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),
isExpanded: true,
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)
.map((e) => DropdownMenuItem(
value: e.$2,
child: Text(e.$1, style: const TextStyle(fontSize: 13)),
child: Text(e.$1,
style: const TextStyle(fontSize: 13)),
))
.toList(),
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) {
_page = int.tryParse(v) ?? 1;
}),
@ -204,8 +214,11 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
_textEditing("Query", context, "ex: one piece", (v) {
_query = v;
}),
if (_serviceIndex == 3 || _serviceIndex == 4 || _serviceIndex == 5)
_textEditing("Url", context, "ex: url of the entry", (v) {
if (_serviceIndex == 3 ||
_serviceIndex == 4 ||
_serviceIndex == 5)
_textEditing("Url", context, "ex: url of the entry",
(v) {
_url = v;
}),
Padding(
@ -219,7 +232,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
source?.sourceCode = controller.text;
});
if (source != null && mounted) {
isar.writeTxnSync(() => isar.sources.putSync(source!));
isar.writeTxnSync(
() => isar.sources.putSync(source!));
}
setState(() {
result = null;
@ -228,36 +242,52 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
_errorText = "";
});
if (source != null) {
final service = getExtensionService(source!);
final service =
getExtensionService(source!);
try {
if (_serviceIndex == 0) {
final getManga =
await ref.watch(getPopularProvider(source: source!, page: _page).future);
final getManga = await ref.watch(
getPopularProvider(
source: source!,
page: _page)
.future);
result = getManga!.toJson();
} else if (_serviceIndex == 1) {
final getManga = await ref
.watch(getLatestUpdatesProvider(source: source!, page: _page).future);
final getManga = await ref.watch(
getLatestUpdatesProvider(
source: source!,
page: _page)
.future);
result = getManga!.toJson();
} else if (_serviceIndex == 2) {
final getManga = await ref.watch(searchProvider(
source: source!, query: _query, page: _page, filterList: filterList)
.future);
final getManga = await ref.watch(
searchProvider(
source: source!,
query: _query,
page: _page,
filterList: filterList)
.future);
result = getManga!.toJson();
} else if (_serviceIndex == 3) {
final getManga =
await ref.watch(getDetailProvider(source: source!, url: _url).future);
final getManga = await ref.watch(
getDetailProvider(
source: source!,
url: _url)
.future);
result = getManga.toJson();
} else if (_serviceIndex == 4) {
result = {
"pages": (await service.getPageList(_url))
"pages": (await service
.getPageList(_url))
.map((e) => e.toJson())
.toList(),
};
} else {
result = (await service.getVideoList(_url))
.map((e) => e.toJson())
.toList();
result =
(await service.getVideoList(_url))
.map((e) => e.toJson())
.toList();
}
if (mounted) {
setState(() {
@ -298,7 +328,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
if (filters.isEmpty) {
filters = filterList;
}
final res = await filterDialog(context);
final res =
await filterDialog(context);
if (res == 'filter' && mounted) {
setState(() {
result = null;
@ -306,9 +337,13 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
_error = false;
_errorText = "";
});
final getManga = await ref.watch(searchProvider(
source: source!, query: _query, page: _page, filterList: filters)
.future);
final getManga = await ref.watch(
searchProvider(
source: source!,
query: _query,
page: _page,
filterList: filters)
.future);
result = getManga!.toJson();
setState(() {
_isLoading = false;
@ -331,22 +366,26 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
child: _error
? SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(_errorText),
],
),
)
: _isLoading
? const Center(child: CircularProgressIndicator())
? const Center(
child: CircularProgressIndicator())
: result != null
? JsonConfig(
data: JsonConfigData(
gap: 100,
style: const JsonStyleScheme(
quotation: JsonQuotation.same('"'),
quotation:
JsonQuotation.same('"'),
openAtStart: false,
arrow: Icon(Icons.arrow_forward),
arrow:
Icon(Icons.arrow_forward),
depth: 4,
),
color: const JsonColorScheme(),
@ -379,7 +418,10 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
itemBuilder: (context, index) {
final value = logs[index];
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(
padding: const EdgeInsets.all(4),
child: TextFormField(
@ -402,9 +445,12 @@ Widget _textEditing(String label, BuildContext context, String hintText, void Fu
isDense: true,
filled: true,
fillColor: Colors.transparent,
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: context.dynamicThemeColor)),
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: context.dynamicThemeColor)),
border: OutlineInputBorder(borderSide: BorderSide(color: context.dynamicThemeColor))),
enabledBorder: 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> {
late Source source = widget.source;
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
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
return Scaffold(
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(
child: Column(
children: [
@ -41,7 +44,9 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
padding: const EdgeInsets.only(top: 20),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).secondaryHeaderColor.withValues(alpha: 0.5),
color: Theme.of(context)
.secondaryHeaderColor
.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(10)),
child: widget.source.iconUrl!.isEmpty
? const Icon(Icons.source_outlined, size: 140)
@ -65,7 +70,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
padding: const EdgeInsets.all(12),
child: Text(
widget.source.name!,
style: const TextStyle(fontSize: 23, fontWeight: FontWeight.bold),
style:
const TextStyle(fontSize: 23, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
@ -73,7 +79,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
padding: const EdgeInsets.all(8.0),
child: Container(
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(
padding: const EdgeInsets.all(20),
child: Row(
@ -83,7 +90,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
children: [
Text(
widget.source.version!,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
style: const TextStyle(
fontSize: 16, fontWeight: FontWeight.bold),
),
Text(
l10n.version,
@ -95,7 +103,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
children: [
Text(
completeLanguageName(widget.source.lang!),
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
style: const TextStyle(
fontSize: 16, fontWeight: FontWeight.bold),
),
Text(
l10n.language,
@ -116,16 +125,19 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0),
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
elevation: 0,
shadowColor: Colors.transparent),
onPressed: () async {
final res = await context.push('/codeEditor', extra: source.id);
final res =
await context.push('/codeEditor', extra: source.id);
if (res != null && mounted) {
setState(() {
source = res as Source;
sourcePreference = getSourcePreference(source: source)
.map((e) => getSourcePreferenceEntry(e.key!, source.id!))
.map((e) =>
getSourcePreferenceEntry(e.key!, source.id!))
.toList();
});
}
@ -137,7 +149,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Text(
l10n.edit_code,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
),
const Icon(Icons.code)
@ -153,7 +166,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0),
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
elevation: 0,
shadowColor: Colors.transparent),
onPressed: () async {
@ -164,7 +178,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
padding: EdgeInsets.symmetric(horizontal: 10),
child: Text(
"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(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0),
side: BorderSide(color: context.primaryColor, width: 0.3),
side:
BorderSide(color: context.primaryColor, width: 0.3),
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
elevation: 0,
shadowColor: Colors.transparent),
onPressed: () {
@ -189,7 +206,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
title: Text(
widget.source.name!,
),
content: Text(l10n.uninstall_extension(widget.source.name!)),
content: Text(l10n
.uninstall_extension(widget.source.name!)),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
@ -204,13 +222,15 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
),
TextButton(
onPressed: () {
final sourcePrefsIds = isar.sourcePreferences
final sourcePrefsIds = isar
.sourcePreferences
.filter()
.sourceIdEqualTo(source.id!)
.findAllSync()
.map((e) => e.id!)
.toList();
final sourcePrefsStringIds = isar.sourcePreferenceStringValues
final sourcePrefsStringIds = isar
.sourcePreferenceStringValues
.filter()
.sourceIdEqualTo(source.id!)
.findAllSync()
@ -218,15 +238,19 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
.toList();
isar.writeTxnSync(() {
if (source.isObsolete ?? false) {
isar.sources.deleteSync(widget.source.id!);
isar.sources.deleteSync(
widget.source.id!);
} else {
isar.sources.putSync(widget.source
..sourceCode = ""
..isAdded = false
..isPinned = false);
}
isar.sourcePreferences.deleteAllSync(sourcePrefsIds);
isar.sourcePreferenceStringValues.deleteAllSync(sourcePrefsStringIds);
isar.sourcePreferences
.deleteAllSync(sourcePrefsIds);
isar.sourcePreferenceStringValues
.deleteAllSync(
sourcePrefsStringIds);
});
Navigator.pop(ctx);
@ -241,11 +265,13 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
},
child: Text(
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) {
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) {
isar.sources.putSync(source..isActive = enable);
}
@ -48,7 +53,12 @@ class ExtensionsLang extends ConsumerWidget {
],
),
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) {
List<Source>? entries = snapshot.hasData ? snapshot.data : [];
final languages = entries!.map((e) => e.lang!).toSet().toList();
@ -70,7 +80,9 @@ class ExtensionsLang extends ConsumerWidget {
});
},
value: entries
.where((element) => element.lang!.toLowerCase() == lang.toLowerCase() && element.isActive!)
.where((element) =>
element.lang!.toLowerCase() == lang.toLowerCase() &&
element.isActive!)
.isNotEmpty,
);
},

View file

@ -14,7 +14,8 @@ import 'package:mangayomi/modules/browse/extension/widgets/extension_list_tile_w
class ExtensionScreen extends ConsumerStatefulWidget {
final bool isManga;
final String query;
const ExtensionScreen({required this.query, required this.isManga, super.key});
const ExtensionScreen(
{required this.query, required this.isManga, super.key});
@override
ConsumerState<ExtensionScreen> createState() => _ExtensionScreenState();
@ -24,7 +25,8 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
final controller = ScrollController();
@override
Widget build(BuildContext context) {
final streamExtensions = ref.watch(getExtensionsStreamProvider(widget.isManga));
final streamExtensions =
ref.watch(getExtensionsStreamProvider(widget.isManga));
if (widget.isManga) {
ref.watch(fetchMangaSourcesListProvider(id: null, reFresh: false));
} else {
@ -33,15 +35,21 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
final l10n = l10nLocalizations(context)!;
return RefreshIndicator(
onRefresh: () => widget.isManga
? ref.refresh(fetchMangaSourcesListProvider(id: null, reFresh: true).future)
: ref.refresh(fetchAnimeSourcesListProvider(id: null, reFresh: true).future),
? ref.refresh(
fetchMangaSourcesListProvider(id: null, reFresh: true).future)
: ref.refresh(
fetchAnimeSourcesListProvider(id: null, reFresh: true).future),
child: Padding(
padding: const EdgeInsets.only(top: 10),
child: streamExtensions.when(
data: (data) {
data = widget.query.isEmpty
? 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
.where((element) => element.version == element.versionLast!)
@ -51,8 +59,10 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
.where((element) => element.version == element.versionLast!)
.where((element) => element.isAdded!)
.toList();
final updateEntries =
data.where((element) => compareVersions(element.version!, element.versionLast!) < 0).toList();
final updateEntries = data
.where((element) =>
compareVersions(element.version!, element.versionLast!) < 0)
.toList();
return Scrollbar(
interactive: true,
controller: controller,
@ -71,16 +81,21 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
children: [
Text(
l10n.update_pending,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13),
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
),
ElevatedButton(
onPressed: () async {
for (var source in updateEntries) {
source.isManga!
? await ref
.watch(fetchMangaSourcesListProvider(id: source.id, reFresh: true).future)
: await ref
.watch(fetchAnimeSourcesListProvider(id: source.id, reFresh: true).future);
? await ref.watch(
fetchMangaSourcesListProvider(
id: source.id, reFresh: true)
.future)
: await ref.watch(
fetchAnimeSourcesListProvider(
id: source.id, reFresh: true)
.future);
}
},
child: Text(l10n.update_all))
@ -92,8 +107,10 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
source: element,
);
},
groupComparator: (group1, group2) => group1.compareTo(group2),
itemComparator: (item1, item2) => item1.name!.compareTo(item2.name!),
groupComparator: (group1, group2) =>
group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC,
),
SliverGroupedListView<Source, String>(
@ -103,26 +120,31 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text(
l10n.installed,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13),
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
),
),
itemBuilder: (context, Source element) {
return ExtensionListTileWidget(source: element);
},
groupComparator: (group1, group2) => group1.compareTo(group2),
itemComparator: (item1, item2) => item1.name!.compareTo(item2.name!),
groupComparator: (group1, group2) =>
group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC,
),
SliverGroupedListView<Source, String>(
elements: notInstalledEntries,
groupBy: (element) => completeLanguageName(element.lang!.toLowerCase()),
groupBy: (element) =>
completeLanguageName(element.lang!.toLowerCase()),
groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(left: 12),
child: Row(
children: [
Text(
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,
);
},
groupComparator: (group1, group2) => group1.compareTo(group2),
itemComparator: (item1, item2) => item1.name!.compareTo(item2.name!),
groupComparator: (group1, group2) =>
group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC,
),
],
@ -144,9 +168,11 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
child: ElevatedButton(
onPressed: () {
if (widget.isManga) {
ref.invalidate(fetchMangaSourcesListProvider(id: null, reFresh: true));
ref.invalidate(
fetchMangaSourcesListProvider(id: null, reFresh: true));
} else {
ref.invalidate(fetchAnimeSourcesListProvider(id: null, reFresh: true));
ref.invalidate(
fetchAnimeSourcesListProvider(id: null, reFresh: true));
}
},
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';
void setPreferenceSetting(SourcePreference sourcePreference, Source source) {
final sourcePref =
isar.sourcePreferences.filter().sourceIdEqualTo(source.id).keyEqualTo(sourcePreference.key).findFirstSync();
final sourcePref = isar.sourcePreferences
.filter()
.sourceIdEqualTo(source.id)
.keyEqualTo(sourcePreference.key)
.findFirstSync();
isar.writeTxnSync(() {
if (sourcePref != null) {
isar.sourcePreferences.putSync(sourcePreference);
@ -33,21 +36,30 @@ getPreferenceValue(int sourceId, String key) {
}
SourcePreference getSourcePreferenceEntry(String key, int sourceId) {
SourcePreference? sourcePreference =
isar.sourcePreferences.filter().sourceIdEqualTo(sourceId).keyEqualTo(key).findFirstSync();
SourcePreference? sourcePreference = isar.sourcePreferences
.filter()
.sourceIdEqualTo(sourceId)
.keyEqualTo(key)
.findFirstSync();
if (sourcePreference == null) {
final source = isar.sources.getSync(sourceId)!;
sourcePreference = getSourcePreference(source: source)
.firstWhere((element) => element.key == key, orElse: () => throw "Error when getting source preference");
sourcePreference = getSourcePreference(source: source).firstWhere(
(element) => element.key == key,
orElse: () => throw "Error when getting source preference");
setPreferenceSetting(sourcePreference, source);
}
return sourcePreference;
}
String getSourcePreferenceStringValue(int sourceId, String key, String defaultValue) {
SourcePreferenceStringValue? sourcePreferenceStringValue =
isar.sourcePreferenceStringValues.filter().sourceIdEqualTo(sourceId).keyEqualTo(key).findFirstSync();
String getSourcePreferenceStringValue(
int sourceId, String key, String defaultValue) {
SourcePreferenceStringValue? sourcePreferenceStringValue = isar
.sourcePreferenceStringValues
.filter()
.sourceIdEqualTo(sourceId)
.keyEqualTo(key)
.findFirstSync();
if (sourcePreferenceStringValue == null) {
setSourcePreferenceStringValue(sourceId, key, defaultValue);
return defaultValue;
@ -57,8 +69,11 @@ String getSourcePreferenceStringValue(int sourceId, String key, String defaultVa
}
void setSourcePreferenceStringValue(int sourceId, String key, String value) {
final sourcePref =
isar.sourcePreferenceStringValues.filter().sourceIdEqualTo(sourceId).keyEqualTo(key).findFirstSync();
final sourcePref = isar.sourcePreferenceStringValues
.filter()
.sourceIdEqualTo(sourceId)
.keyEqualTo(key)
.findFirstSync();
isar.writeTxnSync(() {
if (sourcePref != null) {
isar.sourcePreferenceStringValues.putSync(sourcePref..value = value);

View file

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

View file

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

View file

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

View file

@ -38,7 +38,12 @@ class _GlobalSearchScreenState extends ConsumerState<GlobalSearchScreen> {
@override
Widget build(BuildContext context) {
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
.filter()
.idIsNotNull()
@ -123,7 +128,8 @@ class _SourceSearchScreenState extends State<SourceSearchScreen> {
_init() async {
try {
_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) {
setState(() {
_isLoading = false;
@ -214,7 +220,8 @@ class MangaGlobalImageCard extends ConsumerStatefulWidget {
});
@override
ConsumerState<MangaGlobalImageCard> createState() => _MangaGlobalImageCardState();
ConsumerState<MangaGlobalImageCard> createState() =>
_MangaGlobalImageCardState();
}
class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
@ -251,16 +258,20 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
child: Column(children: [
Builder(
builder: (context) {
if (hasData && snapshot.data!.first.customCoverImage != null) {
return Image.memory(snapshot.data!.first.customCoverImage as Uint8List);
if (hasData &&
snapshot.data!.first.customCoverImage != null) {
return Image.memory(snapshot
.data!.first.customCoverImage as Uint8List);
}
return ClipRRect(
borderRadius: BorderRadius.circular(5),
child: cachedNetworkImage(
headers: ref
.watch(headersProvider(source: widget.source.name!, lang: widget.source.lang!)),
headers: ref.watch(headersProvider(
source: widget.source.name!,
lang: widget.source.lang!)),
imageUrl: toImgUrl(hasData
? snapshot.data!.first.customCoverFromTracker ??
? snapshot.data!.first
.customCoverFromTracker ??
snapshot.data!.first.imageUrl ??
""
: getMangaDetail.imageUrl ?? ""),
@ -281,7 +292,9 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
Container(
width: 110,
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!)
Positioned(
@ -289,7 +302,8 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
left: 0,
child: Padding(
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>(
elements: entries,
groupBy: (element) => element.lang!,
groupSeparatorBuilder: (String groupByValue) => SwitchListTile(
groupSeparatorBuilder: (String groupByValue) =>
SwitchListTile(
value: entries
.where((element) =>
element.lang!.toLowerCase() == groupByValue &&
@ -49,19 +50,24 @@ class SourcesFilterScreen extends ConsumerWidget {
isar.writeTxnSync(() {
for (var source in entries) {
if (source.lang!.toLowerCase() == groupByValue) {
isar.sources.putSync(source..isActive = val == true);
isar.sources
.putSync(source..isActive = val == true);
}
}
});
},
title: Text(
completeLanguageName(groupByValue),
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13),
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
),
),
itemBuilder: (context, Source element) {
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) {
return Container();
}
@ -70,7 +76,9 @@ class SourcesFilterScreen extends ConsumerWidget {
height: 37,
width: 37,
decoration: BoxDecoration(
color: Theme.of(context).secondaryHeaderColor.withValues(alpha: 0.5),
color: Theme.of(context)
.secondaryHeaderColor
.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(5)),
child: element.iconUrl!.isEmpty
? const Icon(Icons.source_outlined)
@ -97,8 +105,10 @@ class SourcesFilterScreen extends ConsumerWidget {
title: Text(element.name!),
);
},
groupComparator: (group1, group2) => group1.compareTo(group2),
itemComparator: (item1, item2) => item1.name!.compareTo(item2.name!),
groupComparator: (group1, group2) =>
group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC,
),
],

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -8,17 +8,23 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'add_torrent.g.dart';
@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;
if (url == null) {
result =
await FilePicker.platform.pickFiles(allowMultiple: true, type: FileType.custom, allowedExtensions: ['torrent']);
result = await FilePicker.platform.pickFiles(
allowMultiple: true,
type: FileType.custom,
allowedExtensions: ['torrent']);
}
if (result != null || url != null) {
String torrentName = "";
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 manga = mManga ??
@ -43,7 +49,8 @@ Future addTorrentFromUrlOrFromFile(Ref ref, Manga? mManga, {required bool init,
manga.customCoverImage = null;
isar.writeTxnSync(() {
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);
chapters.manga.saveSync();
});
@ -57,7 +64,9 @@ Future addTorrentFromUrlOrFromFile(Ref ref, Manga? mManga, {required bool init,
isar.writeTxnSync(() {
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);
chapters.manga.saveSync();
});
@ -68,10 +77,6 @@ Future addTorrentFromUrlOrFromFile(Ref ref, Manga? mManga, {required bool init,
}
String _getName(String path) {
return path
.split('/')
.last
.split("\\")
.last
.replaceAll(RegExp(r'\.(mp4|mov|avi|flv|wmv|mpeg|mkv|cbz|zip|cbt|tar|torrent)'), '');
return path.split('/').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';
@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
? isar.mangas
.filter()
@ -28,7 +29,8 @@ Stream<List<Manga>> getAllMangaStream(Ref ref, {required int? categoryId, requir
}
@riverpod
Stream<List<Manga>> getAllMangaWithoutCategoriesStream(Ref ref, {required bool? isManga}) async* {
Stream<List<Manga>> getAllMangaWithoutCategoriesStream(Ref ref,
{required bool? isManga}) async* {
yield* isar.mangas
.filter()
.idIsNotNull()
@ -47,5 +49,10 @@ Stream<List<Manga>> getAllMangaWithoutCategoriesStream(Ref ref, {required bool?
@riverpod
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;
}
String getLibraryDisplayTypeName(DisplayType displayType, BuildContext context) {
String getLibraryDisplayTypeName(
DisplayType displayType, BuildContext context) {
final l10n = context.l10n;
return switch (displayType) {
DisplayType.compactGrid => l10n.compact_grid,
@ -74,13 +75,18 @@ class LibraryGridSizeState extends _$LibraryGridSizeState {
@riverpod
class MangaFilterDownloadedState extends _$MangaFilterDownloadedState {
@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();
return getType();
}
int getType() {
return isManga ? settings.libraryFilterMangasDownloadType! : settings.libraryFilterAnimeDownloadType ?? 0;
return isManga
? settings.libraryFilterMangasDownloadType!
: settings.libraryFilterAnimeDownloadType ?? 0;
}
void setType(int type) {
@ -110,13 +116,18 @@ class MangaFilterDownloadedState extends _$MangaFilterDownloadedState {
@riverpod
class MangaFilterUnreadState extends _$MangaFilterUnreadState {
@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();
return getType();
}
int getType() {
return isManga ? settings.libraryFilterMangasUnreadType! : settings.libraryFilterAnimeUnreadType ?? 0;
return isManga
? settings.libraryFilterMangasUnreadType!
: settings.libraryFilterAnimeUnreadType ?? 0;
}
void setType(int type) {
@ -195,13 +206,18 @@ class MangaFilterUnreadState extends _$MangaFilterUnreadState {
@riverpod
class MangaFilterStartedState extends _$MangaFilterStartedState {
@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();
return getType();
}
int getType() {
return isManga ? settings.libraryFilterMangasStartedType! : settings.libraryFilterAnimeStartedType ?? 0;
return isManga
? settings.libraryFilterMangasStartedType!
: settings.libraryFilterAnimeStartedType ?? 0;
}
void setType(int type) {
@ -280,13 +296,18 @@ class MangaFilterStartedState extends _$MangaFilterStartedState {
@riverpod
class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState {
@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();
return getType();
}
int getType() {
return isManga ? settings.libraryFilterMangasBookMarkedType! : settings.libraryFilterAnimeBookMarkedType ?? 0;
return isManga
? settings.libraryFilterMangasBookMarkedType!
: settings.libraryFilterAnimeBookMarkedType ?? 0;
}
void setType(int type) {
@ -365,16 +386,22 @@ class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState {
@riverpod
class MangasFilterResultState extends _$MangasFilterResultState {
@override
bool build({required List<Manga> mangaList, required bool isManga, required Settings settings}) {
final downloadFilterType =
ref.watch(mangaFilterDownloadedStateProvider(mangaList: mangaList, isManga: isManga, settings: settings));
final unreadFilterType =
ref.watch(mangaFilterUnreadStateProvider(mangaList: mangaList, isManga: isManga, settings: settings));
final startedFilterType =
ref.watch(mangaFilterStartedStateProvider(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;
bool build(
{required List<Manga> mangaList,
required bool isManga,
required Settings settings}) {
final downloadFilterType = ref.watch(mangaFilterDownloadedStateProvider(
mangaList: mangaList, isManga: isManga, settings: settings));
final unreadFilterType = ref.watch(mangaFilterUnreadStateProvider(
mangaList: mangaList, isManga: isManga, settings: settings));
final startedFilterType = ref.watch(mangaFilterStartedStateProvider(
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 {
@override
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) {
@ -403,7 +432,9 @@ class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
@override
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) {
@ -424,7 +455,9 @@ class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
class LibraryLanguageState extends _$LibraryLanguageState {
@override
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) {
@ -445,7 +478,9 @@ class LibraryLanguageState extends _$LibraryLanguageState {
class LibraryLocalSourceState extends _$LibraryLocalSourceState {
@override
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) {
@ -466,7 +501,9 @@ class LibraryLocalSourceState extends _$LibraryLocalSourceState {
class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
@override
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) {
@ -484,7 +521,8 @@ class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
}
@riverpod
class LibraryShowContinueReadingButtonState extends _$LibraryShowContinueReadingButtonState {
class LibraryShowContinueReadingButtonState
extends _$LibraryShowContinueReadingButtonState {
@override
bool build({required bool isManga, required Settings settings}) {
return isManga
@ -510,7 +548,9 @@ class LibraryShowContinueReadingButtonState extends _$LibraryShowContinueReading
class SortLibraryMangaState extends _$SortLibraryMangaState {
@override
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) {
@ -611,7 +651,9 @@ class MangasSetIsReadState extends _$MangasSetIsReadState {
for (var chapter in chapters) {
chapter.isRead = true;
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);
chapter.manga.saveSync();
}
@ -636,7 +678,9 @@ class MangasSetUnReadState extends _$MangasSetUnReadState {
isar.writeTxnSync(() {
for (var chapter in chapters) {
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);
chapter.manga.saveSync();
}

View file

@ -10,11 +10,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'local_archive.g.dart';
@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(
allowMultiple: true,
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) {
final dateNow = DateTime.now().millisecondsSinceEpoch;
final manga = mManga ??
@ -36,8 +39,9 @@ Future importArchivesFromFile(Ref ref, Manga? mManga, {required bool isManga, re
artist: '',
);
for (var file in result.files.reversed.toList()) {
(String, LocalExtensionType, Uint8List, String)? data =
isManga ? await ref.watch(getArchivesDataFromFileProvider(file.path!).future) : null;
(String, LocalExtensionType, Uint8List, String)? data = isManga
? await ref.watch(getArchivesDataFromFileProvider(file.path!).future)
: null;
String name = _getName(file.path!);
if (init) {
@ -46,9 +50,11 @@ Future importArchivesFromFile(Ref ref, Manga? mManga, {required bool isManga, re
isar.writeTxnSync(() {
isar.mangas.putSync(manga);
final chapters =
Chapter(name: isManga ? data!.$1 : name, archivePath: isManga ? data!.$4 : file.path, mangaId: manga.id)
..manga.value = manga;
final chapters = Chapter(
name: isManga ? data!.$1 : name,
archivePath: isManga ? data!.$4 : file.path,
mangaId: manga.id)
..manga.value = manga;
isar.chapters.putSync(chapters);
chapters.manga.saveSync();
});
@ -58,10 +64,6 @@ Future importArchivesFromFile(Ref ref, Manga? mManga, {required bool isManga, re
}
String _getName(String path) {
return path
.split('/')
.last
.split("\\")
.last
.replaceAll(RegExp(r'\.(mp4|mov|avi|flv|wmv|mpeg|mkv|cbz|zip|cbt|tar)'), '');
return path.split('/').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 isManga = widget.isManga;
final gridSize = ref.watch(libraryGridSizeStateProvider(isManga: isManga));
final gridSize =
ref.watch(libraryGridSizeStateProvider(isManga: isManga));
return GridViewWidget(
gridSize: gridSize,
childAspectRatio: widget.isComfortableGrid ? 0.642 : 0.69,
@ -74,12 +75,16 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
),
isComfortableGrid: widget.isComfortableGrid,
image: entry.customCoverImage != null
? MemoryImage(entry.customCoverImage as Uint8List) as ImageProvider
? MemoryImage(entry.customCoverImage as Uint8List)
as ImageProvider
: CustomExtendedNetworkImageProvider(
toImgUrl(entry.customCoverFromTracker ?? entry.imageUrl ?? ""),
toImgUrl(entry.customCoverFromTracker ??
entry.imageUrl ??
""),
headers: entry.isLocalArchive!
? null
: ref.watch(headersProvider(source: entry.source!, lang: entry.lang!)),
: ref.watch(headersProvider(
source: entry.source!, lang: entry.lang!)),
),
onTap: () async {
if (isLongPressed) {
@ -91,15 +96,19 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
lang: entry.lang!,
mangaM: entry,
source: entry.source!);
ref.invalidate(getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga));
ref.invalidate(getAllMangaStreamProvider(categoryId: null, isManga: widget.isManga));
ref.invalidate(getAllMangaWithoutCategoriesStreamProvider(
isManga: widget.isManga));
ref.invalidate(getAllMangaStreamProvider(
categoryId: null, isManga: widget.isManga));
}
},
onLongPress: () {
if (!isLongPressed) {
ref.read(mangasListStateProvider.notifier).update(entry);
ref.read(isLongPressedMangaStateProvider.notifier).update(!isLongPressed);
ref
.read(isLongPressedMangaStateProvider.notifier)
.update(!isLongPressed);
} else {
ref.read(mangasListStateProvider.notifier).update(entry);
}
@ -108,7 +117,9 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
if (!isLongPressed) {
ref.read(mangasListStateProvider.notifier).update(entry);
ref.read(isLongPressedMangaStateProvider.notifier).update(!isLongPressed);
ref
.read(isLongPressedMangaStateProvider.notifier)
.update(!isLongPressed);
} else {
ref.read(mangasListStateProvider.notifier).update(entry);
}
@ -132,14 +143,18 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
Container(
decoration: BoxDecoration(
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,
),
child: Padding(
padding: const EdgeInsets.only(left: 3, right: 3),
padding: const EdgeInsets.only(
left: 3, right: 3),
child: Text(
"Local",
style: TextStyle(color: context.dynamicBlackWhiteColor),
style: TextStyle(
color: context
.dynamicBlackWhiteColor),
),
),
),
@ -150,14 +165,20 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
List nbrDown = [];
if (widget.downloadedChapter) {
isar.txnSync(() {
for (var i = 0; i < entry.chapters.length; i++) {
for (var i = 0;
i < entry.chapters.length;
i++) {
final entries = isar.downloads
.filter()
.idIsNotNull()
.chapterIdEqualTo(entry.chapters.toList()[i].id)
.chapterIdEqualTo(entry
.chapters
.toList()[i]
.id)
.findAllSync();
if (entries.isNotEmpty && entries.first.isDownload!) {
if (entries.isNotEmpty &&
entries.first.isDownload!) {
nbrDown.add(1);
}
}
@ -166,25 +187,42 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
return Row(
children: [
if (nbrDown.isNotEmpty && widget.downloadedChapter)
if (nbrDown.isNotEmpty &&
widget.downloadedChapter)
Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(3), bottomLeft: Radius.circular(3)),
color: Theme.of(context).secondaryHeaderColor,
borderRadius:
const BorderRadius.only(
topLeft:
Radius.circular(
3),
bottomLeft:
Radius.circular(
3)),
color: Theme.of(context)
.secondaryHeaderColor,
),
child: Padding(
padding: const EdgeInsets.only(left: 3, right: 3),
padding:
const EdgeInsets.only(
left: 3, right: 3),
child: Text(
nbrDown.length.toString(),
),
),
),
Padding(
padding: const EdgeInsets.only(left: 3),
padding: const EdgeInsets.only(
left: 3),
child: Text(
entry.chapters.where((element) => !element.isRead!).length.toString(),
style: TextStyle(color: context.dynamicBlackWhiteColor),
entry.chapters
.where((element) =>
!element.isRead!)
.length
.toString(),
style: TextStyle(
color: context
.dynamicBlackWhiteColor),
),
),
],
@ -207,14 +245,17 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
child: Container(
decoration: BoxDecoration(
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,
),
child: Padding(
padding: const EdgeInsets.only(left: 3, right: 3),
padding: const EdgeInsets.only(
left: 3, right: 3),
child: Text(
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)
Positioned(
bottom: 0,
@ -236,22 +278,31 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
.filter()
.idIsNotNull()
.and()
.chapter((q) => q.manga((q) => q.isMangaEqualTo(entry.isManga!)))
.chapter((q) => q.manga((q) =>
q.isMangaEqualTo(entry.isManga!)))
.watch(fireImmediately: true),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final incognitoMode = ref.watch(incognitoModeStateProvider);
final entries =
snapshot.data!.where((element) => element.mangaId == entry.id).toList();
if (entries.isNotEmpty && !incognitoMode) {
if (snapshot.hasData &&
snapshot.data!.isNotEmpty) {
final incognitoMode =
ref.watch(incognitoModeStateProvider);
final entries = snapshot.data!
.where((element) =>
element.mangaId == entry.id)
.toList();
if (entries.isNotEmpty &&
!incognitoMode) {
return GestureDetector(
onTap: () {
entries.first.chapter.value!.pushToReaderView(context);
entries.first.chapter.value!
.pushToReaderView(context);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: context.primaryColor.withValues(alpha: 0.9),
borderRadius:
BorderRadius.circular(5),
color: context.primaryColor
.withValues(alpha: 0.9),
),
child: const Padding(
padding: EdgeInsets.all(7),
@ -265,12 +316,19 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
}
return GestureDetector(
onTap: () {
entry.chapters.toList().reversed.toList().last.pushToReaderView(context);
entry.chapters
.toList()
.reversed
.toList()
.last
.pushToReaderView(context);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: context.primaryColor.withValues(alpha: 0.9),
borderRadius:
BorderRadius.circular(5),
color: context.primaryColor
.withValues(alpha: 0.9),
),
child: const Padding(
padding: EdgeInsets.all(7),
@ -284,12 +342,19 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
}
return GestureDetector(
onTap: () {
entry.chapters.toList().reversed.toList().last.pushToReaderView(context);
entry.chapters
.toList()
.reversed
.toList()
.last
.pushToReaderView(context);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: context.primaryColor.withValues(alpha: 0.9),
borderRadius:
BorderRadius.circular(5),
color: context.primaryColor
.withValues(alpha: 0.9),
),
child: const Padding(
padding: EdgeInsets.all(7),

View file

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

View file

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

View file

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

View file

@ -54,7 +54,8 @@ class MainScreen extends ConsumerWidget {
final location = ref.watch(
routerCurrentLocationStateProvider(context),
);
bool isReadingScreen = location == '/mangareaderview' || location == '/animePlayerView';
bool isReadingScreen =
location == '/mangareaderview' || location == '/animePlayerView';
int currentIndex = switch (location) {
null || '/MangaLibrary' => 0,
'/AnimeLibrary' => 1,
@ -122,7 +123,9 @@ class MainScreen extends ConsumerWidget {
children: [
NavigationRailTheme(
data: NavigationRailThemeData(
indicatorShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
indicatorShape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(30)),
),
child: Builder(builder: (context) {
return NavigationRail(
@ -130,46 +133,73 @@ class MainScreen extends ConsumerWidget {
useIndicator: true,
destinations: [
NavigationRailDestination(
selectedIcon: const Icon(Icons.collections_bookmark),
icon: const Icon(Icons.collections_bookmark_outlined),
selectedIcon: const Icon(
Icons.collections_bookmark),
icon: const Icon(Icons
.collections_bookmark_outlined),
label: Padding(
padding: const EdgeInsets.only(top: 5), child: Text(l10n.manga))),
padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.manga))),
NavigationRailDestination(
selectedIcon: const Icon(Icons.video_collection),
icon: const Icon(Icons.video_collection_outlined),
selectedIcon: const Icon(
Icons.video_collection),
icon: const Icon(Icons
.video_collection_outlined),
label: Padding(
padding: const EdgeInsets.only(top: 5), child: Text(l10n.anime))),
padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.anime))),
NavigationRailDestination(
selectedIcon: const Icon(Icons.new_releases),
icon: const Icon(Icons.new_releases_outlined),
selectedIcon:
const Icon(Icons.new_releases),
icon: const Icon(
Icons.new_releases_outlined),
label: Padding(
padding: const EdgeInsets.only(top: 5),
padding: const EdgeInsets.only(
top: 5),
child: Stack(
children: [
Text(
getHyphenatedUpdatesLabel(
ref.watch(l10nLocaleStateProvider).languageCode,
ref
.watch(
l10nLocaleStateProvider)
.languageCode,
l10n.updates,
),
textAlign: TextAlign.center,
textAlign:
TextAlign.center,
),
],
))),
NavigationRailDestination(
selectedIcon: const Icon(Icons.history),
icon: const Icon(Icons.history_outlined),
selectedIcon:
const Icon(Icons.history),
icon: const Icon(
Icons.history_outlined),
label: Padding(
padding: const EdgeInsets.only(top: 5), child: Text(l10n.history))),
padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.history))),
NavigationRailDestination(
selectedIcon: const Icon(Icons.explore),
icon: const Icon(Icons.explore_outlined),
selectedIcon:
const Icon(Icons.explore),
icon: const Icon(
Icons.explore_outlined),
label: Padding(
padding: const EdgeInsets.only(top: 5), child: Text(l10n.browse))),
padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.browse))),
NavigationRailDestination(
selectedIcon: const Icon(Icons.more_horiz),
icon: const Icon(Icons.more_horiz_outlined),
selectedIcon:
const Icon(Icons.more_horiz),
icon: const Icon(
Icons.more_horiz_outlined),
label: Padding(
padding: const EdgeInsets.only(top: 5), child: Text(l10n.more))),
padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.more))),
],
selectedIndex: currentIndex,
onDestinationSelected: (newIndex) {
@ -186,8 +216,14 @@ class MainScreen extends ConsumerWidget {
);
}),
),
Positioned(right: 18, top: 140, child: _updatesTotalNumbers(ref)),
Positioned(right: 18, top: 275, child: _extensionUpdateTotalNumbers(ref)),
Positioned(
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(
data: NavigationBarThemeData(
indicatorShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
indicatorShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30)),
),
child: NavigationBar(
animationDuration: const Duration(milliseconds: 500),
animationDuration:
const Duration(milliseconds: 500),
selectedIndex: currentIndex,
destinations: [
NavigationDestination(
selectedIcon: const Icon(Icons.collections_bookmark),
icon: const Icon(Icons.collections_bookmark_outlined),
selectedIcon:
const Icon(Icons.collections_bookmark),
icon: const Icon(
Icons.collections_bookmark_outlined),
label: l10n.manga),
NavigationDestination(
selectedIcon: const Icon(Icons.video_collection),
icon: const Icon(Icons.video_collection_outlined),
selectedIcon:
const Icon(Icons.video_collection),
icon: const Icon(
Icons.video_collection_outlined),
label: l10n.anime),
Stack(
children: [
NavigationDestination(
selectedIcon: const Icon(Icons.new_releases),
icon: const Icon(Icons.new_releases_outlined),
selectedIcon:
const Icon(Icons.new_releases),
icon: const Icon(
Icons.new_releases_outlined),
label: l10n.updates),
Positioned(right: 14, top: 3, child: _updatesTotalNumbers(ref)),
Positioned(
right: 14,
top: 3,
child: _updatesTotalNumbers(ref)),
],
),
NavigationDestination(
@ -249,7 +296,10 @@ class MainScreen extends ConsumerWidget {
selectedIcon: const Icon(Icons.explore),
icon: const Icon(Icons.explore_outlined),
label: l10n.browse),
Positioned(right: 14, top: 3, child: _extensionUpdateTotalNumbers(ref)),
Positioned(
right: 14,
top: 3,
child: _extensionUpdateTotalNumbers(ref)),
],
),
NavigationDestination(
@ -286,21 +336,32 @@ class MainScreen extends ConsumerWidget {
Widget _extensionUpdateTotalNumbers(WidgetRef ref) {
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) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final entries =
snapshot.data!.where((element) => compareVersions(element.version!, element.versionLast!) < 0).toList();
final entries = snapshot.data!
.where((element) =>
compareVersions(element.version!, element.versionLast!) < 0)
.toList();
return entries.isEmpty
? Container()
: Container(
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(
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 3),
padding:
const EdgeInsets.symmetric(horizontal: 5, vertical: 3),
child: Text(
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(
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(
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 3),
padding:
const EdgeInsets.symmetric(horizontal: 5, vertical: 3),
child: Text(
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
Future<void> migration(Ref ref) async {
final chapters = isar.chapters.filter().idIsNotNull().mangaIdIsNull().findAllSync();
final downloads = isar.downloads.filter().idIsNotNull().mangaIdIsNull().findAllSync();
final histories =
isar.historys.filter().idIsNotNull().chapterIdIsNull().or().idIsNotNull().isMangaIsNull().findAllSync();
final tracks = isar.tracks.filter().idIsNotNull().isMangaIsNull().findAllSync();
final chapters =
isar.chapters.filter().idIsNotNull().mangaIdIsNull().findAllSync();
final downloads =
isar.downloads.filter().idIsNotNull().mangaIdIsNull().findAllSync();
final histories = isar.historys
.filter()
.idIsNotNull()
.chapterIdIsNull()
.or()
.idIsNotNull()
.isMangaIsNull()
.findAllSync();
final tracks =
isar.tracks.filter().idIsNotNull().isMangaIsNull().findAllSync();
isar.writeTxnSync(() {
//mangaId in chapter

View file

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

View file

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

View file

@ -7,7 +7,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.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/models/chapter.dart';
import 'package:mangayomi/models/download.dart';

View file

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

View file

@ -16,5 +16,8 @@ Stream<List<Chapter>> getChaptersStream(
Ref ref, {
required int mangaId,
}) 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);
isar.writeTxnSync(() {
isar.settings.putSync(settings..chapterFilterDownloadedList = chapterFilterDownloadedList);
isar.settings.putSync(
settings..chapterFilterDownloadedList = chapterFilterDownloadedList);
});
state = type;
@ -211,7 +212,8 @@ class ChapterFilterUnreadState extends _$ChapterFilterUnreadState {
}
chapterFilterUnreadList.add(value);
isar.writeTxnSync(() {
isar.settings.putSync(settings..chapterFilterUnreadList = chapterFilterUnreadList);
isar.settings
.putSync(settings..chapterFilterUnreadList = chapterFilterUnreadList);
});
state = type;
}
@ -262,7 +264,8 @@ class ChapterFilterBookmarkedState extends _$ChapterFilterBookmarkedState {
}
chapterFilterBookmarkedList.add(value);
isar.writeTxnSync(() {
isar.settings.putSync(settings..chapterFilterBookmarkedList = chapterFilterBookmarkedList);
isar.settings.putSync(
settings..chapterFilterBookmarkedList = chapterFilterBookmarkedList);
});
state = type;
}
@ -282,12 +285,18 @@ class ChapterFilterBookmarkedState extends _$ChapterFilterBookmarkedState {
class ChapterFilterResultState extends _$ChapterFilterResultState {
@override
bool build({required Manga manga}) {
final downloadFilterType = ref.watch(chapterFilterDownloadedStateProvider(mangaId: manga.id!));
final unreadFilterType = ref.watch(chapterFilterUnreadStateProvider(mangaId: manga.id!));
final downloadFilterType =
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));
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(() {
for (var chapter in chapters) {
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);
chapter.manga.saveSync();
}
@ -321,7 +332,9 @@ class ChapterSetIsReadState extends _$ChapterSetIsReadState {
isar.writeTxnSync(() {
for (var chapter in chapters) {
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);
chapter.manga.saveSync();
}
@ -340,7 +353,11 @@ class ChapterSetDownloadState extends _$ChapterSetDownloadState {
ref.read(isLongPressedStateProvider.notifier).update(false);
isar.txnSync(() {
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!) {
ref.watch(downloadChapterProvider(chapter: chapter));
}
@ -378,7 +395,8 @@ class ScanlatorsFilterState extends _$ScanlatorsFilterState {
List<String> _getScanlators() {
List<String> scanlators = [];
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!);
}
}
@ -399,14 +417,16 @@ class ScanlatorsFilterState extends _$ScanlatorsFilterState {
}
filterScanlatorList.add(value);
isar.writeTxnSync(() {
isar.settings.putSync(settings..filterScanlatorList = filterScanlatorList);
isar.settings
.putSync(settings..filterScanlatorList = filterScanlatorList);
});
state = (_getScanlators(), _getFilterScanlator()!, filterScanlators);
}
List<String>? _getFilterScanlator() {
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;
}
@ -421,6 +441,7 @@ class ScanlatorsFilterState extends _$ScanlatorsFilterState {
} else {
scanlatorFilteredList.add(scanlator);
}
state = (_getScanlators(), _getFilterScanlator() ?? [], scanlatorFilteredList);
state =
(_getScanlators(), _getFilterScanlator() ?? [], scanlatorFilteredList);
}
}

View file

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

View file

@ -12,7 +12,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'update_manga_detail_providers.g.dart';
@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!);
if (manga!.chapters.isNotEmpty && isInit) {
return;
@ -20,20 +21,31 @@ Future<dynamic> updateMangaDetail(Ref ref, {required int? mangaId, required bool
final source = getSource(manga.lang!, manga.source!);
MManga getManga;
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) {
botToast(e.toString());
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
..imageUrl = getManga.imageUrl ?? manga.imageUrl
..name = getManga.name?.trim().trimLeft().trimRight() ?? manga.name
..genre = (genre.isEmpty ? null : genre) ?? manga.genre ?? []
..author = getManga.author?.trim().trimLeft().trimRight() ?? manga.author ?? ""
..artist = getManga.artist?.trim().trimLeft().trimRight() ?? manga.artist ?? ""
..status = getManga.status == Status.unknown ? manga.status : getManga.status!
..description = getManga.description?.trim().trimLeft().trimRight() ?? manga.description ?? ""
..author =
getManga.author?.trim().trimLeft().trimRight() ?? manga.author ?? ""
..artist =
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
..source = manga.source
..lang = manga.lang
@ -68,19 +80,24 @@ Future<dynamic> updateMangaDetail(Ref ref, {required int? mangaId, required bool
}
if (chapters.isNotEmpty) {
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);
chap.manga.saveSync();
if (manga.chapters.isNotEmpty) {
final update =
Update(mangaId: mangaId, chapterName: chap.name, date: DateTime.now().millisecondsSinceEpoch.toString())
..chapter.value = chap;
final update = Update(
mangaId: mangaId,
chapterName: chap.name,
date: DateTime.now().millisecondsSinceEpoch.toString())
..chapter.value = chap;
isar.updates.putSync(update);
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) {
for (var i = 0; i < oldChapers.length; i++) {
final oldChap = oldChapers[i];
@ -91,7 +108,9 @@ Future<dynamic> updateMangaDetail(Ref ref, {required int? mangaId, required bool
newChap.name == oldChap.name) {
oldChap.url = newChap.url;
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);
oldChap.manga.saveSync();
}

View file

@ -4,7 +4,11 @@ class ListTileChapterFilter extends StatelessWidget {
final String label;
final int type;
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
Widget build(BuildContext context) {

View file

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

View file

@ -6,15 +6,22 @@ class ListTileChapterSort extends StatelessWidget {
final VoidCallback onTap;
final bool showLeading;
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
Widget build(BuildContext context) {
return ListTile(
iconColor: Theme.of(context).primaryColor,
dense: true,
leading: Icon(reverse ? Icons.arrow_downward_sharp : Icons.arrow_upward_sharp,
color: showLeading ? Theme.of(context).primaryColor : Colors.transparent),
leading: Icon(
reverse ? Icons.arrow_downward_sharp : Icons.arrow_upward_sharp,
color: showLeading
? Theme.of(context).primaryColor
: Colors.transparent),
title: Text(
label,
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';
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 String text;
@ -12,7 +13,8 @@ class ReadMoreWidget extends StatefulWidget {
ReadMoreWidgetState createState() => ReadMoreWidgetState();
}
class ReadMoreWidgetState extends State<ReadMoreWidget> with TickerProviderStateMixin {
class ReadMoreWidgetState extends State<ReadMoreWidget>
with TickerProviderStateMixin {
late bool expanded = true;
@override
Widget build(BuildContext context) {
@ -61,7 +63,9 @@ class ReadMoreWidgetState extends State<ReadMoreWidget> with TickerProviderState
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Theme.of(context).scaffoldBackgroundColor.withValues(alpha: 0.2),
Theme.of(context)
.scaffoldBackgroundColor
.withValues(alpha: 0.2),
Theme.of(context).scaffoldBackgroundColor
],
stops: const [0, .9],

View file

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

View file

@ -38,10 +38,15 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
_init() async {
await Future.delayed(const Duration(microseconds: 100));
final findManga =
await ref.read(trackStateProvider(track: widget.trackRes, isManga: widget.isManga).notifier).findManga();
final findManga = await ref
.read(
trackStateProvider(track: widget.trackRes, isManga: widget.isManga)
.notifier)
.findManga();
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);
return Container(
decoration: BoxDecoration(
color: context.isLight ? Theme.of(context).scaffoldBackgroundColor : Colors.black,
color: context.isLight
? Theme.of(context).scaffoldBackgroundColor
: Colors.black,
borderRadius: BorderRadius.circular(20)),
child: Column(
children: [
@ -59,10 +66,12 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
children: [
if (!widget.hide)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 5),
padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 5),
child: Container(
decoration:
BoxDecoration(borderRadius: BorderRadius.circular(10), color: trackInfos(widget.syncId).$3),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: trackInfos(widget.syncId).$3),
width: 50,
height: 45,
child: Image.asset(
@ -74,16 +83,22 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
Expanded(
child: _elevatedButton(
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
? () async {
final trackSearch =
await trackersSearchraggableMenu(context, isManga: widget.isManga, track: widget.trackRes)
as TrackSearch?;
final trackSearch = await trackersSearchraggableMenu(
context,
isManga: widget.isManga,
track: widget.trackRes) as TrackSearch?;
if (trackSearch != null) {
await ref
.read(trackStateProvider(track: null, isManga: widget.isManga).notifier)
.setTrackSearch(trackSearch, widget.mangaId, widget.syncId);
.read(trackStateProvider(
track: null, isManga: widget.isManga)
.notifier)
.setTrackSearch(
trackSearch, widget.mangaId, widget.syncId);
}
}
: null,
@ -95,7 +110,10 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
child: Text(
widget.trackRes.title!,
style: TextStyle(
color: Theme.of(context).textTheme.bodyMedium!.color,
color: Theme.of(context)
.textTheme
.bodyMedium!
.color,
overflow: TextOverflow.ellipsis,
fontSize: 16,
fontWeight: FontWeight.bold),
@ -105,7 +123,10 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
),
IconButton(
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))
],
@ -130,29 +151,39 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
child: ListView.builder(
shrinkWrap: true,
itemCount: ref
.read(trackStateProvider(track: widget.trackRes, isManga: widget.isManga).notifier)
.read(trackStateProvider(
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.getStatusList()
.length,
itemBuilder: (context, index) {
final status = ref
.read(
trackStateProvider(track: widget.trackRes, isManga: widget.isManga).notifier)
.read(trackStateProvider(
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.getStatusList()[index];
return RadioListTile(
dense: true,
contentPadding: const EdgeInsets.all(0),
value: status,
groupValue:
toTrackStatus(widget.trackRes.status, widget.isManga, widget.trackRes.syncId!),
groupValue: toTrackStatus(
widget.trackRes.status,
widget.isManga,
widget.trackRes.syncId!),
onChanged: (value) {
ref
.read(trackStateProvider(
track: widget.trackRes..status = status, isManga: widget.isManga)
track: widget.trackRes
..status = status,
isManga: widget.isManga)
.notifier)
.updateManga();
Navigator.pop(context);
},
title: Text(getTrackStatus(status, context)),
title:
Text(getTrackStatus(status, context)),
);
},
)),
@ -166,7 +197,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
},
child: Text(
l10n.cancel,
style: TextStyle(color: context.primaryColor),
style: TextStyle(
color: context.primaryColor),
)),
],
)
@ -175,7 +207,9 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
});
},
text: getTrackStatus(
toTrackStatus(widget.trackRes.status, widget.isManga, widget.trackRes.syncId!), context)),
toTrackStatus(widget.trackRes.status, widget.isManga,
widget.trackRes.syncId!),
context)),
),
Expanded(
child: _elevatedButton(context, onPressed: () {
@ -196,10 +230,13 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
NumberPicker(
value: currentIntValue,
minValue: 0,
maxValue: widget.trackRes.totalChapter != 0 ? widget.trackRes.totalChapter! : 10000,
maxValue: widget.trackRes.totalChapter != 0
? widget.trackRes.totalChapter!
: 10000,
step: 1,
haptics: true,
onChanged: (value) => setState(() => currentIntValue = value),
onChanged: (value) =>
setState(() => currentIntValue = value),
),
],
),
@ -215,13 +252,16 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
},
child: Text(
l10n.cancel,
style: TextStyle(color: context.primaryColor),
style: TextStyle(
color: context.primaryColor),
)),
TextButton(
onPressed: () async {
ref
.read(trackStateProvider(
track: widget.trackRes..lastChapterRead = currentIntValue,
track: widget.trackRes
..lastChapterRead =
currentIntValue,
isManga: widget.isManga)
.notifier)
.updateManga();
@ -229,7 +269,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
},
child: Text(
l10n.ok,
style: TextStyle(color: context.primaryColor),
style: TextStyle(
color: context.primaryColor),
)),
],
)
@ -261,21 +302,28 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
value: currentIntValue,
minValue: 0,
maxValue: ref
.read(trackStateProvider(track: widget.trackRes, isManga: widget.isManga)
.read(trackStateProvider(
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.getScoreMaxValue(),
textMapper: (numberText) {
return ref
.read(trackStateProvider(track: widget.trackRes, isManga: widget.isManga)
.read(trackStateProvider(
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.getTextMapper(numberText);
},
step: ref
.read(trackStateProvider(track: widget.trackRes, isManga: widget.isManga)
.read(trackStateProvider(
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.getScoreStep(),
haptics: true,
onChanged: (value) => setState(() => currentIntValue = value),
onChanged: (value) =>
setState(() => currentIntValue = value),
),
],
),
@ -291,13 +339,15 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
},
child: Text(
l10n.cancel,
style: TextStyle(color: context.primaryColor),
style: TextStyle(
color: context.primaryColor),
)),
TextButton(
onPressed: () async {
ref
.read(trackStateProvider(
track: widget.trackRes..score = currentIntValue,
track: widget.trackRes
..score = currentIntValue,
isManga: widget.isManga)
.notifier)
.updateManga();
@ -305,7 +355,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
},
child: Text(
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
? ref
.read(trackStateProvider(track: widget.trackRes, isManga: widget.isManga).notifier)
.read(trackStateProvider(
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.displayScore(widget.trackRes.score!)
: l10n!.score),
)
@ -324,8 +378,9 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
Row(
children: [
Expanded(
child: _elevatedButton(context, borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(20)),
onPressed: () async {
child: _elevatedButton(context,
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(20)), onPressed: () async {
DateTime? newDate = await showDatePicker(
helpText: l10n!.start_date,
locale: l10nLocale,
@ -336,20 +391,27 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
if (newDate == null) return;
ref
.read(trackStateProvider(
track: widget.trackRes..startedReadingDate = newDate.millisecondsSinceEpoch,
track: widget.trackRes
..startedReadingDate =
newDate.millisecondsSinceEpoch,
isManga: widget.isManga)
.notifier)
.updateManga();
},
text: widget.trackRes.startedReadingDate != null &&
widget.trackRes.startedReadingDate! > DateTime(1970).millisecondsSinceEpoch
? dateFormat(widget.trackRes.startedReadingDate.toString(),
ref: ref, useRelativeTimesTamps: false, context: context)
widget.trackRes.startedReadingDate! >
DateTime(1970).millisecondsSinceEpoch
? dateFormat(
widget.trackRes.startedReadingDate.toString(),
ref: ref,
useRelativeTimesTamps: false,
context: context)
: l10n!.start_date),
),
Expanded(
child: _elevatedButton(context, borderRadius: const BorderRadius.only(bottomRight: Radius.circular(20)),
onPressed: () async {
child: _elevatedButton(context,
borderRadius: const BorderRadius.only(
bottomRight: Radius.circular(20)), onPressed: () async {
DateTime? newDate = await showDatePicker(
helpText: l10n!.finish_date,
locale: l10nLocale,
@ -360,15 +422,21 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
if (newDate == null) return;
ref
.read(trackStateProvider(
track: widget.trackRes..finishedReadingDate = newDate.millisecondsSinceEpoch,
track: widget.trackRes
..finishedReadingDate =
newDate.millisecondsSinceEpoch,
isManga: widget.isManga)
.notifier)
.updateManga();
},
text: widget.trackRes.finishedReadingDate != null &&
widget.trackRes.finishedReadingDate! > DateTime(1970).millisecondsSinceEpoch
? dateFormat(widget.trackRes.finishedReadingDate.toString(),
ref: ref, useRelativeTimesTamps: false, context: context)
widget.trackRes.finishedReadingDate! >
DateTime(1970).millisecondsSinceEpoch
? dateFormat(
widget.trackRes.finishedReadingDate.toString(),
ref: ref,
useRelativeTimesTamps: false,
context: context)
: l10n!.finish_date),
)
],
@ -380,20 +448,32 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
}
Widget _elevatedButton(BuildContext context,
{required Function()? onPressed, String text = "", Widget? child, BorderRadiusGeometry? borderRadius}) {
{required Function()? onPressed,
String text = "",
Widget? child,
BorderRadiusGeometry? borderRadius}) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
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,
shadowColor: Colors.transparent,
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))),
onPressed: onPressed,
child: child ??
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();
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!;
void _sendFile() async {
final mangaDir = await _storageProvider.getMangaMainDirectory(widget.chapter);
final path = await _storageProvider.getMangaChapterDirectory(widget.chapter);
final mangaDir =
await _storageProvider.getMangaMainDirectory(widget.chapter);
final path =
await _storageProvider.getMangaChapterDirectory(widget.chapter);
List<XFile> files = [];
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()) {
files = [XFile(cbzFile.path)];
} else if (mp4File.existsSync()) {
@ -61,18 +66,22 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
}
void _deleteFile() async {
final mangaDir = await _storageProvider.getMangaMainDirectory(widget.chapter);
final path = await _storageProvider.getMangaChapterDirectory(widget.chapter);
final mangaDir =
await _storageProvider.getMangaMainDirectory(widget.chapter);
final path =
await _storageProvider.getMangaChapterDirectory(widget.chapter);
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()) {
cbzFile.deleteSync();
}
} catch (_) {}
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()) {
mp4File.deleteSync();
}
@ -80,7 +89,11 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
path!.deleteSync(recursive: true);
} catch (_) {}
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);
});
}
@ -111,7 +124,10 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
child: Icon(
size: 25,
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) {
if (value == 0) {
@ -125,7 +141,8 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
PopupMenuItem(value: 1, child: Text(l10n.delete)),
],
)
: entries.first.isStartDownload! && entries.first.succeeded == 0
: entries.first.isStartDownload! &&
entries.first.succeeded == 0
? SizedBox(
height: 41,
width: 35,
@ -144,7 +161,9 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
}
},
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)),
],
))
@ -159,19 +178,25 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
Align(
alignment: Alignment.center,
child: TweenAnimationBuilder<double>(
duration: const Duration(milliseconds: 250),
duration:
const Duration(milliseconds: 250),
curve: Curves.easeInOut,
tween: Tween<double>(
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,
width: 2,
child: CircularProgressIndicator(
strokeWidth: 19,
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,
child: Icon(
Icons.arrow_downward_sharp,
color: (entries.first.succeeded! / entries.first.total!) > 0.5
? Theme.of(context).scaffoldBackgroundColor
: Theme.of(context).iconTheme.color!.withValues(alpha: 0.7),
color: (entries.first.succeeded! /
entries.first.total!) >
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) => [
PopupMenuItem(value: 1, child: Text(l10n.start_downloading)),
PopupMenuItem(value: 0, child: Text(l10n.cancel)),
PopupMenuItem(
value: 1,
child: Text(l10n.start_downloading)),
PopupMenuItem(
value: 0, child: Text(l10n.cancel)),
],
))
: entries.first.succeeded == 0
@ -212,7 +246,10 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
},
icon: Icon(
FontAwesomeIcons.circleDown,
color: Theme.of(context).iconTheme.color!.withValues(alpha: 0.7),
color: Theme.of(context)
.iconTheme
.color!
.withValues(alpha: 0.7),
size: 25,
))
: SizedBox(
@ -235,7 +272,8 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
}
},
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) => [
PopupMenuItem(value: 1, child: Text(l10n.start_downloading)),
PopupMenuItem(
value: 1, child: Text(l10n.start_downloading)),
PopupMenuItem(value: 0, child: Text(l10n.cancel)),
],
))
@ -287,7 +326,10 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
[];
await FileDownloader().cancelTasksWithIds(_pageUrls);
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) {
final verifyId = isar.downloads.getSync(chapterD.id!);
isar.writeTxnSync(() {

View file

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

View file

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

View file

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

View file

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

View file

@ -7,7 +7,11 @@ class MangasCardSelector extends StatelessWidget {
final bool selected;
final VoidCallback onPressed;
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
Widget build(BuildContext context) {
@ -18,7 +22,8 @@ class MangasCardSelector extends StatelessWidget {
padding: const EdgeInsets.all(0),
side: BorderSide(width: 0.6, color: context.primaryColor),
backgroundColor: selected ? context.primaryColor : null,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(7)),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(7)),
),
onPressed: onPressed,
child: Padding(

View file

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

View file

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

View file

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

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