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

View file

@ -14,6 +14,7 @@ Features include:
* Local reading of downloaded content * Local reading of downloaded content
* Read and manage local archives (.cbz, .zip) * Read and manage local archives (.cbz, .zip)
* A configurable reader with multiple viewers, reading directions. * 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 * Categories to organize your library
* Light and dark themes * Light and dark themes

View file

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

View file

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.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 */ /* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 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 */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 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 */ /* 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 */ /* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = { 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase; isa = PBXCopyFilesBuildPhase;
@ -31,10 +44,15 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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 */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
856C729112305BC7D8FE80C9 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A83607D399EF885A7879ED92 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = { 97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
2E161ED88D6088BA04182D24 /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup 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 */ = { 9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -72,6 +126,9 @@
9740EEB11CF90186004384FC /* Flutter */, 9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
6CD41D1121E5C42BF1E41F31 /* Pods */,
BCA59FF3AA594C41BF8ADD28 /* Frameworks */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@ -79,6 +136,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
97C146EE1CF9000F007C117D /* Runner.app */, 97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -98,19 +156,49 @@
path = Runner; path = Runner;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
BCA59FF3AA594C41BF8ADD28 /* Frameworks */ = {
isa = PBXGroup;
children = (
87B3D97401D2090714EBD2ED /* Pods_Runner.framework */,
F944C966F0D3C46230816475 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget 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 */ = { 97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = ( buildPhases = (
F7E3AB66492405CCCAB00559 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */, 9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */, 97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */, 97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
DC786BE6A6336FF08B227C10 /* [CP] Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
); );
@ -127,9 +215,14 @@
97C146E61CF9000F007C117D /* Project object */ = { 97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1300; LastUpgradeCheck = 1300;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = { 97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100; LastSwiftMigration = 1100;
@ -150,11 +243,19 @@
projectRoot = ""; projectRoot = "";
targets = ( targets = (
97C146ED1CF9000F007C117D /* Runner */, 97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */ /* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = { 97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -176,6 +277,7 @@
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
); );
name = "Thin Binary"; name = "Thin Binary";
outputPaths = ( outputPaths = (
@ -199,9 +301,78 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 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 */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = { 97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -213,6 +384,14 @@
}; };
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */ /* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = { 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup; isa = PBXVariantGroup;
@ -256,6 +435,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -274,7 +454,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@ -292,6 +472,7 @@
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -304,6 +485,56 @@
}; };
name = Profile; 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 */ = { 97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
@ -327,6 +558,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -351,7 +583,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -382,6 +614,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -400,7 +633,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@ -420,6 +653,7 @@
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -442,6 +676,7 @@
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -457,6 +692,16 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList 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" */ = { 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (

View file

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

View file

@ -4,4 +4,7 @@
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "group:Runner.xcodeproj">
</FileRef> </FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace> </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"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
@ -13,7 +15,7 @@
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>Mangayomi</string> <string>mangayomi</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
@ -24,6 +26,12 @@
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
</array>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>
@ -43,9 +51,5 @@
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict> </dict>
</plist> </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.images,
this.statusList}); 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 'dart:typed_data';
import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval.dart';
import 'package:mangayomi/eval/bridge_class/manga_model.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'; import 'package:mangayomi/eval/m_bridge.dart';
Uint8List compilerEval(String sourceCode) { Uint8List compilerEval(String sourceCode) {
@ -8,6 +9,7 @@ Uint8List compilerEval(String sourceCode) {
compiler.defineBridgeClasses([ compiler.defineBridgeClasses([
$MBridge.$declaration, $MBridge.$declaration,
$MangaModel.$declaration, $MangaModel.$declaration,
$VideoModel.$declaration
]); ]);
final program = compiler.compile({ final program = compiler.compile({
'package:mangayomi': {'main.dart': sourceCode} '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/date_symbol_data_local.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:json_path/json_path.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/main.dart';
import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/models/video.dart';
import 'package:mangayomi/modules/webview/webview.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/services/http_service/cloudflare/cloudflare_bypass.dart';
import 'package:mangayomi/utils/constant.dart'; import 'package:mangayomi/utils/constant.dart';
import 'package:mangayomi/utils/reg_exp_matcher.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( static String parseChapterDate(
String date, String dateFormat, String dateFormatLocale) { String date, String dateFormat, String dateFormatLocale) {
int parseRelativeDate(String date) { int parseRelativeDate(String date) {
@ -686,6 +732,29 @@ class $MBridge extends MBridge with $Bridge {
returns: BridgeTypeAnnotation($type), params: [], namedParams: [])) returns: BridgeTypeAnnotation($type), params: [], namedParams: []))
}, },
methods: { 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( 'listParse': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list,
@ -988,6 +1057,74 @@ class $MBridge extends MBridge with $Bridge {
], ],
namedParams: []), namedParams: []),
isStatic: true), 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( 'getHtmlViaWebview': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, 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( static $String $getMapValue(
Runtime runtime, $Value? target, List<$Value?> args) { Runtime runtime, $Value? target, List<$Value?> args) {
return $String(MBridge.getMapValue( return $String(MBridge.getMapValue(
@ -1220,11 +1366,54 @@ class $MBridge extends MBridge with $Bridge {
static $Future $http(Runtime runtime, $Value? target, List<$Value?> args) => static $Future $http(Runtime runtime, $Value? target, List<$Value?> args) =>
$Future.wrap(MBridge.http(args[0]!.$value, args[1]!.$value) $Future.wrap(MBridge.http(args[0]!.$value, args[1]!.$value)
.then((value) => $String(value))); .then((value) => $String(value)));
static $Future $getHtmlViaWebview( static $Future $getHtmlViaWebview(
Runtime runtime, $Value? target, List<$Value?> args) => Runtime runtime, $Value? target, List<$Value?> args) =>
$Future.wrap(MBridge.getHtmlViaWebview(args[0]!.$value, args[1]!.$value) $Future.wrap(MBridge.getHtmlViaWebview(args[0]!.$value, args[1]!.$value)
.then((value) => $String(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 @override
$Value? $bridgeGet(String identifier) { $Value? $bridgeGet(String identifier) {
throw UnimplementedError(); throw UnimplementedError();

View file

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

View file

@ -181,5 +181,18 @@
"one_tracker":"1 tracker", "one_tracker":"1 tracker",
"n_tracker":"{n} trackers", "n_tracker":"{n} trackers",
"tracking": "Tracking", "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", "one_tracker":"Suivi par 1 service",
"n_tracker":"Suivi par {n} services", "n_tracker":"Suivi par {n} services",
"tracking": "Suivi", "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:desktop_webview_window/desktop_webview_window.dart';
import 'package:flex_color_scheme/flex_color_scheme.dart'; import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_meedu_videoplayer/init_meedu_player.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/date_symbol_data_local.dart';
@ -29,6 +30,10 @@ class MyHttpoverrides extends HttpOverrides {
} }
void main(List<String> args) async { void main(List<String> args) async {
initMeeduPlayer(
androidUseMediaKit: true,
iosUseMediaKit: true,
);
HttpOverrides.global = MyHttpoverrides(); HttpOverrides.global = MyHttpoverrides();
if (Platform.isLinux || Platform.isWindows) { if (Platform.isLinux || Platform.isWindows) {
if (runWebViewTitleBarWidget(args)) { if (runWebViewTitleBarWidget(args)) {
@ -125,4 +130,3 @@ class _MyAppState extends ConsumerState<MyApp> {
); );
} }
} }

View file

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

View file

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

View file

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

View file

@ -62,38 +62,43 @@ const MangaSchema = CollectionSchema(
name: r'isLocalArchive', name: r'isLocalArchive',
type: IsarType.bool, type: IsarType.bool,
), ),
r'lang': PropertySchema( r'isManga': PropertySchema(
id: 9, id: 9,
name: r'isManga',
type: IsarType.bool,
),
r'lang': PropertySchema(
id: 10,
name: r'lang', name: r'lang',
type: IsarType.string, type: IsarType.string,
), ),
r'lastRead': PropertySchema( r'lastRead': PropertySchema(
id: 10, id: 11,
name: r'lastRead', name: r'lastRead',
type: IsarType.long, type: IsarType.long,
), ),
r'lastUpdate': PropertySchema( r'lastUpdate': PropertySchema(
id: 11, id: 12,
name: r'lastUpdate', name: r'lastUpdate',
type: IsarType.long, type: IsarType.long,
), ),
r'link': PropertySchema( r'link': PropertySchema(
id: 12, id: 13,
name: r'link', name: r'link',
type: IsarType.string, type: IsarType.string,
), ),
r'name': PropertySchema( r'name': PropertySchema(
id: 13, id: 14,
name: r'name', name: r'name',
type: IsarType.string, type: IsarType.string,
), ),
r'source': PropertySchema( r'source': PropertySchema(
id: 14, id: 15,
name: r'source', name: r'source',
type: IsarType.string, type: IsarType.string,
), ),
r'status': PropertySchema( r'status': PropertySchema(
id: 15, id: 16,
name: r'status', name: r'status',
type: IsarType.byte, type: IsarType.byte,
enumMap: _MangastatusEnumValueMap, enumMap: _MangastatusEnumValueMap,
@ -211,13 +216,14 @@ void _mangaSerialize(
writer.writeStringList(offsets[6], object.genre); writer.writeStringList(offsets[6], object.genre);
writer.writeString(offsets[7], object.imageUrl); writer.writeString(offsets[7], object.imageUrl);
writer.writeBool(offsets[8], object.isLocalArchive); writer.writeBool(offsets[8], object.isLocalArchive);
writer.writeString(offsets[9], object.lang); writer.writeBool(offsets[9], object.isManga);
writer.writeLong(offsets[10], object.lastRead); writer.writeString(offsets[10], object.lang);
writer.writeLong(offsets[11], object.lastUpdate); writer.writeLong(offsets[11], object.lastRead);
writer.writeString(offsets[12], object.link); writer.writeLong(offsets[12], object.lastUpdate);
writer.writeString(offsets[13], object.name); writer.writeString(offsets[13], object.link);
writer.writeString(offsets[14], object.source); writer.writeString(offsets[14], object.name);
writer.writeByte(offsets[15], object.status.index); writer.writeString(offsets[15], object.source);
writer.writeByte(offsets[16], object.status.index);
} }
Manga _mangaDeserialize( Manga _mangaDeserialize(
@ -237,13 +243,14 @@ Manga _mangaDeserialize(
id: id, id: id,
imageUrl: reader.readStringOrNull(offsets[7]), imageUrl: reader.readStringOrNull(offsets[7]),
isLocalArchive: reader.readBoolOrNull(offsets[8]), isLocalArchive: reader.readBoolOrNull(offsets[8]),
lang: reader.readStringOrNull(offsets[9]), isManga: reader.readBoolOrNull(offsets[9]),
lastRead: reader.readLongOrNull(offsets[10]), lang: reader.readStringOrNull(offsets[10]),
lastUpdate: reader.readLongOrNull(offsets[11]), lastRead: reader.readLongOrNull(offsets[11]),
link: reader.readStringOrNull(offsets[12]), lastUpdate: reader.readLongOrNull(offsets[12]),
name: reader.readStringOrNull(offsets[13]), link: reader.readStringOrNull(offsets[13]),
source: reader.readStringOrNull(offsets[14]), name: reader.readStringOrNull(offsets[14]),
status: _MangastatusValueEnumMap[reader.readByteOrNull(offsets[15])] ?? source: reader.readStringOrNull(offsets[15]),
status: _MangastatusValueEnumMap[reader.readByteOrNull(offsets[16])] ??
Status.ongoing, Status.ongoing,
); );
return object; return object;
@ -275,18 +282,20 @@ P _mangaDeserializeProp<P>(
case 8: case 8:
return (reader.readBoolOrNull(offset)) as P; return (reader.readBoolOrNull(offset)) as P;
case 9: case 9:
return (reader.readStringOrNull(offset)) as P; return (reader.readBoolOrNull(offset)) as P;
case 10: case 10:
return (reader.readLongOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 11: case 11:
return (reader.readLongOrNull(offset)) as P; return (reader.readLongOrNull(offset)) as P;
case 12: case 12:
return (reader.readStringOrNull(offset)) as P; return (reader.readLongOrNull(offset)) as P;
case 13: case 13:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 14: case 14:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 15: case 15:
return (reader.readStringOrNull(offset)) as P;
case 16:
return (_MangastatusValueEnumMap[reader.readByteOrNull(offset)] ?? return (_MangastatusValueEnumMap[reader.readByteOrNull(offset)] ??
Status.ongoing) as P; Status.ongoing) as P;
default: 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() { QueryBuilder<Manga, Manga, QAfterFilterCondition> langIsNull() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull( 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() { QueryBuilder<Manga, Manga, QAfterSortBy> sortByLang() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'lang', Sort.asc); 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() { QueryBuilder<Manga, Manga, QAfterSortBy> thenByLang() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'lang', Sort.asc); 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( QueryBuilder<Manga, Manga, QDistinct> distinctByLang(
{bool caseSensitive = true}) { {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) { 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() { QueryBuilder<Manga, String?, QQueryOperations> langProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'lang'); return query.addPropertyName(r'lang');

View file

@ -94,6 +94,31 @@ class Settings {
L10nLocale? locale; 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( Settings(
{this.id = 227, {this.id = 227,
this.displayType = DisplayType.compactGrid, this.displayType = DisplayType.compactGrid,
@ -132,7 +157,19 @@ class Settings {
this.downloadLocation = "", this.downloadLocation = "",
this.cropBorders = false, this.cropBorders = false,
this.libraryLocalSource, 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 { enum DisplayType {
@ -216,5 +253,5 @@ class FilterScanlator {
class L10nLocale { class L10nLocale {
String? languageCode; String? languageCode;
String? countryCode; 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; String? headers;
bool? isManga;
Source({ Source({
this.id = 0, this.id = 0,
this.name = '', this.name = '',
@ -68,6 +70,7 @@ class Source {
this.versionLast = "", this.versionLast = "",
this.sourceCode = '', this.sourceCode = '',
this.headers = '', this.headers = '',
this.isManga = true,
}); });
Source.fromJson(Map<String, dynamic> json) { Source.fromJson(Map<String, dynamic> json) {
name = json['name']; name = json['name'];
@ -83,93 +86,6 @@ class Source {
sourceCodeUrl = json['sourceCodeUrl']; sourceCodeUrl = json['sourceCodeUrl'];
apiUrl = json['apiUrl']; apiUrl = json['apiUrl'];
version = json['version']; 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', name: r'isFullData',
type: IsarType.bool, type: IsarType.bool,
), ),
r'isNsfw': PropertySchema( r'isManga': PropertySchema(
id: 10, id: 10,
name: r'isManga',
type: IsarType.bool,
),
r'isNsfw': PropertySchema(
id: 11,
name: r'isNsfw', name: r'isNsfw',
type: IsarType.bool, type: IsarType.bool,
), ),
r'isPinned': PropertySchema( r'isPinned': PropertySchema(
id: 11, id: 12,
name: r'isPinned', name: r'isPinned',
type: IsarType.bool, type: IsarType.bool,
), ),
r'lang': PropertySchema( r'lang': PropertySchema(
id: 12, id: 13,
name: r'lang', name: r'lang',
type: IsarType.string, type: IsarType.string,
), ),
r'lastUsed': PropertySchema( r'lastUsed': PropertySchema(
id: 13, id: 14,
name: r'lastUsed', name: r'lastUsed',
type: IsarType.bool, type: IsarType.bool,
), ),
r'name': PropertySchema( r'name': PropertySchema(
id: 14, id: 15,
name: r'name', name: r'name',
type: IsarType.string, type: IsarType.string,
), ),
r'sourceCode': PropertySchema( r'sourceCode': PropertySchema(
id: 15, id: 16,
name: r'sourceCode', name: r'sourceCode',
type: IsarType.string, type: IsarType.string,
), ),
r'sourceCodeUrl': PropertySchema( r'sourceCodeUrl': PropertySchema(
id: 16, id: 17,
name: r'sourceCodeUrl', name: r'sourceCodeUrl',
type: IsarType.string, type: IsarType.string,
), ),
r'typeSource': PropertySchema( r'typeSource': PropertySchema(
id: 17, id: 18,
name: r'typeSource', name: r'typeSource',
type: IsarType.string, type: IsarType.string,
), ),
r'version': PropertySchema( r'version': PropertySchema(
id: 18, id: 19,
name: r'version', name: r'version',
type: IsarType.string, type: IsarType.string,
), ),
r'versionLast': PropertySchema( r'versionLast': PropertySchema(
id: 19, id: 20,
name: r'versionLast', name: r'versionLast',
type: IsarType.string, type: IsarType.string,
) )
@ -235,16 +240,17 @@ void _sourceSerialize(
writer.writeBool(offsets[7], object.isActive); writer.writeBool(offsets[7], object.isActive);
writer.writeBool(offsets[8], object.isAdded); writer.writeBool(offsets[8], object.isAdded);
writer.writeBool(offsets[9], object.isFullData); writer.writeBool(offsets[9], object.isFullData);
writer.writeBool(offsets[10], object.isNsfw); writer.writeBool(offsets[10], object.isManga);
writer.writeBool(offsets[11], object.isPinned); writer.writeBool(offsets[11], object.isNsfw);
writer.writeString(offsets[12], object.lang); writer.writeBool(offsets[12], object.isPinned);
writer.writeBool(offsets[13], object.lastUsed); writer.writeString(offsets[13], object.lang);
writer.writeString(offsets[14], object.name); writer.writeBool(offsets[14], object.lastUsed);
writer.writeString(offsets[15], object.sourceCode); writer.writeString(offsets[15], object.name);
writer.writeString(offsets[16], object.sourceCodeUrl); writer.writeString(offsets[16], object.sourceCode);
writer.writeString(offsets[17], object.typeSource); writer.writeString(offsets[17], object.sourceCodeUrl);
writer.writeString(offsets[18], object.version); writer.writeString(offsets[18], object.typeSource);
writer.writeString(offsets[19], object.versionLast); writer.writeString(offsets[19], object.version);
writer.writeString(offsets[20], object.versionLast);
} }
Source _sourceDeserialize( Source _sourceDeserialize(
@ -265,16 +271,17 @@ Source _sourceDeserialize(
isActive: reader.readBoolOrNull(offsets[7]), isActive: reader.readBoolOrNull(offsets[7]),
isAdded: reader.readBoolOrNull(offsets[8]), isAdded: reader.readBoolOrNull(offsets[8]),
isFullData: reader.readBoolOrNull(offsets[9]), isFullData: reader.readBoolOrNull(offsets[9]),
isNsfw: reader.readBoolOrNull(offsets[10]), isManga: reader.readBoolOrNull(offsets[10]),
isPinned: reader.readBoolOrNull(offsets[11]), isNsfw: reader.readBoolOrNull(offsets[11]),
lang: reader.readStringOrNull(offsets[12]), isPinned: reader.readBoolOrNull(offsets[12]),
lastUsed: reader.readBoolOrNull(offsets[13]), lang: reader.readStringOrNull(offsets[13]),
name: reader.readStringOrNull(offsets[14]), lastUsed: reader.readBoolOrNull(offsets[14]),
sourceCode: reader.readStringOrNull(offsets[15]), name: reader.readStringOrNull(offsets[15]),
sourceCodeUrl: reader.readStringOrNull(offsets[16]), sourceCode: reader.readStringOrNull(offsets[16]),
typeSource: reader.readStringOrNull(offsets[17]), sourceCodeUrl: reader.readStringOrNull(offsets[17]),
version: reader.readStringOrNull(offsets[18]), typeSource: reader.readStringOrNull(offsets[18]),
versionLast: reader.readStringOrNull(offsets[19]), version: reader.readStringOrNull(offsets[19]),
versionLast: reader.readStringOrNull(offsets[20]),
); );
return object; return object;
} }
@ -311,11 +318,11 @@ P _sourceDeserializeProp<P>(
case 11: case 11:
return (reader.readBoolOrNull(offset)) as P; return (reader.readBoolOrNull(offset)) as P;
case 12: case 12:
return (reader.readStringOrNull(offset)) as P;
case 13:
return (reader.readBoolOrNull(offset)) as P; return (reader.readBoolOrNull(offset)) as P;
case 14: case 13:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 14:
return (reader.readBoolOrNull(offset)) as P;
case 15: case 15:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 16: case 16:
@ -326,6 +333,8 @@ P _sourceDeserializeProp<P>(
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 19: case 19:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 20:
return (reader.readStringOrNull(offset)) as P;
default: default:
throw IsarError('Unknown property with id $propertyId'); 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() { QueryBuilder<Source, Source, QAfterFilterCondition> isNsfwIsNull() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull( 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() { QueryBuilder<Source, Source, QAfterSortBy> sortByIsNsfw() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isNsfw', Sort.asc); 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() { QueryBuilder<Source, Source, QAfterSortBy> thenByIsNsfw() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isNsfw', Sort.asc); 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() { QueryBuilder<Source, Source, QDistinct> distinctByIsNsfw() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'isNsfw'); 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() { QueryBuilder<Source, bool?, QQueryOperations> isNsfwProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'isNsfw'); return query.addPropertyName(r'isNsfw');

View file

@ -47,4 +47,14 @@ class Track {
this.trackingUrl}); 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, 'dropped': 3,
'planToRead': 4, 'planToRead': 4,
'rereading': 5, 'rereading': 5,
'watching': 6,
'planToWatch': 7,
'reWatching': 8,
}; };
const _TrackstatusValueEnumMap = { const _TrackstatusValueEnumMap = {
0: TrackStatus.reading, 0: TrackStatus.reading,
@ -211,6 +214,9 @@ const _TrackstatusValueEnumMap = {
3: TrackStatus.dropped, 3: TrackStatus.dropped,
4: TrackStatus.planToRead, 4: TrackStatus.planToRead,
5: TrackStatus.rereading, 5: TrackStatus.rereading,
6: TrackStatus.watching,
7: TrackStatus.planToWatch,
8: TrackStatus.reWatching,
}; };
Id _trackGetId(Track object) { 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); 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 @override
void initState() { void initState() {
_tabBarController = TabController(length: 3, vsync: this); _tabBarController = TabController(length: 5, vsync: this);
_tabBarController.animateTo(0); _tabBarController.animateTo(0);
_tabBarController.addListener(() { _tabBarController.addListener(() {
_chekPermission(); _chekPermission();
@ -44,7 +44,7 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return DefaultTabController( return DefaultTabController(
animationDuration: Duration.zero, animationDuration: Duration.zero,
length: 3, length: 5,
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
elevation: 0, elevation: 0,
@ -70,22 +70,25 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
}, },
controller: _textEditingController, controller: _textEditingController,
) )
: _tabBarController.index != 2 : _tabBarController.index != 4
? IconButton( ? IconButton(
splashRadius: 20, splashRadius: 20,
onPressed: () { onPressed: () {
if (_tabBarController.index == 1) { if (_tabBarController.index != 1 &&
_tabBarController.index != 0) {
setState(() { setState(() {
_isSearch = true; _isSearch = true;
}); });
} else if (_tabBarController.index == 0) { } else {
context.push( context.push('/globalSearch',
'/globalSearch', extra: _tabBarController.index == 0
); ? true
: false);
} }
}, },
icon: Icon( icon: Icon(
_tabBarController.index == 0 _tabBarController.index == 0 ||
_tabBarController.index == 1
? Icons.travel_explore_rounded ? Icons.travel_explore_rounded
: Icons.search_rounded, : Icons.search_rounded,
color: Theme.of(context).hintColor)) color: Theme.of(context).hintColor))
@ -94,34 +97,53 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
splashRadius: 20, splashRadius: 20,
onPressed: () { onPressed: () {
if (_tabBarController.index == 0) { if (_tabBarController.index == 0) {
context.push('/sourceFilter'); context.push('/sourceFilter', extra: true);
} else if (_tabBarController.index == 1) { } else if (_tabBarController.index == 1) {
context.push('/sourceFilter', extra: false);
} else if (_tabBarController.index == 2) {
_textEditingController.clear(); _textEditingController.clear();
context.push('/extensionLang'); context.push('/ExtensionLang', extra: true);
} else if (_tabBarController.index == 3) {
_textEditingController.clear();
context.push('/ExtensionLang', extra: false);
} else {} } else {}
}, },
icon: Icon( icon: Icon(
_tabBarController.index == 0 _tabBarController.index == 0 || _tabBarController.index == 1
? Icons.filter_list_sharp ? Icons.filter_list_sharp
: _tabBarController.index == 1 : _tabBarController.index == 2 ||
_tabBarController.index == 3
? Icons.translate_rounded ? Icons.translate_rounded
: Icons.help_outline_outlined, : Icons.help_outline_outlined,
color: Theme.of(context).hintColor)), color: Theme.of(context).hintColor)),
], ],
bottom: TabBar( bottom: TabBar(
indicatorSize: TabBarIndicatorSize.tab, indicatorSize: TabBarIndicatorSize.label,
isScrollable: true,
controller: _tabBarController, controller: _tabBarController,
tabs: [ tabs: [
Tab(text: l10n.sources), Tab(text: l10n.manga_sources),
Tab(text: l10n.extensions), Tab(text: l10n.anime_sources),
Tab(text: l10n.manga_extensions),
Tab(text: l10n.anime_extensions),
Tab(text: l10n.migrate), Tab(text: l10n.migrate),
], ],
), ),
), ),
body: TabBarView(controller: _tabBarController, children: [ body: TabBarView(controller: _tabBarController, children: [
const SourcesScreen(), const SourcesScreen(
isManga: true,
),
const SourcesScreen(
isManga: false,
),
ExtensionScreen( ExtensionScreen(
query: _textEditingController.text, query: _textEditingController.text,
isManga: true,
),
ExtensionScreen(
query: _textEditingController.text,
isManga: false,
), ),
const MigrateScreen() 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'; import 'package:mangayomi/modules/browse/extension/widgets/extension_lang_list_tile_widget.dart';
class ExtensionsLang extends ConsumerWidget { class ExtensionsLang extends ConsumerWidget {
const ExtensionsLang({super.key}); final bool isManga;
const ExtensionsLang({required this.isManga, super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -20,8 +21,12 @@ class ExtensionsLang extends ConsumerWidget {
title: Text(l10n.extensions), title: Text(l10n.extensions),
), ),
body: StreamBuilder( body: StreamBuilder(
stream: stream: isar.sources
isar.sources.filter().idIsNotNull().watch(fireImmediately: true), .filter()
.idIsNotNull()
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
List<Source>? entries = snapshot.hasData ? snapshot.data : []; List<Source>? entries = snapshot.hasData ? snapshot.data : [];
return ListView.builder( return ListView.builder(
@ -33,15 +38,16 @@ class ExtensionsLang extends ConsumerWidget {
onChanged: (val) { onChanged: (val) {
isar.writeTxnSync(() { isar.writeTxnSync(() {
for (var source in entries) { for (var source in entries) {
if (source.lang!.toLowerCase() == lang) { if (source.lang!.toLowerCase() == lang.toLowerCase()) {
isar.sources.putSync(source..isActive = val == true); isar.sources.putSync(source..isActive = val);
} }
} }
}); });
}, },
value: entries! value: entries!
.where((element) => element.lang!.toLowerCase() == lang) .where((element) =>
.where((element) => element.isActive!) element.lang!.toLowerCase() == lang.toLowerCase() &&
element.isActive!)
.isNotEmpty, .isNotEmpty,
); );
}, },

View file

@ -4,20 +4,30 @@ import 'package:grouped_list/grouped_list.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.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/utils/language.dart';
import 'package:mangayomi/modules/browse/extension/widgets/extension_list_tile_widget.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'; import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
class ExtensionScreen extends ConsumerWidget { class ExtensionScreen extends ConsumerWidget {
final bool isManga;
final String query; final String query;
const ExtensionScreen({required this.query, super.key}); const ExtensionScreen(
{required this.query, required this.isManga, super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { 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( 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( child: Padding(
padding: const EdgeInsets.only(top: 10), padding: const EdgeInsets.only(top: 10),
child: StreamBuilder( child: StreamBuilder(
@ -28,12 +38,14 @@ class ExtensionScreen extends ConsumerWidget {
.idIsNotNull() .idIsNotNull()
.and() .and()
.isActiveEqualTo(true) .isActiveEqualTo(true)
.isMangaEqualTo(isManga)
.watch(fireImmediately: true) .watch(fireImmediately: true)
: isar.sources : isar.sources
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.isActiveEqualTo(true) .isActiveEqualTo(true)
.isMangaEqualTo(isManga)
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) { if (snapshot.hasData && snapshot.data!.isNotEmpty) {

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 // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'fetch_sources.dart'; part of 'fetch_anime_sources.dart';
// ************************************************************************** // **************************************************************************
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$fetchSourcesListHash() => r'151bfddc9daf2cde079bf0f98f523d92b7e6ab00'; String _$fetchAnimeSourcesListHash() =>
r'1b16436684b132a5dc6db2159e38200f1dc9b11e';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -29,29 +30,29 @@ class _SystemHash {
} }
} }
typedef FetchSourcesListRef = AutoDisposeFutureProviderRef<dynamic>; typedef FetchAnimeSourcesListRef = AutoDisposeFutureProviderRef<dynamic>;
/// See also [fetchSourcesList]. /// See also [fetchAnimeSourcesList].
@ProviderFor(fetchSourcesList) @ProviderFor(fetchAnimeSourcesList)
const fetchSourcesListProvider = FetchSourcesListFamily(); const fetchAnimeSourcesListProvider = FetchAnimeSourcesListFamily();
/// See also [fetchSourcesList]. /// See also [fetchAnimeSourcesList].
class FetchSourcesListFamily extends Family<AsyncValue<dynamic>> { class FetchAnimeSourcesListFamily extends Family<AsyncValue<dynamic>> {
/// See also [fetchSourcesList]. /// See also [fetchAnimeSourcesList].
const FetchSourcesListFamily(); const FetchAnimeSourcesListFamily();
/// See also [fetchSourcesList]. /// See also [fetchAnimeSourcesList].
FetchSourcesListProvider call({ FetchAnimeSourcesListProvider call({
int? id, int? id,
}) { }) {
return FetchSourcesListProvider( return FetchAnimeSourcesListProvider(
id: id, id: id,
); );
} }
@override @override
FetchSourcesListProvider getProviderOverride( FetchAnimeSourcesListProvider getProviderOverride(
covariant FetchSourcesListProvider provider, covariant FetchAnimeSourcesListProvider provider,
) { ) {
return call( return call(
id: provider.id, id: provider.id,
@ -70,35 +71,35 @@ class FetchSourcesListFamily extends Family<AsyncValue<dynamic>> {
_allTransitiveDependencies; _allTransitiveDependencies;
@override @override
String? get name => r'fetchSourcesListProvider'; String? get name => r'fetchAnimeSourcesListProvider';
} }
/// See also [fetchSourcesList]. /// See also [fetchAnimeSourcesList].
class FetchSourcesListProvider extends AutoDisposeFutureProvider<dynamic> { class FetchAnimeSourcesListProvider extends AutoDisposeFutureProvider<dynamic> {
/// See also [fetchSourcesList]. /// See also [fetchAnimeSourcesList].
FetchSourcesListProvider({ FetchAnimeSourcesListProvider({
this.id, this.id,
}) : super.internal( }) : super.internal(
(ref) => fetchSourcesList( (ref) => fetchAnimeSourcesList(
ref, ref,
id: id, id: id,
), ),
from: fetchSourcesListProvider, from: fetchAnimeSourcesListProvider,
name: r'fetchSourcesListProvider', name: r'fetchAnimeSourcesListProvider',
debugGetCreateSourceHash: debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') const bool.fromEnvironment('dart.vm.product')
? null ? null
: _$fetchSourcesListHash, : _$fetchAnimeSourcesListHash,
dependencies: FetchSourcesListFamily._dependencies, dependencies: FetchAnimeSourcesListFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
FetchSourcesListFamily._allTransitiveDependencies, FetchAnimeSourcesListFamily._allTransitiveDependencies,
); );
final int? id; final int? id;
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is FetchSourcesListProvider && other.id == id; return other is FetchAnimeSourcesListProvider && other.id == id;
} }
@override @override
@ -109,4 +110,5 @@ class FetchSourcesListProvider extends AutoDisposeFutureProvider<dynamic> {
return _SystemHash.finish(hash); 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/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/source.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/utils/language.dart';
class ExtensionListTileWidget extends ConsumerStatefulWidget { class ExtensionListTileWidget extends ConsumerStatefulWidget {
@ -90,8 +91,13 @@ class _ExtensionListTileWidgetState
setState(() { setState(() {
_isLoading = true; _isLoading = true;
}); });
await ref.watch( widget.source.isManga!
fetchSourcesListProvider(id: widget.source.id).future); ? await ref.watch(
fetchMangaSourcesListProvider(id: widget.source.id)
.future)
: await ref.watch(
fetchAnimeSourcesListProvider(id: widget.source.id)
.future);
if (mounted) { if (mounted) {
setState(() { setState(() {
_isLoading = false; _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'; import 'package:mangayomi/modules/widgets/manga_image_card_widget.dart';
class GlobalSearchScreen extends ConsumerStatefulWidget { class GlobalSearchScreen extends ConsumerStatefulWidget {
final bool isManga;
const GlobalSearchScreen({ const GlobalSearchScreen({
required this.isManga,
super.key, super.key,
}); });
@ -35,12 +37,19 @@ class _GlobalSearchScreenState extends ConsumerState<GlobalSearchScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final sourceList = ref.watch(onlyIncludePinnedSourceStateProvider) final sourceList = ref.watch(onlyIncludePinnedSourceStateProvider)
? isar.sources.filter().isPinnedEqualTo(true).findAllSync() ? isar.sources
.filter()
.isPinnedEqualTo(true)
.and()
.isMangaEqualTo(widget.isManga)
.findAllSync()
: isar.sources : isar.sources
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.isAddedEqualTo(true) .isAddedEqualTo(true)
.and()
.isMangaEqualTo(widget.isManga)
.findAllSync(); .findAllSync();
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
@ -186,7 +195,10 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
return GestureDetector( return GestureDetector(
onTap: () async { onTap: () async {
pushToMangaReaderDetail( pushToMangaReaderDetail(
context: context, getManga: data, lang: widget.source.lang!); context: context,
getManga: data,
lang: widget.source.lang!,
isManga: widget.source.isManga ?? true);
}, },
child: StreamBuilder( child: StreamBuilder(
stream: isar.mangas stream: isar.mangas

View file

@ -9,7 +9,8 @@ import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/language.dart'; import 'package:mangayomi/utils/language.dart';
class SourcesFilterScreen extends ConsumerWidget { class SourcesFilterScreen extends ConsumerWidget {
const SourcesFilterScreen({super.key}); final bool isManga;
const SourcesFilterScreen({required this.isManga, super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -26,6 +27,8 @@ class SourcesFilterScreen extends ConsumerWidget {
.idIsNotNull() .idIsNotNull()
.and() .and()
.sourceCodeIsNotEmpty() .sourceCodeIsNotEmpty()
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) { if (snapshot.hasData && snapshot.data!.isNotEmpty) {
@ -43,7 +46,8 @@ class SourcesFilterScreen extends ConsumerWidget {
value: entries value: entries
.where((element) => .where((element) =>
element.lang!.toLowerCase() == groupByValue && element.lang!.toLowerCase() == groupByValue &&
element.isActive!) element.isActive! &&
element.isManga == isManga)
.isNotEmpty, .isNotEmpty,
onChanged: (val) { onChanged: (val) {
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -65,7 +69,8 @@ class SourcesFilterScreen extends ConsumerWidget {
if (entries if (entries
.where((s) => .where((s) =>
s.lang!.toLowerCase() == element.lang && s.lang!.toLowerCase() == element.lang &&
s.isActive!) s.isActive! &&
s.isManga == isManga)
.isEmpty) { .isEmpty) {
return Container(); 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'; import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
class SourcesScreen extends ConsumerWidget { class SourcesScreen extends ConsumerWidget {
const SourcesScreen({super.key}); final bool isManga;
const SourcesScreen({required this.isManga, super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -29,6 +30,8 @@ class SourcesScreen extends ConsumerWidget {
.isActiveEqualTo(true) .isActiveEqualTo(true)
.and() .and()
.lastUsedEqualTo(true) .lastUsedEqualTo(true)
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData) { if (!snapshot.hasData) {
@ -76,6 +79,8 @@ class SourcesScreen extends ConsumerWidget {
.isActiveEqualTo(true) .isActiveEqualTo(true)
.and() .and()
.isPinnedEqualTo(true) .isPinnedEqualTo(true)
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData) { if (!snapshot.hasData) {
@ -123,6 +128,8 @@ class SourcesScreen extends ConsumerWidget {
.isActiveEqualTo(true) .isActiveEqualTo(true)
.and() .and()
.isPinnedEqualTo(false) .isPinnedEqualTo(false)
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData) { if (!snapshot.hasData) {

View file

@ -3,8 +3,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:grouped_list/grouped_list.dart'; import 'package:grouped_list/grouped_list.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/history.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/history/providers/isar_providers.dart';
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart'; import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
@ -22,15 +25,33 @@ class HistoryScreen extends ConsumerStatefulWidget {
ConsumerState<HistoryScreen> createState() => _HistoryScreenState(); 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(); final _textEditingController = TextEditingController();
bool _isSearch = false; bool _isSearch = false;
List<History> entriesData = []; List<History> entriesData = [];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
final history = ref.watch(getAllHistoryStreamProvider); return DefaultTabController(
return Scaffold( animationDuration: Duration.zero,
length: 2,
child: Scaffold(
appBar: AppBar( appBar: AppBar(
elevation: 0, elevation: 0,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
@ -92,8 +113,21 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
List<History> histories = isar.historys
.filter()
.idIsNotNull()
.chapter((q) => q.manga((q) =>
q.isMangaEqualTo(
_tabBarController.index ==
0)))
.findAllSync()
.toList();
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.historys.clearSync(); // _tabBarController.index != 1
for (var history in histories) {
isar.historys.deleteSync(history.id!);
}
}); });
if (mounted) { if (mounted) {
Navigator.pop(context); Navigator.pop(context);
@ -109,226 +143,262 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
icon: Icon(Icons.delete_sweep_outlined, icon: Icon(Icons.delete_sweep_outlined,
color: Theme.of(context).hintColor)), color: Theme.of(context).hintColor)),
], ],
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
controller: _tabBarController,
tabs: [
Tab(text: l10n.manga),
Tab(text: l10n.anime),
],
),
), ),
body: history.when( body: Padding(
data: (data) { padding: const EdgeInsets.only(top: 10),
final entries = data child: TabBarView(controller: _tabBarController, children: [
.where((element) => _textEditingController.text.isNotEmpty HistoryTab(
? element.chapter.value!.manga.value!.name! isManga: true,
.toLowerCase() query: _textEditingController.text,
.contains(_textEditingController.text.toLowerCase()) ),
: true) HistoryTab(
.toList(); isManga: false,
query: _textEditingController.text,
)
]),
),
),
);
}
}
if (entries.isNotEmpty) { class HistoryTab extends ConsumerStatefulWidget {
return GroupedListView<History, String>( final String query;
elements: entries, final bool isManga;
groupBy: (element) => dateFormat(element.date!, 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, context: context,
stringDate: groupByValue,
ref: ref, ref: ref,
forHistoryValue: true, )),
useRelativeTimesTamps: false), ],
groupSeparatorBuilder: (String groupByValue) => Padding( ),
padding: const EdgeInsets.only(bottom: 8, left: 12), ),
child: Row( itemBuilder: (context, History element) {
children: [ final manga = element.chapter.value!.manga.value!;
Text(dateFormat( final chapter = element.chapter.value!;
null, return ElevatedButton(
context: context, style: ElevatedButton.styleFrom(
stringDate: groupByValue, padding: const EdgeInsets.all(0),
ref: ref, backgroundColor: Colors.transparent,
)), shape: RoundedRectangleBorder(
], borderRadius: BorderRadius.circular(0)),
), elevation: 0,
), shadowColor: Colors.transparent),
itemBuilder: (context, History element) { onPressed: () {
final manga = element.chapter.value!.manga.value!; pushMangaReaderView(context: context, chapter: chapter);
final chapter = element.chapter.value!; },
return ElevatedButton( child: Padding(
style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 12),
padding: const EdgeInsets.all(0), child: SizedBox(
backgroundColor: Colors.transparent, height: 105,
shape: RoundedRectangleBorder( child: Row(
borderRadius: BorderRadius.circular(0)), crossAxisAlignment: CrossAxisAlignment.center,
elevation: 0, children: [
shadowColor: Colors.transparent), SizedBox(
onPressed: () { width: 60,
pushMangaReaderView(context: context, chapter: chapter); height: 90,
}, child: ElevatedButton(
child: Padding( style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 12), padding: const EdgeInsets.all(0),
child: SizedBox( shape: RoundedRectangleBorder(
height: 105, borderRadius: BorderRadius.circular(7)),
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),
),
),
), ),
Flexible( onPressed: () {
child: Row( context.push('/manga-reader/detail',
children: [ extra: manga.id);
Expanded( },
child: Container( child: ClipRRect(
color: Colors.transparent, borderRadius: BorderRadius.circular(7),
child: Padding( child: manga.customCoverImage != null
padding: const EdgeInsets.all(8.0), ? Image.memory(
child: Column( manga.customCoverImage as Uint8List)
mainAxisAlignment: : cachedNetworkImage(
MainAxisAlignment.center, 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:
CrossAxisAlignment.start, WrapCrossAlignment.end,
children: [ children: [
Text( Text(
manga.name!, chapter.name!,
style: TextStyle( 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) color: Theme.of(context)
.textTheme .textTheme
.bodyLarge! .bodyLarge!
.color, .color,
fontWeight: FontWeight.bold), fontWeight: FontWeight.w400),
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),
),
],
), ),
], ],
), ),
), ],
), ),
), ),
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( itemComparator: (item1, item2) =>
child: Text(l10n.nothing_read_recently), item1.date!.compareTo(item2.date!),
); order: GroupedListOrder.DESC,
}, );
error: (Object error, StackTrace stackTrace) { }
return ErrorText(error); return Center(
}, child: Text(l10n.nothing_read_recently),
loading: () { );
return const ProgressCenter(); },
}, 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:isar/isar.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/history.dart'; import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'isar_providers.g.dart'; part 'isar_providers.g.dart';
@riverpod @riverpod
Stream<List<History>> getAllHistoryStream( Stream<List<History>> getAllHistoryStream(GetAllHistoryStreamRef ref,
GetAllHistoryStreamRef ref, {required bool isManga}) async* {
) async* { yield* isar.historys
yield* isar.historys.filter().idIsNotNull().watch(fireImmediately: true); .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() => 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]. /// See also [getAllHistoryStream].
@ProviderFor(getAllHistoryStream) @ProviderFor(getAllHistoryStream)
final getAllHistoryStreamProvider = const getAllHistoryStreamProvider = GetAllHistoryStreamFamily();
AutoDisposeStreamProvider<List<History>>.internal(
getAllHistoryStream,
name: r'getAllHistoryStreamProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$getAllHistoryStreamHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef GetAllHistoryStreamRef = AutoDisposeStreamProviderRef<List<History>>; /// See also [getAllHistoryStream].
// 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 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/manga.dart';
import 'package:mangayomi/models/settings.dart'; import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/modules/library/providers/local_archive.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/modules/widgets/manga_image_card_widget.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/providers/storage_provider.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/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_filter_list_tile_widget.dart';
import 'package:mangayomi/modules/manga/detail/widgets/chapter_sort_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/error_text.dart';
import 'package:mangayomi/modules/widgets/progress_center.dart'; import 'package:mangayomi/modules/widgets/progress_center.dart';
class LibraryScreen extends ConsumerStatefulWidget { class LibraryScreen extends ConsumerStatefulWidget {
const LibraryScreen({super.key}); final bool isManga;
const LibraryScreen({required this.isManga, super.key});
@override @override
ConsumerState<LibraryScreen> createState() => _LibraryScreenState(); ConsumerState<LibraryScreen> createState() => _LibraryScreenState();
@ -47,11 +48,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
int _tabIndex = 0; int _tabIndex = 0;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final categories = ref.watch(getMangaCategorieStreamProvider); final categories =
final withoutCategories = ref.watch(getMangaCategorieStreamProvider(isManga: widget.isManga));
ref.watch(getAllMangaWithoutCategoriesStreamProvider); final withoutCategories = ref.watch(
final showCategoryTabs = ref.watch(libraryShowCategoryTabsStateProvider); getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga));
final mangaAll = ref.watch(getAllMangaStreamProvider(categoryId: null)); final showCategoryTabs = ref
.watch(libraryShowCategoryTabsStateProvider(isManga: widget.isManga));
final mangaAll = ref.watch(
getAllMangaStreamProvider(categoryId: null, isManga: widget.isManga));
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return Scaffold( return Scaffold(
body: mangaAll.when( body: mangaAll.when(
@ -73,40 +77,50 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
}); });
return Consumer(builder: (context, ref, child) { return Consumer(builder: (context, ref, child) {
bool reverse = bool reverse = ref
ref.watch(sortLibraryMangaStateProvider).reverse!; .watch(sortLibraryMangaStateProvider(
isManga: widget.isManga))
.reverse!;
final continueReaderBtn = ref.watch( final continueReaderBtn = ref.watch(
libraryShowContinueReadingButtonStateProvider); libraryShowContinueReadingButtonStateProvider(
final showNumbersOfItems = isManga: widget.isManga));
ref.watch(libraryShowNumbersOfItemsStateProvider); final showNumbersOfItems = ref.watch(
final localSource = libraryShowNumbersOfItemsStateProvider(
ref.watch(libraryLocalSourceStateProvider); isManga: widget.isManga));
final downloadedChapter = final localSource = ref.watch(
ref.watch(libraryDownloadedChaptersStateProvider); libraryLocalSourceStateProvider(
final language = isManga: widget.isManga));
ref.watch(libraryLanguageStateProvider); final downloadedChapter = ref.watch(
libraryDownloadedChaptersStateProvider(
isManga: widget.isManga));
final language = ref.watch(libraryLanguageStateProvider(
isManga: widget.isManga));
final displayType = ref final displayType = ref
.read(libraryDisplayTypeStateProvider.notifier) .read(libraryDisplayTypeStateProvider(
.getLibraryDisplayTypeValue( isManga: widget.isManga)
ref.watch(libraryDisplayTypeStateProvider)); .notifier)
.getLibraryDisplayTypeValue(ref.watch(
libraryDisplayTypeStateProvider(
isManga: widget.isManga)));
final isNotFiltering = ref.watch( final isNotFiltering = ref.watch(
mangasFilterResultStateProvider( mangasFilterResultStateProvider(
mangaList: _entries)); isManga: widget.isManga, mangaList: _entries));
final downloadFilterType = ref.watch( final downloadFilterType = ref.watch(
mangaFilterDownloadedStateProvider( mangaFilterDownloadedStateProvider(
mangaList: _entries)); isManga: widget.isManga, mangaList: _entries));
final unreadFilterType = ref.watch( final unreadFilterType = ref.watch(
mangaFilterUnreadStateProvider( mangaFilterUnreadStateProvider(
mangaList: _entries)); isManga: widget.isManga, mangaList: _entries));
final startedFilterType = ref.watch( final startedFilterType = ref.watch(
mangaFilterStartedStateProvider( mangaFilterStartedStateProvider(
mangaList: _entries)); isManga: widget.isManga, mangaList: _entries));
final bookmarkedFilterType = ref.watch( final bookmarkedFilterType = ref.watch(
mangaFilterBookmarkedStateProvider( mangaFilterBookmarkedStateProvider(
mangaList: _entries)); isManga: widget.isManga, mangaList: _entries));
final sortType = ref final sortType = ref
.watch(sortLibraryMangaStateProvider) .watch(sortLibraryMangaStateProvider(
isManga: widget.isManga))
.index as int; .index as int;
final numberOfItemsList = _filterAndSortManga( final numberOfItemsList = _filterAndSortManga(
data: man, data: man,
@ -301,35 +315,50 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
}); });
} }
return Consumer(builder: (context, ref, child) { return Consumer(builder: (context, ref, child) {
bool reverse = bool reverse = ref
ref.watch(sortLibraryMangaStateProvider).reverse!; .watch(sortLibraryMangaStateProvider(
final continueReaderBtn = ref isManga: widget.isManga))
.watch(libraryShowContinueReadingButtonStateProvider); .reverse!;
final showNumbersOfItems = final continueReaderBtn = ref.watch(
ref.watch(libraryShowNumbersOfItemsStateProvider); libraryShowContinueReadingButtonStateProvider(
final localSource = isManga: widget.isManga));
ref.watch(libraryLocalSourceStateProvider); final showNumbersOfItems = ref.watch(
final downloadedChapter = libraryShowNumbersOfItemsStateProvider(
ref.watch(libraryDownloadedChaptersStateProvider); isManga: widget.isManga));
final language = ref.watch(libraryLanguageStateProvider); 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 final displayType = ref
.read(libraryDisplayTypeStateProvider.notifier) .read(libraryDisplayTypeStateProvider(
.getLibraryDisplayTypeValue( isManga: widget.isManga)
ref.watch(libraryDisplayTypeStateProvider)); .notifier)
.getLibraryDisplayTypeValue(ref.watch(
libraryDisplayTypeStateProvider(
isManga: widget.isManga)));
final isNotFiltering = ref.watch( final isNotFiltering = ref.watch(
mangasFilterResultStateProvider(mangaList: _entries)); mangasFilterResultStateProvider(
isManga: widget.isManga, mangaList: _entries));
final downloadFilterType = ref.watch( final downloadFilterType = ref.watch(
mangaFilterDownloadedStateProvider( mangaFilterDownloadedStateProvider(
mangaList: _entries)); isManga: widget.isManga, mangaList: _entries));
final unreadFilterType = ref.watch( final unreadFilterType = ref.watch(
mangaFilterUnreadStateProvider(mangaList: _entries)); mangaFilterUnreadStateProvider(
isManga: widget.isManga, mangaList: _entries));
final startedFilterType = ref.watch( final startedFilterType = ref.watch(
mangaFilterStartedStateProvider(mangaList: _entries)); mangaFilterStartedStateProvider(
isManga: widget.isManga, mangaList: _entries));
final bookmarkedFilterType = ref.watch( final bookmarkedFilterType = ref.watch(
mangaFilterBookmarkedStateProvider( mangaFilterBookmarkedStateProvider(
mangaList: _entries)); isManga: widget.isManga, mangaList: _entries));
final sortType = final sortType = ref
ref.watch(sortLibraryMangaStateProvider).index; .watch(sortLibraryMangaStateProvider(
isManga: widget.isManga))
.index;
final numberOfItemsList = _filterAndSortManga( final numberOfItemsList = _filterAndSortManga(
data: man, data: man,
downloadFilterType: downloadFilterType, downloadFilterType: downloadFilterType,
@ -510,8 +539,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required bool downloadedChapter, required bool downloadedChapter,
required bool continueReaderBtn, required bool continueReaderBtn,
required int categoryId}) { required int categoryId}) {
final mangas = ref.watch(getAllMangaStreamProvider(categoryId: categoryId)); final mangas = ref.watch(getAllMangaStreamProvider(
final sortType = ref.watch(sortLibraryMangaStateProvider).index; categoryId: categoryId, isManga: widget.isManga));
final sortType =
ref.watch(sortLibraryMangaStateProvider(isManga: widget.isManga)).index;
return mangas.when( return mangas.when(
data: (data) { data: (data) {
final categoriNumberOfItemsList = _filterAndSortManga( final categoriNumberOfItemsList = _filterAndSortManga(
@ -555,8 +586,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required WidgetRef ref, required WidgetRef ref,
required DisplayType displayType}) { required DisplayType displayType}) {
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
final mangas = ref.watch(getAllMangaStreamProvider(categoryId: categoryId)); final mangas = ref.watch(getAllMangaStreamProvider(
final sortType = ref.watch(sortLibraryMangaStateProvider).index; categoryId: categoryId, isManga: widget.isManga));
final sortType =
ref.watch(sortLibraryMangaStateProvider(isManga: widget.isManga)).index;
final mangaIdsList = ref.watch(mangasListStateProvider); final mangaIdsList = ref.watch(mangasListStateProvider);
return Scaffold( return Scaffold(
body: mangas.when( body: mangas.when(
@ -616,10 +649,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required DisplayType displayType, required DisplayType displayType,
required WidgetRef ref, required WidgetRef ref,
bool withouCategories = false}) { bool withouCategories = false}) {
final sortType = ref.watch(sortLibraryMangaStateProvider).index; final sortType =
ref.watch(sortLibraryMangaStateProvider(isManga: widget.isManga)).index;
final manga = withouCategories final manga = withouCategories
? ref.watch(getAllMangaWithoutCategoriesStreamProvider) ? ref.watch(
: ref.watch(getAllMangaStreamProvider(categoryId: null)); getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga))
: ref.watch(getAllMangaStreamProvider(
categoryId: null, isManga: widget.isManga));
final mangaIdsList = ref.watch(mangasListStateProvider); final mangaIdsList = ref.watch(mangasListStateProvider);
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return manga.when( return manga.when(
@ -822,99 +858,128 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
} }
return StatefulBuilder( return StatefulBuilder(
builder: (context, setState) { builder: (context, setState) {
return AlertDialog( return StreamBuilder(
title: Text( stream: isar.categorys
l10n.set_categories, .filter()
), .idIsNotNull()
content: SizedBox( .and()
width: mediaWidth(context, 0.8), .forMangaEqualTo(widget.isManga)
child: StreamBuilder( .watch(fireImmediately: true),
stream: isar.categorys builder: (context, snapshot) {
.filter() return AlertDialog(
.idIsNotNull() title: Text(
.watch(fireImmediately: true), l10n.set_categories,
builder: (context, snapshot) { ),
if (snapshot.hasData && snapshot.data!.isNotEmpty) { content: SizedBox(
final entries = snapshot.data!; width: mediaWidth(context, 0.8),
return ListView.builder( child: Builder(builder: (context) {
shrinkWrap: true, if (snapshot.hasData && snapshot.data!.isNotEmpty) {
itemCount: entries.length, final entries = snapshot.data!;
itemBuilder: (context, index) { return ListView.builder(
return ListTileMangaCategory( shrinkWrap: true,
category: entries[index], itemCount: entries.length,
categoryIds: categoryIds, itemBuilder: (context, index) {
mangasList: mangasList, return ListTileMangaCategory(
onTap: () { category: entries[index],
setState(() { categoryIds: categoryIds,
if (categoryIds mangasList: mangasList,
.contains(entries[index].id)) { onTap: () {
categoryIds.remove(entries[index].id); setState(() {
} else { 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!); 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, return Text(l10n.library_no_category_exist);
), }),
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,
)),
],
), ),
], 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, label: l10n.downloaded,
type: ref.watch( type: ref.watch(
mangaFilterDownloadedStateProvider( mangaFilterDownloadedStateProvider(
isManga: widget.isManga,
mangaList: _entries)), mangaList: _entries)),
onTap: () { onTap: () {
ref ref
.read( .read(
mangaFilterDownloadedStateProvider( mangaFilterDownloadedStateProvider(
isManga:
widget.isManga,
mangaList: _entries) mangaList: _entries)
.notifier) .notifier)
.update(); .update();
@ -1127,11 +1195,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
label: l10n.unread, label: l10n.unread,
type: ref.watch( type: ref.watch(
mangaFilterUnreadStateProvider( mangaFilterUnreadStateProvider(
isManga: widget.isManga,
mangaList: _entries)), mangaList: _entries)),
onTap: () { onTap: () {
ref ref
.read( .read(
mangaFilterUnreadStateProvider( mangaFilterUnreadStateProvider(
isManga:
widget.isManga,
mangaList: _entries) mangaList: _entries)
.notifier) .notifier)
.update(); .update();
@ -1140,11 +1211,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
label: l10n.started, label: l10n.started,
type: ref.watch( type: ref.watch(
mangaFilterStartedStateProvider( mangaFilterStartedStateProvider(
isManga: widget.isManga,
mangaList: _entries)), mangaList: _entries)),
onTap: () { onTap: () {
ref ref
.read( .read(
mangaFilterStartedStateProvider( mangaFilterStartedStateProvider(
isManga:
widget.isManga,
mangaList: _entries) mangaList: _entries)
.notifier) .notifier)
.update(); .update();
@ -1153,12 +1227,15 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
label: l10n.bookmarked, label: l10n.bookmarked,
type: ref.watch( type: ref.watch(
mangaFilterBookmarkedStateProvider( mangaFilterBookmarkedStateProvider(
isManga: widget.isManga,
mangaList: _entries)), mangaList: _entries)),
onTap: () { onTap: () {
setState(() { setState(() {
ref ref
.read( .read(
mangaFilterBookmarkedStateProvider( mangaFilterBookmarkedStateProvider(
isManga: widget
.isManga,
mangaList: mangaList:
_entries) _entries)
.notifier) .notifier)
@ -1170,11 +1247,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
}), }),
Consumer(builder: (context, ref, chil) { Consumer(builder: (context, ref, chil) {
final reverse = ref final reverse = ref
.read(sortLibraryMangaStateProvider .read(sortLibraryMangaStateProvider(
isManga: widget.isManga)
.notifier) .notifier)
.isReverse(); .isReverse();
final reverseChapter = final reverseChapter = ref.watch(
ref.watch(sortLibraryMangaStateProvider); sortLibraryMangaStateProvider(
isManga: widget.isManga));
return Column( return Column(
children: [ children: [
for (var i = 0; i < 7; i++) for (var i = 0; i < 7; i++)
@ -1185,7 +1264,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
onTap: () { onTap: () {
ref ref
.read( .read(
sortLibraryMangaStateProvider sortLibraryMangaStateProvider(
isManga:
widget.isManga)
.notifier) .notifier)
.set(i); .set(i);
}, },
@ -1196,22 +1277,31 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
); );
}), }),
Consumer(builder: (context, ref, chil) { Consumer(builder: (context, ref, chil) {
final display = ref final display = ref.watch(
.watch(libraryDisplayTypeStateProvider); libraryDisplayTypeStateProvider(
isManga: widget.isManga));
final displayV = ref.read( final displayV = ref.read(
libraryDisplayTypeStateProvider.notifier); libraryDisplayTypeStateProvider(
isManga: widget.isManga)
.notifier);
final showCategoryTabs = ref.watch( final showCategoryTabs = ref.watch(
libraryShowCategoryTabsStateProvider); libraryShowCategoryTabsStateProvider(
isManga: widget.isManga));
final continueReaderBtn = ref.watch( final continueReaderBtn = ref.watch(
libraryShowContinueReadingButtonStateProvider); libraryShowContinueReadingButtonStateProvider(
isManga: widget.isManga));
final showNumbersOfItems = ref.watch( final showNumbersOfItems = ref.watch(
libraryShowNumbersOfItemsStateProvider); libraryShowNumbersOfItemsStateProvider(
isManga: widget.isManga));
final downloadedChapter = ref.watch( final downloadedChapter = ref.watch(
libraryDownloadedChaptersStateProvider); libraryDownloadedChaptersStateProvider(
final language = isManga: widget.isManga));
ref.watch(libraryLanguageStateProvider); final language = ref.watch(
final localSource = ref libraryLanguageStateProvider(
.watch(libraryLocalSourceStateProvider); isManga: widget.isManga));
final localSource = ref.watch(
libraryLocalSourceStateProvider(
isManga: widget.isManga));
return SingleChildScrollView( return SingleChildScrollView(
physics: physics:
const NeverScrollableScrollPhysics(), const NeverScrollableScrollPhysics(),
@ -1277,9 +1367,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
downloadedChapter ? 1 : 0, downloadedChapter ? 1 : 0,
onTap: () { onTap: () {
ref ref
.read( .read(libraryDownloadedChaptersStateProvider(
libraryDownloadedChaptersStateProvider isManga: widget
.notifier) .isManga)
.notifier)
.set( .set(
!downloadedChapter); !downloadedChapter);
}), }),
@ -1288,9 +1379,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
type: language ? 1 : 0, type: language ? 1 : 0,
onTap: () { onTap: () {
ref ref
.read( .read(libraryLanguageStateProvider(
libraryLanguageStateProvider isManga: widget
.notifier) .isManga)
.notifier)
.set(!language); .set(!language);
}), }),
ListTileChapterFilter( ListTileChapterFilter(
@ -1298,9 +1390,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
type: localSource ? 1 : 0, type: localSource ? 1 : 0,
onTap: () { onTap: () {
ref ref
.read( .read(libraryLocalSourceStateProvider(
libraryLocalSourceStateProvider isManga: widget
.notifier) .isManga)
.notifier)
.set(!localSource); .set(!localSource);
}), }),
], ],
@ -1327,9 +1420,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
showCategoryTabs ? 1 : 0, showCategoryTabs ? 1 : 0,
onTap: () { onTap: () {
ref ref
.read( .read(libraryShowCategoryTabsStateProvider(
libraryShowCategoryTabsStateProvider isManga: widget
.notifier) .isManga)
.notifier)
.set(!showCategoryTabs); .set(!showCategoryTabs);
}), }),
ListTileChapterFilter( ListTileChapterFilter(
@ -1340,9 +1434,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
: 0, : 0,
onTap: () { onTap: () {
ref ref
.read( .read(libraryShowNumbersOfItemsStateProvider(
libraryShowNumbersOfItemsStateProvider isManga: widget
.notifier) .isManga)
.notifier)
.set( .set(
!showNumbersOfItems); !showNumbersOfItems);
}), }),
@ -1370,9 +1465,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
continueReaderBtn ? 1 : 0, continueReaderBtn ? 1 : 0,
onTap: () { onTap: () {
ref ref
.read( .read(libraryShowContinueReadingButtonStateProvider(
libraryShowContinueReadingButtonStateProvider isManga: widget
.notifier) .isManga)
.notifier)
.set( .set(
!continueReaderBtn); !continueReaderBtn);
}), }),
@ -1420,8 +1516,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
final isLongPressed = ref.watch(isLongPressedMangaStateProvider); final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
final mangaIdsList = ref.watch(mangasListStateProvider); final mangaIdsList = ref.watch(mangasListStateProvider);
final manga = categoryId == null final manga = categoryId == null
? ref.watch(getAllMangaWithoutCategoriesStreamProvider) ? ref.watch(
: ref.watch(getAllMangaStreamProvider(categoryId: categoryId)); getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga))
: ref.watch(getAllMangaStreamProvider(
categoryId: categoryId, isManga: widget.isManga));
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return PreferredSize( return PreferredSize(
preferredSize: Size.fromHeight(AppBar().preferredSize.height), preferredSize: Size.fromHeight(AppBar().preferredSize.height),
@ -1490,7 +1588,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
: Row( : Row(
children: [ children: [
Text( Text(
l10n.library, widget.isManga ? l10n.manga : l10n.anime,
style: style:
TextStyle(color: Theme.of(context).hintColor), TextStyle(color: Theme.of(context).hintColor),
), ),
@ -1558,7 +1656,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
return [ return [
PopupMenuItem<int>( PopupMenuItem<int>(
value: 0, child: Text(l10n.open_random_entry)), 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) { }, onSelected: (value) {
if (value == 0) { if (value == 0) {

View file

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

View file

@ -6,7 +6,7 @@ part of 'isar_providers.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$getAllMangaStreamHash() => r'880357b7617f6592cd453186336b8114982a081b'; String _$getAllMangaStreamHash() => r'd06c3a94ba847055746f2d52566cc94db4c28b7e';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -43,9 +43,11 @@ class GetAllMangaStreamFamily extends Family<AsyncValue<List<Manga>>> {
/// See also [getAllMangaStream]. /// See also [getAllMangaStream].
GetAllMangaStreamProvider call({ GetAllMangaStreamProvider call({
required int? categoryId, required int? categoryId,
required bool? isManga,
}) { }) {
return GetAllMangaStreamProvider( return GetAllMangaStreamProvider(
categoryId: categoryId, categoryId: categoryId,
isManga: isManga,
); );
} }
@ -55,6 +57,7 @@ class GetAllMangaStreamFamily extends Family<AsyncValue<List<Manga>>> {
) { ) {
return call( return call(
categoryId: provider.categoryId, categoryId: provider.categoryId,
isManga: provider.isManga,
); );
} }
@ -78,10 +81,12 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
/// See also [getAllMangaStream]. /// See also [getAllMangaStream].
GetAllMangaStreamProvider({ GetAllMangaStreamProvider({
required this.categoryId, required this.categoryId,
required this.isManga,
}) : super.internal( }) : super.internal(
(ref) => getAllMangaStream( (ref) => getAllMangaStream(
ref, ref,
categoryId: categoryId, categoryId: categoryId,
isManga: isManga,
), ),
from: getAllMangaStreamProvider, from: getAllMangaStreamProvider,
name: r'getAllMangaStreamProvider', name: r'getAllMangaStreamProvider',
@ -95,37 +100,111 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
); );
final int? categoryId; final int? categoryId;
final bool? isManga;
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is GetAllMangaStreamProvider && other.categoryId == categoryId; return other is GetAllMangaStreamProvider &&
other.categoryId == categoryId &&
other.isManga == isManga;
} }
@override @override
int get hashCode { int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode); var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, categoryId.hashCode); hash = _SystemHash.combine(hash, categoryId.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode);
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
} }
} }
String _$getAllMangaWithoutCategoriesStreamHash() => String _$getAllMangaWithoutCategoriesStreamHash() =>
r'affd1fab4a6ab0e0bbc16b67384a0b17498fe209'; r'03581754f330a87894f953f8eaae528642b0afc2';
typedef GetAllMangaWithoutCategoriesStreamRef
= AutoDisposeStreamProviderRef<List<Manga>>;
/// See also [getAllMangaWithoutCategoriesStream]. /// See also [getAllMangaWithoutCategoriesStream].
@ProviderFor(getAllMangaWithoutCategoriesStream) @ProviderFor(getAllMangaWithoutCategoriesStream)
final getAllMangaWithoutCategoriesStreamProvider = const getAllMangaWithoutCategoriesStreamProvider =
AutoDisposeStreamProvider<List<Manga>>.internal( GetAllMangaWithoutCategoriesStreamFamily();
getAllMangaWithoutCategoriesStream,
name: r'getAllMangaWithoutCategoriesStreamProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$getAllMangaWithoutCategoriesStreamHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef GetAllMangaWithoutCategoriesStreamRef /// See also [getAllMangaWithoutCategoriesStream].
= AutoDisposeStreamProviderRef<List<Manga>>; class GetAllMangaWithoutCategoriesStreamFamily
// 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 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 @riverpod
class LibraryDisplayTypeState extends _$LibraryDisplayTypeState { class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
@override @override
String build() { String build({required bool isManga}) {
return isar.settings.getSync(227)!.displayType.name; return isManga
? isar.settings.getSync(227)!.displayType.name
: isar.settings.getSync(227)!.animeDisplayType.name;
} }
DisplayType getLibraryDisplayTypeValue(String value) { DisplayType getLibraryDisplayTypeValue(String value) {
@ -36,10 +38,16 @@ class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
} }
void setLibraryDisplayType(DisplayType displayType) { void setLibraryDisplayType(DisplayType displayType) {
final settings = isar.settings.getSync(227)!; Settings settings = isar.settings.getSync(227)!;
state = displayType.name; state = displayType.name;
if (isManga) {
settings = settings..displayType = displayType;
} else {
settings = settings..animeDisplayType = displayType;
}
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(settings..displayType = displayType); isar.settings.putSync(settings);
}); });
} }
} }
@ -47,19 +55,26 @@ class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
@riverpod @riverpod
class MangaFilterDownloadedState extends _$MangaFilterDownloadedState { class MangaFilterDownloadedState extends _$MangaFilterDownloadedState {
@override @override
int build({required List<Manga> mangaList}) { int build({required List<Manga> mangaList, required bool isManga}) {
state = getType(); state = getType();
return getType(); return getType();
} }
int 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) { 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.writeTxnSync(() {
isar.settings.putSync(settings..libraryFilterMangasDownloadType = type); isar.settings.putSync(settings);
}); });
state = type; state = type;
} }
@ -78,19 +93,26 @@ class MangaFilterDownloadedState extends _$MangaFilterDownloadedState {
@riverpod @riverpod
class MangaFilterUnreadState extends _$MangaFilterUnreadState { class MangaFilterUnreadState extends _$MangaFilterUnreadState {
@override @override
int build({required List<Manga> mangaList}) { int build({required List<Manga> mangaList, required bool isManga}) {
state = getType(); state = getType();
return getType(); return getType();
} }
int 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) { 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.writeTxnSync(() {
isar.settings.putSync(settings..libraryFilterMangasUnreadType = type); isar.settings.putSync(settings);
}); });
state = type; state = type;
} }
@ -158,19 +180,26 @@ class MangaFilterUnreadState extends _$MangaFilterUnreadState {
@riverpod @riverpod
class MangaFilterStartedState extends _$MangaFilterStartedState { class MangaFilterStartedState extends _$MangaFilterStartedState {
@override @override
int build({required List<Manga> mangaList}) { int build({required List<Manga> mangaList, required bool isManga}) {
state = getType(); state = getType();
return getType(); return getType();
} }
int 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) { 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.writeTxnSync(() {
isar.settings.putSync(settings..libraryFilterMangasStartedType = type); isar.settings.putSync(settings);
}); });
state = type; state = type;
} }
@ -238,19 +267,26 @@ class MangaFilterStartedState extends _$MangaFilterStartedState {
@riverpod @riverpod
class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState { class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState {
@override @override
int build({required List<Manga> mangaList}) { int build({required List<Manga> mangaList, required bool isManga}) {
state = getType(); state = getType();
return getType(); return getType();
} }
int 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) { 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.writeTxnSync(() {
isar.settings.putSync(settings..libraryFilterMangasBookMarkedType = type); isar.settings.putSync(settings);
}); });
state = type; state = type;
} }
@ -318,15 +354,15 @@ class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState {
@riverpod @riverpod
class MangasFilterResultState extends _$MangasFilterResultState { class MangasFilterResultState extends _$MangasFilterResultState {
@override @override
bool build({required List<Manga> mangaList}) { bool build({required List<Manga> mangaList, required bool isManga}) {
final downloadFilterType = final downloadFilterType = ref.watch(mangaFilterDownloadedStateProvider(
ref.watch(mangaFilterDownloadedStateProvider(mangaList: mangaList)); mangaList: mangaList, isManga: isManga));
final unreadFilterType = final unreadFilterType = ref.watch(
ref.watch(mangaFilterUnreadStateProvider(mangaList: mangaList)); mangaFilterUnreadStateProvider(mangaList: mangaList, isManga: isManga));
final startedFilterType = final startedFilterType = ref.watch(mangaFilterStartedStateProvider(
ref.watch(mangaFilterStartedStateProvider(mangaList: mangaList)); mangaList: mangaList, isManga: isManga));
final bookmarkedFilterType = final bookmarkedFilterType = ref.watch(mangaFilterBookmarkedStateProvider(
ref.watch(mangaFilterBookmarkedStateProvider(mangaList: mangaList)); mangaList: mangaList, isManga: isManga));
return downloadFilterType == 0 && return downloadFilterType == 0 &&
unreadFilterType == 0 && unreadFilterType == 0 &&
startedFilterType == 0 && startedFilterType == 0 &&
@ -337,15 +373,22 @@ class MangasFilterResultState extends _$MangasFilterResultState {
@riverpod @riverpod
class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState { class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
@override @override
bool build() { bool build({required bool isManga}) {
return isar.settings.getSync(227)!.libraryShowCategoryTabs!; return isManga
? isar.settings.getSync(227)!.libraryShowCategoryTabs!
: isar.settings.getSync(227)!.animeLibraryShowCategoryTabs ?? false;
} }
void set(bool value) { 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; state = value;
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryShowCategoryTabs = value); isar.settings.putSync(settings);
}); });
} }
} }
@ -353,15 +396,22 @@ class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
@riverpod @riverpod
class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState { class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
@override @override
bool build() { bool build({required bool isManga}) {
return isar.settings.getSync(227)!.libraryDownloadedChapters!; return isManga
? isar.settings.getSync(227)!.libraryDownloadedChapters!
: isar.settings.getSync(227)!.animeLibraryDownloadedChapters ?? false;
} }
void set(bool value) { 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; state = value;
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryDownloadedChapters = value); isar.settings.putSync(settings);
}); });
} }
} }
@ -369,15 +419,22 @@ class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
@riverpod @riverpod
class LibraryLanguageState extends _$LibraryLanguageState { class LibraryLanguageState extends _$LibraryLanguageState {
@override @override
bool build() { bool build({required bool isManga}) {
return isar.settings.getSync(227)!.libraryShowLanguage!; return isManga
? isar.settings.getSync(227)!.libraryShowLanguage!
: isar.settings.getSync(227)!.animeLibraryShowLanguage ?? false;
} }
void set(bool value) { 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; state = value;
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryShowLanguage = value); isar.settings.putSync(settings);
}); });
} }
} }
@ -385,15 +442,22 @@ class LibraryLanguageState extends _$LibraryLanguageState {
@riverpod @riverpod
class LibraryLocalSourceState extends _$LibraryLocalSourceState { class LibraryLocalSourceState extends _$LibraryLocalSourceState {
@override @override
bool build() { bool build({required bool isManga}) {
return isar.settings.getSync(227)!.libraryLocalSource ?? false; return isManga
? isar.settings.getSync(227)!.libraryLocalSource ?? false
: isar.settings.getSync(227)!.animeLibraryLocalSource ?? false;
} }
void set(bool value) { 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; state = value;
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryShowLanguage = value); isar.settings.putSync(settings);
}); });
} }
} }
@ -401,15 +465,22 @@ class LibraryLocalSourceState extends _$LibraryLocalSourceState {
@riverpod @riverpod
class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState { class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
@override @override
bool build() { bool build({required bool isManga}) {
return isar.settings.getSync(227)!.libraryShowNumbersOfItems!; return isManga
? isar.settings.getSync(227)!.libraryShowNumbersOfItems!
: isar.settings.getSync(227)!.animeLibraryShowNumbersOfItems ?? false;
} }
void set(bool value) { 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; state = value;
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryShowNumbersOfItems = value); isar.settings.putSync(settings);
}); });
} }
} }
@ -418,15 +489,23 @@ class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
class LibraryShowContinueReadingButtonState class LibraryShowContinueReadingButtonState
extends _$LibraryShowContinueReadingButtonState { extends _$LibraryShowContinueReadingButtonState {
@override @override
bool build() { bool build({required bool isManga}) {
return isar.settings.getSync(227)!.libraryShowContinueReadingButton!; return isManga
? isar.settings.getSync(227)!.libraryShowContinueReadingButton!
: isar.settings.getSync(227)!.animeLibraryShowContinueReadingButton ??
false;
} }
void set(bool value) { 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; state = value;
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(settings..libraryShowContinueReadingButton = value); isar.settings.putSync(settings);
}); });
} }
} }
@ -434,18 +513,25 @@ class LibraryShowContinueReadingButtonState
@riverpod @riverpod
class SortLibraryMangaState extends _$SortLibraryMangaState { class SortLibraryMangaState extends _$SortLibraryMangaState {
@override @override
SortLibraryManga build() { SortLibraryManga build({required bool isManga}) {
return isar.settings.getSync(227)!.sortLibraryManga ?? SortLibraryManga(); return isManga
? isar.settings.getSync(227)!.sortLibraryManga ?? SortLibraryManga()
: isar.settings.getSync(227)!.sortLibraryAnime ?? SortLibraryManga();
} }
void update(bool reverse, int index) { void update(bool reverse, int index) {
var value = SortLibraryManga() var value = SortLibraryManga()
..index = index ..index = index
..reverse = state.index == index ? !reverse : reverse; ..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(() { isar.writeTxnSync(() {
final settings = isar.settings.getSync(227)!; final settings = isar.settings.getSync(227)!;
isar.settings.putSync(settings..sortLibraryManga = value); isar.settings.putSync(settings);
}); });
state = value; state = value;
} }

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,7 +6,7 @@ part of 'track_state_providers.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$trackStateHash() => r'7004528230213b458c7db417947eecfc700d44d7'; String _$trackStateHash() => r'eeca421125ff52ccf671d434c41e0198bb7b6fea';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -31,9 +31,11 @@ class _SystemHash {
abstract class _$TrackState extends BuildlessAutoDisposeNotifier<Track> { abstract class _$TrackState extends BuildlessAutoDisposeNotifier<Track> {
late final Track? track; late final Track? track;
late final bool? isManga;
Track build({ Track build({
Track? track, Track? track,
required bool? isManga,
}); });
} }
@ -49,9 +51,11 @@ class TrackStateFamily extends Family<Track> {
/// See also [TrackState]. /// See also [TrackState].
TrackStateProvider call({ TrackStateProvider call({
Track? track, Track? track,
required bool? isManga,
}) { }) {
return TrackStateProvider( return TrackStateProvider(
track: track, track: track,
isManga: isManga,
); );
} }
@ -61,6 +65,7 @@ class TrackStateFamily extends Family<Track> {
) { ) {
return call( return call(
track: provider.track, track: provider.track,
isManga: provider.isManga,
); );
} }
@ -85,8 +90,11 @@ class TrackStateProvider
/// See also [TrackState]. /// See also [TrackState].
TrackStateProvider({ TrackStateProvider({
this.track, this.track,
required this.isManga,
}) : super.internal( }) : super.internal(
() => TrackState()..track = track, () => TrackState()
..track = track
..isManga = isManga,
from: trackStateProvider, from: trackStateProvider,
name: r'trackStateProvider', name: r'trackStateProvider',
debugGetCreateSourceHash: debugGetCreateSourceHash:
@ -99,16 +107,20 @@ class TrackStateProvider
); );
final Track? track; final Track? track;
final bool? isManga;
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is TrackStateProvider && other.track == track; return other is TrackStateProvider &&
other.track == track &&
other.isManga == isManga;
} }
@override @override
int get hashCode { int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode); var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, track.hashCode); hash = _SystemHash.combine(hash, track.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode);
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
} }
@ -119,7 +131,9 @@ class TrackStateProvider
) { ) {
return notifier.build( return notifier.build(
track: track, 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); dateFormatLocale: source.dateFormatLocale);
final getManga = await ref final getManga = await ref
.watch(getMangaDetailProvider(manga: mangaS, source: source).future); .watch(getMangaDetailProvider(manga: mangaS, source: source).future);
final imageUrl = getManga.imageUrl != null && getManga.imageUrl!.isNotEmpty final imageUrl = getManga.imageUrl != null && getManga.imageUrl!.isNotEmpty
? getManga.imageUrl ? getManga.imageUrl
: manga.imageUrl ?? ""; : manga.imageUrl ?? "";
@ -39,6 +40,7 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
.toSet() .toSet()
.toList() .toList()
: manga.genre ?? []; : manga.genre ?? [];
final author = getManga.author != null && getManga.author!.isNotEmpty final author = getManga.author != null && getManga.author!.isNotEmpty
? getManga.author!.trim().trimLeft().trimRight() ? getManga.author!.trim().trimLeft().trimRight()
: manga.author ?? ""; : manga.author ?? "";
@ -72,6 +74,7 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
..link = link ..link = link
..source = sourceA ..source = sourceA
..lang = lang ..lang = lang
..isManga = source.isManga
..lastUpdate = DateTime.now().millisecondsSinceEpoch; ..lastUpdate = DateTime.now().millisecondsSinceEpoch;
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -99,7 +102,9 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
final chapters = Chapter( final chapters = Chapter(
name: title, name: title,
url: getManga.urls![i].trim().trimLeft().trimRight(), url: getManga.urls![i].trim().trimLeft().trimRight(),
dateUpload: getManga.chaptersDateUploads![i], dateUpload: getManga.chaptersDateUploads!.isEmpty
? null
: getManga.chaptersDateUploads![i],
scanlator: scanlator, scanlator: scanlator,
)..manga.value = manga; )..manga.value = manga;
isar.chapters.putSync(chapters); isar.chapters.putSync(chapters);

View file

@ -6,7 +6,7 @@ part of 'update_manga_detail_providers.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$updateMangaDetailHash() => r'7c8e4cae20be71b2cab42f7d784888fb4037aa00'; String _$updateMangaDetailHash() => r'143fc36898ba2d83ee6d42d71b01077ce33dcb19';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -118,4 +118,5 @@ class UpdateMangaDetailProvider extends AutoDisposeFutureProvider<dynamic> {
return _SystemHash.finish(hash); 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:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/providers/l10n_providers.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/utils/date.dart';
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart'; import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
import 'package:mangayomi/utils/colors.dart'; import 'package:mangayomi/utils/colors.dart';
@ -74,7 +75,12 @@ class ChapterListTileWidget extends ConsumerWidget {
children: [ children: [
if ((chapter.manga.value!.isLocalArchive ?? false) == false) if ((chapter.manga.value!.isLocalArchive ?? false) == false)
Text( 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), style: const TextStyle(fontSize: 11),
), ),
if (!chapter.isRead!) if (!chapter.isRead!)
@ -84,7 +90,13 @@ class ChapterListTileWidget extends ConsumerWidget {
children: [ children: [
const Text(''), const Text(''),
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( style: TextStyle(
fontSize: 11, fontSize: 11,
color: isLight(context) color: isLight(context)

View file

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

View file

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

View file

@ -134,4 +134,5 @@ class ConvertToCBZProvider extends AutoDisposeFutureProvider<List<String>> {
return _SystemHash.finish(hash); 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); bool onlyOnWifi = useWifi ?? ref.watch(onlyOnWifiStateProvider);
Directory? path; Directory? path;
final getDownloadLocation = ref.watch(downloadLocationStateProvider).$2; final getDownloadLocation = ref.watch(downloadLocationStateProvider).$2;
final desktopCustomDownloadLocation = final customDownloadLocation = getDownloadLocation.isNotEmpty;
Platform.isWindows && getDownloadLocation.isNotEmpty;
bool isOk = false; bool isOk = false;
final manga = chapter.manga.value!; final manga = chapter.manga.value!;
final path1 = await storageProvider.getDirectory(); final path1 = await storageProvider.getDirectory();
@ -99,10 +98,9 @@ Future<List<String>> downloadChapter(
headersProvider(source: manga.source!, lang: manga.lang!)), headersProvider(source: manga.source!, lang: manga.lang!)),
url: pageUrls[index].trim().trimLeft().trimRight(), url: pageUrls[index].trim().trimLeft().trimRight(),
filename: "${padIndex(index + 1)}.jpg", filename: "${padIndex(index + 1)}.jpg",
baseDirectory: baseDirectory: customDownloadLocation
Platform.isAndroid || desktopCustomDownloadLocation ? BaseDirectory.temporary
? BaseDirectory.temporary : BaseDirectory.applicationDocuments,
: BaseDirectory.applicationDocuments,
directory: 'Mangayomi/$finalPath', directory: 'Mangayomi/$finalPath',
updates: Updates.statusAndProgress, updates: Updates.statusAndProgress,
allowPause: true, allowPause: true,
@ -119,10 +117,9 @@ Future<List<String>> downloadChapter(
headersProvider(source: manga.source!, lang: manga.lang!)), headersProvider(source: manga.source!, lang: manga.lang!)),
url: pageUrls[index].trim().trimLeft().trimRight(), url: pageUrls[index].trim().trimLeft().trimRight(),
filename: "${padIndex(index + 1)}.jpg", filename: "${padIndex(index + 1)}.jpg",
baseDirectory: baseDirectory: customDownloadLocation
Platform.isAndroid || desktopCustomDownloadLocation ? BaseDirectory.temporary
? BaseDirectory.temporary : BaseDirectory.applicationDocuments,
: BaseDirectory.applicationDocuments,
directory: 'Mangayomi/$finalPath', directory: 'Mangayomi/$finalPath',
updates: Updates.statusAndProgress, updates: Updates.statusAndProgress,
allowPause: true, allowPause: true,
@ -188,7 +185,7 @@ Future<List<String>> downloadChapter(
}, },
taskProgressCallback: (taskProgress) async { taskProgressCallback: (taskProgress) async {
if (taskProgress.progress == 1.0) { if (taskProgress.progress == 1.0) {
if (Platform.isAndroid || desktopCustomDownloadLocation) { if (customDownloadLocation) {
await File( await File(
"${tempDir.path}/${taskProgress.task.directory}/${taskProgress.task.filename}") "${tempDir.path}/${taskProgress.task.directory}/${taskProgress.task.filename}")
.copy("${path!.path}/${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); 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 buildProgressIndicator();
} }
return MangaHomeImageCard( return MangaHomeImageCard(
isManga: widget.source.isManga ?? true,
manga: data[index]!, manga: data[index]!,
source: widget.source, source: widget.source,
); );
@ -409,11 +410,13 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
class MangaHomeImageCard extends ConsumerStatefulWidget { class MangaHomeImageCard extends ConsumerStatefulWidget {
final MangaModel manga; final MangaModel manga;
final bool isManga;
final Source source; final Source source;
const MangaHomeImageCard({ const MangaHomeImageCard({
super.key, super.key,
required this.manga, required this.manga,
required this.source, required this.source,
required this.isManga,
}); });
@override @override
@ -431,6 +434,7 @@ class _MangaHomeImageCardState extends ConsumerState<MangaHomeImageCard>
..lang = widget.source.lang ..lang = widget.source.lang
..source = widget.source.name, ..source = widget.source.name,
lang: widget.source.lang!, lang: widget.source.lang!,
isManga: widget.isManga,
); );
} }

View file

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

View file

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

View file

@ -135,4 +135,5 @@ class AutoCropBorderProvider
return _SystemHash.finish(hash); 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 BuildContext context,
required Chapter chapter, 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({ 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:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/category.dart'; import 'package:mangayomi/models/category.dart';
import 'package:mangayomi/modules/more/categoties/providers/isar_providers.dart'; import 'package:mangayomi/modules/more/categories/providers/isar_providers.dart';
import 'package:mangayomi/modules/more/categoties/widgets/custom_textfield.dart'; import 'package:mangayomi/modules/more/categories/widgets/custom_textfield.dart';
import 'package:mangayomi/modules/widgets/progress_center.dart'; import 'package:mangayomi/modules/widgets/progress_center.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
class CategoriesScreen extends ConsumerStatefulWidget { class CategoriesScreen extends ConsumerStatefulWidget {
const CategoriesScreen({super.key}); final (bool, int) data;
const CategoriesScreen({required this.data, super.key});
@override @override
ConsumerState<CategoriesScreen> createState() => _CategoriesScreenState(); 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 = []; List<Category> _entries = [];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = l10nLocalizations(context); final l10n = l10nLocalizations(context)!;
final categories = ref.watch(getMangaCategorieStreamProvider); final categories =
ref.watch(getMangaCategorieStreamProvider(isManga: widget.isManga));
return Scaffold( return Scaffold(
appBar: AppBar(
title: Text(l10n!.edit_categories),
),
body: categories.when( body: categories.when(
data: (data) { data: (data) {
if (data.isEmpty) { if (data.isEmpty) {
@ -215,6 +269,7 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
: () async { : () async {
await isar.writeTxn(() async { await isar.writeTxn(() async {
await isar.categorys.put(Category( await isar.categorys.put(Category(
forManga: widget.isManga,
name: controller.text, name: controller.text,
)); ));
}); });

View file

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

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