New feature : add Anime

-add trackers support for anime
This commit is contained in:
kodjomoustapha 2023-07-27 19:24:18 +01:00
parent 202db0cced
commit 35e5e2a015
176 changed files with 8024 additions and 1786 deletions

View file

@ -4,7 +4,7 @@
# This file should be version controlled.
version:
revision: 90c64ed42ba53a52d18f0cb3b17666c8662ed2a0
revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
channel: stable
project_type: app
@ -13,11 +13,11 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: 90c64ed42ba53a52d18f0cb3b17666c8662ed2a0
base_revision: 90c64ed42ba53a52d18f0cb3b17666c8662ed2a0
- platform: windows
create_revision: 90c64ed42ba53a52d18f0cb3b17666c8662ed2a0
base_revision: 90c64ed42ba53a52d18f0cb3b17666c8662ed2a0
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: macos
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
# User provided section

View file

@ -14,6 +14,7 @@ Features include:
* Local reading of downloaded content
* Read and manage local archives (.cbz, .zip)
* A configurable reader with multiple viewers, reading directions.
* Tracker support: [MyAnimeList](https://myanimelist.net/) and [AniList](https://anilist.co/) support
* Categories to organize your library
* Light and dark themes

View file

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View file

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

44
ios/Podfile Normal file
View file

@ -0,0 +1,44 @@
# Uncomment this line to define a global platform for your project
platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end

150
ios/Podfile.lock Normal file
View file

@ -0,0 +1,150 @@
PODS:
- background_downloader (0.0.1):
- Flutter
- DKImagePickerController/Core (4.3.4):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.4)
- DKImagePickerController/PhotoGallery (4.3.4):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.4)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
- DKPhotoGallery/Preview (= 0.0.17)
- DKPhotoGallery/Resource (= 0.0.17)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.17):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.17):
- SDWebImage
- SwiftyGif
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Flutter (1.0.0)
- flutter_inappwebview (0.0.1):
- Flutter
- flutter_inappwebview/Core (= 0.0.1)
- OrderedSet (~> 5.0)
- flutter_inappwebview/Core (0.0.1):
- Flutter
- OrderedSet (~> 5.0)
- flutter_js (0.1.0):
- Flutter
- flutter_web_auth_2 (1.1.1):
- Flutter
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- isar_flutter_libs (1.0.0):
- Flutter
- OrderedSet (5.0.0)
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- permission_handler_apple (9.0.4):
- Flutter
- SDWebImage (5.17.0):
- SDWebImage/Core (= 5.17.0)
- SDWebImage/Core (5.17.0)
- share_plus (0.0.1):
- Flutter
- sqflite (0.0.3):
- Flutter
- FMDB (>= 2.7.5)
- SwiftyGif (5.4.4)
- url_launcher_ios (0.0.1):
- Flutter
DEPENDENCIES:
- background_downloader (from `.symlinks/plugins/background_downloader/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
- flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
- flutter_js (from `.symlinks/plugins/flutter_js/ios`)
- flutter_web_auth_2 (from `.symlinks/plugins/flutter_web_auth_2/ios`)
- isar_flutter_libs (from `.symlinks/plugins/isar_flutter_libs/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
- FMDB
- OrderedSet
- SDWebImage
- SwiftyGif
EXTERNAL SOURCES:
background_downloader:
:path: ".symlinks/plugins/background_downloader/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
flutter_inappwebview:
:path: ".symlinks/plugins/flutter_inappwebview/ios"
flutter_js:
:path: ".symlinks/plugins/flutter_js/ios"
flutter_web_auth_2:
:path: ".symlinks/plugins/flutter_web_auth_2/ios"
isar_flutter_libs:
:path: ".symlinks/plugins/isar_flutter_libs/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
background_downloader: 6f55e5548875be2ad4bb91b542558b5be22f339a
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_inappwebview: 50b55a88f5dddadc9e741a7caf72f378116e2156
flutter_js: 95929d4e146e8ceb1c8e1889d8c2065c5d840076
flutter_web_auth_2: a1bc00762c408a8f80b72a538cd7ff5b601c3e71
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9
permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce
SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9
share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
PODFILE CHECKSUM: 351dbda8241c6ae667acbc7bc0353a0d9978d7f1
COCOAPODS: 1.12.1

View file

@ -8,13 +8,26 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
2E161ED88D6088BA04182D24 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 87B3D97401D2090714EBD2ED /* Pods_Runner.framework */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
A83607D399EF885A7879ED92 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F944C966F0D3C46230816475 /* Pods_RunnerTests.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
@ -31,10 +44,15 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
48F414924F0EBD7233D9B3FB /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
87B3D97401D2090714EBD2ED /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8FEFB82C0F5EBF076D246DED /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -42,19 +60,55 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9D7FF371C06E43EB2821A307 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
E3DBD23DF4F6477DD1B2D619 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
F2F655C8A844E54BF4806B9E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
F6B35AE9FD7580BD87744873 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
F944C966F0D3C46230816475 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
856C729112305BC7D8FE80C9 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A83607D399EF885A7879ED92 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
2E161ED88D6088BA04182D24 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
6CD41D1121E5C42BF1E41F31 /* Pods */ = {
isa = PBXGroup;
children = (
9D7FF371C06E43EB2821A307 /* Pods-Runner.debug.xcconfig */,
F6B35AE9FD7580BD87744873 /* Pods-Runner.release.xcconfig */,
F2F655C8A844E54BF4806B9E /* Pods-Runner.profile.xcconfig */,
E3DBD23DF4F6477DD1B2D619 /* Pods-RunnerTests.debug.xcconfig */,
48F414924F0EBD7233D9B3FB /* Pods-RunnerTests.release.xcconfig */,
8FEFB82C0F5EBF076D246DED /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@ -72,6 +126,9 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
6CD41D1121E5C42BF1E41F31 /* Pods */,
BCA59FF3AA594C41BF8ADD28 /* Frameworks */,
);
sourceTree = "<group>";
};
@ -79,6 +136,7 @@
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@ -98,19 +156,49 @@
path = Runner;
sourceTree = "<group>";
};
BCA59FF3AA594C41BF8ADD28 /* Frameworks */ = {
isa = PBXGroup;
children = (
87B3D97401D2090714EBD2ED /* Pods_Runner.framework */,
F944C966F0D3C46230816475 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
EF1F895BD02D12F0BC740A9E /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
856C729112305BC7D8FE80C9 /* Frameworks */,
);
buildRules = (
);
dependencies = (
331C8086294A63A400263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
F7E3AB66492405CCCAB00559 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
DC786BE6A6336FF08B227C10 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@ -127,9 +215,14 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
@ -150,11 +243,19 @@
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@ -176,6 +277,7 @@
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
@ -199,9 +301,78 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
DC786BE6A6336FF08B227C10 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
EF1F895BD02D12F0BC740A9E /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
F7E3AB66492405CCCAB00559 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -213,6 +384,14 @@
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
@ -256,6 +435,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -274,7 +454,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@ -292,6 +472,7 @@
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -304,6 +485,56 @@
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = E3DBD23DF4F6477DD1B2D619 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.kodjodevf.mangayomi.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 48F414924F0EBD7233D9B3FB /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.kodjodevf.mangayomi.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8FEFB82C0F5EBF076D246DED /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.kodjodevf.mangayomi.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -327,6 +558,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -351,7 +583,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -382,6 +614,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -400,7 +633,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@ -420,6 +653,7 @@
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -442,6 +676,7 @@
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -457,6 +692,16 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View file

@ -37,6 +37,17 @@
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction

View file

@ -4,4 +4,7 @@
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 B

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
@ -13,7 +15,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Mangayomi</string>
<string>mangayomi</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
@ -24,6 +26,12 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
@ -43,9 +51,5 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,12 @@
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}

View file

@ -65,3 +65,12 @@ class MangaModel {
this.images,
this.statusList});
}
class VideoModel {
String? url;
String? quality;
String? originalUrl;
Map<dynamic, dynamic>? headers;
VideoModel({this.url, this.quality, this.originalUrl, this.headers});
}

View file

@ -0,0 +1,134 @@
import 'package:dart_eval/dart_eval.dart';
import 'package:dart_eval/dart_eval_bridge.dart';
import 'package:dart_eval/stdlib/core.dart';
import 'package:mangayomi/eval/bridge_class/model.dart';
class $VideoModel implements VideoModel, $Instance {
$VideoModel.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(
BridgeTypeSpec('package:bridge_lib/bridge_lib.dart', 'VideoModel'));
static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation($type),
params: [],
namedParams: [
BridgeParameter(
'url',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'quality',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'originalUrl',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'headers',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.mapType)),
false),
]))
},
// Specify class fields
fields: {
'url': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef.type(RuntimeTypes.stringType))),
'quality': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef.type(RuntimeTypes.stringType))),
'originalUrl': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef.type(RuntimeTypes.stringType))),
'headers': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef.type(RuntimeTypes.mapType))),
},
wrap: true);
static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) {
return $VideoModel.wrap(VideoModel());
}
@override
final VideoModel $value;
@override
VideoModel get $reified => $value;
final $Instance _superclass;
@override
$Value? $getProperty(Runtime runtime, String identifier) {
switch (identifier) {
case 'url':
return $String($value.url!);
case 'quality':
return $String($value.quality!);
case 'originalUrl':
return $String($value.originalUrl!);
case 'headers':
return $Map.wrap($value.headers!);
default:
return _superclass.$getProperty(runtime, identifier);
}
}
@override
int $getRuntimeType(Runtime runtime) => runtime.lookupType($type.spec!);
@override
void $setProperty(Runtime runtime, String identifier, $Value value) {
switch (identifier) {
case 'url':
$value.url = value.$reified;
case 'quality':
$value.quality = value.$reified;
case 'originalUrl':
$value.originalUrl = value.$reified;
case 'headers':
$value.headers = value.$reified as Map;
default:
_superclass.$setProperty(runtime, identifier, value);
}
}
@override
String? get url => $value.url;
@override
String? get quality => $value.quality;
@override
Map? get headers => $value.headers;
@override
String? get originalUrl => $value.originalUrl;
@override
set url(String? url) {
// implement apiUrl
}
@override
set quality(String? quality) {
// implement baseUrl
}
@override
set headers(Map? headers) {
// implement dateFormat
}
@override
set originalUrl(String? originalUrl) {
// implement dateFormatLocale
}
}

View file

@ -1,6 +1,7 @@
import 'dart:typed_data';
import 'package:dart_eval/dart_eval.dart';
import 'package:mangayomi/eval/bridge_class/manga_model.dart';
import 'package:mangayomi/eval/bridge_class/video_model.dart';
import 'package:mangayomi/eval/m_bridge.dart';
Uint8List compilerEval(String sourceCode) {
@ -8,6 +9,7 @@ Uint8List compilerEval(String sourceCode) {
compiler.defineBridgeClasses([
$MBridge.$declaration,
$MangaModel.$declaration,
$VideoModel.$declaration
]);
final program = compiler.compile({
'package:mangayomi': {'main.dart': sourceCode}

View file

@ -11,9 +11,16 @@ import 'package:flutter_js/flutter_js.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:intl/intl.dart';
import 'package:json_path/json_path.dart';
import 'package:mangayomi/eval/bridge_class/model.dart';
import 'package:mangayomi/eval/bridge_class/video_model.dart';
import 'package:mangayomi/services/anime_servers/dood_extractor.dart';
import 'package:mangayomi/services/anime_servers/gogo_cdn_extractor.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/models/video.dart';
import 'package:mangayomi/modules/webview/webview.dart';
import 'package:mangayomi/services/anime_servers/mp4_upload_extractor.dart';
import 'package:mangayomi/services/anime_servers/stream_tape_extractor.dart';
import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.dart';
import 'package:mangayomi/utils/constant.dart';
import 'package:mangayomi/utils/reg_exp_matcher.dart';
@ -499,6 +506,45 @@ class MBridge {
}
}
static Future<List<Video>> gogoCdnExtractor(String url) async {
return await GogoCdnExtractor().videosFromUrl(
url,
);
}
static Future<List<Video>> doodExtractor(String url) async {
return await DoodExtractor().videosFromUrl(
url,
);
}
static Future<List<Video>> mp4UploadExtractor(String url,
Map<String, String>? headers, String prefix, String suffix) async {
return await Mp4uploadExtractor()
.videosFromUrl(url, headers ?? {}, prefix: prefix, suffix: suffix);
}
static Future<List<Video>> streamTapeExtractor(String url) async {
return await StreamTapeExtractor().videosFromUrl(
url,
);
}
static String subString(String text, String pattern, int type) {
String result = "";
//substring before
if (type == 0) {
result = text.split(pattern).first;
} else
// substring after last
if (type == 1) {
result = text.split(pattern).last;
} else if (type == 2) {
result = text.substring(text.lastIndexOf(pattern) + 1);
}
return result;
}
static String parseChapterDate(
String date, String dateFormat, String dateFormatLocale) {
int parseRelativeDate(String date) {
@ -686,6 +732,29 @@ class $MBridge extends MBridge with $Bridge {
returns: BridgeTypeAnnotation($type), params: [], namedParams: []))
},
methods: {
'subString': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
params: [
BridgeParameter(
'text',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'pattern',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'type',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.intType)),
false),
],
namedParams: []),
isStatic: true),
'listParse': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list,
@ -988,6 +1057,74 @@ class $MBridge extends MBridge with $Bridge {
],
namedParams: []),
isStatic: true),
'gogoCdnExtractor': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
params: [
BridgeParameter(
'url',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
],
namedParams: []),
isStatic: true),
'doodExtractor': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
params: [
BridgeParameter(
'url',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
],
namedParams: []),
isStatic: true),
'streamTapeExtractor': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
params: [
BridgeParameter(
'url',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
],
namedParams: []),
isStatic: true),
'mp4UploadExtractor': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
params: [
BridgeParameter(
'url',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'headers',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.mapType),
nullable: true),
false),
BridgeParameter(
'prefix',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'suffix',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
],
namedParams: []),
isStatic: true),
'getHtmlViaWebview': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
@ -1140,6 +1277,15 @@ class $MBridge extends MBridge with $Bridge {
));
}
static $String $subString(
Runtime runtime, $Value? target, List<$Value?> args) {
return $String(MBridge.subString(
args[0]!.$value,
args[1]!.$value,
args[2]!.$value,
));
}
static $String $getMapValue(
Runtime runtime, $Value? target, List<$Value?> args) {
return $String(MBridge.getMapValue(
@ -1220,11 +1366,54 @@ class $MBridge extends MBridge with $Bridge {
static $Future $http(Runtime runtime, $Value? target, List<$Value?> args) =>
$Future.wrap(MBridge.http(args[0]!.$value, args[1]!.$value)
.then((value) => $String(value)));
static $Future $getHtmlViaWebview(
Runtime runtime, $Value? target, List<$Value?> args) =>
$Future.wrap(MBridge.getHtmlViaWebview(args[0]!.$value, args[1]!.$value)
.then((value) => $String(value)));
static $Future $gogoCdnExtractor(
Runtime runtime, $Value? target, List<$Value?> args) =>
$Future.wrap(MBridge.gogoCdnExtractor(args[0]!.$value)
.then((value) => $List.wrap(value
.map((e) => $VideoModel.wrap(VideoModel()
..headers = e.headers
..originalUrl = e.originalUrl
..quality = e.quality
..url = e.url))
.toList())));
static $Future $doodExtractor(
Runtime runtime, $Value? target, List<$Value?> args) =>
$Future.wrap(MBridge.doodExtractor(args[0]!.$value)
.then((value) => $List.wrap(value
.map((e) => $VideoModel.wrap(VideoModel()
..headers = e.headers
..originalUrl = e.originalUrl
..quality = e.quality
..url = e.url))
.toList())));
static $Future $streamTapeExtractor(
Runtime runtime, $Value? target, List<$Value?> args) =>
$Future.wrap(MBridge.streamTapeExtractor(args[0]!.$value)
.then((value) => $List.wrap(value
.map((e) => $VideoModel.wrap(VideoModel()
..headers = e.headers
..originalUrl = e.originalUrl
..quality = e.quality
..url = e.url))
.toList())));
static $Future $mp4UploadExtractor(
Runtime runtime, $Value? target, List<$Value?> args) =>
$Future.wrap(MBridge.mp4UploadExtractor(args[0]!.$value, args[1]!.$value,
args[2]!.$value, args[3]!.$value)
.then((value) => $List.wrap(value
.map((e) => $VideoModel.wrap(VideoModel()
..headers = e.headers
..originalUrl = e.originalUrl
..quality = e.quality
..url = e.url))
.toList())));
@override
$Value? $bridgeGet(String identifier) {
throw UnimplementedError();

View file

@ -1,6 +1,7 @@
import 'dart:typed_data';
import 'package:dart_eval/dart_eval.dart';
import 'package:mangayomi/eval/bridge_class/video_model.dart';
import 'package:mangayomi/eval/m_bridge.dart';
import 'package:mangayomi/eval/bridge_class/manga_model.dart';
@ -11,10 +12,20 @@ Runtime runtimeEval(Uint8List bytecode) {
isBridge: true);
runtime.registerBridgeFunc(
'package:bridge_lib/bridge_lib.dart', 'MangaModel.', $MangaModel.$new);
runtime.registerBridgeFunc(
'package:bridge_lib/bridge_lib.dart', 'VideoModel.', $VideoModel.$new);
runtime.registerBridgeFunc(
'package:bridge_lib/bridge_lib.dart', 'MBridge.http', $MBridge.$http);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.listParseDateTime', $MBridge.$listParseDateTime);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.gogoCdnExtractor', $MBridge.$gogoCdnExtractor);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.doodExtractor', $MBridge.$doodExtractor);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.streamTapeExtractor', $MBridge.$streamTapeExtractor);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.mp4UploadExtractor', $MBridge.$mp4UploadExtractor);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.jsonPathToString', $MBridge.$jsonPathToString);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
@ -35,6 +46,8 @@ Runtime runtimeEval(Uint8List bytecode) {
'MBridge.parseChapterDate', $MBridge.$parseChapterDate);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.stringParse', $MBridge.$stringParse);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.subString', $MBridge.$subString);
runtime.registerBridgeFunc(
'package:bridge_lib/bridge_lib.dart', 'MBridge.evalJs', $MBridge.$evalJs);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',

View file

@ -181,5 +181,18 @@
"one_tracker":"1 tracker",
"n_tracker":"{n} trackers",
"tracking": "Tracking",
"description": "Description"
"description": "Description",
"episode_progress": "Progress: {n}",
"n_episodes": "{n} episodes",
"manga_sources":"Manga Sources",
"anime_sources":"Anime Sources",
"anime_extensions":"Anime Extensions",
"manga_extensions":"Manga Extensions",
"anime":"Anime",
"manga":"Manga",
"library_no_category_exist":"You don't have any categories yet",
"watching":"Watching",
"plan_to_watch":"Plan to watch",
"re_watching":"Rewatching"
}

View file

@ -181,5 +181,17 @@
"one_tracker":"Suivi par 1 service",
"n_tracker":"Suivi par {n} services",
"tracking": "Suivi",
"description": "Description"
"description": "Description",
"episode_progress": "Progression: {n}",
"n_episodes": "{n} épisodes",
"manga_sources":"Sources d'animés",
"anime_sources":"Sources des mangas",
"anime_extensions":"Extensions d'animés",
"manga_extensions":"Extensions des mangas",
"anime":"Animé",
"manga":"Manga",
"library_no_category_exist":"Vous n'avez pas encore de catégories",
"watching":"En lecture",
"plan_to_watch":"À regarder",
"re_watching":"Revisionnage"
}

View file

@ -3,6 +3,7 @@ import 'package:bot_toast/bot_toast.dart';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_meedu_videoplayer/init_meedu_player.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/date_symbol_data_local.dart';
@ -29,6 +30,10 @@ class MyHttpoverrides extends HttpOverrides {
}
void main(List<String> args) async {
initMeeduPlayer(
androidUseMediaKit: true,
iosUseMediaKit: true,
);
HttpOverrides.global = MyHttpoverrides();
if (Platform.isLinux || Platform.isWindows) {
if (runWebViewTitleBarWidget(args)) {
@ -125,4 +130,3 @@ class _MyAppState extends ConsumerState<MyApp> {
);
}
}

View file

@ -6,8 +6,10 @@ part 'category.g.dart';
class Category {
Id? id;
String? name;
bool? forManga;
Category({
this.id = Isar.autoIncrement,
required this.name,
required this.forManga
});
}

View file

@ -17,8 +17,13 @@ const CategorySchema = CollectionSchema(
name: r'Category',
id: 5751694338128944171,
properties: {
r'name': PropertySchema(
r'forManga': PropertySchema(
id: 0,
name: r'forManga',
type: IsarType.bool,
),
r'name': PropertySchema(
id: 1,
name: r'name',
type: IsarType.string,
)
@ -58,7 +63,8 @@ void _categorySerialize(
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
writer.writeString(offsets[0], object.name);
writer.writeBool(offsets[0], object.forManga);
writer.writeString(offsets[1], object.name);
}
Category _categoryDeserialize(
@ -68,8 +74,9 @@ Category _categoryDeserialize(
Map<Type, List<int>> allOffsets,
) {
final object = Category(
forManga: reader.readBoolOrNull(offsets[0]),
id: id,
name: reader.readStringOrNull(offsets[0]),
name: reader.readStringOrNull(offsets[1]),
);
return object;
}
@ -82,6 +89,8 @@ P _categoryDeserializeProp<P>(
) {
switch (propertyId) {
case 0:
return (reader.readBoolOrNull(offset)) as P;
case 1:
return (reader.readStringOrNull(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@ -177,6 +186,32 @@ extension CategoryQueryWhere on QueryBuilder<Category, Category, QWhereClause> {
extension CategoryQueryFilter
on QueryBuilder<Category, Category, QFilterCondition> {
QueryBuilder<Category, Category, QAfterFilterCondition> forMangaIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'forManga',
));
});
}
QueryBuilder<Category, Category, QAfterFilterCondition> forMangaIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'forManga',
));
});
}
QueryBuilder<Category, Category, QAfterFilterCondition> forMangaEqualTo(
bool? value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'forManga',
value: value,
));
});
}
QueryBuilder<Category, Category, QAfterFilterCondition> idIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
@ -399,6 +434,18 @@ extension CategoryQueryLinks
on QueryBuilder<Category, Category, QFilterCondition> {}
extension CategoryQuerySortBy on QueryBuilder<Category, Category, QSortBy> {
QueryBuilder<Category, Category, QAfterSortBy> sortByForManga() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'forManga', Sort.asc);
});
}
QueryBuilder<Category, Category, QAfterSortBy> sortByForMangaDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'forManga', Sort.desc);
});
}
QueryBuilder<Category, Category, QAfterSortBy> sortByName() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'name', Sort.asc);
@ -414,6 +461,18 @@ extension CategoryQuerySortBy on QueryBuilder<Category, Category, QSortBy> {
extension CategoryQuerySortThenBy
on QueryBuilder<Category, Category, QSortThenBy> {
QueryBuilder<Category, Category, QAfterSortBy> thenByForManga() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'forManga', Sort.asc);
});
}
QueryBuilder<Category, Category, QAfterSortBy> thenByForMangaDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'forManga', Sort.desc);
});
}
QueryBuilder<Category, Category, QAfterSortBy> thenById() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'id', Sort.asc);
@ -441,6 +500,12 @@ extension CategoryQuerySortThenBy
extension CategoryQueryWhereDistinct
on QueryBuilder<Category, Category, QDistinct> {
QueryBuilder<Category, Category, QDistinct> distinctByForManga() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'forManga');
});
}
QueryBuilder<Category, Category, QDistinct> distinctByName(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
@ -457,6 +522,12 @@ extension CategoryQueryProperty
});
}
QueryBuilder<Category, bool?, QQueryOperations> forMangaProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'forManga');
});
}
QueryBuilder<Category, String?, QQueryOperations> nameProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'name');

View file

@ -20,6 +20,8 @@ class Manga {
@enumerated
Status status;
bool? isManga;
List<String>? genre;
bool favorite;
@ -55,6 +57,7 @@ class Manga {
required this.name,
required this.status,
required this.description,
this.isManga = true,
this.dateAdded,
this.lastUpdate,
this.categories,
@ -71,3 +74,4 @@ enum Status {
onHiatus,
publishingFinished
}

View file

@ -62,38 +62,43 @@ const MangaSchema = CollectionSchema(
name: r'isLocalArchive',
type: IsarType.bool,
),
r'lang': PropertySchema(
r'isManga': PropertySchema(
id: 9,
name: r'isManga',
type: IsarType.bool,
),
r'lang': PropertySchema(
id: 10,
name: r'lang',
type: IsarType.string,
),
r'lastRead': PropertySchema(
id: 10,
id: 11,
name: r'lastRead',
type: IsarType.long,
),
r'lastUpdate': PropertySchema(
id: 11,
id: 12,
name: r'lastUpdate',
type: IsarType.long,
),
r'link': PropertySchema(
id: 12,
id: 13,
name: r'link',
type: IsarType.string,
),
r'name': PropertySchema(
id: 13,
id: 14,
name: r'name',
type: IsarType.string,
),
r'source': PropertySchema(
id: 14,
id: 15,
name: r'source',
type: IsarType.string,
),
r'status': PropertySchema(
id: 15,
id: 16,
name: r'status',
type: IsarType.byte,
enumMap: _MangastatusEnumValueMap,
@ -211,13 +216,14 @@ void _mangaSerialize(
writer.writeStringList(offsets[6], object.genre);
writer.writeString(offsets[7], object.imageUrl);
writer.writeBool(offsets[8], object.isLocalArchive);
writer.writeString(offsets[9], object.lang);
writer.writeLong(offsets[10], object.lastRead);
writer.writeLong(offsets[11], object.lastUpdate);
writer.writeString(offsets[12], object.link);
writer.writeString(offsets[13], object.name);
writer.writeString(offsets[14], object.source);
writer.writeByte(offsets[15], object.status.index);
writer.writeBool(offsets[9], object.isManga);
writer.writeString(offsets[10], object.lang);
writer.writeLong(offsets[11], object.lastRead);
writer.writeLong(offsets[12], object.lastUpdate);
writer.writeString(offsets[13], object.link);
writer.writeString(offsets[14], object.name);
writer.writeString(offsets[15], object.source);
writer.writeByte(offsets[16], object.status.index);
}
Manga _mangaDeserialize(
@ -237,13 +243,14 @@ Manga _mangaDeserialize(
id: id,
imageUrl: reader.readStringOrNull(offsets[7]),
isLocalArchive: reader.readBoolOrNull(offsets[8]),
lang: reader.readStringOrNull(offsets[9]),
lastRead: reader.readLongOrNull(offsets[10]),
lastUpdate: reader.readLongOrNull(offsets[11]),
link: reader.readStringOrNull(offsets[12]),
name: reader.readStringOrNull(offsets[13]),
source: reader.readStringOrNull(offsets[14]),
status: _MangastatusValueEnumMap[reader.readByteOrNull(offsets[15])] ??
isManga: reader.readBoolOrNull(offsets[9]),
lang: reader.readStringOrNull(offsets[10]),
lastRead: reader.readLongOrNull(offsets[11]),
lastUpdate: reader.readLongOrNull(offsets[12]),
link: reader.readStringOrNull(offsets[13]),
name: reader.readStringOrNull(offsets[14]),
source: reader.readStringOrNull(offsets[15]),
status: _MangastatusValueEnumMap[reader.readByteOrNull(offsets[16])] ??
Status.ongoing,
);
return object;
@ -275,18 +282,20 @@ P _mangaDeserializeProp<P>(
case 8:
return (reader.readBoolOrNull(offset)) as P;
case 9:
return (reader.readStringOrNull(offset)) as P;
return (reader.readBoolOrNull(offset)) as P;
case 10:
return (reader.readLongOrNull(offset)) as P;
return (reader.readStringOrNull(offset)) as P;
case 11:
return (reader.readLongOrNull(offset)) as P;
case 12:
return (reader.readStringOrNull(offset)) as P;
return (reader.readLongOrNull(offset)) as P;
case 13:
return (reader.readStringOrNull(offset)) as P;
case 14:
return (reader.readStringOrNull(offset)) as P;
case 15:
return (reader.readStringOrNull(offset)) as P;
case 16:
return (_MangastatusValueEnumMap[reader.readByteOrNull(offset)] ??
Status.ongoing) as P;
default:
@ -1555,6 +1564,32 @@ extension MangaQueryFilter on QueryBuilder<Manga, Manga, QFilterCondition> {
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> isMangaIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'isManga',
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> isMangaIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'isManga',
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> isMangaEqualTo(
bool? value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'isManga',
value: value,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> langIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
@ -2457,6 +2492,18 @@ extension MangaQuerySortBy on QueryBuilder<Manga, Manga, QSortBy> {
});
}
QueryBuilder<Manga, Manga, QAfterSortBy> sortByIsManga() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.asc);
});
}
QueryBuilder<Manga, Manga, QAfterSortBy> sortByIsMangaDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.desc);
});
}
QueryBuilder<Manga, Manga, QAfterSortBy> sortByLang() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'lang', Sort.asc);
@ -2627,6 +2674,18 @@ extension MangaQuerySortThenBy on QueryBuilder<Manga, Manga, QSortThenBy> {
});
}
QueryBuilder<Manga, Manga, QAfterSortBy> thenByIsManga() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.asc);
});
}
QueryBuilder<Manga, Manga, QAfterSortBy> thenByIsMangaDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.desc);
});
}
QueryBuilder<Manga, Manga, QAfterSortBy> thenByLang() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'lang', Sort.asc);
@ -2770,6 +2829,12 @@ extension MangaQueryWhereDistinct on QueryBuilder<Manga, Manga, QDistinct> {
});
}
QueryBuilder<Manga, Manga, QDistinct> distinctByIsManga() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'isManga');
});
}
QueryBuilder<Manga, Manga, QDistinct> distinctByLang(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
@ -2878,6 +2943,12 @@ extension MangaQueryProperty on QueryBuilder<Manga, Manga, QQueryProperty> {
});
}
QueryBuilder<Manga, bool?, QQueryOperations> isMangaProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'isManga');
});
}
QueryBuilder<Manga, String?, QQueryOperations> langProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'lang');

View file

@ -94,6 +94,31 @@ class Settings {
L10nLocale? locale;
@enumerated
DisplayType animeDisplayType;
int? libraryFilterAnimeDownloadType;
int? libraryFilterAnimeUnreadType;
int? libraryFilterAnimeStartedType;
int? libraryFilterAnimeBookMarkedType;
bool? animeLibraryShowCategoryTabs;
bool? animeLibraryDownloadedChapters;
bool? animeLibraryShowLanguage;
bool? animeLibraryShowNumbersOfItems;
bool? animeLibraryShowContinueReadingButton;
bool? animeLibraryLocalSource;
SortLibraryManga? sortLibraryAnime;
Settings(
{this.id = 227,
this.displayType = DisplayType.compactGrid,
@ -132,7 +157,19 @@ class Settings {
this.downloadLocation = "",
this.cropBorders = false,
this.libraryLocalSource,
this.autoUpdateExtensions = false});
this.autoUpdateExtensions = false,
this.animeDisplayType = DisplayType.compactGrid,
this.libraryFilterAnimeDownloadType = 0,
this.libraryFilterAnimeUnreadType = 0,
this.libraryFilterAnimeStartedType = 0,
this.libraryFilterAnimeBookMarkedType = 0,
this.animeLibraryShowCategoryTabs = false,
this.animeLibraryDownloadedChapters = false,
this.animeLibraryShowLanguage = false,
this.animeLibraryShowNumbersOfItems = false,
this.animeLibraryShowContinueReadingButton = false,
this.animeLibraryLocalSource,
this.sortLibraryAnime});
}
enum DisplayType {
@ -216,5 +253,5 @@ class FilterScanlator {
class L10nLocale {
String? languageCode;
String? countryCode;
L10nLocale({this.languageCode,this.countryCode});
L10nLocale({this.languageCode, this.countryCode});
}

File diff suppressed because it is too large Load diff

View file

@ -46,6 +46,8 @@ class Source {
String? headers;
bool? isManga;
Source({
this.id = 0,
this.name = '',
@ -68,6 +70,7 @@ class Source {
this.versionLast = "",
this.sourceCode = '',
this.headers = '',
this.isManga = true,
});
Source.fromJson(Map<String, dynamic> json) {
name = json['name'];
@ -83,93 +86,6 @@ class Source {
sourceCodeUrl = json['sourceCodeUrl'];
apiUrl = json['apiUrl'];
version = json['version'];
isManga = json['isManga'] ?? true;
}
}
// enum TypeSource {
// single,
// mangathemesia,
// comick,
// mmrcms,
// heancms,
// madara,
// mangadex
// }
// class Source {
// String? name;
// String? baseUrl;
// String? lang;
// bool? isActive;
// bool? isAdded;
// bool? isPinned;
// bool? lastUsed;
// bool? isFullData;
// bool? isNsfw;
// String? sourceCodeUrl;
// String? typeSource;
// String? iconUrl;
// bool? hasCloudflare;
// String? dateFormat;
// String? dateFormatLocale;
// String? apiUrl;
// String? version;
// Source({
// this.name = "",
// this.baseUrl = "",
// this.lang = "",
// this.typeSource = "",
// this.iconUrl = "",
// this.dateFormat,
// this.dateFormatLocale,
// this.isActive = true,
// this.isAdded = false,
// this.isNsfw = false,
// this.isFullData = false,
// this.hasCloudflare = false,
// this.isPinned = false,
// this.lastUsed = false,
// this.sourceCodeUrl = "",
// this.apiUrl = "",
// this.version = "",
// });
// Source.fromJson(Map<String, dynamic> json) {
// name = json['name'];
// id = json['id'];
// baseUrl = json['baseUrl'];
// lang = json['lang'];
// typeSource = json['typeSource'];
// iconUrl = json['iconUrl'];
// dateFormat = json['dateFormat'];
// dateFormatLocale = json['dateFormatLocale'];
// isNsfw = json['isNsfw'];
// hasCloudflare = json['hasCloudflare'];
// sourceCodeUrl = json['sourceCodeUrl'];
// apiUrl = json['apiUrl'];
// version = json['version'];
// }
// }

View file

@ -67,53 +67,58 @@ const SourceSchema = CollectionSchema(
name: r'isFullData',
type: IsarType.bool,
),
r'isNsfw': PropertySchema(
r'isManga': PropertySchema(
id: 10,
name: r'isManga',
type: IsarType.bool,
),
r'isNsfw': PropertySchema(
id: 11,
name: r'isNsfw',
type: IsarType.bool,
),
r'isPinned': PropertySchema(
id: 11,
id: 12,
name: r'isPinned',
type: IsarType.bool,
),
r'lang': PropertySchema(
id: 12,
id: 13,
name: r'lang',
type: IsarType.string,
),
r'lastUsed': PropertySchema(
id: 13,
id: 14,
name: r'lastUsed',
type: IsarType.bool,
),
r'name': PropertySchema(
id: 14,
id: 15,
name: r'name',
type: IsarType.string,
),
r'sourceCode': PropertySchema(
id: 15,
id: 16,
name: r'sourceCode',
type: IsarType.string,
),
r'sourceCodeUrl': PropertySchema(
id: 16,
id: 17,
name: r'sourceCodeUrl',
type: IsarType.string,
),
r'typeSource': PropertySchema(
id: 17,
id: 18,
name: r'typeSource',
type: IsarType.string,
),
r'version': PropertySchema(
id: 18,
id: 19,
name: r'version',
type: IsarType.string,
),
r'versionLast': PropertySchema(
id: 19,
id: 20,
name: r'versionLast',
type: IsarType.string,
)
@ -235,16 +240,17 @@ void _sourceSerialize(
writer.writeBool(offsets[7], object.isActive);
writer.writeBool(offsets[8], object.isAdded);
writer.writeBool(offsets[9], object.isFullData);
writer.writeBool(offsets[10], object.isNsfw);
writer.writeBool(offsets[11], object.isPinned);
writer.writeString(offsets[12], object.lang);
writer.writeBool(offsets[13], object.lastUsed);
writer.writeString(offsets[14], object.name);
writer.writeString(offsets[15], object.sourceCode);
writer.writeString(offsets[16], object.sourceCodeUrl);
writer.writeString(offsets[17], object.typeSource);
writer.writeString(offsets[18], object.version);
writer.writeString(offsets[19], object.versionLast);
writer.writeBool(offsets[10], object.isManga);
writer.writeBool(offsets[11], object.isNsfw);
writer.writeBool(offsets[12], object.isPinned);
writer.writeString(offsets[13], object.lang);
writer.writeBool(offsets[14], object.lastUsed);
writer.writeString(offsets[15], object.name);
writer.writeString(offsets[16], object.sourceCode);
writer.writeString(offsets[17], object.sourceCodeUrl);
writer.writeString(offsets[18], object.typeSource);
writer.writeString(offsets[19], object.version);
writer.writeString(offsets[20], object.versionLast);
}
Source _sourceDeserialize(
@ -265,16 +271,17 @@ Source _sourceDeserialize(
isActive: reader.readBoolOrNull(offsets[7]),
isAdded: reader.readBoolOrNull(offsets[8]),
isFullData: reader.readBoolOrNull(offsets[9]),
isNsfw: reader.readBoolOrNull(offsets[10]),
isPinned: reader.readBoolOrNull(offsets[11]),
lang: reader.readStringOrNull(offsets[12]),
lastUsed: reader.readBoolOrNull(offsets[13]),
name: reader.readStringOrNull(offsets[14]),
sourceCode: reader.readStringOrNull(offsets[15]),
sourceCodeUrl: reader.readStringOrNull(offsets[16]),
typeSource: reader.readStringOrNull(offsets[17]),
version: reader.readStringOrNull(offsets[18]),
versionLast: reader.readStringOrNull(offsets[19]),
isManga: reader.readBoolOrNull(offsets[10]),
isNsfw: reader.readBoolOrNull(offsets[11]),
isPinned: reader.readBoolOrNull(offsets[12]),
lang: reader.readStringOrNull(offsets[13]),
lastUsed: reader.readBoolOrNull(offsets[14]),
name: reader.readStringOrNull(offsets[15]),
sourceCode: reader.readStringOrNull(offsets[16]),
sourceCodeUrl: reader.readStringOrNull(offsets[17]),
typeSource: reader.readStringOrNull(offsets[18]),
version: reader.readStringOrNull(offsets[19]),
versionLast: reader.readStringOrNull(offsets[20]),
);
return object;
}
@ -311,11 +318,11 @@ P _sourceDeserializeProp<P>(
case 11:
return (reader.readBoolOrNull(offset)) as P;
case 12:
return (reader.readStringOrNull(offset)) as P;
case 13:
return (reader.readBoolOrNull(offset)) as P;
case 14:
case 13:
return (reader.readStringOrNull(offset)) as P;
case 14:
return (reader.readBoolOrNull(offset)) as P;
case 15:
return (reader.readStringOrNull(offset)) as P;
case 16:
@ -326,6 +333,8 @@ P _sourceDeserializeProp<P>(
return (reader.readStringOrNull(offset)) as P;
case 19:
return (reader.readStringOrNull(offset)) as P;
case 20:
return (reader.readStringOrNull(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
}
@ -1472,6 +1481,32 @@ extension SourceQueryFilter on QueryBuilder<Source, Source, QFilterCondition> {
});
}
QueryBuilder<Source, Source, QAfterFilterCondition> isMangaIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'isManga',
));
});
}
QueryBuilder<Source, Source, QAfterFilterCondition> isMangaIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'isManga',
));
});
}
QueryBuilder<Source, Source, QAfterFilterCondition> isMangaEqualTo(
bool? value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'isManga',
value: value,
));
});
}
QueryBuilder<Source, Source, QAfterFilterCondition> isNsfwIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
@ -2697,6 +2732,18 @@ extension SourceQuerySortBy on QueryBuilder<Source, Source, QSortBy> {
});
}
QueryBuilder<Source, Source, QAfterSortBy> sortByIsManga() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.asc);
});
}
QueryBuilder<Source, Source, QAfterSortBy> sortByIsMangaDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.desc);
});
}
QueryBuilder<Source, Source, QAfterSortBy> sortByIsNsfw() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isNsfw', Sort.asc);
@ -2951,6 +2998,18 @@ extension SourceQuerySortThenBy on QueryBuilder<Source, Source, QSortThenBy> {
});
}
QueryBuilder<Source, Source, QAfterSortBy> thenByIsManga() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.asc);
});
}
QueryBuilder<Source, Source, QAfterSortBy> thenByIsMangaDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.desc);
});
}
QueryBuilder<Source, Source, QAfterSortBy> thenByIsNsfw() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isNsfw', Sort.asc);
@ -3140,6 +3199,12 @@ extension SourceQueryWhereDistinct on QueryBuilder<Source, Source, QDistinct> {
});
}
QueryBuilder<Source, Source, QDistinct> distinctByIsManga() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'isManga');
});
}
QueryBuilder<Source, Source, QDistinct> distinctByIsNsfw() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'isNsfw');
@ -3276,6 +3341,12 @@ extension SourceQueryProperty on QueryBuilder<Source, Source, QQueryProperty> {
});
}
QueryBuilder<Source, bool?, QQueryOperations> isMangaProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'isManga');
});
}
QueryBuilder<Source, bool?, QQueryOperations> isNsfwProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'isNsfw');

View file

@ -47,4 +47,14 @@ class Track {
this.trackingUrl});
}
enum TrackStatus { reading, completed, onHold, dropped, planToRead, rereading }
enum TrackStatus {
reading,
completed,
onHold,
dropped,
planToRead,
rereading,
watching,
planToWatch,
reWatching
}

View file

@ -203,6 +203,9 @@ const _TrackstatusEnumValueMap = {
'dropped': 3,
'planToRead': 4,
'rereading': 5,
'watching': 6,
'planToWatch': 7,
'reWatching': 8,
};
const _TrackstatusValueEnumMap = {
0: TrackStatus.reading,
@ -211,6 +214,9 @@ const _TrackstatusValueEnumMap = {
3: TrackStatus.dropped,
4: TrackStatus.planToRead,
5: TrackStatus.rereading,
6: TrackStatus.watching,
7: TrackStatus.planToWatch,
8: TrackStatus.reWatching,
};
Id _trackGetId(Track object) {

8
lib/models/video.dart Normal file
View file

@ -0,0 +1,8 @@
class Video {
final String url;
final String quality;
final String originalUrl;
final Map<String, String>? headers;
Video(this.url, this.quality, this.originalUrl, {this.headers});
}

View file

@ -0,0 +1,296 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_meedu_videoplayer/meedu_player.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart' as riv;
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/video.dart';
import 'package:mangayomi/modules/anime/providers/stream_controller_provider.dart';
import 'package:mangayomi/modules/widgets/progress_center.dart';
import 'package:mangayomi/services/get_anime_servers.dart';
import 'package:mangayomi/utils/media_query.dart';
class AnimeStreamView extends riv.ConsumerWidget {
final Chapter episode;
const AnimeStreamView({
super.key,
required this.episode,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky,
overlays: []);
final serversData = ref.watch(getAnimeServersProvider(
chapter: episode,
));
return serversData.when(
data: (data) {
if (data.isEmpty &&
(episode.manga.value!.isLocalArchive ?? false) == false) {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(
title: const Text(''),
leading: BackButton(
onPressed: () {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context);
},
),
),
body: WillPopScope(
onWillPop: () async {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context);
return false;
},
child: const Center(
child: Text("Error"),
),
),
);
}
return AnimeStreamPage(
episode: episode,
videos: data,
);
},
error: (error, stackTrace) => Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(
title: const Text(''),
leading: BackButton(
onPressed: () {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context);
},
),
),
body: WillPopScope(
onWillPop: () async {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context);
return false;
},
child: Center(
child: Text(error.toString()),
),
),
),
loading: () {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
body: WillPopScope(
onWillPop: () async {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context);
return false;
},
child: Stack(
children: [
MeeduVideoPlayer(
header: (context, controller, responsive) => AppBar(
leading: BackButton(
color: Colors.white,
onPressed: () {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context);
},
),
),
controller: MeeduPlayerController(
autoHideControls: false,
enabledButtons:
const EnabledButtons(playPauseAndRepeat: false),
screenManager: const ScreenManager(
forceLandScapeInFullscreen: false,
),
),
),
const ProgressCenter(),
],
),
),
);
},
);
}
}
class AnimeStreamPage extends StatefulWidget {
final List<Video> videos;
final Chapter episode;
const AnimeStreamPage({Key? key, required this.videos, required this.episode})
: super(key: key);
@override
State<AnimeStreamPage> createState() => _AnimeStreamPageState();
}
class _AnimeStreamPageState extends State<AnimeStreamPage> {
final _controller = MeeduPlayerController(
screenManager: const ScreenManager(
forceLandScapeInFullscreen: false,
),
);
late final streamController = AnimeStreamController(episode: widget.episode);
/// listener for the video quality
final ValueNotifier<Video?> _video = ValueNotifier(null);
late Duration _currentPosition =
streamController.geTCurrentPosition(); // to save the video position
/// subscription to listen the video position changes
StreamSubscription? _currentPositionSubs;
@override
void initState() {
super.initState();
_video.value = widget.videos[0]; // set the default video quality (480p)
// listen the video position
_currentPositionSubs = _controller.onPositionChanged.listen(
(Duration position) {
_currentPosition = position; // save the video position
streamController.setCurrentPosition(position.inMilliseconds);
streamController.setAnimeHistoryUpdate();
},
);
WidgetsBinding.instance.addPostFrameCallback((_) {
_setDataSource();
});
}
@override
void dispose() {
_currentPositionSubs?.cancel(); // cancel the subscription
_controller.dispose();
super.dispose();
}
void _onChangeVideoQuality() {
showCupertinoModalPopup(
context: context,
builder: (_) => CupertinoActionSheet(
actions: List.generate(
widget.videos.length,
(index) {
final quality = widget.videos[index];
return CupertinoActionSheetAction(
child: Text(quality.quality),
onPressed: () {
_video.value = quality; // change the video quality
_setDataSource(); // update the datasource
Navigator.maybePop(_);
},
);
},
),
cancelButton: CupertinoActionSheetAction(
onPressed: () => Navigator.maybePop(_),
isDestructiveAction: true,
child: const Text("Cancel"),
),
),
);
}
Future<void> _setDataSource() async {
// set the data source and play the video in the last video position
await _controller.setDataSource(
DataSource(
type: DataSourceType.network,
source: _video.value!.url,
httpHeaders: _video.value!.headers),
autoplay: true,
seekTo: _currentPosition,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: WillPopScope(
onWillPop: () async {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context);
return false;
},
child: MeeduVideoPlayer(
controller: _controller,
header: (ctx, controller, responsive) {
// creates a responsive fontSize using the size of video container
final double fontSize = responsive.ip(3);
return AppBar(
title: ListTile(
dense: true,
title: SizedBox(
width: mediaWidth(context, 0.8),
child: Text(
widget.episode.manga.value!.name!,
style: const TextStyle(
fontWeight: FontWeight.bold, color: Colors.white),
overflow: TextOverflow.ellipsis,
),
),
subtitle: SizedBox(
width: mediaWidth(context, 0.8),
child: Text(
widget.episode.name!,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w400,
color: Colors.white),
overflow: TextOverflow.ellipsis,
),
),
),
leading: BackButton(
color: Colors.white,
onPressed: () {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context);
},
),
actions: [
Padding(
padding: const EdgeInsets.all(8.0),
child: CupertinoButton(
padding: const EdgeInsets.all(5),
onPressed: _onChangeVideoQuality,
child: ValueListenableBuilder<Video?>(
valueListenable: _video,
builder: (context, Video? video, child) {
return Text(
video!.quality,
style: TextStyle(
fontSize: fontSize > 18 ? 18 : fontSize,
color: Colors.white,
),
);
},
),
),
)
],
);
},
),
),
);
}
}

View file

@ -0,0 +1,124 @@
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
class AnimeStreamController {
final Chapter episode;
AnimeStreamController({required this.episode});
Manga getAnime() {
return episode.manga.value!;
}
Chapter geAnime() {
return episode;
}
final incognitoMode = isar.settings.getSync(227)!.incognitoMode!;
Settings getIsarSetting() {
return isar.settings.getSync(227)!;
}
int getPrevEpisodeIndex() {
final episodes = getAnime().chapters.toList();
int? index;
for (var i = 0; i < episodes.length; i++) {
if (episodes[i].id == episode.id) {
index = i + 1;
}
}
return index!;
}
int getNextEpisodeIndex() {
final episodes = getAnime().chapters.toList();
int? index;
for (var i = 0; i < episodes.length; i++) {
if (episodes[i].id == episode.id) {
index = i - 1;
}
}
return index!;
}
Chapter getPrevEpisode() {
return getAnime().chapters.toList()[getPrevEpisodeIndex()];
}
Chapter getNextEpisode() {
return getAnime().chapters.toList()[getNextEpisodeIndex()];
}
int getChaptersLength() {
return getAnime().chapters.length;
}
Duration geTCurrentPosition() {
if (!incognitoMode) {
String position = episode.lastPageRead ?? "0";
return Duration(
milliseconds: episode.isRead!
? 0
: int.parse(position.isEmpty ? "0" : position));
}
return Duration.zero;
}
void setAnimeHistoryUpdate() {
if (!incognitoMode) {
isar.writeTxnSync(() {
Manga? manga = episode.manga.value;
manga!.lastRead = DateTime.now().millisecondsSinceEpoch;
isar.mangas.putSync(manga);
});
History? history;
final empty =
isar.historys.filter().mangaIdEqualTo(getAnime().id).isEmptySync();
if (empty) {
history = History(
mangaId: getAnime().id,
date: DateTime.now().millisecondsSinceEpoch.toString())
..chapter.value = episode;
} else {
history = (isar.historys
.filter()
.mangaIdEqualTo(getAnime().id)
.findFirstSync())!
..chapter.value = episode
..date = DateTime.now().millisecondsSinceEpoch.toString();
}
isar.writeTxnSync(() {
isar.historys.putSync(history!);
history.chapter.saveSync();
});
}
}
void setCurrentPosition(int duration) {
if (!incognitoMode) {
final chap = episode;
isar.writeTxnSync(() {
chap.lastPageRead = (duration).toString();
isar.chapters.putSync(chap);
});
}
}
String getAnimeName() {
return getAnime().name!;
}
String getSourceName() {
return getAnime().source!;
}
String getChapterTitle() {
return episode.name!;
}
}

View file

@ -370,4 +370,5 @@ class GetArchiveDataFromFileProvider
return _SystemHash.finish(hash);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -21,7 +21,7 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
@override
void initState() {
_tabBarController = TabController(length: 3, vsync: this);
_tabBarController = TabController(length: 5, vsync: this);
_tabBarController.animateTo(0);
_tabBarController.addListener(() {
_chekPermission();
@ -44,7 +44,7 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
final l10n = l10nLocalizations(context)!;
return DefaultTabController(
animationDuration: Duration.zero,
length: 3,
length: 5,
child: Scaffold(
appBar: AppBar(
elevation: 0,
@ -70,22 +70,25 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
},
controller: _textEditingController,
)
: _tabBarController.index != 2
: _tabBarController.index != 4
? IconButton(
splashRadius: 20,
onPressed: () {
if (_tabBarController.index == 1) {
if (_tabBarController.index != 1 &&
_tabBarController.index != 0) {
setState(() {
_isSearch = true;
});
} else if (_tabBarController.index == 0) {
context.push(
'/globalSearch',
);
} else {
context.push('/globalSearch',
extra: _tabBarController.index == 0
? true
: false);
}
},
icon: Icon(
_tabBarController.index == 0
_tabBarController.index == 0 ||
_tabBarController.index == 1
? Icons.travel_explore_rounded
: Icons.search_rounded,
color: Theme.of(context).hintColor))
@ -94,34 +97,53 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
splashRadius: 20,
onPressed: () {
if (_tabBarController.index == 0) {
context.push('/sourceFilter');
context.push('/sourceFilter', extra: true);
} else if (_tabBarController.index == 1) {
context.push('/sourceFilter', extra: false);
} else if (_tabBarController.index == 2) {
_textEditingController.clear();
context.push('/extensionLang');
context.push('/ExtensionLang', extra: true);
} else if (_tabBarController.index == 3) {
_textEditingController.clear();
context.push('/ExtensionLang', extra: false);
} else {}
},
icon: Icon(
_tabBarController.index == 0
_tabBarController.index == 0 || _tabBarController.index == 1
? Icons.filter_list_sharp
: _tabBarController.index == 1
: _tabBarController.index == 2 ||
_tabBarController.index == 3
? Icons.translate_rounded
: Icons.help_outline_outlined,
color: Theme.of(context).hintColor)),
],
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
indicatorSize: TabBarIndicatorSize.label,
isScrollable: true,
controller: _tabBarController,
tabs: [
Tab(text: l10n.sources),
Tab(text: l10n.extensions),
Tab(text: l10n.manga_sources),
Tab(text: l10n.anime_sources),
Tab(text: l10n.manga_extensions),
Tab(text: l10n.anime_extensions),
Tab(text: l10n.migrate),
],
),
),
body: TabBarView(controller: _tabBarController, children: [
const SourcesScreen(),
const SourcesScreen(
isManga: true,
),
const SourcesScreen(
isManga: false,
),
ExtensionScreen(
query: _textEditingController.text,
isManga: true,
),
ExtensionScreen(
query: _textEditingController.text,
isManga: false,
),
const MigrateScreen()
]),

View file

@ -8,7 +8,8 @@ import 'package:mangayomi/utils/language.dart';
import 'package:mangayomi/modules/browse/extension/widgets/extension_lang_list_tile_widget.dart';
class ExtensionsLang extends ConsumerWidget {
const ExtensionsLang({super.key});
final bool isManga;
const ExtensionsLang({required this.isManga, super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
@ -20,8 +21,12 @@ class ExtensionsLang extends ConsumerWidget {
title: Text(l10n.extensions),
),
body: StreamBuilder(
stream:
isar.sources.filter().idIsNotNull().watch(fireImmediately: true),
stream: isar.sources
.filter()
.idIsNotNull()
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true),
builder: (context, snapshot) {
List<Source>? entries = snapshot.hasData ? snapshot.data : [];
return ListView.builder(
@ -33,15 +38,16 @@ class ExtensionsLang extends ConsumerWidget {
onChanged: (val) {
isar.writeTxnSync(() {
for (var source in entries) {
if (source.lang!.toLowerCase() == lang) {
isar.sources.putSync(source..isActive = val == true);
if (source.lang!.toLowerCase() == lang.toLowerCase()) {
isar.sources.putSync(source..isActive = val);
}
}
});
},
value: entries!
.where((element) => element.lang!.toLowerCase() == lang)
.where((element) => element.isActive!)
.where((element) =>
element.lang!.toLowerCase() == lang.toLowerCase() &&
element.isActive!)
.isNotEmpty,
);
},

View file

@ -4,20 +4,30 @@ import 'package:grouped_list/grouped_list.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/browse/extension/providers/fetch_sources.dart';
import 'package:mangayomi/modules/browse/extension/providers/fetch_anime_sources.dart';
import 'package:mangayomi/modules/browse/extension/providers/fetch_manga_sources.dart';
import 'package:mangayomi/utils/language.dart';
import 'package:mangayomi/modules/browse/extension/widgets/extension_list_tile_widget.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
class ExtensionScreen extends ConsumerWidget {
final bool isManga;
final String query;
const ExtensionScreen({required this.query, super.key});
const ExtensionScreen(
{required this.query, required this.isManga, super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
ref.watch(fetchSourcesListProvider(id: null));
if (isManga) {
ref.watch(fetchMangaSourcesListProvider(id: null));
} else {
ref.watch(fetchAnimeSourcesListProvider(id: null));
}
return RefreshIndicator(
onRefresh: () => ref.refresh(fetchSourcesListProvider(id: null).future),
onRefresh: () => isManga
? ref.refresh(fetchMangaSourcesListProvider(id: null).future)
: ref.refresh(fetchAnimeSourcesListProvider(id: null).future),
child: Padding(
padding: const EdgeInsets.only(top: 10),
child: StreamBuilder(
@ -28,12 +38,14 @@ class ExtensionScreen extends ConsumerWidget {
.idIsNotNull()
.and()
.isActiveEqualTo(true)
.isMangaEqualTo(isManga)
.watch(fireImmediately: true)
: isar.sources
.filter()
.idIsNotNull()
.and()
.isActiveEqualTo(true)
.isMangaEqualTo(isManga)
.watch(fireImmediately: true),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {

View file

@ -0,0 +1,106 @@
import 'dart:convert';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/browse/extension/providers/fetch_manga_sources.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:http/http.dart' as http;
part 'fetch_anime_sources.g.dart';
@riverpod
Future fetchAnimeSourcesList(FetchAnimeSourcesListRef ref, {int? id}) async {
final req = await http.get(Uri.parse(
"https://kodjodevf.github.io/mangayomi-extensions/anime_index.json"));
final res = jsonDecode(req.body) as List;
final sourceList = res.map((e) => Source.fromJson(e)).toList();
isar.writeTxnSync(() async {
for (var source in sourceList) {
if (!source.isManga!) {
if (id != null) {
if (id == source.id) {
final sourc = isar.sources.getSync(id)!;
final req = await http.get(Uri.parse(source.sourceCodeUrl!));
final headers = await getHeaders(req.body, source.baseUrl!);
isar.writeTxnSync(() {
isar.sources.putSync(sourc
..headers = headers ?? ""
..isAdded = true
..sourceCode = req.body
..sourceCodeUrl = source.sourceCodeUrl
..id = id
..apiUrl = source.apiUrl
..baseUrl = source.baseUrl
..dateFormat = source.dateFormat
..dateFormatLocale = source.dateFormatLocale
..hasCloudflare = source.hasCloudflare
..iconUrl = source.iconUrl
..typeSource = source.typeSource
..lang = source.lang
..isNsfw = source.isNsfw
..name = source.name
..version = source.version
..versionLast = source.version
..isManga = source.isManga);
});
// log("successfully installed");
}
} else if (isar.sources.getSync(source.id!) != null) {
// log("exist");
final sourc = isar.sources.getSync(source.id!)!;
if (compareVersions(sourc.version!, source.version!) < 0) {
// log("update aivalable auto update");
if (isar.settings.getSync(227)!.autoUpdateExtensions ?? false) {
final req = await http.get(Uri.parse(source.sourceCodeUrl!));
final headers = await getHeaders(req.body, source.baseUrl!);
isar.writeTxnSync(() {
isar.sources.putSync(sourc
..headers = headers
..sourceCode = req.body
..sourceCodeUrl = source.sourceCodeUrl
..id = source.id
..apiUrl = source.apiUrl
..baseUrl = source.baseUrl
..dateFormat = source.dateFormat
..dateFormatLocale = source.dateFormatLocale
..hasCloudflare = source.hasCloudflare
..iconUrl = source.iconUrl
..typeSource = source.typeSource
..isFullData = source.isFullData
..lang = source.lang
..isNsfw = source.isNsfw
..name = source.name
..version = source.version
..versionLast = source.version
..isManga = source.isManga);
});
} else {
// log("update aivalable");
isar.sources.putSync(sourc..versionLast = source.version);
}
}
} else {
isar.sources.putSync(Source()
..sourceCodeUrl = source.sourceCodeUrl
..id = source.id
..sourceCode = source.sourceCode
..apiUrl = source.apiUrl
..baseUrl = source.baseUrl
..dateFormat = source.dateFormat
..dateFormatLocale = source.dateFormatLocale
..hasCloudflare = source.hasCloudflare
..iconUrl = source.iconUrl
..typeSource = source.typeSource
..lang = source.lang
..isNsfw = source.isNsfw
..name = source.name
..version = source.version
..versionLast = source.version
..isManga = source.isManga);
// log("new source");
}
}
}
});
}

View file

@ -1,12 +1,13 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'fetch_sources.dart';
part of 'fetch_anime_sources.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$fetchSourcesListHash() => r'151bfddc9daf2cde079bf0f98f523d92b7e6ab00';
String _$fetchAnimeSourcesListHash() =>
r'1b16436684b132a5dc6db2159e38200f1dc9b11e';
/// Copied from Dart SDK
class _SystemHash {
@ -29,29 +30,29 @@ class _SystemHash {
}
}
typedef FetchSourcesListRef = AutoDisposeFutureProviderRef<dynamic>;
typedef FetchAnimeSourcesListRef = AutoDisposeFutureProviderRef<dynamic>;
/// See also [fetchSourcesList].
@ProviderFor(fetchSourcesList)
const fetchSourcesListProvider = FetchSourcesListFamily();
/// See also [fetchAnimeSourcesList].
@ProviderFor(fetchAnimeSourcesList)
const fetchAnimeSourcesListProvider = FetchAnimeSourcesListFamily();
/// See also [fetchSourcesList].
class FetchSourcesListFamily extends Family<AsyncValue<dynamic>> {
/// See also [fetchSourcesList].
const FetchSourcesListFamily();
/// See also [fetchAnimeSourcesList].
class FetchAnimeSourcesListFamily extends Family<AsyncValue<dynamic>> {
/// See also [fetchAnimeSourcesList].
const FetchAnimeSourcesListFamily();
/// See also [fetchSourcesList].
FetchSourcesListProvider call({
/// See also [fetchAnimeSourcesList].
FetchAnimeSourcesListProvider call({
int? id,
}) {
return FetchSourcesListProvider(
return FetchAnimeSourcesListProvider(
id: id,
);
}
@override
FetchSourcesListProvider getProviderOverride(
covariant FetchSourcesListProvider provider,
FetchAnimeSourcesListProvider getProviderOverride(
covariant FetchAnimeSourcesListProvider provider,
) {
return call(
id: provider.id,
@ -70,35 +71,35 @@ class FetchSourcesListFamily extends Family<AsyncValue<dynamic>> {
_allTransitiveDependencies;
@override
String? get name => r'fetchSourcesListProvider';
String? get name => r'fetchAnimeSourcesListProvider';
}
/// See also [fetchSourcesList].
class FetchSourcesListProvider extends AutoDisposeFutureProvider<dynamic> {
/// See also [fetchSourcesList].
FetchSourcesListProvider({
/// See also [fetchAnimeSourcesList].
class FetchAnimeSourcesListProvider extends AutoDisposeFutureProvider<dynamic> {
/// See also [fetchAnimeSourcesList].
FetchAnimeSourcesListProvider({
this.id,
}) : super.internal(
(ref) => fetchSourcesList(
(ref) => fetchAnimeSourcesList(
ref,
id: id,
),
from: fetchSourcesListProvider,
name: r'fetchSourcesListProvider',
from: fetchAnimeSourcesListProvider,
name: r'fetchAnimeSourcesListProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$fetchSourcesListHash,
dependencies: FetchSourcesListFamily._dependencies,
: _$fetchAnimeSourcesListHash,
dependencies: FetchAnimeSourcesListFamily._dependencies,
allTransitiveDependencies:
FetchSourcesListFamily._allTransitiveDependencies,
FetchAnimeSourcesListFamily._allTransitiveDependencies,
);
final int? id;
@override
bool operator ==(Object other) {
return other is FetchSourcesListProvider && other.id == id;
return other is FetchAnimeSourcesListProvider && other.id == id;
}
@override
@ -109,4 +110,5 @@ class FetchSourcesListProvider extends AutoDisposeFutureProvider<dynamic> {
return _SystemHash.finish(hash);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -0,0 +1,152 @@
import 'dart:convert';
import 'package:dart_eval/stdlib/core.dart';
import 'package:mangayomi/eval/compiler/compiler.dart';
import 'package:mangayomi/eval/runtime/runtime.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/models/source.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:http/http.dart' as http;
part 'fetch_manga_sources.g.dart';
@riverpod
Future fetchMangaSourcesList(FetchMangaSourcesListRef ref, {int? id}) async {
final req = await http.get(
Uri.parse("https://kodjodevf.github.io/mangayomi-extensions/index.json"));
final res = jsonDecode(req.body) as List;
final sourceList = res.map((e) => Source.fromJson(e)).toList();
isar.writeTxnSync(() async {
for (var source in sourceList) {
if (source.isManga!) {
if (id != null) {
if (id == source.id) {
final sourc = isar.sources.getSync(id)!;
final req = await http.get(Uri.parse(source.sourceCodeUrl!));
final headers = await getHeaders(req.body, source.baseUrl!);
isar.writeTxnSync(() {
isar.sources.putSync(sourc
..headers = headers ?? ""
..isAdded = true
..sourceCode = req.body
..sourceCodeUrl = source.sourceCodeUrl
..id = id
..apiUrl = source.apiUrl
..baseUrl = source.baseUrl
..dateFormat = source.dateFormat
..dateFormatLocale = source.dateFormatLocale
..hasCloudflare = source.hasCloudflare
..iconUrl = source.iconUrl
..typeSource = source.typeSource
..lang = source.lang
..isNsfw = source.isNsfw
..name = source.name
..version = source.version
..versionLast = source.version
..isManga = source.isManga);
});
// log("successfully installed");
}
} else if (isar.sources.getSync(source.id!) != null) {
// log("exist");
final sourc = isar.sources.getSync(source.id!)!;
if (compareVersions(sourc.version!, source.version!) < 0) {
// log("update aivalable auto update");
if (isar.settings.getSync(227)!.autoUpdateExtensions ?? false) {
final req = await http.get(Uri.parse(source.sourceCodeUrl!));
final headers = await getHeaders(req.body, source.baseUrl!);
isar.writeTxnSync(() {
isar.sources.putSync(sourc
..headers = headers
..sourceCode = req.body
..sourceCodeUrl = source.sourceCodeUrl
..id = source.id
..apiUrl = source.apiUrl
..baseUrl = source.baseUrl
..dateFormat = source.dateFormat
..dateFormatLocale = source.dateFormatLocale
..hasCloudflare = source.hasCloudflare
..iconUrl = source.iconUrl
..typeSource = source.typeSource
..isFullData = source.isFullData
..lang = source.lang
..isNsfw = source.isNsfw
..name = source.name
..version = source.version
..versionLast = source.version
..isManga = source.isManga);
});
} else {
// log("update aivalable");
isar.sources.putSync(sourc..versionLast = source.version);
}
}
} else {
isar.sources.putSync(Source()
..sourceCodeUrl = source.sourceCodeUrl
..id = source.id
..sourceCode = source.sourceCode
..apiUrl = source.apiUrl
..baseUrl = source.baseUrl
..dateFormat = source.dateFormat
..dateFormatLocale = source.dateFormatLocale
..hasCloudflare = source.hasCloudflare
..iconUrl = source.iconUrl
..typeSource = source.typeSource
..lang = source.lang
..isNsfw = source.isNsfw
..name = source.name
..version = source.version
..versionLast = source.version
..isManga = source.isManga);
// log("new source");
}
}
}
});
}
int compareVersions(String version1, String version2) {
List<String> v1Components = version1.split('.');
List<String> v2Components = version2.split('.');
for (int i = 0; i < v1Components.length && i < v2Components.length; i++) {
int v1Value = int.parse(v1Components[i]);
int v2Value = int.parse(v2Components[i]);
if (v1Value < v2Value) {
return -1;
} else if (v1Value > v2Value) {
return 1;
}
}
if (v1Components.length < v2Components.length) {
return -1;
} else if (v1Components.length > v2Components.length) {
return 1;
}
return 0;
}
Future<String?> getHeaders(String codeSource, String baseUrl) async {
try {
final bytecode = compilerEval(codeSource);
final runtime = runtimeEval(bytecode);
runtime.args = [$String(baseUrl)];
var res = await runtime.executeLib(
'package:mangayomi/main.dart',
'getHeader',
);
Map<String, String> headers = {};
if (res is $Map) {
headers = res.$reified
.map((key, value) => MapEntry(key.toString(), value.toString()));
}
return jsonEncode(headers);
} catch (_) {
return null;
}
}

View file

@ -0,0 +1,114 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'fetch_manga_sources.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$fetchMangaSourcesListHash() =>
r'82665771175f4fea39c0dee77d06d568737ea989';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
typedef FetchMangaSourcesListRef = AutoDisposeFutureProviderRef<dynamic>;
/// See also [fetchMangaSourcesList].
@ProviderFor(fetchMangaSourcesList)
const fetchMangaSourcesListProvider = FetchMangaSourcesListFamily();
/// See also [fetchMangaSourcesList].
class FetchMangaSourcesListFamily extends Family<AsyncValue<dynamic>> {
/// See also [fetchMangaSourcesList].
const FetchMangaSourcesListFamily();
/// See also [fetchMangaSourcesList].
FetchMangaSourcesListProvider call({
int? id,
}) {
return FetchMangaSourcesListProvider(
id: id,
);
}
@override
FetchMangaSourcesListProvider getProviderOverride(
covariant FetchMangaSourcesListProvider provider,
) {
return call(
id: provider.id,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'fetchMangaSourcesListProvider';
}
/// See also [fetchMangaSourcesList].
class FetchMangaSourcesListProvider extends AutoDisposeFutureProvider<dynamic> {
/// See also [fetchMangaSourcesList].
FetchMangaSourcesListProvider({
this.id,
}) : super.internal(
(ref) => fetchMangaSourcesList(
ref,
id: id,
),
from: fetchMangaSourcesListProvider,
name: r'fetchMangaSourcesListProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$fetchMangaSourcesListHash,
dependencies: FetchMangaSourcesListFamily._dependencies,
allTransitiveDependencies:
FetchMangaSourcesListFamily._allTransitiveDependencies,
);
final int? id;
@override
bool operator ==(Object other) {
return other is FetchMangaSourcesListProvider && other.id == id;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, id.hashCode);
return _SystemHash.finish(hash);
}
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -1,147 +0,0 @@
import 'dart:convert';
import 'package:dart_eval/stdlib/core.dart';
import 'package:mangayomi/eval/compiler/compiler.dart';
import 'package:mangayomi/eval/runtime/runtime.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/models/source.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:http/http.dart' as http;
part 'fetch_sources.g.dart';
@riverpod
Future fetchSourcesList(FetchSourcesListRef ref, {int? id}) async {
final req = await http
.get(Uri.parse("https://kodjodevf.github.io/mangayomi-extensions/index.json"));
final res = jsonDecode(req.body) as List;
final sourceList = res.map((e) => Source.fromJson(e)).toList();
isar.writeTxnSync(() async {
for (var source in sourceList) {
if (id != null) {
if (id == source.id) {
final sourc = isar.sources.getSync(id)!;
final req = await http.get(Uri.parse(source.sourceCodeUrl!));
final headers = await getHeaders(req.body, source.baseUrl!);
isar.writeTxnSync(() {
isar.sources.putSync(sourc
..headers = headers ?? ""
..isAdded = true
..sourceCode = req.body
..sourceCodeUrl = source.sourceCodeUrl
..id = id
..apiUrl = source.apiUrl
..baseUrl = source.baseUrl
..dateFormat = source.dateFormat
..dateFormatLocale = source.dateFormatLocale
..hasCloudflare = source.hasCloudflare
..iconUrl = source.iconUrl
..typeSource = source.typeSource
..lang = source.lang
..isNsfw = source.isNsfw
..name = source.name
..version = source.version
..versionLast = source.version);
});
// log("successfully installed");
}
} else if (isar.sources.getSync(source.id!) != null) {
// log("exist");
final sourc = isar.sources.getSync(source.id!)!;
if (compareVersions(sourc.version!, source.version!) < 0) {
// log("update aivalable auto update");
if (isar.settings.getSync(227)!.autoUpdateExtensions ?? false) {
final req = await http.get(Uri.parse(source.sourceCodeUrl!));
final headers = await getHeaders(req.body, source.baseUrl!);
isar.writeTxnSync(() {
isar.sources.putSync(sourc
..headers = headers
..sourceCode = req.body
..sourceCodeUrl = source.sourceCodeUrl
..id = source.id
..apiUrl = source.apiUrl
..baseUrl = source.baseUrl
..dateFormat = source.dateFormat
..dateFormatLocale = source.dateFormatLocale
..hasCloudflare = source.hasCloudflare
..iconUrl = source.iconUrl
..typeSource = source.typeSource
..isFullData = source.isFullData
..lang = source.lang
..isNsfw = source.isNsfw
..name = source.name
..version = source.version
..versionLast = source.version);
});
} else {
// log("update aivalable");
isar.sources.putSync(sourc..versionLast = source.version);
}
}
} else {
isar.sources.putSync(Source()
..sourceCodeUrl = source.sourceCodeUrl
..id = source.id
..sourceCode = source.sourceCode
..apiUrl = source.apiUrl
..baseUrl = source.baseUrl
..dateFormat = source.dateFormat
..dateFormatLocale = source.dateFormatLocale
..hasCloudflare = source.hasCloudflare
..iconUrl = source.iconUrl
..typeSource = source.typeSource
..lang = source.lang
..isNsfw = source.isNsfw
..name = source.name
..version = source.version
..versionLast = source.version);
// log("new source");
}
}
});
}
int compareVersions(String version1, String version2) {
List<String> v1Components = version1.split('.');
List<String> v2Components = version2.split('.');
for (int i = 0; i < v1Components.length && i < v2Components.length; i++) {
int v1Value = int.parse(v1Components[i]);
int v2Value = int.parse(v2Components[i]);
if (v1Value < v2Value) {
return -1;
} else if (v1Value > v2Value) {
return 1;
}
}
if (v1Components.length < v2Components.length) {
return -1;
} else if (v1Components.length > v2Components.length) {
return 1;
}
return 0;
}
Future<String?> getHeaders(String codeSource, String baseUrl) async {
try {
final bytecode = compilerEval(codeSource);
final runtime = runtimeEval(bytecode);
runtime.args = [$String(baseUrl)];
var result2 = await runtime.executeLib(
'package:package:mangayomi/main.dart',
'getHeader',
);
Map<String, String> headers = {};
if (result2 is $Map) {
headers = result2.$reified
.map((key, value) => MapEntry(key.toString(), value.toString()));
}
return jsonEncode(headers);
} catch (_) {
return null;
}
}

View file

@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/browse/extension/providers/fetch_sources.dart';
import 'package:mangayomi/modules/browse/extension/providers/fetch_anime_sources.dart';
import 'package:mangayomi/modules/browse/extension/providers/fetch_manga_sources.dart';
import 'package:mangayomi/utils/language.dart';
class ExtensionListTileWidget extends ConsumerStatefulWidget {
@ -90,8 +91,13 @@ class _ExtensionListTileWidgetState
setState(() {
_isLoading = true;
});
await ref.watch(
fetchSourcesListProvider(id: widget.source.id).future);
widget.source.isManga!
? await ref.watch(
fetchMangaSourcesListProvider(id: widget.source.id)
.future)
: await ref.watch(
fetchAnimeSourcesListProvider(id: widget.source.id)
.future);
if (mounted) {
setState(() {
_isLoading = false;

View file

@ -21,7 +21,9 @@ import 'package:mangayomi/modules/widgets/bottom_text_widget.dart';
import 'package:mangayomi/modules/widgets/manga_image_card_widget.dart';
class GlobalSearchScreen extends ConsumerStatefulWidget {
final bool isManga;
const GlobalSearchScreen({
required this.isManga,
super.key,
});
@ -35,12 +37,19 @@ class _GlobalSearchScreenState extends ConsumerState<GlobalSearchScreen> {
@override
Widget build(BuildContext context) {
final sourceList = ref.watch(onlyIncludePinnedSourceStateProvider)
? isar.sources.filter().isPinnedEqualTo(true).findAllSync()
? isar.sources
.filter()
.isPinnedEqualTo(true)
.and()
.isMangaEqualTo(widget.isManga)
.findAllSync()
: isar.sources
.filter()
.idIsNotNull()
.and()
.isAddedEqualTo(true)
.and()
.isMangaEqualTo(widget.isManga)
.findAllSync();
return Scaffold(
appBar: AppBar(
@ -186,7 +195,10 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
return GestureDetector(
onTap: () async {
pushToMangaReaderDetail(
context: context, getManga: data, lang: widget.source.lang!);
context: context,
getManga: data,
lang: widget.source.lang!,
isManga: widget.source.isManga ?? true);
},
child: StreamBuilder(
stream: isar.mangas

View file

@ -9,7 +9,8 @@ import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/language.dart';
class SourcesFilterScreen extends ConsumerWidget {
const SourcesFilterScreen({super.key});
final bool isManga;
const SourcesFilterScreen({required this.isManga, super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
@ -26,6 +27,8 @@ class SourcesFilterScreen extends ConsumerWidget {
.idIsNotNull()
.and()
.sourceCodeIsNotEmpty()
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
@ -43,7 +46,8 @@ class SourcesFilterScreen extends ConsumerWidget {
value: entries
.where((element) =>
element.lang!.toLowerCase() == groupByValue &&
element.isActive!)
element.isActive! &&
element.isManga == isManga)
.isNotEmpty,
onChanged: (val) {
isar.writeTxnSync(() {
@ -65,7 +69,8 @@ class SourcesFilterScreen extends ConsumerWidget {
if (entries
.where((s) =>
s.lang!.toLowerCase() == element.lang &&
s.isActive!)
s.isActive! &&
s.isManga == isManga)
.isEmpty) {
return Container();
}

View file

@ -10,7 +10,8 @@ import 'package:mangayomi/utils/language.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
class SourcesScreen extends ConsumerWidget {
const SourcesScreen({super.key});
final bool isManga;
const SourcesScreen({required this.isManga, super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
@ -29,6 +30,8 @@ class SourcesScreen extends ConsumerWidget {
.isActiveEqualTo(true)
.and()
.lastUsedEqualTo(true)
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true),
builder: (context, snapshot) {
if (!snapshot.hasData) {
@ -76,6 +79,8 @@ class SourcesScreen extends ConsumerWidget {
.isActiveEqualTo(true)
.and()
.isPinnedEqualTo(true)
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true),
builder: (context, snapshot) {
if (!snapshot.hasData) {
@ -123,6 +128,8 @@ class SourcesScreen extends ConsumerWidget {
.isActiveEqualTo(true)
.and()
.isPinnedEqualTo(false)
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true),
builder: (context, snapshot) {
if (!snapshot.hasData) {

View file

@ -3,8 +3,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:grouped_list/grouped_list.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/modules/history/providers/isar_providers.dart';
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
@ -22,15 +25,33 @@ class HistoryScreen extends ConsumerStatefulWidget {
ConsumerState<HistoryScreen> createState() => _HistoryScreenState();
}
class _HistoryScreenState extends ConsumerState<HistoryScreen> {
class _HistoryScreenState extends ConsumerState<HistoryScreen>
with TickerProviderStateMixin {
late TabController _tabBarController;
@override
void initState() {
_tabBarController = TabController(length: 2, vsync: this);
_tabBarController.animateTo(0);
_tabBarController.addListener(() {
setState(() {
_textEditingController.clear();
_isSearch = false;
});
});
super.initState();
}
final _textEditingController = TextEditingController();
bool _isSearch = false;
List<History> entriesData = [];
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
final history = ref.watch(getAllHistoryStreamProvider);
return Scaffold(
return DefaultTabController(
animationDuration: Duration.zero,
length: 2,
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
@ -92,8 +113,21 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
),
TextButton(
onPressed: () {
List<History> histories = isar.historys
.filter()
.idIsNotNull()
.chapter((q) => q.manga((q) =>
q.isMangaEqualTo(
_tabBarController.index ==
0)))
.findAllSync()
.toList();
isar.writeTxnSync(() {
isar.historys.clearSync();
// _tabBarController.index != 1
for (var history in histories) {
isar.historys.deleteSync(history.id!);
}
});
if (mounted) {
Navigator.pop(context);
@ -109,226 +143,262 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
icon: Icon(Icons.delete_sweep_outlined,
color: Theme.of(context).hintColor)),
],
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
controller: _tabBarController,
tabs: [
Tab(text: l10n.manga),
Tab(text: l10n.anime),
],
),
),
body: history.when(
data: (data) {
final entries = data
.where((element) => _textEditingController.text.isNotEmpty
? element.chapter.value!.manga.value!.name!
.toLowerCase()
.contains(_textEditingController.text.toLowerCase())
: true)
.toList();
body: Padding(
padding: const EdgeInsets.only(top: 10),
child: TabBarView(controller: _tabBarController, children: [
HistoryTab(
isManga: true,
query: _textEditingController.text,
),
HistoryTab(
isManga: false,
query: _textEditingController.text,
)
]),
),
),
);
}
}
if (entries.isNotEmpty) {
return GroupedListView<History, String>(
elements: entries,
groupBy: (element) => dateFormat(element.date!,
class HistoryTab extends ConsumerStatefulWidget {
final String query;
final bool isManga;
const HistoryTab({required this.isManga, required this.query, super.key});
@override
ConsumerState<HistoryTab> createState() => _HistoryTabState();
}
class _HistoryTabState extends ConsumerState<HistoryTab> {
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
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())
: true)
.toList();
if (entries.isNotEmpty) {
return GroupedListView<History, String>(
elements: entries,
groupBy: (element) => dateFormat(element.date!,
context: context,
ref: ref,
forHistoryValue: true,
useRelativeTimesTamps: false),
groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(bottom: 8, left: 12),
child: Row(
children: [
Text(dateFormat(
null,
context: context,
stringDate: groupByValue,
ref: ref,
forHistoryValue: true,
useRelativeTimesTamps: false),
groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(bottom: 8, left: 12),
child: Row(
children: [
Text(dateFormat(
null,
context: context,
stringDate: groupByValue,
ref: ref,
)),
],
),
),
itemBuilder: (context, History element) {
final manga = element.chapter.value!.manga.value!;
final chapter = element.chapter.value!;
return ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0),
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0)),
elevation: 0,
shadowColor: Colors.transparent),
onPressed: () {
pushMangaReaderView(context: context, chapter: chapter);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: SizedBox(
height: 105,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 60,
height: 90,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7)),
),
onPressed: () {
context.push('/manga-reader/detail',
extra: manga.id);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(7),
child: manga.customCoverImage != null
? Image.memory(
manga.customCoverImage as Uint8List)
: cachedNetworkImage(
headers: ref.watch(headersProvider(
source: manga.source!,
lang: manga.lang!)),
imageUrl: manga.imageUrl!,
width: 60,
height: 90,
fit: BoxFit.cover),
),
),
)),
],
),
),
itemBuilder: (context, History element) {
final manga = element.chapter.value!.manga.value!;
final chapter = element.chapter.value!;
return ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0),
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0)),
elevation: 0,
shadowColor: Colors.transparent),
onPressed: () {
pushMangaReaderView(context: context, chapter: chapter);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: SizedBox(
height: 105,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 60,
height: 90,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7)),
),
Flexible(
child: Row(
children: [
Expanded(
child: Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
onPressed: () {
context.push('/manga-reader/detail',
extra: manga.id);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(7),
child: manga.customCoverImage != null
? Image.memory(
manga.customCoverImage as Uint8List)
: cachedNetworkImage(
headers: ref.watch(headersProvider(
source: manga.source!,
lang: manga.lang!)),
imageUrl: manga.imageUrl!,
width: 60,
height: 90,
fit: BoxFit.cover),
),
),
),
Flexible(
child: Row(
children: [
Expanded(
child: Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
manga.name!,
style: TextStyle(
fontSize: 14,
color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
fontWeight: FontWeight.bold),
textAlign: TextAlign.start,
),
Wrap(
crossAxisAlignment:
CrossAxisAlignment.start,
WrapCrossAlignment.end,
children: [
Text(
manga.name!,
chapter.name!,
style: TextStyle(
fontSize: 14,
fontSize: 11,
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.bold),
textAlign: TextAlign.start,
),
Wrap(
crossAxisAlignment:
WrapCrossAlignment.end,
children: [
Text(
chapter.name!,
style: TextStyle(
fontSize: 11,
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),
),
],
fontWeight: FontWeight.w400),
),
],
),
),
],
),
),
IconButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(
l10n.remove,
),
content: Text(
l10n.remove_history_msg),
actions: [
Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(
context);
},
child: Text(
l10n.cancel)),
const SizedBox(
width: 15,
),
TextButton(
onPressed: () async {
await isar.writeTxn(
() async {
await isar
.historys
.delete(
element
.id!);
});
if (mounted) {
Navigator.pop(
context);
}
},
child: Text(
l10n.remove)),
],
)
],
);
});
},
icon: Icon(
Icons.delete_outline,
size: 25,
color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
)),
],
),
),
)
],
),
),
IconButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(
l10n.remove,
),
content:
Text(l10n.remove_history_msg),
actions: [
Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
TextButton(
onPressed: () async {
await isar
.writeTxn(() async {
await isar.historys
.delete(
element.id!);
});
if (mounted) {
Navigator.pop(
context);
}
},
child: Text(l10n.remove)),
],
)
],
);
});
},
icon: Icon(
Icons.delete_outline,
size: 25,
color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
)),
],
),
)
],
),
);
},
itemComparator: (item1, item2) =>
item1.date!.compareTo(item2.date!),
order: GroupedListOrder.DESC,
),
),
);
}
return Center(
child: Text(l10n.nothing_read_recently),
);
},
error: (Object error, StackTrace stackTrace) {
return ErrorText(error);
},
loading: () {
return const ProgressCenter();
},
));
},
itemComparator: (item1, item2) =>
item1.date!.compareTo(item2.date!),
order: GroupedListOrder.DESC,
);
}
return Center(
child: Text(l10n.nothing_read_recently),
);
},
error: (Object error, StackTrace stackTrace) {
return ErrorText(error);
},
loading: () {
return const ProgressCenter();
},
));
}
}

View file

@ -1,11 +1,18 @@
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'isar_providers.g.dart';
@riverpod
Stream<List<History>> getAllHistoryStream(
GetAllHistoryStreamRef ref,
) async* {
yield* isar.historys.filter().idIsNotNull().watch(fireImmediately: true);
Stream<List<History>> getAllHistoryStream(GetAllHistoryStreamRef ref,
{required bool isManga}) async* {
yield* isar.historys
.filter()
.idIsNotNull()
.and()
.chapter((q) => q.manga((q) => q.isMangaEqualTo(isManga)))
.watch(fireImmediately: true);
}

View file

@ -7,20 +7,109 @@ part of 'isar_providers.dart';
// **************************************************************************
String _$getAllHistoryStreamHash() =>
r'361f085ba7b3269583a09cd7b2e2629d8f3282aa';
r'32dc5fa16315f199a5c86ee99cf59b7190c4d28e';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
typedef GetAllHistoryStreamRef = AutoDisposeStreamProviderRef<List<History>>;
/// See also [getAllHistoryStream].
@ProviderFor(getAllHistoryStream)
final getAllHistoryStreamProvider =
AutoDisposeStreamProvider<List<History>>.internal(
getAllHistoryStream,
name: r'getAllHistoryStreamProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$getAllHistoryStreamHash,
dependencies: null,
allTransitiveDependencies: null,
);
const getAllHistoryStreamProvider = GetAllHistoryStreamFamily();
typedef GetAllHistoryStreamRef = AutoDisposeStreamProviderRef<List<History>>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
/// See also [getAllHistoryStream].
class GetAllHistoryStreamFamily extends Family<AsyncValue<List<History>>> {
/// See also [getAllHistoryStream].
const GetAllHistoryStreamFamily();
/// See also [getAllHistoryStream].
GetAllHistoryStreamProvider call({
required bool isManga,
}) {
return GetAllHistoryStreamProvider(
isManga: isManga,
);
}
@override
GetAllHistoryStreamProvider getProviderOverride(
covariant GetAllHistoryStreamProvider provider,
) {
return call(
isManga: provider.isManga,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'getAllHistoryStreamProvider';
}
/// See also [getAllHistoryStream].
class GetAllHistoryStreamProvider
extends AutoDisposeStreamProvider<List<History>> {
/// See also [getAllHistoryStream].
GetAllHistoryStreamProvider({
required this.isManga,
}) : super.internal(
(ref) => getAllHistoryStream(
ref,
isManga: isManga,
),
from: getAllHistoryStreamProvider,
name: r'getAllHistoryStreamProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$getAllHistoryStreamHash,
dependencies: GetAllHistoryStreamFamily._dependencies,
allTransitiveDependencies:
GetAllHistoryStreamFamily._allTransitiveDependencies,
);
final bool isManga;
@override
bool operator ==(Object other) {
return other is GetAllHistoryStreamProvider && other.isManga == isManga;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode);
return _SystemHash.finish(hash);
}
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -14,6 +14,7 @@ import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/modules/library/providers/local_archive.dart';
import 'package:mangayomi/modules/more/categories/providers/isar_providers.dart';
import 'package:mangayomi/modules/widgets/manga_image_card_widget.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/providers/storage_provider.dart';
@ -27,12 +28,12 @@ import 'package:mangayomi/modules/library/widgets/library_listview_widget.dart';
import 'package:mangayomi/modules/library/widgets/list_tile_manga_category.dart';
import 'package:mangayomi/modules/manga/detail/widgets/chapter_filter_list_tile_widget.dart';
import 'package:mangayomi/modules/manga/detail/widgets/chapter_sort_list_tile_widget.dart';
import 'package:mangayomi/modules/more/categoties/providers/isar_providers.dart';
import 'package:mangayomi/modules/widgets/error_text.dart';
import 'package:mangayomi/modules/widgets/progress_center.dart';
class LibraryScreen extends ConsumerStatefulWidget {
const LibraryScreen({super.key});
final bool isManga;
const LibraryScreen({required this.isManga, super.key});
@override
ConsumerState<LibraryScreen> createState() => _LibraryScreenState();
@ -47,11 +48,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
int _tabIndex = 0;
@override
Widget build(BuildContext context) {
final categories = ref.watch(getMangaCategorieStreamProvider);
final withoutCategories =
ref.watch(getAllMangaWithoutCategoriesStreamProvider);
final showCategoryTabs = ref.watch(libraryShowCategoryTabsStateProvider);
final mangaAll = ref.watch(getAllMangaStreamProvider(categoryId: null));
final categories =
ref.watch(getMangaCategorieStreamProvider(isManga: widget.isManga));
final withoutCategories = ref.watch(
getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga));
final showCategoryTabs = ref
.watch(libraryShowCategoryTabsStateProvider(isManga: widget.isManga));
final mangaAll = ref.watch(
getAllMangaStreamProvider(categoryId: null, isManga: widget.isManga));
final l10n = l10nLocalizations(context)!;
return Scaffold(
body: mangaAll.when(
@ -73,40 +77,50 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
});
return Consumer(builder: (context, ref, child) {
bool reverse =
ref.watch(sortLibraryMangaStateProvider).reverse!;
bool reverse = ref
.watch(sortLibraryMangaStateProvider(
isManga: widget.isManga))
.reverse!;
final continueReaderBtn = ref.watch(
libraryShowContinueReadingButtonStateProvider);
final showNumbersOfItems =
ref.watch(libraryShowNumbersOfItemsStateProvider);
final localSource =
ref.watch(libraryLocalSourceStateProvider);
final downloadedChapter =
ref.watch(libraryDownloadedChaptersStateProvider);
final language =
ref.watch(libraryLanguageStateProvider);
libraryShowContinueReadingButtonStateProvider(
isManga: widget.isManga));
final showNumbersOfItems = ref.watch(
libraryShowNumbersOfItemsStateProvider(
isManga: widget.isManga));
final localSource = ref.watch(
libraryLocalSourceStateProvider(
isManga: widget.isManga));
final downloadedChapter = ref.watch(
libraryDownloadedChaptersStateProvider(
isManga: widget.isManga));
final language = ref.watch(libraryLanguageStateProvider(
isManga: widget.isManga));
final displayType = ref
.read(libraryDisplayTypeStateProvider.notifier)
.getLibraryDisplayTypeValue(
ref.watch(libraryDisplayTypeStateProvider));
.read(libraryDisplayTypeStateProvider(
isManga: widget.isManga)
.notifier)
.getLibraryDisplayTypeValue(ref.watch(
libraryDisplayTypeStateProvider(
isManga: widget.isManga)));
final isNotFiltering = ref.watch(
mangasFilterResultStateProvider(
mangaList: _entries));
isManga: widget.isManga, mangaList: _entries));
final downloadFilterType = ref.watch(
mangaFilterDownloadedStateProvider(
mangaList: _entries));
isManga: widget.isManga, mangaList: _entries));
final unreadFilterType = ref.watch(
mangaFilterUnreadStateProvider(
mangaList: _entries));
isManga: widget.isManga, mangaList: _entries));
final startedFilterType = ref.watch(
mangaFilterStartedStateProvider(
mangaList: _entries));
isManga: widget.isManga, mangaList: _entries));
final bookmarkedFilterType = ref.watch(
mangaFilterBookmarkedStateProvider(
mangaList: _entries));
isManga: widget.isManga, mangaList: _entries));
final sortType = ref
.watch(sortLibraryMangaStateProvider)
.watch(sortLibraryMangaStateProvider(
isManga: widget.isManga))
.index as int;
final numberOfItemsList = _filterAndSortManga(
data: man,
@ -301,35 +315,50 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
});
}
return Consumer(builder: (context, ref, child) {
bool reverse =
ref.watch(sortLibraryMangaStateProvider).reverse!;
final continueReaderBtn = ref
.watch(libraryShowContinueReadingButtonStateProvider);
final showNumbersOfItems =
ref.watch(libraryShowNumbersOfItemsStateProvider);
final localSource =
ref.watch(libraryLocalSourceStateProvider);
final downloadedChapter =
ref.watch(libraryDownloadedChaptersStateProvider);
final language = ref.watch(libraryLanguageStateProvider);
bool reverse = ref
.watch(sortLibraryMangaStateProvider(
isManga: widget.isManga))
.reverse!;
final continueReaderBtn = ref.watch(
libraryShowContinueReadingButtonStateProvider(
isManga: widget.isManga));
final showNumbersOfItems = ref.watch(
libraryShowNumbersOfItemsStateProvider(
isManga: widget.isManga));
final localSource = ref.watch(
libraryLocalSourceStateProvider(
isManga: widget.isManga));
final downloadedChapter = ref.watch(
libraryDownloadedChaptersStateProvider(
isManga: widget.isManga));
final language = ref.watch(libraryLanguageStateProvider(
isManga: widget.isManga));
final displayType = ref
.read(libraryDisplayTypeStateProvider.notifier)
.getLibraryDisplayTypeValue(
ref.watch(libraryDisplayTypeStateProvider));
.read(libraryDisplayTypeStateProvider(
isManga: widget.isManga)
.notifier)
.getLibraryDisplayTypeValue(ref.watch(
libraryDisplayTypeStateProvider(
isManga: widget.isManga)));
final isNotFiltering = ref.watch(
mangasFilterResultStateProvider(mangaList: _entries));
mangasFilterResultStateProvider(
isManga: widget.isManga, mangaList: _entries));
final downloadFilterType = ref.watch(
mangaFilterDownloadedStateProvider(
mangaList: _entries));
isManga: widget.isManga, mangaList: _entries));
final unreadFilterType = ref.watch(
mangaFilterUnreadStateProvider(mangaList: _entries));
mangaFilterUnreadStateProvider(
isManga: widget.isManga, mangaList: _entries));
final startedFilterType = ref.watch(
mangaFilterStartedStateProvider(mangaList: _entries));
mangaFilterStartedStateProvider(
isManga: widget.isManga, mangaList: _entries));
final bookmarkedFilterType = ref.watch(
mangaFilterBookmarkedStateProvider(
mangaList: _entries));
final sortType =
ref.watch(sortLibraryMangaStateProvider).index;
isManga: widget.isManga, mangaList: _entries));
final sortType = ref
.watch(sortLibraryMangaStateProvider(
isManga: widget.isManga))
.index;
final numberOfItemsList = _filterAndSortManga(
data: man,
downloadFilterType: downloadFilterType,
@ -510,8 +539,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required bool downloadedChapter,
required bool continueReaderBtn,
required int categoryId}) {
final mangas = ref.watch(getAllMangaStreamProvider(categoryId: categoryId));
final sortType = ref.watch(sortLibraryMangaStateProvider).index;
final mangas = ref.watch(getAllMangaStreamProvider(
categoryId: categoryId, isManga: widget.isManga));
final sortType =
ref.watch(sortLibraryMangaStateProvider(isManga: widget.isManga)).index;
return mangas.when(
data: (data) {
final categoriNumberOfItemsList = _filterAndSortManga(
@ -555,8 +586,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required WidgetRef ref,
required DisplayType displayType}) {
final l10n = l10nLocalizations(context)!;
final mangas = ref.watch(getAllMangaStreamProvider(categoryId: categoryId));
final sortType = ref.watch(sortLibraryMangaStateProvider).index;
final mangas = ref.watch(getAllMangaStreamProvider(
categoryId: categoryId, isManga: widget.isManga));
final sortType =
ref.watch(sortLibraryMangaStateProvider(isManga: widget.isManga)).index;
final mangaIdsList = ref.watch(mangasListStateProvider);
return Scaffold(
body: mangas.when(
@ -616,10 +649,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required DisplayType displayType,
required WidgetRef ref,
bool withouCategories = false}) {
final sortType = ref.watch(sortLibraryMangaStateProvider).index;
final sortType =
ref.watch(sortLibraryMangaStateProvider(isManga: widget.isManga)).index;
final manga = withouCategories
? ref.watch(getAllMangaWithoutCategoriesStreamProvider)
: ref.watch(getAllMangaStreamProvider(categoryId: null));
? ref.watch(
getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga))
: ref.watch(getAllMangaStreamProvider(
categoryId: null, isManga: widget.isManga));
final mangaIdsList = ref.watch(mangasListStateProvider);
final l10n = l10nLocalizations(context)!;
return manga.when(
@ -822,99 +858,128 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
}
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text(
l10n.set_categories,
),
content: SizedBox(
width: mediaWidth(context, 0.8),
child: StreamBuilder(
stream: isar.categorys
.filter()
.idIsNotNull()
.watch(fireImmediately: true),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final entries = snapshot.data!;
return ListView.builder(
shrinkWrap: true,
itemCount: entries.length,
itemBuilder: (context, index) {
return ListTileMangaCategory(
category: entries[index],
categoryIds: categoryIds,
mangasList: mangasList,
onTap: () {
setState(() {
if (categoryIds
.contains(entries[index].id)) {
categoryIds.remove(entries[index].id);
} else {
return StreamBuilder(
stream: isar.categorys
.filter()
.idIsNotNull()
.and()
.forMangaEqualTo(widget.isManga)
.watch(fireImmediately: true),
builder: (context, snapshot) {
return AlertDialog(
title: Text(
l10n.set_categories,
),
content: SizedBox(
width: mediaWidth(context, 0.8),
child: Builder(builder: (context) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final entries = snapshot.data!;
return ListView.builder(
shrinkWrap: true,
itemCount: entries.length,
itemBuilder: (context, index) {
return ListTileMangaCategory(
category: entries[index],
categoryIds: categoryIds,
mangasList: mangasList,
onTap: () {
setState(() {
if (categoryIds
.contains(entries[index].id)) {
categoryIds.remove(entries[index].id);
} else {
categoryIds.add(entries[index].id!);
}
});
},
res: (res) {
if (res.isNotEmpty) {
categoryIds.add(entries[index].id!);
}
});
},
res: (res) {
if (res.isNotEmpty) {
categoryIds.add(entries[index].id!);
}
},
);
},
);
}
return Container();
}),
),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
context.push("/categories");
Navigator.pop(context);
},
child: Text(l10n.edit)),
Row(
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
);
},
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
TextButton(
onPressed: () {
isar.writeTxnSync(() {
for (var id in mangaIdsList) {
Manga? manga = isar.mangas.getSync(id);
manga!.categories = categoryIds;
isar.mangas.putSync(manga);
}
});
ref
.read(mangasListStateProvider.notifier)
.clear();
ref
.read(isLongPressedMangaStateProvider
.notifier)
.update(false);
if (mounted) {
Navigator.pop(context);
}
},
child: Text(
l10n.ok,
)),
],
);
}
return Text(l10n.library_no_category_exist);
}),
),
],
)
],
);
actions: [
snapshot.hasData && snapshot.data!.isNotEmpty
? Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
context.push("/categories", extra: (
true,
widget.isManga ? 0 : 1
));
Navigator.pop(context);
},
child: Text(l10n.edit)),
Row(
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
TextButton(
onPressed: () {
isar.writeTxnSync(() {
for (var id in mangaIdsList) {
Manga? manga =
isar.mangas.getSync(id);
manga!.categories =
categoryIds;
isar.mangas.putSync(manga);
}
});
ref
.read(mangasListStateProvider
.notifier)
.clear();
ref
.read(
isLongPressedMangaStateProvider
.notifier)
.update(false);
if (mounted) {
Navigator.pop(context);
}
},
child: Text(
l10n.ok,
)),
],
),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
context.push("/categories", extra: (
true,
widget.isManga ? 0 : 1
));
Navigator.pop(context);
},
child: Text(
l10n.edit_categories,
)),
],
)
],
);
});
},
);
});
@ -1114,11 +1179,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
label: l10n.downloaded,
type: ref.watch(
mangaFilterDownloadedStateProvider(
isManga: widget.isManga,
mangaList: _entries)),
onTap: () {
ref
.read(
mangaFilterDownloadedStateProvider(
isManga:
widget.isManga,
mangaList: _entries)
.notifier)
.update();
@ -1127,11 +1195,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
label: l10n.unread,
type: ref.watch(
mangaFilterUnreadStateProvider(
isManga: widget.isManga,
mangaList: _entries)),
onTap: () {
ref
.read(
mangaFilterUnreadStateProvider(
isManga:
widget.isManga,
mangaList: _entries)
.notifier)
.update();
@ -1140,11 +1211,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
label: l10n.started,
type: ref.watch(
mangaFilterStartedStateProvider(
isManga: widget.isManga,
mangaList: _entries)),
onTap: () {
ref
.read(
mangaFilterStartedStateProvider(
isManga:
widget.isManga,
mangaList: _entries)
.notifier)
.update();
@ -1153,12 +1227,15 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
label: l10n.bookmarked,
type: ref.watch(
mangaFilterBookmarkedStateProvider(
isManga: widget.isManga,
mangaList: _entries)),
onTap: () {
setState(() {
ref
.read(
mangaFilterBookmarkedStateProvider(
isManga: widget
.isManga,
mangaList:
_entries)
.notifier)
@ -1170,11 +1247,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
}),
Consumer(builder: (context, ref, chil) {
final reverse = ref
.read(sortLibraryMangaStateProvider
.read(sortLibraryMangaStateProvider(
isManga: widget.isManga)
.notifier)
.isReverse();
final reverseChapter =
ref.watch(sortLibraryMangaStateProvider);
final reverseChapter = ref.watch(
sortLibraryMangaStateProvider(
isManga: widget.isManga));
return Column(
children: [
for (var i = 0; i < 7; i++)
@ -1185,7 +1264,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
onTap: () {
ref
.read(
sortLibraryMangaStateProvider
sortLibraryMangaStateProvider(
isManga:
widget.isManga)
.notifier)
.set(i);
},
@ -1196,22 +1277,31 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
);
}),
Consumer(builder: (context, ref, chil) {
final display = ref
.watch(libraryDisplayTypeStateProvider);
final display = ref.watch(
libraryDisplayTypeStateProvider(
isManga: widget.isManga));
final displayV = ref.read(
libraryDisplayTypeStateProvider.notifier);
libraryDisplayTypeStateProvider(
isManga: widget.isManga)
.notifier);
final showCategoryTabs = ref.watch(
libraryShowCategoryTabsStateProvider);
libraryShowCategoryTabsStateProvider(
isManga: widget.isManga));
final continueReaderBtn = ref.watch(
libraryShowContinueReadingButtonStateProvider);
libraryShowContinueReadingButtonStateProvider(
isManga: widget.isManga));
final showNumbersOfItems = ref.watch(
libraryShowNumbersOfItemsStateProvider);
libraryShowNumbersOfItemsStateProvider(
isManga: widget.isManga));
final downloadedChapter = ref.watch(
libraryDownloadedChaptersStateProvider);
final language =
ref.watch(libraryLanguageStateProvider);
final localSource = ref
.watch(libraryLocalSourceStateProvider);
libraryDownloadedChaptersStateProvider(
isManga: widget.isManga));
final language = ref.watch(
libraryLanguageStateProvider(
isManga: widget.isManga));
final localSource = ref.watch(
libraryLocalSourceStateProvider(
isManga: widget.isManga));
return SingleChildScrollView(
physics:
const NeverScrollableScrollPhysics(),
@ -1277,9 +1367,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
downloadedChapter ? 1 : 0,
onTap: () {
ref
.read(
libraryDownloadedChaptersStateProvider
.notifier)
.read(libraryDownloadedChaptersStateProvider(
isManga: widget
.isManga)
.notifier)
.set(
!downloadedChapter);
}),
@ -1288,9 +1379,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
type: language ? 1 : 0,
onTap: () {
ref
.read(
libraryLanguageStateProvider
.notifier)
.read(libraryLanguageStateProvider(
isManga: widget
.isManga)
.notifier)
.set(!language);
}),
ListTileChapterFilter(
@ -1298,9 +1390,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
type: localSource ? 1 : 0,
onTap: () {
ref
.read(
libraryLocalSourceStateProvider
.notifier)
.read(libraryLocalSourceStateProvider(
isManga: widget
.isManga)
.notifier)
.set(!localSource);
}),
],
@ -1327,9 +1420,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
showCategoryTabs ? 1 : 0,
onTap: () {
ref
.read(
libraryShowCategoryTabsStateProvider
.notifier)
.read(libraryShowCategoryTabsStateProvider(
isManga: widget
.isManga)
.notifier)
.set(!showCategoryTabs);
}),
ListTileChapterFilter(
@ -1340,9 +1434,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
: 0,
onTap: () {
ref
.read(
libraryShowNumbersOfItemsStateProvider
.notifier)
.read(libraryShowNumbersOfItemsStateProvider(
isManga: widget
.isManga)
.notifier)
.set(
!showNumbersOfItems);
}),
@ -1370,9 +1465,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
continueReaderBtn ? 1 : 0,
onTap: () {
ref
.read(
libraryShowContinueReadingButtonStateProvider
.notifier)
.read(libraryShowContinueReadingButtonStateProvider(
isManga: widget
.isManga)
.notifier)
.set(
!continueReaderBtn);
}),
@ -1420,8 +1516,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
final mangaIdsList = ref.watch(mangasListStateProvider);
final manga = categoryId == null
? ref.watch(getAllMangaWithoutCategoriesStreamProvider)
: ref.watch(getAllMangaStreamProvider(categoryId: categoryId));
? ref.watch(
getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga))
: ref.watch(getAllMangaStreamProvider(
categoryId: categoryId, isManga: widget.isManga));
final l10n = l10nLocalizations(context)!;
return PreferredSize(
preferredSize: Size.fromHeight(AppBar().preferredSize.height),
@ -1490,7 +1588,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
: Row(
children: [
Text(
l10n.library,
widget.isManga ? l10n.manga : l10n.anime,
style:
TextStyle(color: Theme.of(context).hintColor),
),
@ -1558,7 +1656,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
return [
PopupMenuItem<int>(
value: 0, child: Text(l10n.open_random_entry)),
PopupMenuItem<int>(value: 1, child: Text(l10n.import)),
if (widget.isManga)
PopupMenuItem<int>(value: 1, child: Text(l10n.import)),
];
}, onSelected: (value) {
if (value == 0) {

View file

@ -6,12 +6,14 @@ part 'isar_providers.g.dart';
@riverpod
Stream<List<Manga>> getAllMangaStream(GetAllMangaStreamRef ref,
{required int? categoryId}) async* {
{required int? categoryId, required bool? isManga}) async* {
yield* categoryId == null
? isar.mangas
.filter()
.idIsNotNull()
.favoriteEqualTo(true)
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true)
: isar.mangas
.filter()
@ -19,21 +21,27 @@ Stream<List<Manga>> getAllMangaStream(GetAllMangaStreamRef ref,
.favoriteEqualTo(true)
.categoriesIsNotEmpty()
.categoriesElementEqualTo(categoryId)
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true);
}
@riverpod
Stream<List<Manga>> getAllMangaWithoutCategoriesStream(
GetAllMangaWithoutCategoriesStreamRef ref,
) async* {
GetAllMangaWithoutCategoriesStreamRef ref,
{required bool? isManga}) async* {
yield* isar.mangas
.filter()
.idIsNotNull()
.favoriteEqualTo(true)
.categoriesIsEmpty()
.and()
.isMangaEqualTo(isManga)
.or()
.idIsNotNull()
.categoriesIsNull()
.favoriteEqualTo(true)
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true);
}

View file

@ -6,7 +6,7 @@ part of 'isar_providers.dart';
// RiverpodGenerator
// **************************************************************************
String _$getAllMangaStreamHash() => r'880357b7617f6592cd453186336b8114982a081b';
String _$getAllMangaStreamHash() => r'd06c3a94ba847055746f2d52566cc94db4c28b7e';
/// Copied from Dart SDK
class _SystemHash {
@ -43,9 +43,11 @@ class GetAllMangaStreamFamily extends Family<AsyncValue<List<Manga>>> {
/// See also [getAllMangaStream].
GetAllMangaStreamProvider call({
required int? categoryId,
required bool? isManga,
}) {
return GetAllMangaStreamProvider(
categoryId: categoryId,
isManga: isManga,
);
}
@ -55,6 +57,7 @@ class GetAllMangaStreamFamily extends Family<AsyncValue<List<Manga>>> {
) {
return call(
categoryId: provider.categoryId,
isManga: provider.isManga,
);
}
@ -78,10 +81,12 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
/// See also [getAllMangaStream].
GetAllMangaStreamProvider({
required this.categoryId,
required this.isManga,
}) : super.internal(
(ref) => getAllMangaStream(
ref,
categoryId: categoryId,
isManga: isManga,
),
from: getAllMangaStreamProvider,
name: r'getAllMangaStreamProvider',
@ -95,37 +100,111 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
);
final int? categoryId;
final bool? isManga;
@override
bool operator ==(Object other) {
return other is GetAllMangaStreamProvider && other.categoryId == categoryId;
return other is GetAllMangaStreamProvider &&
other.categoryId == categoryId &&
other.isManga == isManga;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, categoryId.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode);
return _SystemHash.finish(hash);
}
}
String _$getAllMangaWithoutCategoriesStreamHash() =>
r'affd1fab4a6ab0e0bbc16b67384a0b17498fe209';
r'03581754f330a87894f953f8eaae528642b0afc2';
typedef GetAllMangaWithoutCategoriesStreamRef
= AutoDisposeStreamProviderRef<List<Manga>>;
/// See also [getAllMangaWithoutCategoriesStream].
@ProviderFor(getAllMangaWithoutCategoriesStream)
final getAllMangaWithoutCategoriesStreamProvider =
AutoDisposeStreamProvider<List<Manga>>.internal(
getAllMangaWithoutCategoriesStream,
name: r'getAllMangaWithoutCategoriesStreamProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$getAllMangaWithoutCategoriesStreamHash,
dependencies: null,
allTransitiveDependencies: null,
);
const getAllMangaWithoutCategoriesStreamProvider =
GetAllMangaWithoutCategoriesStreamFamily();
typedef GetAllMangaWithoutCategoriesStreamRef
= AutoDisposeStreamProviderRef<List<Manga>>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
/// See also [getAllMangaWithoutCategoriesStream].
class GetAllMangaWithoutCategoriesStreamFamily
extends Family<AsyncValue<List<Manga>>> {
/// See also [getAllMangaWithoutCategoriesStream].
const GetAllMangaWithoutCategoriesStreamFamily();
/// See also [getAllMangaWithoutCategoriesStream].
GetAllMangaWithoutCategoriesStreamProvider call({
required bool? isManga,
}) {
return GetAllMangaWithoutCategoriesStreamProvider(
isManga: isManga,
);
}
@override
GetAllMangaWithoutCategoriesStreamProvider getProviderOverride(
covariant GetAllMangaWithoutCategoriesStreamProvider provider,
) {
return call(
isManga: provider.isManga,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'getAllMangaWithoutCategoriesStreamProvider';
}
/// See also [getAllMangaWithoutCategoriesStream].
class GetAllMangaWithoutCategoriesStreamProvider
extends AutoDisposeStreamProvider<List<Manga>> {
/// See also [getAllMangaWithoutCategoriesStream].
GetAllMangaWithoutCategoriesStreamProvider({
required this.isManga,
}) : super.internal(
(ref) => getAllMangaWithoutCategoriesStream(
ref,
isManga: isManga,
),
from: getAllMangaWithoutCategoriesStreamProvider,
name: r'getAllMangaWithoutCategoriesStreamProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$getAllMangaWithoutCategoriesStreamHash,
dependencies: GetAllMangaWithoutCategoriesStreamFamily._dependencies,
allTransitiveDependencies: GetAllMangaWithoutCategoriesStreamFamily
._allTransitiveDependencies,
);
final bool? isManga;
@override
bool operator ==(Object other) {
return other is GetAllMangaWithoutCategoriesStreamProvider &&
other.isManga == isManga;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode);
return _SystemHash.finish(hash);
}
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -10,8 +10,10 @@ part 'library_state_provider.g.dart';
@riverpod
class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
@override
String build() {
return isar.settings.getSync(227)!.displayType.name;
String build({required bool isManga}) {
return isManga
? isar.settings.getSync(227)!.displayType.name
: isar.settings.getSync(227)!.animeDisplayType.name;
}
DisplayType getLibraryDisplayTypeValue(String value) {
@ -36,10 +38,16 @@ class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
}
void setLibraryDisplayType(DisplayType displayType) {
final settings = isar.settings.getSync(227)!;
Settings settings = isar.settings.getSync(227)!;
state = displayType.name;
if (isManga) {
settings = settings..displayType = displayType;
} else {
settings = settings..animeDisplayType = displayType;
}
isar.writeTxnSync(() {
isar.settings.putSync(settings..displayType = displayType);
isar.settings.putSync(settings);
});
}
}
@ -47,19 +55,26 @@ class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
@riverpod
class MangaFilterDownloadedState extends _$MangaFilterDownloadedState {
@override
int build({required List<Manga> mangaList}) {
int build({required List<Manga> mangaList, required bool isManga}) {
state = getType();
return getType();
}
int getType() {
return isar.settings.getSync(227)!.libraryFilterMangasDownloadType!;
return isManga
? isar.settings.getSync(227)!.libraryFilterMangasDownloadType!
: isar.settings.getSync(227)!.libraryFilterAnimeDownloadType ?? 0;
}
void setType(int type) {
final settings = isar.settings.getSync(227)!;
Settings settings = isar.settings.getSync(227)!;
if (isManga) {
settings = settings..libraryFilterMangasDownloadType = type;
} else {
settings = settings..libraryFilterAnimeDownloadType = type;
}
isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryFilterMangasDownloadType = type);
isar.settings.putSync(settings);
});
state = type;
}
@ -78,19 +93,26 @@ class MangaFilterDownloadedState extends _$MangaFilterDownloadedState {
@riverpod
class MangaFilterUnreadState extends _$MangaFilterUnreadState {
@override
int build({required List<Manga> mangaList}) {
int build({required List<Manga> mangaList, required bool isManga}) {
state = getType();
return getType();
}
int getType() {
return isar.settings.getSync(227)!.libraryFilterMangasUnreadType!;
return isManga
? isar.settings.getSync(227)!.libraryFilterMangasUnreadType!
: isar.settings.getSync(227)!.libraryFilterAnimeUnreadType ?? 0;
}
void setType(int type) {
final settings = isar.settings.getSync(227)!;
Settings settings = isar.settings.getSync(227)!;
if (isManga) {
settings = settings..libraryFilterMangasUnreadType = type;
} else {
settings = settings..libraryFilterAnimeUnreadType = type;
}
isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryFilterMangasUnreadType = type);
isar.settings.putSync(settings);
});
state = type;
}
@ -158,19 +180,26 @@ class MangaFilterUnreadState extends _$MangaFilterUnreadState {
@riverpod
class MangaFilterStartedState extends _$MangaFilterStartedState {
@override
int build({required List<Manga> mangaList}) {
int build({required List<Manga> mangaList, required bool isManga}) {
state = getType();
return getType();
}
int getType() {
return isar.settings.getSync(227)!.libraryFilterMangasStartedType!;
return isManga
? isar.settings.getSync(227)!.libraryFilterMangasStartedType!
: isar.settings.getSync(227)!.libraryFilterAnimeStartedType ?? 0;
}
void setType(int type) {
final settings = isar.settings.getSync(227)!;
Settings settings = isar.settings.getSync(227)!;
if (isManga) {
settings = settings..libraryFilterMangasStartedType = type;
} else {
settings = settings..libraryFilterAnimeStartedType = type;
}
isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryFilterMangasStartedType = type);
isar.settings.putSync(settings);
});
state = type;
}
@ -238,19 +267,26 @@ class MangaFilterStartedState extends _$MangaFilterStartedState {
@riverpod
class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState {
@override
int build({required List<Manga> mangaList}) {
int build({required List<Manga> mangaList, required bool isManga}) {
state = getType();
return getType();
}
int getType() {
return isar.settings.getSync(227)!.libraryFilterMangasBookMarkedType!;
return isManga
? isar.settings.getSync(227)!.libraryFilterMangasBookMarkedType!
: isar.settings.getSync(227)!.libraryFilterAnimeBookMarkedType ?? 0;
}
void setType(int type) {
final settings = isar.settings.getSync(227)!;
Settings settings = isar.settings.getSync(227)!;
if (isManga) {
settings = settings..libraryFilterMangasBookMarkedType = type;
} else {
settings = settings..libraryFilterAnimeBookMarkedType = type;
}
isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryFilterMangasBookMarkedType = type);
isar.settings.putSync(settings);
});
state = type;
}
@ -318,15 +354,15 @@ class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState {
@riverpod
class MangasFilterResultState extends _$MangasFilterResultState {
@override
bool build({required List<Manga> mangaList}) {
final downloadFilterType =
ref.watch(mangaFilterDownloadedStateProvider(mangaList: mangaList));
final unreadFilterType =
ref.watch(mangaFilterUnreadStateProvider(mangaList: mangaList));
final startedFilterType =
ref.watch(mangaFilterStartedStateProvider(mangaList: mangaList));
final bookmarkedFilterType =
ref.watch(mangaFilterBookmarkedStateProvider(mangaList: mangaList));
bool build({required List<Manga> mangaList, required bool isManga}) {
final downloadFilterType = ref.watch(mangaFilterDownloadedStateProvider(
mangaList: mangaList, isManga: isManga));
final unreadFilterType = ref.watch(
mangaFilterUnreadStateProvider(mangaList: mangaList, isManga: isManga));
final startedFilterType = ref.watch(mangaFilterStartedStateProvider(
mangaList: mangaList, isManga: isManga));
final bookmarkedFilterType = ref.watch(mangaFilterBookmarkedStateProvider(
mangaList: mangaList, isManga: isManga));
return downloadFilterType == 0 &&
unreadFilterType == 0 &&
startedFilterType == 0 &&
@ -337,15 +373,22 @@ class MangasFilterResultState extends _$MangasFilterResultState {
@riverpod
class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
@override
bool build() {
return isar.settings.getSync(227)!.libraryShowCategoryTabs!;
bool build({required bool isManga}) {
return isManga
? isar.settings.getSync(227)!.libraryShowCategoryTabs!
: isar.settings.getSync(227)!.animeLibraryShowCategoryTabs ?? false;
}
void set(bool value) {
final settings = isar.settings.getSync(227)!;
Settings settings = isar.settings.getSync(227)!;
if (isManga) {
settings = settings..libraryShowCategoryTabs = value;
} else {
settings = settings..animeLibraryShowCategoryTabs = value;
}
state = value;
isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryShowCategoryTabs = value);
isar.settings.putSync(settings);
});
}
}
@ -353,15 +396,22 @@ class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
@riverpod
class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
@override
bool build() {
return isar.settings.getSync(227)!.libraryDownloadedChapters!;
bool build({required bool isManga}) {
return isManga
? isar.settings.getSync(227)!.libraryDownloadedChapters!
: isar.settings.getSync(227)!.animeLibraryDownloadedChapters ?? false;
}
void set(bool value) {
final settings = isar.settings.getSync(227)!;
Settings settings = isar.settings.getSync(227)!;
if (isManga) {
settings = settings..libraryDownloadedChapters = value;
} else {
settings = settings..animeLibraryDownloadedChapters = value;
}
state = value;
isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryDownloadedChapters = value);
isar.settings.putSync(settings);
});
}
}
@ -369,15 +419,22 @@ class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
@riverpod
class LibraryLanguageState extends _$LibraryLanguageState {
@override
bool build() {
return isar.settings.getSync(227)!.libraryShowLanguage!;
bool build({required bool isManga}) {
return isManga
? isar.settings.getSync(227)!.libraryShowLanguage!
: isar.settings.getSync(227)!.animeLibraryShowLanguage ?? false;
}
void set(bool value) {
final settings = isar.settings.getSync(227)!;
Settings settings = isar.settings.getSync(227)!;
if (isManga) {
settings = settings..libraryShowLanguage = value;
} else {
settings = settings..animeLibraryShowLanguage = value;
}
state = value;
isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryShowLanguage = value);
isar.settings.putSync(settings);
});
}
}
@ -385,15 +442,22 @@ class LibraryLanguageState extends _$LibraryLanguageState {
@riverpod
class LibraryLocalSourceState extends _$LibraryLocalSourceState {
@override
bool build() {
return isar.settings.getSync(227)!.libraryLocalSource ?? false;
bool build({required bool isManga}) {
return isManga
? isar.settings.getSync(227)!.libraryLocalSource ?? false
: isar.settings.getSync(227)!.animeLibraryLocalSource ?? false;
}
void set(bool value) {
final settings = isar.settings.getSync(227)!;
Settings settings = isar.settings.getSync(227)!;
if (isManga) {
settings = settings..libraryShowLanguage = value;
} else {
settings = settings..animeLibraryShowLanguage = value;
}
state = value;
isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryShowLanguage = value);
isar.settings.putSync(settings);
});
}
}
@ -401,15 +465,22 @@ class LibraryLocalSourceState extends _$LibraryLocalSourceState {
@riverpod
class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
@override
bool build() {
return isar.settings.getSync(227)!.libraryShowNumbersOfItems!;
bool build({required bool isManga}) {
return isManga
? isar.settings.getSync(227)!.libraryShowNumbersOfItems!
: isar.settings.getSync(227)!.animeLibraryShowNumbersOfItems ?? false;
}
void set(bool value) {
final settings = isar.settings.getSync(227)!;
Settings settings = isar.settings.getSync(227)!;
if (isManga) {
settings = settings..libraryShowNumbersOfItems = value;
} else {
settings = settings..animeLibraryShowNumbersOfItems = value;
}
state = value;
isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryShowNumbersOfItems = value);
isar.settings.putSync(settings);
});
}
}
@ -418,15 +489,23 @@ class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
class LibraryShowContinueReadingButtonState
extends _$LibraryShowContinueReadingButtonState {
@override
bool build() {
return isar.settings.getSync(227)!.libraryShowContinueReadingButton!;
bool build({required bool isManga}) {
return isManga
? isar.settings.getSync(227)!.libraryShowContinueReadingButton!
: isar.settings.getSync(227)!.animeLibraryShowContinueReadingButton ??
false;
}
void set(bool value) {
final settings = isar.settings.getSync(227)!;
Settings settings = isar.settings.getSync(227)!;
if (isManga) {
settings = settings..libraryShowContinueReadingButton = value;
} else {
settings = settings..animeLibraryShowContinueReadingButton = value;
}
state = value;
isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryShowContinueReadingButton = value);
isar.settings.putSync(settings);
});
}
}
@ -434,18 +513,25 @@ class LibraryShowContinueReadingButtonState
@riverpod
class SortLibraryMangaState extends _$SortLibraryMangaState {
@override
SortLibraryManga build() {
return isar.settings.getSync(227)!.sortLibraryManga ?? SortLibraryManga();
SortLibraryManga build({required bool isManga}) {
return isManga
? isar.settings.getSync(227)!.sortLibraryManga ?? SortLibraryManga()
: isar.settings.getSync(227)!.sortLibraryAnime ?? SortLibraryManga();
}
void update(bool reverse, int index) {
var value = SortLibraryManga()
..index = index
..reverse = state.index == index ? !reverse : reverse;
Settings settings = isar.settings.getSync(227)!;
if (isManga) {
settings = settings..sortLibraryManga = value;
} else {
settings = settings..sortLibraryAnime = value;
}
isar.writeTxnSync(() {
final settings = isar.settings.getSync(227)!;
isar.settings.putSync(settings..sortLibraryManga = value);
isar.settings.putSync(settings);
});
state = value;
}

File diff suppressed because it is too large Load diff

View file

@ -128,4 +128,5 @@ class ImportArchivesFromFileProvider
return _SystemHash.finish(hash);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -45,55 +45,48 @@ class LibraryGridViewWidget extends StatelessWidget {
childAspectRatio: isComfortableGrid ? 0.642 : 0.69,
itemCount: entriesManga.length,
itemBuilder: (context, index) {
final entry = entriesManga[index];
return Consumer(builder: (context, ref, child) {
bool isLocalArchive = entriesManga[index].isLocalArchive ?? false;
bool isLocalArchive = entry.isLocalArchive ?? false;
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
return Padding(
padding: const EdgeInsets.all(2),
child: CoverViewWidget(
isLongPressed: mangaIdsList.contains(entriesManga[index].id),
isLongPressed: mangaIdsList.contains(entry.id),
bottomTextWidget: BottomTextWidget(
maxLines: 1,
text: entriesManga[index].name!,
text: entry.name!,
isComfortableGrid: isComfortableGrid,
),
isComfortableGrid: isComfortableGrid,
image: entriesManga[index].customCoverImage != null
? MemoryImage(
entriesManga[index].customCoverImage as Uint8List)
image: entry.customCoverImage != null
? MemoryImage(entry.customCoverImage as Uint8List)
as ImageProvider
: CachedNetworkImageProvider(
entriesManga[index].imageUrl!,
entry.imageUrl!,
headers: ref.watch(headersProvider(
source: entriesManga[index].source!,
lang: entriesManga[index].lang!)),
source: entry.source!, lang: entry.lang!)),
),
onTap: () {
if (isLongPressed) {
ref
.read(mangasListStateProvider.notifier)
.update(entriesManga[index]);
ref.read(mangasListStateProvider.notifier).update(entry);
} else {
pushToMangaReaderDetail(
archiveId: isLocalArchive ? entriesManga[index].id : null,
archiveId: isLocalArchive ? entry.id : null,
context: context,
lang: entriesManga[index].lang!,
mangaM: entriesManga[index]);
lang: entry.lang!,
mangaM: entry);
}
},
onLongPress: () {
if (!isLongPressed) {
ref
.read(mangasListStateProvider.notifier)
.update(entriesManga[index]);
ref.read(mangasListStateProvider.notifier).update(entry);
ref
.read(isLongPressedMangaStateProvider.notifier)
.update(!isLongPressed);
} else {
ref
.read(mangasListStateProvider.notifier)
.update(entriesManga[index]);
ref.read(mangasListStateProvider.notifier).update(entry);
}
},
children: [
@ -136,19 +129,14 @@ class LibraryGridViewWidget extends StatelessWidget {
List nbrDown = [];
isar.txnSync(() {
for (var i = 0;
i <
entriesManga[index]
.chapters
.length;
i < entry.chapters.length;
i++) {
final entries = isar.downloads
.filter()
.idIsNotNull()
.chapterIdEqualTo(
entriesManga[index]
.chapters
.toList()[i]
.id)
.chapterIdEqualTo(entry.chapters
.toList()[i]
.id)
.findAllSync();
if (entries.isNotEmpty &&
@ -189,10 +177,7 @@ class LibraryGridViewWidget extends StatelessWidget {
Padding(
padding: const EdgeInsets.only(right: 3),
child: Text(
entriesManga[index]
.chapters
.length
.toString(),
entry.chapters.length.toString(),
style: const TextStyle(color: Colors.white),
),
),
@ -200,7 +185,7 @@ class LibraryGridViewWidget extends StatelessWidget {
),
),
)),
if (language && entriesManga[index].lang!.isNotEmpty)
if (language && entry.lang!.isNotEmpty)
Positioned(
top: 0,
right: 0,
@ -219,7 +204,7 @@ class LibraryGridViewWidget extends StatelessWidget {
padding:
const EdgeInsets.only(left: 3, right: 3),
child: Text(
entriesManga[index].lang!.toUpperCase(),
entry.lang!.toUpperCase(),
style: const TextStyle(color: Colors.white),
),
),
@ -229,7 +214,7 @@ class LibraryGridViewWidget extends StatelessWidget {
],
),
if (!isComfortableGrid && !isCoverOnlyGrid)
BottomTextWidget(text: entriesManga[index].name!),
BottomTextWidget(text: entry.name!),
if (continueReaderBtn)
Positioned(
bottom: 0,
@ -238,16 +223,16 @@ class LibraryGridViewWidget extends StatelessWidget {
padding: const EdgeInsets.all(9),
child: Consumer(
builder: (context, ref, child) {
final history =
ref.watch(getAllHistoryStreamProvider);
final history = ref.watch(
getAllHistoryStreamProvider(
isManga: entry.isManga!));
return history.when(
data: (data) {
final incognitoMode =
ref.watch(incognitoModeStateProvider);
final entries = data
.where((element) =>
element.mangaId ==
entriesManga[index].id)
element.mangaId == entry.id)
.toList();
if (entries.isNotEmpty && !incognitoMode) {
return GestureDetector(
@ -278,9 +263,7 @@ class LibraryGridViewWidget extends StatelessWidget {
onTap: () {
pushMangaReaderView(
context: context,
chapter: entriesManga[index]
.chapters
.last);
chapter: entry.chapters.last);
},
child: Container(
decoration: BoxDecoration(

View file

@ -38,7 +38,8 @@ class LibraryListViewWidget extends StatelessWidget {
return ListViewWidget(
itemCount: entriesManga.length,
itemBuilder: (context, index) {
bool isLocalArchive = entriesManga[index].isLocalArchive ?? false;
final entry = entriesManga[index];
bool isLocalArchive = entry.isLocalArchive ?? false;
return Consumer(builder: (context, ref, child) {
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
return Material(
@ -48,34 +49,28 @@ class LibraryListViewWidget extends StatelessWidget {
child: InkWell(
onTap: () {
if (isLongPressed) {
ref
.read(mangasListStateProvider.notifier)
.update(entriesManga[index]);
ref.read(mangasListStateProvider.notifier).update(entry);
} else {
pushToMangaReaderDetail(
archiveId: isLocalArchive ? entriesManga[index].id : null,
archiveId: isLocalArchive ? entry.id : null,
context: context,
lang: entriesManga[index].lang!,
mangaM: entriesManga[index]);
lang: entry.lang!,
mangaM: entry);
}
},
onLongPress: () {
if (!isLongPressed) {
ref
.read(mangasListStateProvider.notifier)
.update(entriesManga[index]);
ref.read(mangasListStateProvider.notifier).update(entry);
ref
.read(isLongPressedMangaStateProvider.notifier)
.update(!isLongPressed);
} else {
ref
.read(mangasListStateProvider.notifier)
.update(entriesManga[index]);
ref.read(mangasListStateProvider.notifier).update(entry);
}
},
child: Container(
color: mangaIdsList.contains(entriesManga[index].id)
color: mangaIdsList.contains(entry.id)
? primaryColor(context).withOpacity(0.4)
: Colors.transparent,
child: Padding(
@ -98,24 +93,18 @@ class LibraryListViewWidget extends StatelessWidget {
fit: BoxFit.cover,
width: 40,
height: 45,
image: entriesManga[index]
.customCoverImage !=
null
? MemoryImage(
entriesManga[index].customCoverImage
as Uint8List) as ImageProvider
image: entry.customCoverImage != null
? MemoryImage(entry.customCoverImage
as Uint8List) as ImageProvider
: CachedNetworkImageProvider(
entriesManga[index].imageUrl!,
entry.imageUrl!,
headers: ref.watch(headersProvider(
source:
entriesManga[index].source!,
lang:
entriesManga[index].lang!)),
source: entry.source!,
lang: entry.lang!)),
),
child: InkWell(
child: Container(
color: mangaIdsList
.contains(entriesManga[index].id)
color: mangaIdsList.contains(entry.id)
? primaryColor(context)
.withOpacity(0.4)
: Colors.transparent,
@ -127,7 +116,7 @@ class LibraryListViewWidget extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10),
child: Text(entriesManga[index].name!),
child: Text(entry.name!),
),
)
],
@ -168,19 +157,15 @@ class LibraryListViewWidget extends StatelessWidget {
List nbrDown = [];
isar.txnSync(() {
for (var i = 0;
i <
entriesManga[index]
.chapters
.length;
i < entry.chapters.length;
i++) {
final entries = isar.downloads
.filter()
.idIsNotNull()
.chapterIdEqualTo(
entriesManga[index]
.chapters
.toList()[i]
.id)
.chapterIdEqualTo(entry
.chapters
.toList()[i]
.id)
.findAllSync();
if (entries.isNotEmpty &&
@ -220,16 +205,12 @@ class LibraryListViewWidget extends StatelessWidget {
Padding(
padding: const EdgeInsets.only(right: 3),
child: Text(
entriesManga[index]
.chapters
.length
.toString(),
entry.chapters.length.toString(),
style:
const TextStyle(color: Colors.white),
),
),
if (language &&
entriesManga[index].lang!.isNotEmpty)
if (language && entry.lang!.isNotEmpty)
Container(
color: primaryColor(context),
child: Container(
@ -243,9 +224,7 @@ class LibraryListViewWidget extends StatelessWidget {
padding: const EdgeInsets.only(
left: 3, right: 3),
child: Text(
entriesManga[index]
.lang!
.toUpperCase(),
entry.lang!.toUpperCase(),
style: const TextStyle(
color: Colors.white),
),
@ -260,16 +239,16 @@ class LibraryListViewWidget extends StatelessWidget {
if (continueReaderBtn)
Consumer(
builder: (context, ref, child) {
final history =
ref.watch(getAllHistoryStreamProvider);
final history = ref.watch(
getAllHistoryStreamProvider(
isManga: entry.isManga!));
return history.when(
data: (data) {
final incognitoMode =
ref.watch(incognitoModeStateProvider);
final entries = data
.where((element) =>
element.mangaId ==
entriesManga[index].id)
element.mangaId == entry.id)
.toList();
if (entries.isNotEmpty && !incognitoMode) {
return GestureDetector(
@ -300,9 +279,7 @@ class LibraryListViewWidget extends StatelessWidget {
onTap: () {
pushMangaReaderView(
context: context,
chapter: entriesManga[index]
.chapters
.last);
chapter: entry.chapters.last);
},
child: Container(
decoration: BoxDecoration(

View file

@ -24,11 +24,11 @@ class _MainScreenState extends State<MainScreen> {
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
final route = GoRouter.of(context);
int currentIndex = route.location == '/library'
int currentIndex = route.location == '/MangaLibrary'
? 0
: route.location == '/updates'
: route.location == '/AnimeLibrary'
? 1
: route.location == '/history'
: route.location == '/updates'
? 2
: route.location == '/browse'
? 3
@ -80,9 +80,9 @@ class _MainScreenState extends State<MainScreen> {
duration: const Duration(milliseconds: 0),
width: isLongPressed
? 0
: route.location != '/library' &&
: route.location != '/MangaLibrary' &&
route.location != '/AnimeLibrary' &&
route.location != '/updates' &&
route.location != '/history' &&
route.location != '/browse' &&
route.location != '/more'
? 0
@ -105,7 +105,18 @@ class _MainScreenState extends State<MainScreen> {
),
label: Padding(
padding: const EdgeInsets.only(top: 5),
child: Text(l10n.library))),
child: Text(l10n.manga))),
NavigationRailDestination(
selectedIcon: const Icon(
Icons.video_collection,
),
icon: const Icon(
Icons.video_collection_outlined,
),
label: Padding(
padding: const EdgeInsets.only(top: 5),
child: Text(l10n.anime),
)),
NavigationRailDestination(
selectedIcon: const Icon(
Icons.new_releases,
@ -116,17 +127,6 @@ class _MainScreenState extends State<MainScreen> {
label: Padding(
padding: const EdgeInsets.only(top: 5),
child: Text(l10n.updates))),
NavigationRailDestination(
selectedIcon: const Icon(
Icons.history,
),
icon: const Icon(
Icons.history_outlined,
),
label: Padding(
padding: const EdgeInsets.only(top: 5),
child: Text(l10n.history),
)),
NavigationRailDestination(
selectedIcon: const Icon(
Icons.explore,
@ -158,11 +158,11 @@ class _MainScreenState extends State<MainScreen> {
});
}
if (newIndex == 0) {
route.go('/library');
route.go('/MangaLibrary');
} else if (newIndex == 1) {
route.go('/updates');
route.go('/AnimeLibrary');
} else if (newIndex == 2) {
route.go('/history');
route.go('/updates');
} else if (newIndex == 3) {
route.go('/browse');
} else if (newIndex == 4) {
@ -187,9 +187,9 @@ class _MainScreenState extends State<MainScreen> {
width: mediaWidth(context, 1),
height: isLongPressed
? 0
: route.location != '/library' &&
: route.location != '/MangaLibrary' &&
route.location != '/AnimeLibrary' &&
route.location != '/updates' &&
route.location != '/history' &&
route.location != '/browse' &&
route.location != '/more'
? 0
@ -211,7 +211,15 @@ class _MainScreenState extends State<MainScreen> {
icon: const Icon(
Icons.collections_bookmark_outlined,
),
label: l10n.library),
label: l10n.manga),
NavigationDestination(
selectedIcon: const Icon(
Icons.video_collection,
),
icon: const Icon(
Icons.video_collection_outlined,
),
label: l10n.anime),
NavigationDestination(
selectedIcon: const Icon(
Icons.new_releases,
@ -220,14 +228,6 @@ class _MainScreenState extends State<MainScreen> {
Icons.new_releases_outlined,
),
label: l10n.updates),
NavigationDestination(
selectedIcon: const Icon(
Icons.history,
),
icon: const Icon(
Icons.history_outlined,
),
label: l10n.history),
NavigationDestination(
selectedIcon: const Icon(
Icons.explore,
@ -252,11 +252,11 @@ class _MainScreenState extends State<MainScreen> {
});
}
if (newIndex == 0) {
route.go('/library');
route.go('/MangaLibrary');
} else if (newIndex == 1) {
route.go('/updates');
route.go('/AnimeLibrary');
} else if (newIndex == 2) {
route.go('/history');
route.go('/updates');
} else if (newIndex == 3) {
route.go('/browse');
} else if (newIndex == 4) {

View file

@ -373,7 +373,10 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
];
}, onSelected: (value) {
if (value == 0) {
context.push("/categories");
context.push("/categories", extra: (
true,
widget.manga!.isManga! ? 0 : 1
));
} else if (value == 1) {
} else if (value == 2) {
final source = getSource(widget.manga!.lang!,
@ -450,8 +453,11 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
.symmetric(
horizontal: 8),
child: Text(
l10n.n_chapters(
chapters.length),
widget.manga!.isManga!
? l10n.n_chapters(
chapters.length)
: l10n.n_episodes(
chapters.length),
style: const TextStyle(
fontWeight:
FontWeight.bold),
@ -1199,7 +1205,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
padding:
const EdgeInsets.symmetric(horizontal: 8),
child: Text(
l10n.n_chapters(chapterLength),
widget.manga!.isManga!
? l10n.n_chapters(chapterLength)
: l10n.n_episodes(chapterLength),
style: const TextStyle(
fontWeight: FontWeight.bold),
),
@ -1656,13 +1664,14 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
mangaId: widget.manga!.id!,
trackPreference: entries[index],
trackRes: trackRes.first,
)
isManga: widget.manga!.isManga!)
: TrackListile(
text: l10nLocalizations(context)!.add_tracker,
onTap: () async {
final trackSearch =
await trackersSearchraggableMenu(
context,
isManga: widget.manga!.isManga!,
track: Track(
status: TrackStatus.planToRead,
syncId: entries[index].syncId!,
@ -1670,7 +1679,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
) as TrackSearch?;
if (trackSearch != null) {
await ref
.read(trackStateProvider(track: null)
.read(trackStateProvider(
track: null,
isManga: widget.manga!.isManga!)
.notifier)
.setTrackSearch(
trackSearch,

View file

@ -38,7 +38,8 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
return Scaffold(
floatingActionButton: Consumer(
builder: (context, ref, child) {
final history = ref.watch(getAllHistoryStreamProvider);
final history = ref.watch(
getAllHistoryStreamProvider(isManga: widget.manga.isManga!));
final chaptersList = ref.watch(chaptersListttStateProvider);
final isExtended = ref.watch(isExtendedStateProvider);
return ref.watch(isLongPressedStateProvider) == true
@ -161,8 +162,12 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
elevation: 0),
onPressed: () {
final checkCategoryList =
isar.categorys.filter().idIsNotNull().isNotEmptySync();
final checkCategoryList = isar.categorys
.filter()
.idIsNotNull()
.and()
.forMangaEqualTo(widget.manga.isManga)
.isNotEmptySync();
if (checkCategoryList) {
_openCategory(widget.manga);
} else {
@ -219,6 +224,8 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
stream: isar.categorys
.filter()
.idIsNotNull()
.and()
.forMangaEqualTo(widget.manga.isManga)
.watch(fireImmediately: true),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
@ -255,7 +262,8 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
children: [
TextButton(
onPressed: () {
context.push("/categories");
context.push("/categories",
extra: (true, widget.manga.isManga! ? 0 : 1));
Navigator.pop(context);
},
child: Text(l10n.edit)),

View file

@ -193,4 +193,5 @@ class GetChaptersStreamProvider
return _SystemHash.finish(hash);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -979,4 +979,5 @@ class ScanlatorsFilterStateProvider extends AutoDisposeNotifierProviderImpl<
);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -9,20 +9,34 @@ part 'track_state_providers.g.dart';
@riverpod
class TrackState extends _$TrackState {
@override
Track build({Track? track}) {
Track build({Track? track, required bool? isManga}) {
return track!;
}
Future updateManga() async {
Track? updateTrack;
if (track!.syncId == 1) {
updateTrack = await ref
.read(myAnimeListProvider(syncId: track!.syncId!).notifier)
.updateManga(track!);
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!);
} else if (track!.syncId == 2) {
updateTrack = await ref
.read(anilistProvider(syncId: track!.syncId!).notifier)
.updateLibManga(track!);
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!);
}
ref
@ -36,7 +50,8 @@ class TrackState extends _$TrackState {
maxValue = 10;
} else if (track!.syncId == 2) {
maxValue = ref
.read(anilistProvider(syncId: track!.syncId!).notifier)
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.getScoreValue()
.$1;
}
@ -47,7 +62,7 @@ class TrackState extends _$TrackState {
if (track!.syncId == 1) {
} else {
numberText = ref
.read(anilistProvider(syncId: 2).notifier)
.read(anilistProvider(syncId: 2, isManga: isManga).notifier)
.displayScore(int.parse(numberText));
}
return numberText;
@ -59,7 +74,8 @@ class TrackState extends _$TrackState {
step = 1;
} else if (track!.syncId == 2) {
step = ref
.read(anilistProvider(syncId: track!.syncId!).notifier)
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.getScoreValue()
.$2;
}
@ -71,8 +87,9 @@ class TrackState extends _$TrackState {
if (track!.syncId == 1) {
result = score.toString();
} else {
result =
ref.read(anilistProvider(syncId: 2).notifier).displayScore(score);
result = ref
.read(anilistProvider(syncId: 2, isManga: isManga).notifier)
.displayScore(score);
}
return result;
}
@ -94,19 +111,35 @@ class TrackState extends _$TrackState {
finishedReadingDate: 0);
if (syncId == 1) {
findManga = await ref
.read(myAnimeListProvider(syncId: syncId).notifier)
.read(myAnimeListProvider(syncId: syncId, isManga: isManga).notifier)
.findManga(track);
} else if (syncId == 2) {
findManga = findManga = await ref
.read(anilistProvider(syncId: syncId).notifier)
.findLibManga(track);
findManga = isManga!
? await ref
.read(anilistProvider(syncId: syncId, isManga: isManga).notifier)
.findLibManga(track)
: await ref
.read(anilistProvider(syncId: syncId, isManga: isManga).notifier)
.findLibAnime(track);
if (findManga == null) {
await ref
.read(anilistProvider(syncId: syncId).notifier)
.addLibManga(track);
findManga = await ref
.read(anilistProvider(syncId: syncId).notifier)
.findLibManga(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);
findManga = isManga!
? await ref
.read(
anilistProvider(syncId: syncId, isManga: isManga).notifier)
.findLibManga(track)
: await ref
.read(
anilistProvider(syncId: syncId, isManga: isManga).notifier)
.findLibAnime(track);
}
}
ref
@ -118,13 +151,27 @@ class TrackState extends _$TrackState {
List<TrackStatus> statusList = [];
List<TrackStatus> list = [];
if (track!.syncId == 1) {
statusList = ref
.read(myAnimeListProvider(syncId: track!.syncId!).notifier)
.myAnimeListStatusList;
statusList = isManga!
? 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 = ref
.read(anilistProvider(syncId: track!.syncId!).notifier)
.aniListStatusList;
statusList = isManga!
? ref
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.aniListStatusListManga
: ref
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.aniListStatusListAnime;
}
for (var element in TrackStatus.values) {
if (statusList.contains(element)) {
@ -138,12 +185,19 @@ class TrackState extends _$TrackState {
Track? findManga;
if (track!.syncId == 1) {
findManga = await ref
.read(myAnimeListProvider(syncId: track!.syncId!).notifier)
.read(myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.findManga(track!);
} else if (track!.syncId == 2) {
findManga = findManga = await ref
.read(anilistProvider(syncId: track!.syncId!).notifier)
.findLibManga(track!);
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!);
}
return findManga;
}
@ -152,12 +206,19 @@ class TrackState extends _$TrackState {
List<TrackSearch>? tracks;
if (track!.syncId == 1) {
tracks = await ref
.read(myAnimeListProvider(syncId: track!.syncId!).notifier)
.read(myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.search(query);
} else if (track!.syncId == 2) {
tracks = await ref
.read(anilistProvider(syncId: track!.syncId!).notifier)
.search(query);
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);
}
return tracks;
}

View file

@ -6,7 +6,7 @@ part of 'track_state_providers.dart';
// RiverpodGenerator
// **************************************************************************
String _$trackStateHash() => r'7004528230213b458c7db417947eecfc700d44d7';
String _$trackStateHash() => r'eeca421125ff52ccf671d434c41e0198bb7b6fea';
/// Copied from Dart SDK
class _SystemHash {
@ -31,9 +31,11 @@ class _SystemHash {
abstract class _$TrackState extends BuildlessAutoDisposeNotifier<Track> {
late final Track? track;
late final bool? isManga;
Track build({
Track? track,
required bool? isManga,
});
}
@ -49,9 +51,11 @@ class TrackStateFamily extends Family<Track> {
/// See also [TrackState].
TrackStateProvider call({
Track? track,
required bool? isManga,
}) {
return TrackStateProvider(
track: track,
isManga: isManga,
);
}
@ -61,6 +65,7 @@ class TrackStateFamily extends Family<Track> {
) {
return call(
track: provider.track,
isManga: provider.isManga,
);
}
@ -85,8 +90,11 @@ class TrackStateProvider
/// See also [TrackState].
TrackStateProvider({
this.track,
required this.isManga,
}) : super.internal(
() => TrackState()..track = track,
() => TrackState()
..track = track
..isManga = isManga,
from: trackStateProvider,
name: r'trackStateProvider',
debugGetCreateSourceHash:
@ -99,16 +107,20 @@ class TrackStateProvider
);
final Track? track;
final bool? isManga;
@override
bool operator ==(Object other) {
return other is TrackStateProvider && other.track == track;
return other is TrackStateProvider &&
other.track == track &&
other.isManga == isManga;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, track.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode);
return _SystemHash.finish(hash);
}
@ -119,7 +131,9 @@ class TrackStateProvider
) {
return notifier.build(
track: track,
isManga: isManga,
);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -26,6 +26,7 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
dateFormatLocale: source.dateFormatLocale);
final getManga = await ref
.watch(getMangaDetailProvider(manga: mangaS, source: source).future);
final imageUrl = getManga.imageUrl != null && getManga.imageUrl!.isNotEmpty
? getManga.imageUrl
: manga.imageUrl ?? "";
@ -39,6 +40,7 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
.toSet()
.toList()
: manga.genre ?? [];
final author = getManga.author != null && getManga.author!.isNotEmpty
? getManga.author!.trim().trimLeft().trimRight()
: manga.author ?? "";
@ -72,6 +74,7 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
..link = link
..source = sourceA
..lang = lang
..isManga = source.isManga
..lastUpdate = DateTime.now().millisecondsSinceEpoch;
isar.writeTxnSync(() {
@ -99,7 +102,9 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
final chapters = Chapter(
name: title,
url: getManga.urls![i].trim().trimLeft().trimRight(),
dateUpload: getManga.chaptersDateUploads![i],
dateUpload: getManga.chaptersDateUploads!.isEmpty
? null
: getManga.chaptersDateUploads![i],
scanlator: scanlator,
)..manga.value = manga;
isar.chapters.putSync(chapters);

View file

@ -6,7 +6,7 @@ part of 'update_manga_detail_providers.dart';
// RiverpodGenerator
// **************************************************************************
String _$updateMangaDetailHash() => r'7c8e4cae20be71b2cab42f7d784888fb4037aa00';
String _$updateMangaDetailHash() => r'143fc36898ba2d83ee6d42d71b01077ce33dcb19';
/// Copied from Dart SDK
class _SystemHash {
@ -118,4 +118,5 @@ class UpdateMangaDetailProvider extends AutoDisposeFutureProvider<dynamic> {
return _SystemHash.finish(hash);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/services/anime_servers/gogo_cdn_extractor.dart';
import 'package:mangayomi/utils/date.dart';
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
import 'package:mangayomi/utils/colors.dart';
@ -74,7 +75,12 @@ class ChapterListTileWidget extends ConsumerWidget {
children: [
if ((chapter.manga.value!.isLocalArchive ?? false) == false)
Text(
dateFormat(chapter.dateUpload!, ref: ref, context: context),
dateFormat(
!chapter.manga.value!.isManga!
? DateTime.now().millisecondsSinceEpoch.toString()
: chapter.dateUpload!,
ref: ref,
context: context),
style: const TextStyle(fontSize: 11),
),
if (!chapter.isRead!)
@ -84,7 +90,13 @@ class ChapterListTileWidget extends ConsumerWidget {
children: [
const Text(''),
Text(
l10n.page(chapter.lastPageRead!),
!chapter.manga.value!.isManga!
? l10n.episode_progress(Duration(
milliseconds:
int.parse(chapter.lastPageRead!))
.toString()
.substringBefore("."))
: l10n.page(chapter.lastPageRead!),
style: TextStyle(
fontSize: 11,
color: isLight(context)

View file

@ -10,8 +10,10 @@ import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/media_query.dart';
class TrackerWidgetSearch extends ConsumerStatefulWidget {
final bool isManga;
final Track track;
const TrackerWidgetSearch({required this.track, super.key});
const TrackerWidgetSearch(
{required this.isManga, required this.track, super.key});
@override
ConsumerState<TrackerWidgetSearch> createState() =>
@ -30,7 +32,8 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
_init() async {
await Future.delayed(const Duration(microseconds: 100));
tracks = await ref
.read(trackStateProvider(track: widget.track).notifier)
.read(trackStateProvider(track: widget.track, isManga: widget.isManga)
.notifier)
.search(query);
if (mounted) {
setState(() {
@ -169,7 +172,9 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
_isLoading = true;
});
tracks = await ref
.read(trackStateProvider(track: widget.track)
.read(trackStateProvider(
track: widget.track,
isManga: widget.isManga)
.notifier)
.search(d.trim());
if (mounted) {
@ -210,7 +215,8 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
}
}
trackersSearchraggableMenu(BuildContext context, {required Track track}) async {
trackersSearchraggableMenu(BuildContext context,
{required Track track, required bool isManga}) async {
return await DraggableMenu.open(
context,
DraggableMenu(
@ -240,5 +246,6 @@ trackersSearchraggableMenu(BuildContext context, {required Track track}) async {
maxHeight: mediaHeight(context, 0.9),
child: TrackerWidgetSearch(
track: track,
isManga: isManga,
)));
}

View file

@ -15,11 +15,13 @@ import 'package:mangayomi/utils/utils.dart';
import 'package:numberpicker/numberpicker.dart';
class TrackerWidget extends ConsumerStatefulWidget {
final bool isManga;
final Track trackRes;
final int mangaId;
final TrackPreference trackPreference;
const TrackerWidget(
{super.key,
required this.isManga,
required this.trackPreference,
required this.trackRes,
required this.mangaId});
@ -38,7 +40,9 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
_init() async {
await Future.delayed(const Duration(microseconds: 100));
final findManga = await ref
.read(trackStateProvider(track: widget.trackRes).notifier)
.read(
trackStateProvider(track: widget.trackRes, isManga: widget.isManga)
.notifier)
.findManga();
if (mounted) {
ref
@ -83,10 +87,13 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
onPressed: () async {
final trackSearch = await trackersSearchraggableMenu(
context,
isManga: widget.isManga,
track: widget.trackRes) as TrackSearch?;
if (trackSearch != null) {
await ref
.read(trackStateProvider(track: null).notifier)
.read(trackStateProvider(
track: null, isManga: widget.isManga)
.notifier)
.setTrackSearch(trackSearch, widget.mangaId,
widget.trackPreference.syncId!);
}
@ -142,26 +149,33 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
shrinkWrap: true,
itemCount: ref
.read(trackStateProvider(
track: widget.trackRes)
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.getStatusList()
.length,
itemBuilder: (context, index) {
final status = ref
.read(trackStateProvider(
track: widget.trackRes)
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.getStatusList()[index];
print(status);
return RadioListTile(
dense: true,
contentPadding: const EdgeInsets.all(0),
value: status,
groupValue: widget.trackRes.status,
groupValue: toStatus(
widget.trackRes.status,
widget.isManga,
widget.trackRes.syncId!),
onChanged: (value) {
ref
.read(trackStateProvider(
track: widget.trackRes
..status = status)
..status = status,
isManga: widget.isManga)
.notifier)
.updateManga();
Navigator.pop(context);
@ -189,7 +203,11 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
],
);
});
}, text: getTrackStatus(widget.trackRes.status, context)),
},
text: getTrackStatus(
toStatus(widget.trackRes.status, widget.isManga,
widget.trackRes.syncId!),
context)),
),
Expanded(
child: _elevatedButton(context, onPressed: () {
@ -241,7 +259,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
.read(trackStateProvider(
track: widget.trackRes
..lastChapterRead =
currentIntValue)
currentIntValue,
isManga: widget.isManga)
.notifier)
.updateManga();
Navigator.pop(context);
@ -282,19 +301,22 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
minValue: 0,
maxValue: ref
.read(trackStateProvider(
track: widget.trackRes)
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.getScoreMaxValue(),
textMapper: (numberText) {
return ref
.read(trackStateProvider(
track: widget.trackRes)
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.getTextMapper(numberText);
},
step: ref
.read(trackStateProvider(
track: widget.trackRes)
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.getScoreStep(),
haptics: true,
@ -323,7 +345,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
ref
.read(trackStateProvider(
track: widget.trackRes
..score = currentIntValue)
..score = currentIntValue,
isManga: widget.isManga)
.notifier)
.updateManga();
Navigator.pop(context);
@ -341,7 +364,9 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
},
text: widget.trackRes.score != 0
? ref
.read(trackStateProvider(track: widget.trackRes)
.read(trackStateProvider(
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.displayScore(widget.trackRes.score!)
: l10n!.score),
@ -366,7 +391,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
.read(trackStateProvider(
track: widget.trackRes
..startedReadingDate =
newDate.millisecondsSinceEpoch)
newDate.millisecondsSinceEpoch,
isManga: widget.isManga)
.notifier)
.updateManga();
},
@ -396,7 +422,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
.read(trackStateProvider(
track: widget.trackRes
..finishedReadingDate =
newDate.millisecondsSinceEpoch)
newDate.millisecondsSinceEpoch,
isManga: widget.isManga)
.notifier)
.updateManga();
},

View file

@ -134,4 +134,5 @@ class ConvertToCBZProvider extends AutoDisposeFutureProvider<List<String>> {
return _SystemHash.finish(hash);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -29,8 +29,7 @@ Future<List<String>> downloadChapter(
bool onlyOnWifi = useWifi ?? ref.watch(onlyOnWifiStateProvider);
Directory? path;
final getDownloadLocation = ref.watch(downloadLocationStateProvider).$2;
final desktopCustomDownloadLocation =
Platform.isWindows && getDownloadLocation.isNotEmpty;
final customDownloadLocation = getDownloadLocation.isNotEmpty;
bool isOk = false;
final manga = chapter.manga.value!;
final path1 = await storageProvider.getDirectory();
@ -99,10 +98,9 @@ Future<List<String>> downloadChapter(
headersProvider(source: manga.source!, lang: manga.lang!)),
url: pageUrls[index].trim().trimLeft().trimRight(),
filename: "${padIndex(index + 1)}.jpg",
baseDirectory:
Platform.isAndroid || desktopCustomDownloadLocation
? BaseDirectory.temporary
: BaseDirectory.applicationDocuments,
baseDirectory: customDownloadLocation
? BaseDirectory.temporary
: BaseDirectory.applicationDocuments,
directory: 'Mangayomi/$finalPath',
updates: Updates.statusAndProgress,
allowPause: true,
@ -119,10 +117,9 @@ Future<List<String>> downloadChapter(
headersProvider(source: manga.source!, lang: manga.lang!)),
url: pageUrls[index].trim().trimLeft().trimRight(),
filename: "${padIndex(index + 1)}.jpg",
baseDirectory:
Platform.isAndroid || desktopCustomDownloadLocation
? BaseDirectory.temporary
: BaseDirectory.applicationDocuments,
baseDirectory: customDownloadLocation
? BaseDirectory.temporary
: BaseDirectory.applicationDocuments,
directory: 'Mangayomi/$finalPath',
updates: Updates.statusAndProgress,
allowPause: true,
@ -188,7 +185,7 @@ Future<List<String>> downloadChapter(
},
taskProgressCallback: (taskProgress) async {
if (taskProgress.progress == 1.0) {
if (Platform.isAndroid || desktopCustomDownloadLocation) {
if (customDownloadLocation) {
await File(
"${tempDir.path}/${taskProgress.task.directory}/${taskProgress.task.filename}")
.copy("${path!.path}/${taskProgress.task.filename}");

View file

@ -118,4 +118,5 @@ class DownloadChapterProvider extends AutoDisposeFutureProvider<List<String>> {
return _SystemHash.finish(hash);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -390,6 +390,7 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
return buildProgressIndicator();
}
return MangaHomeImageCard(
isManga: widget.source.isManga ?? true,
manga: data[index]!,
source: widget.source,
);
@ -409,11 +410,13 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
class MangaHomeImageCard extends ConsumerStatefulWidget {
final MangaModel manga;
final bool isManga;
final Source source;
const MangaHomeImageCard({
super.key,
required this.manga,
required this.source,
required this.isManga,
});
@override
@ -431,6 +434,7 @@ class _MangaHomeImageCardState extends ConsumerState<MangaHomeImageCard>
..lang = widget.source.lang
..source = widget.source.name,
lang: widget.source.lang!,
isManga: widget.isManga,
);
}

View file

@ -41,6 +41,7 @@ class SearchResultScreen extends ConsumerWidget {
return MangaHomeImageCard(
manga: data[index]!,
source: source,
isManga: source.isManga ?? true,
);
},
);

View file

@ -86,86 +86,86 @@ class CropBorderClass {
void _autocropImageIsolate(CropBorderClass cropData) async {
Image? croppedImage;
Image? image = decodeImage(cropData.image!);
final old = image;
image = copyCrop(image!, 0, 0, image.width, image.height);
// // Image? image = decodeImage(cropData.image!);
// // final old = image;
// // image = copyCrop(image!, 0, 0, image.width, image.height);
int left = 0;
int top = 0;
int right = image.width - 1;
int bottom = image.height - 1;
// // int left = 0;
// // int top = 0;
// // int right = image.width - 1;
// // int bottom = image.height - 1;
// Find left coordinate
for (int x = 0; x < image.width; x++) {
bool stop = false;
for (int y = 0; y < image.height; y++) {
if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
stop = true;
break;
}
}
if (stop) {
left = x;
break;
}
}
// // // Find left coordinate
// // for (int x = 0; x < image.width; x++) {
// // bool stop = false;
// // for (int y = 0; y < image.height; y++) {
// // if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
// // stop = true;
// // break;
// // }
// // }
// // if (stop) {
// // left = x;
// // break;
// // }
// // }
// Find top coordinate
for (int y = 0; y < image.height; y++) {
bool stop = false;
for (int x = 0; x < image.width; x++) {
if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
stop = true;
break;
}
}
if (stop) {
top = y;
break;
}
}
// // // Find top coordinate
// // for (int y = 0; y < image.height; y++) {
// // bool stop = false;
// // for (int x = 0; x < image.width; x++) {
// // if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
// // stop = true;
// // break;
// // }
// // }
// // if (stop) {
// // top = y;
// // break;
// // }
// // }
// Find right coordinate
for (int x = image.width - 1; x >= 0; x--) {
bool stop = false;
for (int y = 0; y < image.height; y++) {
if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
stop = true;
break;
}
}
if (stop) {
right = x;
break;
}
}
// // // Find right coordinate
// // for (int x = image.width - 1; x >= 0; x--) {
// // bool stop = false;
// // for (int y = 0; y < image.height; y++) {
// // if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
// // stop = true;
// // break;
// // }
// // }
// // if (stop) {
// // right = x;
// // break;
// // }
// // }
// Find bottom coordinate
for (int y = image.height - 1; y >= 0; y--) {
bool stop = false;
for (int x = 0; x < image.width; x++) {
if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
stop = true;
break;
}
}
if (stop) {
bottom = y;
break;
}
}
// // // Find bottom coordinate
// // for (int y = image.height - 1; y >= 0; y--) {
// // bool stop = false;
// // for (int x = 0; x < image.width; x++) {
// // if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
// // stop = true;
// // break;
// // }
// // }
// // if (stop) {
// // bottom = y;
// // break;
// // }
// // }
// Crop the image
croppedImage = copyCrop(
image,
left,
top,
right - left + 1,
bottom - top + 1,
);
if (old != croppedImage) {
cropData.sendPort.send(encodeJpg(croppedImage) as Uint8List);
} else {
cropData.sendPort.send(null);
}
// // // Crop the image
// // croppedImage = copyCrop(
// // image,
// // left,
// // top,
// // right - left + 1,
// // bottom - top + 1,
// // );
// if (old != croppedImage) {
// cropData.sendPort.send(encodeJpg(croppedImage) as Uint8List);
// } else {
// cropData.sendPort.send(null);
// }
}

View file

@ -135,4 +135,5 @@ class AutoCropBorderProvider
return _SystemHash.finish(hash);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -6,7 +6,14 @@ pushMangaReaderView({
required BuildContext context,
required Chapter chapter,
}) {
context.push('/mangareaderview', extra: chapter);
print(chapter.manga.value!.isManga!);
if (chapter.manga.value!.isManga!) {
print("aaz");
context.pushReplacement('/mangareaderview', extra: chapter);
} else {
print("object");
context.push('/animestreamview', extra: chapter);
}
}
pushReplacementMangaReaderView({

View file

@ -122,4 +122,5 @@ class CurrentIndexProvider
);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member

View file

@ -2,28 +2,82 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/category.dart';
import 'package:mangayomi/modules/more/categoties/providers/isar_providers.dart';
import 'package:mangayomi/modules/more/categoties/widgets/custom_textfield.dart';
import 'package:mangayomi/modules/more/categories/providers/isar_providers.dart';
import 'package:mangayomi/modules/more/categories/widgets/custom_textfield.dart';
import 'package:mangayomi/modules/widgets/progress_center.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class CategoriesScreen extends ConsumerStatefulWidget {
const CategoriesScreen({super.key});
final (bool, int) data;
const CategoriesScreen({required this.data, super.key});
@override
ConsumerState<CategoriesScreen> createState() => _CategoriesScreenState();
}
class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
with TickerProviderStateMixin {
late TabController _tabBarController;
@override
void initState() {
_tabBarController = TabController(length: 2, vsync: this);
_tabBarController.animateTo(widget.data.$2);
super.initState();
}
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
return DefaultTabController(
animationDuration: Duration.zero,
length: 2,
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
title: Text(
widget.data.$1 ? l10n.edit_categories : l10n.categories,
style: TextStyle(color: Theme.of(context).hintColor),
),
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
controller: _tabBarController,
tabs: [
Tab(text: l10n.manga),
Tab(text: l10n.anime),
],
),
),
body: TabBarView(controller: _tabBarController, children: const [
CategoriesTab(
isManga: true,
),
CategoriesTab(
isManga: false,
)
]),
),
);
}
}
class CategoriesTab extends ConsumerStatefulWidget {
final bool isManga;
const CategoriesTab({required this.isManga, super.key});
@override
ConsumerState<CategoriesTab> createState() => _CategoriesTabState();
}
class _CategoriesTabState extends ConsumerState<CategoriesTab> {
List<Category> _entries = [];
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context);
final categories = ref.watch(getMangaCategorieStreamProvider);
final l10n = l10nLocalizations(context)!;
final categories =
ref.watch(getMangaCategorieStreamProvider(isManga: widget.isManga));
return Scaffold(
appBar: AppBar(
title: Text(l10n!.edit_categories),
),
body: categories.when(
data: (data) {
if (data.isEmpty) {
@ -215,6 +269,7 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
: () async {
await isar.writeTxn(() async {
await isar.categorys.put(Category(
forManga: widget.isManga,
name: controller.text,
));
});

View file

@ -5,11 +5,12 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'isar_providers.g.dart';
@riverpod
Stream<List<Category>> getMangaCategorieStream(
GetMangaCategorieStreamRef ref,
) async* {
Stream<List<Category>> getMangaCategorieStream(GetMangaCategorieStreamRef ref,
{required bool isManga}) async* {
yield* isar.categorys
.filter()
.idIsNotNull()
.and()
.forMangaEqualTo(isManga)
.watch(fireImmediately: true);
}

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