New feature : add Anime
-add trackers support for anime
12
.metadata
|
|
@ -4,7 +4,7 @@
|
|||
# This file should be version controlled.
|
||||
|
||||
version:
|
||||
revision: 90c64ed42ba53a52d18f0cb3b17666c8662ed2a0
|
||||
revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
|
||||
channel: stable
|
||||
|
||||
project_type: app
|
||||
|
|
@ -13,11 +13,11 @@ project_type: app
|
|||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 90c64ed42ba53a52d18f0cb3b17666c8662ed2a0
|
||||
base_revision: 90c64ed42ba53a52d18f0cb3b17666c8662ed2a0
|
||||
- platform: windows
|
||||
create_revision: 90c64ed42ba53a52d18f0cb3b17666c8662ed2a0
|
||||
base_revision: 90c64ed42ba53a52d18f0cb3b17666c8662ed2a0
|
||||
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
|
||||
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
|
||||
- platform: macos
|
||||
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
|
||||
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
|
||||
|
||||
# User provided section
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ Features include:
|
|||
* Local reading of downloaded content
|
||||
* Read and manage local archives (.cbz, .zip)
|
||||
* A configurable reader with multiple viewers, reading directions.
|
||||
* Tracker support: [MyAnimeList](https://myanimelist.net/) and [AniList](https://anilist.co/) support
|
||||
* Categories to organize your library
|
||||
* Light and dark themes
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
|
|
|||
44
ios/Podfile
Normal 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
|
|
@ -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
|
||||
|
|
@ -8,13 +8,26 @@
|
|||
|
||||
/* Begin PBXBuildFile section */
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
2E161ED88D6088BA04182D24 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 87B3D97401D2090714EBD2ED /* Pods_Runner.framework */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
A83607D399EF885A7879ED92 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F944C966F0D3C46230816475 /* Pods_RunnerTests.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
||||
remoteInfo = Runner;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
|
|
@ -31,10 +44,15 @@
|
|||
/* Begin PBXFileReference section */
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
48F414924F0EBD7233D9B3FB /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
87B3D97401D2090714EBD2ED /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8FEFB82C0F5EBF076D246DED /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
|
@ -42,19 +60,55 @@
|
|||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
9D7FF371C06E43EB2821A307 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
E3DBD23DF4F6477DD1B2D619 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
F2F655C8A844E54BF4806B9E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
F6B35AE9FD7580BD87744873 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
F944C966F0D3C46230816475 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
856C729112305BC7D8FE80C9 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A83607D399EF885A7879ED92 /* Pods_RunnerTests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2E161ED88D6088BA04182D24 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */,
|
||||
);
|
||||
path = RunnerTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6CD41D1121E5C42BF1E41F31 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9D7FF371C06E43EB2821A307 /* Pods-Runner.debug.xcconfig */,
|
||||
F6B35AE9FD7580BD87744873 /* Pods-Runner.release.xcconfig */,
|
||||
F2F655C8A844E54BF4806B9E /* Pods-Runner.profile.xcconfig */,
|
||||
E3DBD23DF4F6477DD1B2D619 /* Pods-RunnerTests.debug.xcconfig */,
|
||||
48F414924F0EBD7233D9B3FB /* Pods-RunnerTests.release.xcconfig */,
|
||||
8FEFB82C0F5EBF076D246DED /* Pods-RunnerTests.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -72,6 +126,9 @@
|
|||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
6CD41D1121E5C42BF1E41F31 /* Pods */,
|
||||
BCA59FF3AA594C41BF8ADD28 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
|
|
@ -79,6 +136,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -98,19 +156,49 @@
|
|||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BCA59FF3AA594C41BF8ADD28 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
87B3D97401D2090714EBD2ED /* Pods_Runner.framework */,
|
||||
F944C966F0D3C46230816475 /* Pods_RunnerTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
331C8080294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
EF1F895BD02D12F0BC740A9E /* [CP] Check Pods Manifest.lock */,
|
||||
331C807D294A63A400263BE5 /* Sources */,
|
||||
331C807F294A63A400263BE5 /* Resources */,
|
||||
856C729112305BC7D8FE80C9 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */,
|
||||
);
|
||||
name = RunnerTests;
|
||||
productName = RunnerTests;
|
||||
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
F7E3AB66492405CCCAB00559 /* [CP] Check Pods Manifest.lock */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
DC786BE6A6336FF08B227C10 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
|
@ -127,9 +215,14 @@
|
|||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1300;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
331C8080294A63A400263BE5 = {
|
||||
CreatedOnToolsVersion = 14.0;
|
||||
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||
};
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 1100;
|
||||
|
|
@ -150,11 +243,19 @@
|
|||
projectRoot = "";
|
||||
targets = (
|
||||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
331C807F294A63A400263BE5 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -176,6 +277,7 @@
|
|||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
|
|
@ -199,9 +301,78 @@
|
|||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
DC786BE6A6336FF08B227C10 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
EF1F895BD02D12F0BC740A9E /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
F7E3AB66492405CCCAB00559 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
331C807D294A63A400263BE5 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -213,6 +384,14 @@
|
|||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
|
|
@ -256,6 +435,7 @@
|
|||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
|
|
@ -274,7 +454,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
|
|
@ -292,6 +472,7 @@
|
|||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
|
@ -304,6 +485,56 @@
|
|||
};
|
||||
name = Profile;
|
||||
};
|
||||
331C8088294A63A400263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = E3DBD23DF4F6477DD1B2D619 /* Pods-RunnerTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.kodjodevf.mangayomi.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
331C8089294A63A400263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 48F414924F0EBD7233D9B3FB /* Pods-RunnerTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.kodjodevf.mangayomi.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
331C808A294A63A400263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 8FEFB82C0F5EBF076D246DED /* Pods-RunnerTests.profile.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.kodjodevf.mangayomi.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
97C147031CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
|
|
@ -327,6 +558,7 @@
|
|||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
|
|
@ -351,7 +583,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
|
|
@ -382,6 +614,7 @@
|
|||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
|
|
@ -400,7 +633,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
|
|
@ -420,6 +653,7 @@
|
|||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
|
@ -442,6 +676,7 @@
|
|||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
|
@ -457,6 +692,16 @@
|
|||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
331C8088294A63A400263BE5 /* Debug */,
|
||||
331C8089294A63A400263BE5 /* Release */,
|
||||
331C808A294A63A400263BE5 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
|
|
|||
|
|
@ -37,6 +37,17 @@
|
|||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "331C8080294A63A400263BE5"
|
||||
BuildableName = "RunnerTests.xctest"
|
||||
BlueprintName = "RunnerTests"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
|
|
|
|||
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
|
|
@ -4,4 +4,7 @@
|
|||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 723 B After Width: | Height: | Size: 295 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 450 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 282 B |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 462 B |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 704 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 586 B |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 862 B |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 862 B |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 8 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 762 B |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 1.4 KiB |
|
|
@ -2,6 +2,8 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
|
|
@ -13,7 +15,7 @@
|
|||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Mangayomi</string>
|
||||
<string>mangayomi</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
|
|
@ -24,6 +26,12 @@
|
|||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
|
|
@ -43,9 +51,5 @@
|
|||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
12
ios/RunnerTests/RunnerTests.swift
Normal 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.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -65,3 +65,12 @@ class MangaModel {
|
|||
this.images,
|
||||
this.statusList});
|
||||
}
|
||||
|
||||
class VideoModel {
|
||||
String? url;
|
||||
String? quality;
|
||||
String? originalUrl;
|
||||
Map<dynamic, dynamic>? headers;
|
||||
|
||||
VideoModel({this.url, this.quality, this.originalUrl, this.headers});
|
||||
}
|
||||
|
|
|
|||
134
lib/eval/bridge_class/video_model.dart
Normal 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
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:dart_eval/dart_eval.dart';
|
||||
import 'package:mangayomi/eval/bridge_class/manga_model.dart';
|
||||
import 'package:mangayomi/eval/bridge_class/video_model.dart';
|
||||
import 'package:mangayomi/eval/m_bridge.dart';
|
||||
|
||||
Uint8List compilerEval(String sourceCode) {
|
||||
|
|
@ -8,6 +9,7 @@ Uint8List compilerEval(String sourceCode) {
|
|||
compiler.defineBridgeClasses([
|
||||
$MBridge.$declaration,
|
||||
$MangaModel.$declaration,
|
||||
$VideoModel.$declaration
|
||||
]);
|
||||
final program = compiler.compile({
|
||||
'package:mangayomi': {'main.dart': sourceCode}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,16 @@ import 'package:flutter_js/flutter_js.dart';
|
|||
import 'package:intl/date_symbol_data_local.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:json_path/json_path.dart';
|
||||
import 'package:mangayomi/eval/bridge_class/model.dart';
|
||||
import 'package:mangayomi/eval/bridge_class/video_model.dart';
|
||||
import 'package:mangayomi/services/anime_servers/dood_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_servers/gogo_cdn_extractor.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/modules/webview/webview.dart';
|
||||
import 'package:mangayomi/services/anime_servers/mp4_upload_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_servers/stream_tape_extractor.dart';
|
||||
import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
import 'package:mangayomi/utils/reg_exp_matcher.dart';
|
||||
|
|
@ -499,6 +506,45 @@ class MBridge {
|
|||
}
|
||||
}
|
||||
|
||||
static Future<List<Video>> gogoCdnExtractor(String url) async {
|
||||
return await GogoCdnExtractor().videosFromUrl(
|
||||
url,
|
||||
);
|
||||
}
|
||||
|
||||
static Future<List<Video>> doodExtractor(String url) async {
|
||||
return await DoodExtractor().videosFromUrl(
|
||||
url,
|
||||
);
|
||||
}
|
||||
|
||||
static Future<List<Video>> mp4UploadExtractor(String url,
|
||||
Map<String, String>? headers, String prefix, String suffix) async {
|
||||
return await Mp4uploadExtractor()
|
||||
.videosFromUrl(url, headers ?? {}, prefix: prefix, suffix: suffix);
|
||||
}
|
||||
|
||||
static Future<List<Video>> streamTapeExtractor(String url) async {
|
||||
return await StreamTapeExtractor().videosFromUrl(
|
||||
url,
|
||||
);
|
||||
}
|
||||
|
||||
static String subString(String text, String pattern, int type) {
|
||||
String result = "";
|
||||
//substring before
|
||||
if (type == 0) {
|
||||
result = text.split(pattern).first;
|
||||
} else
|
||||
// substring after last
|
||||
if (type == 1) {
|
||||
result = text.split(pattern).last;
|
||||
} else if (type == 2) {
|
||||
result = text.substring(text.lastIndexOf(pattern) + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static String parseChapterDate(
|
||||
String date, String dateFormat, String dateFormatLocale) {
|
||||
int parseRelativeDate(String date) {
|
||||
|
|
@ -686,6 +732,29 @@ class $MBridge extends MBridge with $Bridge {
|
|||
returns: BridgeTypeAnnotation($type), params: [], namedParams: []))
|
||||
},
|
||||
methods: {
|
||||
'subString': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
params: [
|
||||
BridgeParameter(
|
||||
'text',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
BridgeParameter(
|
||||
'pattern',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
BridgeParameter(
|
||||
'type',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.intType)),
|
||||
false),
|
||||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'listParse': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list,
|
||||
|
|
@ -988,6 +1057,74 @@ class $MBridge extends MBridge with $Bridge {
|
|||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'gogoCdnExtractor': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
|
||||
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
|
||||
params: [
|
||||
BridgeParameter(
|
||||
'url',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'doodExtractor': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
|
||||
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
|
||||
params: [
|
||||
BridgeParameter(
|
||||
'url',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'streamTapeExtractor': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
|
||||
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
|
||||
params: [
|
||||
BridgeParameter(
|
||||
'url',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'mp4UploadExtractor': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
|
||||
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
|
||||
params: [
|
||||
BridgeParameter(
|
||||
'url',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
BridgeParameter(
|
||||
'headers',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.mapType),
|
||||
nullable: true),
|
||||
false),
|
||||
BridgeParameter(
|
||||
'prefix',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
BridgeParameter(
|
||||
'suffix',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'getHtmlViaWebview': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
|
||||
|
|
@ -1140,6 +1277,15 @@ class $MBridge extends MBridge with $Bridge {
|
|||
));
|
||||
}
|
||||
|
||||
static $String $subString(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) {
|
||||
return $String(MBridge.subString(
|
||||
args[0]!.$value,
|
||||
args[1]!.$value,
|
||||
args[2]!.$value,
|
||||
));
|
||||
}
|
||||
|
||||
static $String $getMapValue(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) {
|
||||
return $String(MBridge.getMapValue(
|
||||
|
|
@ -1220,11 +1366,54 @@ class $MBridge extends MBridge with $Bridge {
|
|||
static $Future $http(Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.http(args[0]!.$value, args[1]!.$value)
|
||||
.then((value) => $String(value)));
|
||||
|
||||
static $Future $getHtmlViaWebview(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.getHtmlViaWebview(args[0]!.$value, args[1]!.$value)
|
||||
.then((value) => $String(value)));
|
||||
|
||||
static $Future $gogoCdnExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.gogoCdnExtractor(args[0]!.$value)
|
||||
.then((value) => $List.wrap(value
|
||||
.map((e) => $VideoModel.wrap(VideoModel()
|
||||
..headers = e.headers
|
||||
..originalUrl = e.originalUrl
|
||||
..quality = e.quality
|
||||
..url = e.url))
|
||||
.toList())));
|
||||
|
||||
static $Future $doodExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.doodExtractor(args[0]!.$value)
|
||||
.then((value) => $List.wrap(value
|
||||
.map((e) => $VideoModel.wrap(VideoModel()
|
||||
..headers = e.headers
|
||||
..originalUrl = e.originalUrl
|
||||
..quality = e.quality
|
||||
..url = e.url))
|
||||
.toList())));
|
||||
static $Future $streamTapeExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.streamTapeExtractor(args[0]!.$value)
|
||||
.then((value) => $List.wrap(value
|
||||
.map((e) => $VideoModel.wrap(VideoModel()
|
||||
..headers = e.headers
|
||||
..originalUrl = e.originalUrl
|
||||
..quality = e.quality
|
||||
..url = e.url))
|
||||
.toList())));
|
||||
static $Future $mp4UploadExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.mp4UploadExtractor(args[0]!.$value, args[1]!.$value,
|
||||
args[2]!.$value, args[3]!.$value)
|
||||
.then((value) => $List.wrap(value
|
||||
.map((e) => $VideoModel.wrap(VideoModel()
|
||||
..headers = e.headers
|
||||
..originalUrl = e.originalUrl
|
||||
..quality = e.quality
|
||||
..url = e.url))
|
||||
.toList())));
|
||||
@override
|
||||
$Value? $bridgeGet(String identifier) {
|
||||
throw UnimplementedError();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:dart_eval/dart_eval.dart';
|
||||
import 'package:mangayomi/eval/bridge_class/video_model.dart';
|
||||
import 'package:mangayomi/eval/m_bridge.dart';
|
||||
import 'package:mangayomi/eval/bridge_class/manga_model.dart';
|
||||
|
||||
|
|
@ -11,10 +12,20 @@ Runtime runtimeEval(Uint8List bytecode) {
|
|||
isBridge: true);
|
||||
runtime.registerBridgeFunc(
|
||||
'package:bridge_lib/bridge_lib.dart', 'MangaModel.', $MangaModel.$new);
|
||||
runtime.registerBridgeFunc(
|
||||
'package:bridge_lib/bridge_lib.dart', 'VideoModel.', $VideoModel.$new);
|
||||
runtime.registerBridgeFunc(
|
||||
'package:bridge_lib/bridge_lib.dart', 'MBridge.http', $MBridge.$http);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.listParseDateTime', $MBridge.$listParseDateTime);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.gogoCdnExtractor', $MBridge.$gogoCdnExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.doodExtractor', $MBridge.$doodExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.streamTapeExtractor', $MBridge.$streamTapeExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.mp4UploadExtractor', $MBridge.$mp4UploadExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.jsonPathToString', $MBridge.$jsonPathToString);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
|
|
@ -35,6 +46,8 @@ Runtime runtimeEval(Uint8List bytecode) {
|
|||
'MBridge.parseChapterDate', $MBridge.$parseChapterDate);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.stringParse', $MBridge.$stringParse);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.subString', $MBridge.$subString);
|
||||
runtime.registerBridgeFunc(
|
||||
'package:bridge_lib/bridge_lib.dart', 'MBridge.evalJs', $MBridge.$evalJs);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
|
|
|
|||
|
|
@ -181,5 +181,18 @@
|
|||
"one_tracker":"1 tracker",
|
||||
"n_tracker":"{n} trackers",
|
||||
"tracking": "Tracking",
|
||||
"description": "Description"
|
||||
"description": "Description",
|
||||
"episode_progress": "Progress: {n}",
|
||||
"n_episodes": "{n} episodes",
|
||||
"manga_sources":"Manga Sources",
|
||||
"anime_sources":"Anime Sources",
|
||||
"anime_extensions":"Anime Extensions",
|
||||
"manga_extensions":"Manga Extensions",
|
||||
"anime":"Anime",
|
||||
"manga":"Manga",
|
||||
"library_no_category_exist":"You don't have any categories yet",
|
||||
"watching":"Watching",
|
||||
"plan_to_watch":"Plan to watch",
|
||||
"re_watching":"Rewatching"
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,5 +181,17 @@
|
|||
"one_tracker":"Suivi par 1 service",
|
||||
"n_tracker":"Suivi par {n} services",
|
||||
"tracking": "Suivi",
|
||||
"description": "Description"
|
||||
"description": "Description",
|
||||
"episode_progress": "Progression: {n}",
|
||||
"n_episodes": "{n} épisodes",
|
||||
"manga_sources":"Sources d'animés",
|
||||
"anime_sources":"Sources des mangas",
|
||||
"anime_extensions":"Extensions d'animés",
|
||||
"manga_extensions":"Extensions des mangas",
|
||||
"anime":"Animé",
|
||||
"manga":"Manga",
|
||||
"library_no_category_exist":"Vous n'avez pas encore de catégories",
|
||||
"watching":"En lecture",
|
||||
"plan_to_watch":"À regarder",
|
||||
"re_watching":"Revisionnage"
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ import 'package:bot_toast/bot_toast.dart';
|
|||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
||||
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_meedu_videoplayer/init_meedu_player.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:intl/date_symbol_data_local.dart';
|
||||
|
|
@ -29,6 +30,10 @@ class MyHttpoverrides extends HttpOverrides {
|
|||
}
|
||||
|
||||
void main(List<String> args) async {
|
||||
initMeeduPlayer(
|
||||
androidUseMediaKit: true,
|
||||
iosUseMediaKit: true,
|
||||
);
|
||||
HttpOverrides.global = MyHttpoverrides();
|
||||
if (Platform.isLinux || Platform.isWindows) {
|
||||
if (runWebViewTitleBarWidget(args)) {
|
||||
|
|
@ -125,4 +130,3 @@ class _MyAppState extends ConsumerState<MyApp> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ part 'category.g.dart';
|
|||
class Category {
|
||||
Id? id;
|
||||
String? name;
|
||||
bool? forManga;
|
||||
Category({
|
||||
this.id = Isar.autoIncrement,
|
||||
required this.name,
|
||||
required this.forManga
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,13 @@ const CategorySchema = CollectionSchema(
|
|||
name: r'Category',
|
||||
id: 5751694338128944171,
|
||||
properties: {
|
||||
r'name': PropertySchema(
|
||||
r'forManga': PropertySchema(
|
||||
id: 0,
|
||||
name: r'forManga',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'name': PropertySchema(
|
||||
id: 1,
|
||||
name: r'name',
|
||||
type: IsarType.string,
|
||||
)
|
||||
|
|
@ -58,7 +63,8 @@ void _categorySerialize(
|
|||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
writer.writeString(offsets[0], object.name);
|
||||
writer.writeBool(offsets[0], object.forManga);
|
||||
writer.writeString(offsets[1], object.name);
|
||||
}
|
||||
|
||||
Category _categoryDeserialize(
|
||||
|
|
@ -68,8 +74,9 @@ Category _categoryDeserialize(
|
|||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
final object = Category(
|
||||
forManga: reader.readBoolOrNull(offsets[0]),
|
||||
id: id,
|
||||
name: reader.readStringOrNull(offsets[0]),
|
||||
name: reader.readStringOrNull(offsets[1]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
|
@ -82,6 +89,8 @@ P _categoryDeserializeProp<P>(
|
|||
) {
|
||||
switch (propertyId) {
|
||||
case 0:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 1:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
|
|
@ -177,6 +186,32 @@ extension CategoryQueryWhere on QueryBuilder<Category, Category, QWhereClause> {
|
|||
|
||||
extension CategoryQueryFilter
|
||||
on QueryBuilder<Category, Category, QFilterCondition> {
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> forMangaIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'forManga',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> forMangaIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'forManga',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> forMangaEqualTo(
|
||||
bool? value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'forManga',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> idIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
|
@ -399,6 +434,18 @@ extension CategoryQueryLinks
|
|||
on QueryBuilder<Category, Category, QFilterCondition> {}
|
||||
|
||||
extension CategoryQuerySortBy on QueryBuilder<Category, Category, QSortBy> {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByForManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'forManga', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByForMangaDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'forManga', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByName() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'name', Sort.asc);
|
||||
|
|
@ -414,6 +461,18 @@ extension CategoryQuerySortBy on QueryBuilder<Category, Category, QSortBy> {
|
|||
|
||||
extension CategoryQuerySortThenBy
|
||||
on QueryBuilder<Category, Category, QSortThenBy> {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByForManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'forManga', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByForMangaDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'forManga', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenById() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'id', Sort.asc);
|
||||
|
|
@ -441,6 +500,12 @@ extension CategoryQuerySortThenBy
|
|||
|
||||
extension CategoryQueryWhereDistinct
|
||||
on QueryBuilder<Category, Category, QDistinct> {
|
||||
QueryBuilder<Category, Category, QDistinct> distinctByForManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'forManga');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QDistinct> distinctByName(
|
||||
{bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
|
|
@ -457,6 +522,12 @@ extension CategoryQueryProperty
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, bool?, QQueryOperations> forMangaProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'forManga');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, String?, QQueryOperations> nameProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'name');
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ class Manga {
|
|||
@enumerated
|
||||
Status status;
|
||||
|
||||
bool? isManga;
|
||||
|
||||
List<String>? genre;
|
||||
|
||||
bool favorite;
|
||||
|
|
@ -55,6 +57,7 @@ class Manga {
|
|||
required this.name,
|
||||
required this.status,
|
||||
required this.description,
|
||||
this.isManga = true,
|
||||
this.dateAdded,
|
||||
this.lastUpdate,
|
||||
this.categories,
|
||||
|
|
@ -71,3 +74,4 @@ enum Status {
|
|||
onHiatus,
|
||||
publishingFinished
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,38 +62,43 @@ const MangaSchema = CollectionSchema(
|
|||
name: r'isLocalArchive',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'lang': PropertySchema(
|
||||
r'isManga': PropertySchema(
|
||||
id: 9,
|
||||
name: r'isManga',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'lang': PropertySchema(
|
||||
id: 10,
|
||||
name: r'lang',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'lastRead': PropertySchema(
|
||||
id: 10,
|
||||
id: 11,
|
||||
name: r'lastRead',
|
||||
type: IsarType.long,
|
||||
),
|
||||
r'lastUpdate': PropertySchema(
|
||||
id: 11,
|
||||
id: 12,
|
||||
name: r'lastUpdate',
|
||||
type: IsarType.long,
|
||||
),
|
||||
r'link': PropertySchema(
|
||||
id: 12,
|
||||
id: 13,
|
||||
name: r'link',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'name': PropertySchema(
|
||||
id: 13,
|
||||
id: 14,
|
||||
name: r'name',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'source': PropertySchema(
|
||||
id: 14,
|
||||
id: 15,
|
||||
name: r'source',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'status': PropertySchema(
|
||||
id: 15,
|
||||
id: 16,
|
||||
name: r'status',
|
||||
type: IsarType.byte,
|
||||
enumMap: _MangastatusEnumValueMap,
|
||||
|
|
@ -211,13 +216,14 @@ void _mangaSerialize(
|
|||
writer.writeStringList(offsets[6], object.genre);
|
||||
writer.writeString(offsets[7], object.imageUrl);
|
||||
writer.writeBool(offsets[8], object.isLocalArchive);
|
||||
writer.writeString(offsets[9], object.lang);
|
||||
writer.writeLong(offsets[10], object.lastRead);
|
||||
writer.writeLong(offsets[11], object.lastUpdate);
|
||||
writer.writeString(offsets[12], object.link);
|
||||
writer.writeString(offsets[13], object.name);
|
||||
writer.writeString(offsets[14], object.source);
|
||||
writer.writeByte(offsets[15], object.status.index);
|
||||
writer.writeBool(offsets[9], object.isManga);
|
||||
writer.writeString(offsets[10], object.lang);
|
||||
writer.writeLong(offsets[11], object.lastRead);
|
||||
writer.writeLong(offsets[12], object.lastUpdate);
|
||||
writer.writeString(offsets[13], object.link);
|
||||
writer.writeString(offsets[14], object.name);
|
||||
writer.writeString(offsets[15], object.source);
|
||||
writer.writeByte(offsets[16], object.status.index);
|
||||
}
|
||||
|
||||
Manga _mangaDeserialize(
|
||||
|
|
@ -237,13 +243,14 @@ Manga _mangaDeserialize(
|
|||
id: id,
|
||||
imageUrl: reader.readStringOrNull(offsets[7]),
|
||||
isLocalArchive: reader.readBoolOrNull(offsets[8]),
|
||||
lang: reader.readStringOrNull(offsets[9]),
|
||||
lastRead: reader.readLongOrNull(offsets[10]),
|
||||
lastUpdate: reader.readLongOrNull(offsets[11]),
|
||||
link: reader.readStringOrNull(offsets[12]),
|
||||
name: reader.readStringOrNull(offsets[13]),
|
||||
source: reader.readStringOrNull(offsets[14]),
|
||||
status: _MangastatusValueEnumMap[reader.readByteOrNull(offsets[15])] ??
|
||||
isManga: reader.readBoolOrNull(offsets[9]),
|
||||
lang: reader.readStringOrNull(offsets[10]),
|
||||
lastRead: reader.readLongOrNull(offsets[11]),
|
||||
lastUpdate: reader.readLongOrNull(offsets[12]),
|
||||
link: reader.readStringOrNull(offsets[13]),
|
||||
name: reader.readStringOrNull(offsets[14]),
|
||||
source: reader.readStringOrNull(offsets[15]),
|
||||
status: _MangastatusValueEnumMap[reader.readByteOrNull(offsets[16])] ??
|
||||
Status.ongoing,
|
||||
);
|
||||
return object;
|
||||
|
|
@ -275,18 +282,20 @@ P _mangaDeserializeProp<P>(
|
|||
case 8:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 9:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 10:
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 11:
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
case 12:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
case 13:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 14:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 15:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 16:
|
||||
return (_MangastatusValueEnumMap[reader.readByteOrNull(offset)] ??
|
||||
Status.ongoing) as P;
|
||||
default:
|
||||
|
|
@ -1555,6 +1564,32 @@ extension MangaQueryFilter on QueryBuilder<Manga, Manga, QFilterCondition> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterFilterCondition> isMangaIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'isManga',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterFilterCondition> isMangaIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'isManga',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterFilterCondition> isMangaEqualTo(
|
||||
bool? value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'isManga',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterFilterCondition> langIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
|
@ -2457,6 +2492,18 @@ extension MangaQuerySortBy on QueryBuilder<Manga, Manga, QSortBy> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterSortBy> sortByIsManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isManga', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterSortBy> sortByIsMangaDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isManga', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterSortBy> sortByLang() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'lang', Sort.asc);
|
||||
|
|
@ -2627,6 +2674,18 @@ extension MangaQuerySortThenBy on QueryBuilder<Manga, Manga, QSortThenBy> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterSortBy> thenByIsManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isManga', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterSortBy> thenByIsMangaDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isManga', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterSortBy> thenByLang() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'lang', Sort.asc);
|
||||
|
|
@ -2770,6 +2829,12 @@ extension MangaQueryWhereDistinct on QueryBuilder<Manga, Manga, QDistinct> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QDistinct> distinctByIsManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'isManga');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QDistinct> distinctByLang(
|
||||
{bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
|
|
@ -2878,6 +2943,12 @@ extension MangaQueryProperty on QueryBuilder<Manga, Manga, QQueryProperty> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, bool?, QQueryOperations> isMangaProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'isManga');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, String?, QQueryOperations> langProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'lang');
|
||||
|
|
|
|||
|
|
@ -94,6 +94,31 @@ class Settings {
|
|||
|
||||
L10nLocale? locale;
|
||||
|
||||
@enumerated
|
||||
DisplayType animeDisplayType;
|
||||
|
||||
int? libraryFilterAnimeDownloadType;
|
||||
|
||||
int? libraryFilterAnimeUnreadType;
|
||||
|
||||
int? libraryFilterAnimeStartedType;
|
||||
|
||||
int? libraryFilterAnimeBookMarkedType;
|
||||
|
||||
bool? animeLibraryShowCategoryTabs;
|
||||
|
||||
bool? animeLibraryDownloadedChapters;
|
||||
|
||||
bool? animeLibraryShowLanguage;
|
||||
|
||||
bool? animeLibraryShowNumbersOfItems;
|
||||
|
||||
bool? animeLibraryShowContinueReadingButton;
|
||||
|
||||
bool? animeLibraryLocalSource;
|
||||
|
||||
SortLibraryManga? sortLibraryAnime;
|
||||
|
||||
Settings(
|
||||
{this.id = 227,
|
||||
this.displayType = DisplayType.compactGrid,
|
||||
|
|
@ -132,7 +157,19 @@ class Settings {
|
|||
this.downloadLocation = "",
|
||||
this.cropBorders = false,
|
||||
this.libraryLocalSource,
|
||||
this.autoUpdateExtensions = false});
|
||||
this.autoUpdateExtensions = false,
|
||||
this.animeDisplayType = DisplayType.compactGrid,
|
||||
this.libraryFilterAnimeDownloadType = 0,
|
||||
this.libraryFilterAnimeUnreadType = 0,
|
||||
this.libraryFilterAnimeStartedType = 0,
|
||||
this.libraryFilterAnimeBookMarkedType = 0,
|
||||
this.animeLibraryShowCategoryTabs = false,
|
||||
this.animeLibraryDownloadedChapters = false,
|
||||
this.animeLibraryShowLanguage = false,
|
||||
this.animeLibraryShowNumbersOfItems = false,
|
||||
this.animeLibraryShowContinueReadingButton = false,
|
||||
this.animeLibraryLocalSource,
|
||||
this.sortLibraryAnime});
|
||||
}
|
||||
|
||||
enum DisplayType {
|
||||
|
|
@ -216,5 +253,5 @@ class FilterScanlator {
|
|||
class L10nLocale {
|
||||
String? languageCode;
|
||||
String? countryCode;
|
||||
L10nLocale({this.languageCode,this.countryCode});
|
||||
L10nLocale({this.languageCode, this.countryCode});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ class Source {
|
|||
|
||||
String? headers;
|
||||
|
||||
bool? isManga;
|
||||
|
||||
Source({
|
||||
this.id = 0,
|
||||
this.name = '',
|
||||
|
|
@ -68,6 +70,7 @@ class Source {
|
|||
this.versionLast = "",
|
||||
this.sourceCode = '',
|
||||
this.headers = '',
|
||||
this.isManga = true,
|
||||
});
|
||||
Source.fromJson(Map<String, dynamic> json) {
|
||||
name = json['name'];
|
||||
|
|
@ -83,93 +86,6 @@ class Source {
|
|||
sourceCodeUrl = json['sourceCodeUrl'];
|
||||
apiUrl = json['apiUrl'];
|
||||
version = json['version'];
|
||||
isManga = json['isManga'] ?? true;
|
||||
}
|
||||
}
|
||||
|
||||
// enum TypeSource {
|
||||
// single,
|
||||
|
||||
// mangathemesia,
|
||||
|
||||
// comick,
|
||||
|
||||
// mmrcms,
|
||||
|
||||
// heancms,
|
||||
|
||||
// madara,
|
||||
|
||||
// mangadex
|
||||
// }
|
||||
|
||||
// class Source {
|
||||
// String? name;
|
||||
|
||||
// String? baseUrl;
|
||||
|
||||
// String? lang;
|
||||
|
||||
// bool? isActive;
|
||||
|
||||
// bool? isAdded;
|
||||
|
||||
// bool? isPinned;
|
||||
|
||||
// bool? lastUsed;
|
||||
|
||||
// bool? isFullData;
|
||||
|
||||
// bool? isNsfw;
|
||||
|
||||
// String? sourceCodeUrl;
|
||||
|
||||
// String? typeSource;
|
||||
|
||||
// String? iconUrl;
|
||||
|
||||
// bool? hasCloudflare;
|
||||
|
||||
// String? dateFormat;
|
||||
|
||||
// String? dateFormatLocale;
|
||||
|
||||
// String? apiUrl;
|
||||
|
||||
// String? version;
|
||||
|
||||
// Source({
|
||||
// this.name = "",
|
||||
// this.baseUrl = "",
|
||||
// this.lang = "",
|
||||
// this.typeSource = "",
|
||||
// this.iconUrl = "",
|
||||
// this.dateFormat,
|
||||
// this.dateFormatLocale,
|
||||
// this.isActive = true,
|
||||
// this.isAdded = false,
|
||||
// this.isNsfw = false,
|
||||
// this.isFullData = false,
|
||||
// this.hasCloudflare = false,
|
||||
// this.isPinned = false,
|
||||
// this.lastUsed = false,
|
||||
// this.sourceCodeUrl = "",
|
||||
// this.apiUrl = "",
|
||||
// this.version = "",
|
||||
// });
|
||||
|
||||
// Source.fromJson(Map<String, dynamic> json) {
|
||||
// name = json['name'];
|
||||
// id = json['id'];
|
||||
// baseUrl = json['baseUrl'];
|
||||
// lang = json['lang'];
|
||||
// typeSource = json['typeSource'];
|
||||
// iconUrl = json['iconUrl'];
|
||||
// dateFormat = json['dateFormat'];
|
||||
// dateFormatLocale = json['dateFormatLocale'];
|
||||
// isNsfw = json['isNsfw'];
|
||||
// hasCloudflare = json['hasCloudflare'];
|
||||
// sourceCodeUrl = json['sourceCodeUrl'];
|
||||
// apiUrl = json['apiUrl'];
|
||||
// version = json['version'];
|
||||
// }
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -67,53 +67,58 @@ const SourceSchema = CollectionSchema(
|
|||
name: r'isFullData',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'isNsfw': PropertySchema(
|
||||
r'isManga': PropertySchema(
|
||||
id: 10,
|
||||
name: r'isManga',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'isNsfw': PropertySchema(
|
||||
id: 11,
|
||||
name: r'isNsfw',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'isPinned': PropertySchema(
|
||||
id: 11,
|
||||
id: 12,
|
||||
name: r'isPinned',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'lang': PropertySchema(
|
||||
id: 12,
|
||||
id: 13,
|
||||
name: r'lang',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'lastUsed': PropertySchema(
|
||||
id: 13,
|
||||
id: 14,
|
||||
name: r'lastUsed',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'name': PropertySchema(
|
||||
id: 14,
|
||||
id: 15,
|
||||
name: r'name',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'sourceCode': PropertySchema(
|
||||
id: 15,
|
||||
id: 16,
|
||||
name: r'sourceCode',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'sourceCodeUrl': PropertySchema(
|
||||
id: 16,
|
||||
id: 17,
|
||||
name: r'sourceCodeUrl',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'typeSource': PropertySchema(
|
||||
id: 17,
|
||||
id: 18,
|
||||
name: r'typeSource',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'version': PropertySchema(
|
||||
id: 18,
|
||||
id: 19,
|
||||
name: r'version',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'versionLast': PropertySchema(
|
||||
id: 19,
|
||||
id: 20,
|
||||
name: r'versionLast',
|
||||
type: IsarType.string,
|
||||
)
|
||||
|
|
@ -235,16 +240,17 @@ void _sourceSerialize(
|
|||
writer.writeBool(offsets[7], object.isActive);
|
||||
writer.writeBool(offsets[8], object.isAdded);
|
||||
writer.writeBool(offsets[9], object.isFullData);
|
||||
writer.writeBool(offsets[10], object.isNsfw);
|
||||
writer.writeBool(offsets[11], object.isPinned);
|
||||
writer.writeString(offsets[12], object.lang);
|
||||
writer.writeBool(offsets[13], object.lastUsed);
|
||||
writer.writeString(offsets[14], object.name);
|
||||
writer.writeString(offsets[15], object.sourceCode);
|
||||
writer.writeString(offsets[16], object.sourceCodeUrl);
|
||||
writer.writeString(offsets[17], object.typeSource);
|
||||
writer.writeString(offsets[18], object.version);
|
||||
writer.writeString(offsets[19], object.versionLast);
|
||||
writer.writeBool(offsets[10], object.isManga);
|
||||
writer.writeBool(offsets[11], object.isNsfw);
|
||||
writer.writeBool(offsets[12], object.isPinned);
|
||||
writer.writeString(offsets[13], object.lang);
|
||||
writer.writeBool(offsets[14], object.lastUsed);
|
||||
writer.writeString(offsets[15], object.name);
|
||||
writer.writeString(offsets[16], object.sourceCode);
|
||||
writer.writeString(offsets[17], object.sourceCodeUrl);
|
||||
writer.writeString(offsets[18], object.typeSource);
|
||||
writer.writeString(offsets[19], object.version);
|
||||
writer.writeString(offsets[20], object.versionLast);
|
||||
}
|
||||
|
||||
Source _sourceDeserialize(
|
||||
|
|
@ -265,16 +271,17 @@ Source _sourceDeserialize(
|
|||
isActive: reader.readBoolOrNull(offsets[7]),
|
||||
isAdded: reader.readBoolOrNull(offsets[8]),
|
||||
isFullData: reader.readBoolOrNull(offsets[9]),
|
||||
isNsfw: reader.readBoolOrNull(offsets[10]),
|
||||
isPinned: reader.readBoolOrNull(offsets[11]),
|
||||
lang: reader.readStringOrNull(offsets[12]),
|
||||
lastUsed: reader.readBoolOrNull(offsets[13]),
|
||||
name: reader.readStringOrNull(offsets[14]),
|
||||
sourceCode: reader.readStringOrNull(offsets[15]),
|
||||
sourceCodeUrl: reader.readStringOrNull(offsets[16]),
|
||||
typeSource: reader.readStringOrNull(offsets[17]),
|
||||
version: reader.readStringOrNull(offsets[18]),
|
||||
versionLast: reader.readStringOrNull(offsets[19]),
|
||||
isManga: reader.readBoolOrNull(offsets[10]),
|
||||
isNsfw: reader.readBoolOrNull(offsets[11]),
|
||||
isPinned: reader.readBoolOrNull(offsets[12]),
|
||||
lang: reader.readStringOrNull(offsets[13]),
|
||||
lastUsed: reader.readBoolOrNull(offsets[14]),
|
||||
name: reader.readStringOrNull(offsets[15]),
|
||||
sourceCode: reader.readStringOrNull(offsets[16]),
|
||||
sourceCodeUrl: reader.readStringOrNull(offsets[17]),
|
||||
typeSource: reader.readStringOrNull(offsets[18]),
|
||||
version: reader.readStringOrNull(offsets[19]),
|
||||
versionLast: reader.readStringOrNull(offsets[20]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
|
@ -311,11 +318,11 @@ P _sourceDeserializeProp<P>(
|
|||
case 11:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 12:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 13:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 14:
|
||||
case 13:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 14:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 15:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 16:
|
||||
|
|
@ -326,6 +333,8 @@ P _sourceDeserializeProp<P>(
|
|||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 19:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 20:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
}
|
||||
|
|
@ -1472,6 +1481,32 @@ extension SourceQueryFilter on QueryBuilder<Source, Source, QFilterCondition> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterFilterCondition> isMangaIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'isManga',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterFilterCondition> isMangaIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'isManga',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterFilterCondition> isMangaEqualTo(
|
||||
bool? value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'isManga',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterFilterCondition> isNsfwIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
|
@ -2697,6 +2732,18 @@ extension SourceQuerySortBy on QueryBuilder<Source, Source, QSortBy> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterSortBy> sortByIsManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isManga', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterSortBy> sortByIsMangaDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isManga', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterSortBy> sortByIsNsfw() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isNsfw', Sort.asc);
|
||||
|
|
@ -2951,6 +2998,18 @@ extension SourceQuerySortThenBy on QueryBuilder<Source, Source, QSortThenBy> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterSortBy> thenByIsManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isManga', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterSortBy> thenByIsMangaDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isManga', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterSortBy> thenByIsNsfw() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isNsfw', Sort.asc);
|
||||
|
|
@ -3140,6 +3199,12 @@ extension SourceQueryWhereDistinct on QueryBuilder<Source, Source, QDistinct> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QDistinct> distinctByIsManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'isManga');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QDistinct> distinctByIsNsfw() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'isNsfw');
|
||||
|
|
@ -3276,6 +3341,12 @@ extension SourceQueryProperty on QueryBuilder<Source, Source, QQueryProperty> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, bool?, QQueryOperations> isMangaProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'isManga');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, bool?, QQueryOperations> isNsfwProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'isNsfw');
|
||||
|
|
|
|||
|
|
@ -47,4 +47,14 @@ class Track {
|
|||
this.trackingUrl});
|
||||
}
|
||||
|
||||
enum TrackStatus { reading, completed, onHold, dropped, planToRead, rereading }
|
||||
enum TrackStatus {
|
||||
reading,
|
||||
completed,
|
||||
onHold,
|
||||
dropped,
|
||||
planToRead,
|
||||
rereading,
|
||||
watching,
|
||||
planToWatch,
|
||||
reWatching
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,6 +203,9 @@ const _TrackstatusEnumValueMap = {
|
|||
'dropped': 3,
|
||||
'planToRead': 4,
|
||||
'rereading': 5,
|
||||
'watching': 6,
|
||||
'planToWatch': 7,
|
||||
'reWatching': 8,
|
||||
};
|
||||
const _TrackstatusValueEnumMap = {
|
||||
0: TrackStatus.reading,
|
||||
|
|
@ -211,6 +214,9 @@ const _TrackstatusValueEnumMap = {
|
|||
3: TrackStatus.dropped,
|
||||
4: TrackStatus.planToRead,
|
||||
5: TrackStatus.rereading,
|
||||
6: TrackStatus.watching,
|
||||
7: TrackStatus.planToWatch,
|
||||
8: TrackStatus.reWatching,
|
||||
};
|
||||
|
||||
Id _trackGetId(Track object) {
|
||||
|
|
|
|||
8
lib/models/video.dart
Normal file
|
|
@ -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});
|
||||
}
|
||||
296
lib/modules/anime/anime_stream_view.dart
Normal 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,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
124
lib/modules/anime/providers/stream_controller_provider.dart
Normal 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!;
|
||||
}
|
||||
}
|
||||
|
|
@ -370,4 +370,5 @@ class GetArchiveDataFromFileProvider
|
|||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
_tabBarController = TabController(length: 3, vsync: this);
|
||||
_tabBarController = TabController(length: 5, vsync: this);
|
||||
_tabBarController.animateTo(0);
|
||||
_tabBarController.addListener(() {
|
||||
_chekPermission();
|
||||
|
|
@ -44,7 +44,7 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
|
|||
final l10n = l10nLocalizations(context)!;
|
||||
return DefaultTabController(
|
||||
animationDuration: Duration.zero,
|
||||
length: 3,
|
||||
length: 5,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
|
|
@ -70,22 +70,25 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
|
|||
},
|
||||
controller: _textEditingController,
|
||||
)
|
||||
: _tabBarController.index != 2
|
||||
: _tabBarController.index != 4
|
||||
? IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
if (_tabBarController.index == 1) {
|
||||
if (_tabBarController.index != 1 &&
|
||||
_tabBarController.index != 0) {
|
||||
setState(() {
|
||||
_isSearch = true;
|
||||
});
|
||||
} else if (_tabBarController.index == 0) {
|
||||
context.push(
|
||||
'/globalSearch',
|
||||
);
|
||||
} else {
|
||||
context.push('/globalSearch',
|
||||
extra: _tabBarController.index == 0
|
||||
? true
|
||||
: false);
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
_tabBarController.index == 0
|
||||
_tabBarController.index == 0 ||
|
||||
_tabBarController.index == 1
|
||||
? Icons.travel_explore_rounded
|
||||
: Icons.search_rounded,
|
||||
color: Theme.of(context).hintColor))
|
||||
|
|
@ -94,34 +97,53 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
|
|||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
if (_tabBarController.index == 0) {
|
||||
context.push('/sourceFilter');
|
||||
context.push('/sourceFilter', extra: true);
|
||||
} else if (_tabBarController.index == 1) {
|
||||
context.push('/sourceFilter', extra: false);
|
||||
} else if (_tabBarController.index == 2) {
|
||||
_textEditingController.clear();
|
||||
context.push('/extensionLang');
|
||||
context.push('/ExtensionLang', extra: true);
|
||||
} else if (_tabBarController.index == 3) {
|
||||
_textEditingController.clear();
|
||||
context.push('/ExtensionLang', extra: false);
|
||||
} else {}
|
||||
},
|
||||
icon: Icon(
|
||||
_tabBarController.index == 0
|
||||
_tabBarController.index == 0 || _tabBarController.index == 1
|
||||
? Icons.filter_list_sharp
|
||||
: _tabBarController.index == 1
|
||||
: _tabBarController.index == 2 ||
|
||||
_tabBarController.index == 3
|
||||
? Icons.translate_rounded
|
||||
: Icons.help_outline_outlined,
|
||||
color: Theme.of(context).hintColor)),
|
||||
],
|
||||
bottom: TabBar(
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
indicatorSize: TabBarIndicatorSize.label,
|
||||
isScrollable: true,
|
||||
controller: _tabBarController,
|
||||
tabs: [
|
||||
Tab(text: l10n.sources),
|
||||
Tab(text: l10n.extensions),
|
||||
Tab(text: l10n.manga_sources),
|
||||
Tab(text: l10n.anime_sources),
|
||||
Tab(text: l10n.manga_extensions),
|
||||
Tab(text: l10n.anime_extensions),
|
||||
Tab(text: l10n.migrate),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: TabBarView(controller: _tabBarController, children: [
|
||||
const SourcesScreen(),
|
||||
const SourcesScreen(
|
||||
isManga: true,
|
||||
),
|
||||
const SourcesScreen(
|
||||
isManga: false,
|
||||
),
|
||||
ExtensionScreen(
|
||||
query: _textEditingController.text,
|
||||
isManga: true,
|
||||
),
|
||||
ExtensionScreen(
|
||||
query: _textEditingController.text,
|
||||
isManga: false,
|
||||
),
|
||||
const MigrateScreen()
|
||||
]),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ import 'package:mangayomi/utils/language.dart';
|
|||
import 'package:mangayomi/modules/browse/extension/widgets/extension_lang_list_tile_widget.dart';
|
||||
|
||||
class ExtensionsLang extends ConsumerWidget {
|
||||
const ExtensionsLang({super.key});
|
||||
final bool isManga;
|
||||
const ExtensionsLang({required this.isManga, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -20,8 +21,12 @@ class ExtensionsLang extends ConsumerWidget {
|
|||
title: Text(l10n.extensions),
|
||||
),
|
||||
body: StreamBuilder(
|
||||
stream:
|
||||
isar.sources.filter().idIsNotNull().watch(fireImmediately: true),
|
||||
stream: isar.sources
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
List<Source>? entries = snapshot.hasData ? snapshot.data : [];
|
||||
return ListView.builder(
|
||||
|
|
@ -33,15 +38,16 @@ class ExtensionsLang extends ConsumerWidget {
|
|||
onChanged: (val) {
|
||||
isar.writeTxnSync(() {
|
||||
for (var source in entries) {
|
||||
if (source.lang!.toLowerCase() == lang) {
|
||||
isar.sources.putSync(source..isActive = val == true);
|
||||
if (source.lang!.toLowerCase() == lang.toLowerCase()) {
|
||||
isar.sources.putSync(source..isActive = val);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
value: entries!
|
||||
.where((element) => element.lang!.toLowerCase() == lang)
|
||||
.where((element) => element.isActive!)
|
||||
.where((element) =>
|
||||
element.lang!.toLowerCase() == lang.toLowerCase() &&
|
||||
element.isActive!)
|
||||
.isNotEmpty,
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,20 +4,30 @@ import 'package:grouped_list/grouped_list.dart';
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/modules/browse/extension/providers/fetch_sources.dart';
|
||||
import 'package:mangayomi/modules/browse/extension/providers/fetch_anime_sources.dart';
|
||||
import 'package:mangayomi/modules/browse/extension/providers/fetch_manga_sources.dart';
|
||||
import 'package:mangayomi/utils/language.dart';
|
||||
import 'package:mangayomi/modules/browse/extension/widgets/extension_list_tile_widget.dart';
|
||||
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
|
||||
|
||||
class ExtensionScreen extends ConsumerWidget {
|
||||
final bool isManga;
|
||||
final String query;
|
||||
const ExtensionScreen({required this.query, super.key});
|
||||
const ExtensionScreen(
|
||||
{required this.query, required this.isManga, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
ref.watch(fetchSourcesListProvider(id: null));
|
||||
if (isManga) {
|
||||
ref.watch(fetchMangaSourcesListProvider(id: null));
|
||||
} else {
|
||||
ref.watch(fetchAnimeSourcesListProvider(id: null));
|
||||
}
|
||||
|
||||
return RefreshIndicator(
|
||||
onRefresh: () => ref.refresh(fetchSourcesListProvider(id: null).future),
|
||||
onRefresh: () => isManga
|
||||
? ref.refresh(fetchMangaSourcesListProvider(id: null).future)
|
||||
: ref.refresh(fetchAnimeSourcesListProvider(id: null).future),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: StreamBuilder(
|
||||
|
|
@ -28,12 +38,14 @@ class ExtensionScreen extends ConsumerWidget {
|
|||
.idIsNotNull()
|
||||
.and()
|
||||
.isActiveEqualTo(true)
|
||||
.isMangaEqualTo(isManga)
|
||||
.watch(fireImmediately: true)
|
||||
: isar.sources
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.isActiveEqualTo(true)
|
||||
.isMangaEqualTo(isManga)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
|
||||
|
|
|
|||
106
lib/modules/browse/extension/providers/fetch_anime_sources.dart
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'fetch_sources.dart';
|
||||
part of 'fetch_anime_sources.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$fetchSourcesListHash() => r'151bfddc9daf2cde079bf0f98f523d92b7e6ab00';
|
||||
String _$fetchAnimeSourcesListHash() =>
|
||||
r'1b16436684b132a5dc6db2159e38200f1dc9b11e';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -29,29 +30,29 @@ class _SystemHash {
|
|||
}
|
||||
}
|
||||
|
||||
typedef FetchSourcesListRef = AutoDisposeFutureProviderRef<dynamic>;
|
||||
typedef FetchAnimeSourcesListRef = AutoDisposeFutureProviderRef<dynamic>;
|
||||
|
||||
/// See also [fetchSourcesList].
|
||||
@ProviderFor(fetchSourcesList)
|
||||
const fetchSourcesListProvider = FetchSourcesListFamily();
|
||||
/// See also [fetchAnimeSourcesList].
|
||||
@ProviderFor(fetchAnimeSourcesList)
|
||||
const fetchAnimeSourcesListProvider = FetchAnimeSourcesListFamily();
|
||||
|
||||
/// See also [fetchSourcesList].
|
||||
class FetchSourcesListFamily extends Family<AsyncValue<dynamic>> {
|
||||
/// See also [fetchSourcesList].
|
||||
const FetchSourcesListFamily();
|
||||
/// See also [fetchAnimeSourcesList].
|
||||
class FetchAnimeSourcesListFamily extends Family<AsyncValue<dynamic>> {
|
||||
/// See also [fetchAnimeSourcesList].
|
||||
const FetchAnimeSourcesListFamily();
|
||||
|
||||
/// See also [fetchSourcesList].
|
||||
FetchSourcesListProvider call({
|
||||
/// See also [fetchAnimeSourcesList].
|
||||
FetchAnimeSourcesListProvider call({
|
||||
int? id,
|
||||
}) {
|
||||
return FetchSourcesListProvider(
|
||||
return FetchAnimeSourcesListProvider(
|
||||
id: id,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
FetchSourcesListProvider getProviderOverride(
|
||||
covariant FetchSourcesListProvider provider,
|
||||
FetchAnimeSourcesListProvider getProviderOverride(
|
||||
covariant FetchAnimeSourcesListProvider provider,
|
||||
) {
|
||||
return call(
|
||||
id: provider.id,
|
||||
|
|
@ -70,35 +71,35 @@ class FetchSourcesListFamily extends Family<AsyncValue<dynamic>> {
|
|||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'fetchSourcesListProvider';
|
||||
String? get name => r'fetchAnimeSourcesListProvider';
|
||||
}
|
||||
|
||||
/// See also [fetchSourcesList].
|
||||
class FetchSourcesListProvider extends AutoDisposeFutureProvider<dynamic> {
|
||||
/// See also [fetchSourcesList].
|
||||
FetchSourcesListProvider({
|
||||
/// See also [fetchAnimeSourcesList].
|
||||
class FetchAnimeSourcesListProvider extends AutoDisposeFutureProvider<dynamic> {
|
||||
/// See also [fetchAnimeSourcesList].
|
||||
FetchAnimeSourcesListProvider({
|
||||
this.id,
|
||||
}) : super.internal(
|
||||
(ref) => fetchSourcesList(
|
||||
(ref) => fetchAnimeSourcesList(
|
||||
ref,
|
||||
id: id,
|
||||
),
|
||||
from: fetchSourcesListProvider,
|
||||
name: r'fetchSourcesListProvider',
|
||||
from: fetchAnimeSourcesListProvider,
|
||||
name: r'fetchAnimeSourcesListProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$fetchSourcesListHash,
|
||||
dependencies: FetchSourcesListFamily._dependencies,
|
||||
: _$fetchAnimeSourcesListHash,
|
||||
dependencies: FetchAnimeSourcesListFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
FetchSourcesListFamily._allTransitiveDependencies,
|
||||
FetchAnimeSourcesListFamily._allTransitiveDependencies,
|
||||
);
|
||||
|
||||
final int? id;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is FetchSourcesListProvider && other.id == id;
|
||||
return other is FetchAnimeSourcesListProvider && other.id == id;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -109,4 +110,5 @@ class FetchSourcesListProvider extends AutoDisposeFutureProvider<dynamic> {
|
|||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member
|
||||
152
lib/modules/browse/extension/providers/fetch_manga_sources.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/modules/browse/extension/providers/fetch_sources.dart';
|
||||
import 'package:mangayomi/modules/browse/extension/providers/fetch_anime_sources.dart';
|
||||
import 'package:mangayomi/modules/browse/extension/providers/fetch_manga_sources.dart';
|
||||
import 'package:mangayomi/utils/language.dart';
|
||||
|
||||
class ExtensionListTileWidget extends ConsumerStatefulWidget {
|
||||
|
|
@ -90,8 +91,13 @@ class _ExtensionListTileWidgetState
|
|||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
await ref.watch(
|
||||
fetchSourcesListProvider(id: widget.source.id).future);
|
||||
widget.source.isManga!
|
||||
? await ref.watch(
|
||||
fetchMangaSourcesListProvider(id: widget.source.id)
|
||||
.future)
|
||||
: await ref.watch(
|
||||
fetchAnimeSourcesListProvider(id: widget.source.id)
|
||||
.future);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ import 'package:mangayomi/modules/widgets/bottom_text_widget.dart';
|
|||
import 'package:mangayomi/modules/widgets/manga_image_card_widget.dart';
|
||||
|
||||
class GlobalSearchScreen extends ConsumerStatefulWidget {
|
||||
final bool isManga;
|
||||
const GlobalSearchScreen({
|
||||
required this.isManga,
|
||||
super.key,
|
||||
});
|
||||
|
||||
|
|
@ -35,12 +37,19 @@ class _GlobalSearchScreenState extends ConsumerState<GlobalSearchScreen> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sourceList = ref.watch(onlyIncludePinnedSourceStateProvider)
|
||||
? isar.sources.filter().isPinnedEqualTo(true).findAllSync()
|
||||
? isar.sources
|
||||
.filter()
|
||||
.isPinnedEqualTo(true)
|
||||
.and()
|
||||
.isMangaEqualTo(widget.isManga)
|
||||
.findAllSync()
|
||||
: isar.sources
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.isAddedEqualTo(true)
|
||||
.and()
|
||||
.isMangaEqualTo(widget.isManga)
|
||||
.findAllSync();
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
|
|
@ -186,7 +195,10 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
|
|||
return GestureDetector(
|
||||
onTap: () async {
|
||||
pushToMangaReaderDetail(
|
||||
context: context, getManga: data, lang: widget.source.lang!);
|
||||
context: context,
|
||||
getManga: data,
|
||||
lang: widget.source.lang!,
|
||||
isManga: widget.source.isManga ?? true);
|
||||
},
|
||||
child: StreamBuilder(
|
||||
stream: isar.mangas
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ import 'package:mangayomi/providers/l10n_providers.dart';
|
|||
import 'package:mangayomi/utils/language.dart';
|
||||
|
||||
class SourcesFilterScreen extends ConsumerWidget {
|
||||
const SourcesFilterScreen({super.key});
|
||||
final bool isManga;
|
||||
const SourcesFilterScreen({required this.isManga, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -26,6 +27,8 @@ class SourcesFilterScreen extends ConsumerWidget {
|
|||
.idIsNotNull()
|
||||
.and()
|
||||
.sourceCodeIsNotEmpty()
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
|
||||
|
|
@ -43,7 +46,8 @@ class SourcesFilterScreen extends ConsumerWidget {
|
|||
value: entries
|
||||
.where((element) =>
|
||||
element.lang!.toLowerCase() == groupByValue &&
|
||||
element.isActive!)
|
||||
element.isActive! &&
|
||||
element.isManga == isManga)
|
||||
.isNotEmpty,
|
||||
onChanged: (val) {
|
||||
isar.writeTxnSync(() {
|
||||
|
|
@ -65,7 +69,8 @@ class SourcesFilterScreen extends ConsumerWidget {
|
|||
if (entries
|
||||
.where((s) =>
|
||||
s.lang!.toLowerCase() == element.lang &&
|
||||
s.isActive!)
|
||||
s.isActive! &&
|
||||
s.isManga == isManga)
|
||||
.isEmpty) {
|
||||
return Container();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ import 'package:mangayomi/utils/language.dart';
|
|||
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
|
||||
|
||||
class SourcesScreen extends ConsumerWidget {
|
||||
const SourcesScreen({super.key});
|
||||
final bool isManga;
|
||||
const SourcesScreen({required this.isManga, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -29,6 +30,8 @@ class SourcesScreen extends ConsumerWidget {
|
|||
.isActiveEqualTo(true)
|
||||
.and()
|
||||
.lastUsedEqualTo(true)
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
|
|
@ -76,6 +79,8 @@ class SourcesScreen extends ConsumerWidget {
|
|||
.isActiveEqualTo(true)
|
||||
.and()
|
||||
.isPinnedEqualTo(true)
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
|
|
@ -123,6 +128,8 @@ class SourcesScreen extends ConsumerWidget {
|
|||
.isActiveEqualTo(true)
|
||||
.and()
|
||||
.isPinnedEqualTo(false)
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,11 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:grouped_list/grouped_list.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/history.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/modules/history/providers/isar_providers.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
|
|
@ -22,15 +25,33 @@ class HistoryScreen extends ConsumerStatefulWidget {
|
|||
ConsumerState<HistoryScreen> createState() => _HistoryScreenState();
|
||||
}
|
||||
|
||||
class _HistoryScreenState extends ConsumerState<HistoryScreen> {
|
||||
class _HistoryScreenState extends ConsumerState<HistoryScreen>
|
||||
with TickerProviderStateMixin {
|
||||
late TabController _tabBarController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_tabBarController = TabController(length: 2, vsync: this);
|
||||
_tabBarController.animateTo(0);
|
||||
_tabBarController.addListener(() {
|
||||
setState(() {
|
||||
_textEditingController.clear();
|
||||
_isSearch = false;
|
||||
});
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
final _textEditingController = TextEditingController();
|
||||
bool _isSearch = false;
|
||||
List<History> entriesData = [];
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
final history = ref.watch(getAllHistoryStreamProvider);
|
||||
return Scaffold(
|
||||
return DefaultTabController(
|
||||
animationDuration: Duration.zero,
|
||||
length: 2,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
|
|
@ -92,8 +113,21 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
|
|||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
List<History> histories = isar.historys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.chapter((q) => q.manga((q) =>
|
||||
q.isMangaEqualTo(
|
||||
_tabBarController.index ==
|
||||
0)))
|
||||
.findAllSync()
|
||||
.toList();
|
||||
isar.writeTxnSync(() {
|
||||
isar.historys.clearSync();
|
||||
// _tabBarController.index != 1
|
||||
|
||||
for (var history in histories) {
|
||||
isar.historys.deleteSync(history.id!);
|
||||
}
|
||||
});
|
||||
if (mounted) {
|
||||
Navigator.pop(context);
|
||||
|
|
@ -109,226 +143,262 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
|
|||
icon: Icon(Icons.delete_sweep_outlined,
|
||||
color: Theme.of(context).hintColor)),
|
||||
],
|
||||
bottom: TabBar(
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
controller: _tabBarController,
|
||||
tabs: [
|
||||
Tab(text: l10n.manga),
|
||||
Tab(text: l10n.anime),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: history.when(
|
||||
data: (data) {
|
||||
final entries = data
|
||||
.where((element) => _textEditingController.text.isNotEmpty
|
||||
? element.chapter.value!.manga.value!.name!
|
||||
.toLowerCase()
|
||||
.contains(_textEditingController.text.toLowerCase())
|
||||
: true)
|
||||
.toList();
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: TabBarView(controller: _tabBarController, children: [
|
||||
HistoryTab(
|
||||
isManga: true,
|
||||
query: _textEditingController.text,
|
||||
),
|
||||
HistoryTab(
|
||||
isManga: false,
|
||||
query: _textEditingController.text,
|
||||
)
|
||||
]),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (entries.isNotEmpty) {
|
||||
return GroupedListView<History, String>(
|
||||
elements: entries,
|
||||
groupBy: (element) => dateFormat(element.date!,
|
||||
class HistoryTab extends ConsumerStatefulWidget {
|
||||
final String query;
|
||||
final bool isManga;
|
||||
const HistoryTab({required this.isManga, required this.query, super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<HistoryTab> createState() => _HistoryTabState();
|
||||
}
|
||||
|
||||
class _HistoryTabState extends ConsumerState<HistoryTab> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
final history =
|
||||
ref.watch(getAllHistoryStreamProvider(isManga: widget.isManga));
|
||||
return Scaffold(
|
||||
body: history.when(
|
||||
data: (data) {
|
||||
final entries = data
|
||||
.where((element) => widget.query.isNotEmpty
|
||||
? element.chapter.value!.manga.value!.name!
|
||||
.toLowerCase()
|
||||
.contains(widget.query.toLowerCase())
|
||||
: true)
|
||||
.toList();
|
||||
|
||||
if (entries.isNotEmpty) {
|
||||
return GroupedListView<History, String>(
|
||||
elements: entries,
|
||||
groupBy: (element) => dateFormat(element.date!,
|
||||
context: context,
|
||||
ref: ref,
|
||||
forHistoryValue: true,
|
||||
useRelativeTimesTamps: false),
|
||||
groupSeparatorBuilder: (String groupByValue) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8, left: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(dateFormat(
|
||||
null,
|
||||
context: context,
|
||||
stringDate: groupByValue,
|
||||
ref: ref,
|
||||
forHistoryValue: true,
|
||||
useRelativeTimesTamps: false),
|
||||
groupSeparatorBuilder: (String groupByValue) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8, left: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(dateFormat(
|
||||
null,
|
||||
context: context,
|
||||
stringDate: groupByValue,
|
||||
ref: ref,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
itemBuilder: (context, History element) {
|
||||
final manga = element.chapter.value!.manga.value!;
|
||||
final chapter = element.chapter.value!;
|
||||
return ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.all(0),
|
||||
backgroundColor: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(0)),
|
||||
elevation: 0,
|
||||
shadowColor: Colors.transparent),
|
||||
onPressed: () {
|
||||
pushMangaReaderView(context: context, chapter: chapter);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: SizedBox(
|
||||
height: 105,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 60,
|
||||
height: 90,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.all(0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(7)),
|
||||
),
|
||||
onPressed: () {
|
||||
context.push('/manga-reader/detail',
|
||||
extra: manga.id);
|
||||
},
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(7),
|
||||
child: manga.customCoverImage != null
|
||||
? Image.memory(
|
||||
manga.customCoverImage as Uint8List)
|
||||
: cachedNetworkImage(
|
||||
headers: ref.watch(headersProvider(
|
||||
source: manga.source!,
|
||||
lang: manga.lang!)),
|
||||
imageUrl: manga.imageUrl!,
|
||||
width: 60,
|
||||
height: 90,
|
||||
fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
itemBuilder: (context, History element) {
|
||||
final manga = element.chapter.value!.manga.value!;
|
||||
final chapter = element.chapter.value!;
|
||||
return ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.all(0),
|
||||
backgroundColor: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(0)),
|
||||
elevation: 0,
|
||||
shadowColor: Colors.transparent),
|
||||
onPressed: () {
|
||||
pushMangaReaderView(context: context, chapter: chapter);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: SizedBox(
|
||||
height: 105,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 60,
|
||||
height: 90,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.all(0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(7)),
|
||||
),
|
||||
Flexible(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
onPressed: () {
|
||||
context.push('/manga-reader/detail',
|
||||
extra: manga.id);
|
||||
},
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(7),
|
||||
child: manga.customCoverImage != null
|
||||
? Image.memory(
|
||||
manga.customCoverImage as Uint8List)
|
||||
: cachedNetworkImage(
|
||||
headers: ref.watch(headersProvider(
|
||||
source: manga.source!,
|
||||
lang: manga.lang!)),
|
||||
imageUrl: manga.imageUrl!,
|
||||
width: 60,
|
||||
height: 90,
|
||||
fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
manga.name!,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyLarge!
|
||||
.color,
|
||||
fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
Wrap(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
WrapCrossAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
manga.name!,
|
||||
chapter.name!,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontSize: 11,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyLarge!
|
||||
.color,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
" - ${dateFormatHour(element.date!, context)}",
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyLarge!
|
||||
.color,
|
||||
fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
Wrap(
|
||||
crossAxisAlignment:
|
||||
WrapCrossAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
chapter.name!,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyLarge!
|
||||
.color,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
" - ${dateFormatHour(element.date!, context)}",
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyLarge!
|
||||
.color,
|
||||
fontWeight:
|
||||
FontWeight.w400),
|
||||
),
|
||||
],
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
l10n.remove,
|
||||
),
|
||||
content: Text(
|
||||
l10n.remove_history_msg),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(
|
||||
context);
|
||||
},
|
||||
child: Text(
|
||||
l10n.cancel)),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await isar.writeTxn(
|
||||
() async {
|
||||
await isar
|
||||
.historys
|
||||
.delete(
|
||||
element
|
||||
.id!);
|
||||
});
|
||||
if (mounted) {
|
||||
Navigator.pop(
|
||||
context);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
l10n.remove)),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.delete_outline,
|
||||
size: 25,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyLarge!
|
||||
.color,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
l10n.remove,
|
||||
),
|
||||
content:
|
||||
Text(l10n.remove_history_msg),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(l10n.cancel)),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await isar
|
||||
.writeTxn(() async {
|
||||
await isar.historys
|
||||
.delete(
|
||||
element.id!);
|
||||
});
|
||||
if (mounted) {
|
||||
Navigator.pop(
|
||||
context);
|
||||
}
|
||||
},
|
||||
child: Text(l10n.remove)),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.delete_outline,
|
||||
size: 25,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyLarge!
|
||||
.color,
|
||||
)),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
itemComparator: (item1, item2) =>
|
||||
item1.date!.compareTo(item2.date!),
|
||||
order: GroupedListOrder.DESC,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Center(
|
||||
child: Text(l10n.nothing_read_recently),
|
||||
);
|
||||
},
|
||||
error: (Object error, StackTrace stackTrace) {
|
||||
return ErrorText(error);
|
||||
},
|
||||
loading: () {
|
||||
return const ProgressCenter();
|
||||
},
|
||||
));
|
||||
},
|
||||
itemComparator: (item1, item2) =>
|
||||
item1.date!.compareTo(item2.date!),
|
||||
order: GroupedListOrder.DESC,
|
||||
);
|
||||
}
|
||||
return Center(
|
||||
child: Text(l10n.nothing_read_recently),
|
||||
);
|
||||
},
|
||||
error: (Object error, StackTrace stackTrace) {
|
||||
return ErrorText(error);
|
||||
},
|
||||
loading: () {
|
||||
return const ProgressCenter();
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/history.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'isar_providers.g.dart';
|
||||
|
||||
@riverpod
|
||||
Stream<List<History>> getAllHistoryStream(
|
||||
GetAllHistoryStreamRef ref,
|
||||
) async* {
|
||||
yield* isar.historys.filter().idIsNotNull().watch(fireImmediately: true);
|
||||
Stream<List<History>> getAllHistoryStream(GetAllHistoryStreamRef ref,
|
||||
{required bool isManga}) async* {
|
||||
yield* isar.historys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.chapter((q) => q.manga((q) => q.isMangaEqualTo(isManga)))
|
||||
.watch(fireImmediately: true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,20 +7,109 @@ part of 'isar_providers.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$getAllHistoryStreamHash() =>
|
||||
r'361f085ba7b3269583a09cd7b2e2629d8f3282aa';
|
||||
r'32dc5fa16315f199a5c86ee99cf59b7190c4d28e';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
typedef GetAllHistoryStreamRef = AutoDisposeStreamProviderRef<List<History>>;
|
||||
|
||||
/// See also [getAllHistoryStream].
|
||||
@ProviderFor(getAllHistoryStream)
|
||||
final getAllHistoryStreamProvider =
|
||||
AutoDisposeStreamProvider<List<History>>.internal(
|
||||
getAllHistoryStream,
|
||||
name: r'getAllHistoryStreamProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$getAllHistoryStreamHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
const getAllHistoryStreamProvider = GetAllHistoryStreamFamily();
|
||||
|
||||
typedef GetAllHistoryStreamRef = AutoDisposeStreamProviderRef<List<History>>;
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
/// See also [getAllHistoryStream].
|
||||
class GetAllHistoryStreamFamily extends Family<AsyncValue<List<History>>> {
|
||||
/// See also [getAllHistoryStream].
|
||||
const GetAllHistoryStreamFamily();
|
||||
|
||||
/// See also [getAllHistoryStream].
|
||||
GetAllHistoryStreamProvider call({
|
||||
required bool isManga,
|
||||
}) {
|
||||
return GetAllHistoryStreamProvider(
|
||||
isManga: isManga,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
GetAllHistoryStreamProvider getProviderOverride(
|
||||
covariant GetAllHistoryStreamProvider provider,
|
||||
) {
|
||||
return call(
|
||||
isManga: provider.isManga,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'getAllHistoryStreamProvider';
|
||||
}
|
||||
|
||||
/// See also [getAllHistoryStream].
|
||||
class GetAllHistoryStreamProvider
|
||||
extends AutoDisposeStreamProvider<List<History>> {
|
||||
/// See also [getAllHistoryStream].
|
||||
GetAllHistoryStreamProvider({
|
||||
required this.isManga,
|
||||
}) : super.internal(
|
||||
(ref) => getAllHistoryStream(
|
||||
ref,
|
||||
isManga: isManga,
|
||||
),
|
||||
from: getAllHistoryStreamProvider,
|
||||
name: r'getAllHistoryStreamProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$getAllHistoryStreamHash,
|
||||
dependencies: GetAllHistoryStreamFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
GetAllHistoryStreamFamily._allTransitiveDependencies,
|
||||
);
|
||||
|
||||
final bool isManga;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is GetAllHistoryStreamProvider && other.isManga == isManga;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, isManga.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import 'package:mangayomi/models/history.dart';
|
|||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/modules/library/providers/local_archive.dart';
|
||||
import 'package:mangayomi/modules/more/categories/providers/isar_providers.dart';
|
||||
import 'package:mangayomi/modules/widgets/manga_image_card_widget.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/providers/storage_provider.dart';
|
||||
|
|
@ -27,12 +28,12 @@ import 'package:mangayomi/modules/library/widgets/library_listview_widget.dart';
|
|||
import 'package:mangayomi/modules/library/widgets/list_tile_manga_category.dart';
|
||||
import 'package:mangayomi/modules/manga/detail/widgets/chapter_filter_list_tile_widget.dart';
|
||||
import 'package:mangayomi/modules/manga/detail/widgets/chapter_sort_list_tile_widget.dart';
|
||||
import 'package:mangayomi/modules/more/categoties/providers/isar_providers.dart';
|
||||
import 'package:mangayomi/modules/widgets/error_text.dart';
|
||||
import 'package:mangayomi/modules/widgets/progress_center.dart';
|
||||
|
||||
class LibraryScreen extends ConsumerStatefulWidget {
|
||||
const LibraryScreen({super.key});
|
||||
final bool isManga;
|
||||
const LibraryScreen({required this.isManga, super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<LibraryScreen> createState() => _LibraryScreenState();
|
||||
|
|
@ -47,11 +48,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
int _tabIndex = 0;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final categories = ref.watch(getMangaCategorieStreamProvider);
|
||||
final withoutCategories =
|
||||
ref.watch(getAllMangaWithoutCategoriesStreamProvider);
|
||||
final showCategoryTabs = ref.watch(libraryShowCategoryTabsStateProvider);
|
||||
final mangaAll = ref.watch(getAllMangaStreamProvider(categoryId: null));
|
||||
final categories =
|
||||
ref.watch(getMangaCategorieStreamProvider(isManga: widget.isManga));
|
||||
final withoutCategories = ref.watch(
|
||||
getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga));
|
||||
final showCategoryTabs = ref
|
||||
.watch(libraryShowCategoryTabsStateProvider(isManga: widget.isManga));
|
||||
final mangaAll = ref.watch(
|
||||
getAllMangaStreamProvider(categoryId: null, isManga: widget.isManga));
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return Scaffold(
|
||||
body: mangaAll.when(
|
||||
|
|
@ -73,40 +77,50 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
});
|
||||
|
||||
return Consumer(builder: (context, ref, child) {
|
||||
bool reverse =
|
||||
ref.watch(sortLibraryMangaStateProvider).reverse!;
|
||||
bool reverse = ref
|
||||
.watch(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga))
|
||||
.reverse!;
|
||||
|
||||
final continueReaderBtn = ref.watch(
|
||||
libraryShowContinueReadingButtonStateProvider);
|
||||
final showNumbersOfItems =
|
||||
ref.watch(libraryShowNumbersOfItemsStateProvider);
|
||||
final localSource =
|
||||
ref.watch(libraryLocalSourceStateProvider);
|
||||
final downloadedChapter =
|
||||
ref.watch(libraryDownloadedChaptersStateProvider);
|
||||
final language =
|
||||
ref.watch(libraryLanguageStateProvider);
|
||||
libraryShowContinueReadingButtonStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final showNumbersOfItems = ref.watch(
|
||||
libraryShowNumbersOfItemsStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final localSource = ref.watch(
|
||||
libraryLocalSourceStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final downloadedChapter = ref.watch(
|
||||
libraryDownloadedChaptersStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final language = ref.watch(libraryLanguageStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final displayType = ref
|
||||
.read(libraryDisplayTypeStateProvider.notifier)
|
||||
.getLibraryDisplayTypeValue(
|
||||
ref.watch(libraryDisplayTypeStateProvider));
|
||||
.read(libraryDisplayTypeStateProvider(
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.getLibraryDisplayTypeValue(ref.watch(
|
||||
libraryDisplayTypeStateProvider(
|
||||
isManga: widget.isManga)));
|
||||
final isNotFiltering = ref.watch(
|
||||
mangasFilterResultStateProvider(
|
||||
mangaList: _entries));
|
||||
isManga: widget.isManga, mangaList: _entries));
|
||||
final downloadFilterType = ref.watch(
|
||||
mangaFilterDownloadedStateProvider(
|
||||
mangaList: _entries));
|
||||
isManga: widget.isManga, mangaList: _entries));
|
||||
final unreadFilterType = ref.watch(
|
||||
mangaFilterUnreadStateProvider(
|
||||
mangaList: _entries));
|
||||
isManga: widget.isManga, mangaList: _entries));
|
||||
final startedFilterType = ref.watch(
|
||||
mangaFilterStartedStateProvider(
|
||||
mangaList: _entries));
|
||||
isManga: widget.isManga, mangaList: _entries));
|
||||
final bookmarkedFilterType = ref.watch(
|
||||
mangaFilterBookmarkedStateProvider(
|
||||
mangaList: _entries));
|
||||
isManga: widget.isManga, mangaList: _entries));
|
||||
final sortType = ref
|
||||
.watch(sortLibraryMangaStateProvider)
|
||||
.watch(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga))
|
||||
.index as int;
|
||||
final numberOfItemsList = _filterAndSortManga(
|
||||
data: man,
|
||||
|
|
@ -301,35 +315,50 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
});
|
||||
}
|
||||
return Consumer(builder: (context, ref, child) {
|
||||
bool reverse =
|
||||
ref.watch(sortLibraryMangaStateProvider).reverse!;
|
||||
final continueReaderBtn = ref
|
||||
.watch(libraryShowContinueReadingButtonStateProvider);
|
||||
final showNumbersOfItems =
|
||||
ref.watch(libraryShowNumbersOfItemsStateProvider);
|
||||
final localSource =
|
||||
ref.watch(libraryLocalSourceStateProvider);
|
||||
final downloadedChapter =
|
||||
ref.watch(libraryDownloadedChaptersStateProvider);
|
||||
final language = ref.watch(libraryLanguageStateProvider);
|
||||
bool reverse = ref
|
||||
.watch(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga))
|
||||
.reverse!;
|
||||
final continueReaderBtn = ref.watch(
|
||||
libraryShowContinueReadingButtonStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final showNumbersOfItems = ref.watch(
|
||||
libraryShowNumbersOfItemsStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final localSource = ref.watch(
|
||||
libraryLocalSourceStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final downloadedChapter = ref.watch(
|
||||
libraryDownloadedChaptersStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final language = ref.watch(libraryLanguageStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final displayType = ref
|
||||
.read(libraryDisplayTypeStateProvider.notifier)
|
||||
.getLibraryDisplayTypeValue(
|
||||
ref.watch(libraryDisplayTypeStateProvider));
|
||||
.read(libraryDisplayTypeStateProvider(
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.getLibraryDisplayTypeValue(ref.watch(
|
||||
libraryDisplayTypeStateProvider(
|
||||
isManga: widget.isManga)));
|
||||
final isNotFiltering = ref.watch(
|
||||
mangasFilterResultStateProvider(mangaList: _entries));
|
||||
mangasFilterResultStateProvider(
|
||||
isManga: widget.isManga, mangaList: _entries));
|
||||
final downloadFilterType = ref.watch(
|
||||
mangaFilterDownloadedStateProvider(
|
||||
mangaList: _entries));
|
||||
isManga: widget.isManga, mangaList: _entries));
|
||||
final unreadFilterType = ref.watch(
|
||||
mangaFilterUnreadStateProvider(mangaList: _entries));
|
||||
mangaFilterUnreadStateProvider(
|
||||
isManga: widget.isManga, mangaList: _entries));
|
||||
final startedFilterType = ref.watch(
|
||||
mangaFilterStartedStateProvider(mangaList: _entries));
|
||||
mangaFilterStartedStateProvider(
|
||||
isManga: widget.isManga, mangaList: _entries));
|
||||
final bookmarkedFilterType = ref.watch(
|
||||
mangaFilterBookmarkedStateProvider(
|
||||
mangaList: _entries));
|
||||
final sortType =
|
||||
ref.watch(sortLibraryMangaStateProvider).index;
|
||||
isManga: widget.isManga, mangaList: _entries));
|
||||
final sortType = ref
|
||||
.watch(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga))
|
||||
.index;
|
||||
final numberOfItemsList = _filterAndSortManga(
|
||||
data: man,
|
||||
downloadFilterType: downloadFilterType,
|
||||
|
|
@ -510,8 +539,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
required bool downloadedChapter,
|
||||
required bool continueReaderBtn,
|
||||
required int categoryId}) {
|
||||
final mangas = ref.watch(getAllMangaStreamProvider(categoryId: categoryId));
|
||||
final sortType = ref.watch(sortLibraryMangaStateProvider).index;
|
||||
final mangas = ref.watch(getAllMangaStreamProvider(
|
||||
categoryId: categoryId, isManga: widget.isManga));
|
||||
final sortType =
|
||||
ref.watch(sortLibraryMangaStateProvider(isManga: widget.isManga)).index;
|
||||
return mangas.when(
|
||||
data: (data) {
|
||||
final categoriNumberOfItemsList = _filterAndSortManga(
|
||||
|
|
@ -555,8 +586,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
required WidgetRef ref,
|
||||
required DisplayType displayType}) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
final mangas = ref.watch(getAllMangaStreamProvider(categoryId: categoryId));
|
||||
final sortType = ref.watch(sortLibraryMangaStateProvider).index;
|
||||
final mangas = ref.watch(getAllMangaStreamProvider(
|
||||
categoryId: categoryId, isManga: widget.isManga));
|
||||
final sortType =
|
||||
ref.watch(sortLibraryMangaStateProvider(isManga: widget.isManga)).index;
|
||||
final mangaIdsList = ref.watch(mangasListStateProvider);
|
||||
return Scaffold(
|
||||
body: mangas.when(
|
||||
|
|
@ -616,10 +649,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
required DisplayType displayType,
|
||||
required WidgetRef ref,
|
||||
bool withouCategories = false}) {
|
||||
final sortType = ref.watch(sortLibraryMangaStateProvider).index;
|
||||
final sortType =
|
||||
ref.watch(sortLibraryMangaStateProvider(isManga: widget.isManga)).index;
|
||||
final manga = withouCategories
|
||||
? ref.watch(getAllMangaWithoutCategoriesStreamProvider)
|
||||
: ref.watch(getAllMangaStreamProvider(categoryId: null));
|
||||
? ref.watch(
|
||||
getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga))
|
||||
: ref.watch(getAllMangaStreamProvider(
|
||||
categoryId: null, isManga: widget.isManga));
|
||||
final mangaIdsList = ref.watch(mangasListStateProvider);
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return manga.when(
|
||||
|
|
@ -822,99 +858,128 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
}
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
l10n.set_categories,
|
||||
),
|
||||
content: SizedBox(
|
||||
width: mediaWidth(context, 0.8),
|
||||
child: StreamBuilder(
|
||||
stream: isar.categorys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
|
||||
final entries = snapshot.data!;
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: entries.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ListTileMangaCategory(
|
||||
category: entries[index],
|
||||
categoryIds: categoryIds,
|
||||
mangasList: mangasList,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (categoryIds
|
||||
.contains(entries[index].id)) {
|
||||
categoryIds.remove(entries[index].id);
|
||||
} else {
|
||||
return StreamBuilder(
|
||||
stream: isar.categorys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.forMangaEqualTo(widget.isManga)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
l10n.set_categories,
|
||||
),
|
||||
content: SizedBox(
|
||||
width: mediaWidth(context, 0.8),
|
||||
child: Builder(builder: (context) {
|
||||
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
|
||||
final entries = snapshot.data!;
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: entries.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ListTileMangaCategory(
|
||||
category: entries[index],
|
||||
categoryIds: categoryIds,
|
||||
mangasList: mangasList,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (categoryIds
|
||||
.contains(entries[index].id)) {
|
||||
categoryIds.remove(entries[index].id);
|
||||
} else {
|
||||
categoryIds.add(entries[index].id!);
|
||||
}
|
||||
});
|
||||
},
|
||||
res: (res) {
|
||||
if (res.isNotEmpty) {
|
||||
categoryIds.add(entries[index].id!);
|
||||
}
|
||||
});
|
||||
},
|
||||
res: (res) {
|
||||
if (res.isNotEmpty) {
|
||||
categoryIds.add(entries[index].id!);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
return Container();
|
||||
}),
|
||||
),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.push("/categories");
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(l10n.edit)),
|
||||
Row(
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Text(l10n.cancel)),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
isar.writeTxnSync(() {
|
||||
for (var id in mangaIdsList) {
|
||||
Manga? manga = isar.mangas.getSync(id);
|
||||
manga!.categories = categoryIds;
|
||||
isar.mangas.putSync(manga);
|
||||
}
|
||||
});
|
||||
ref
|
||||
.read(mangasListStateProvider.notifier)
|
||||
.clear();
|
||||
ref
|
||||
.read(isLongPressedMangaStateProvider
|
||||
.notifier)
|
||||
.update(false);
|
||||
if (mounted) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
l10n.ok,
|
||||
)),
|
||||
],
|
||||
);
|
||||
}
|
||||
return Text(l10n.library_no_category_exist);
|
||||
}),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
actions: [
|
||||
snapshot.hasData && snapshot.data!.isNotEmpty
|
||||
? Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.push("/categories", extra: (
|
||||
true,
|
||||
widget.isManga ? 0 : 1
|
||||
));
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(l10n.edit)),
|
||||
Row(
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(l10n.cancel)),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
isar.writeTxnSync(() {
|
||||
for (var id in mangaIdsList) {
|
||||
Manga? manga =
|
||||
isar.mangas.getSync(id);
|
||||
manga!.categories =
|
||||
categoryIds;
|
||||
isar.mangas.putSync(manga);
|
||||
}
|
||||
});
|
||||
ref
|
||||
.read(mangasListStateProvider
|
||||
.notifier)
|
||||
.clear();
|
||||
ref
|
||||
.read(
|
||||
isLongPressedMangaStateProvider
|
||||
.notifier)
|
||||
.update(false);
|
||||
if (mounted) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
l10n.ok,
|
||||
)),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.push("/categories", extra: (
|
||||
true,
|
||||
widget.isManga ? 0 : 1
|
||||
));
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(
|
||||
l10n.edit_categories,
|
||||
)),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
@ -1114,11 +1179,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
label: l10n.downloaded,
|
||||
type: ref.watch(
|
||||
mangaFilterDownloadedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
mangaList: _entries)),
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
mangaFilterDownloadedStateProvider(
|
||||
isManga:
|
||||
widget.isManga,
|
||||
mangaList: _entries)
|
||||
.notifier)
|
||||
.update();
|
||||
|
|
@ -1127,11 +1195,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
label: l10n.unread,
|
||||
type: ref.watch(
|
||||
mangaFilterUnreadStateProvider(
|
||||
isManga: widget.isManga,
|
||||
mangaList: _entries)),
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
mangaFilterUnreadStateProvider(
|
||||
isManga:
|
||||
widget.isManga,
|
||||
mangaList: _entries)
|
||||
.notifier)
|
||||
.update();
|
||||
|
|
@ -1140,11 +1211,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
label: l10n.started,
|
||||
type: ref.watch(
|
||||
mangaFilterStartedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
mangaList: _entries)),
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
mangaFilterStartedStateProvider(
|
||||
isManga:
|
||||
widget.isManga,
|
||||
mangaList: _entries)
|
||||
.notifier)
|
||||
.update();
|
||||
|
|
@ -1153,12 +1227,15 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
label: l10n.bookmarked,
|
||||
type: ref.watch(
|
||||
mangaFilterBookmarkedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
mangaList: _entries)),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
ref
|
||||
.read(
|
||||
mangaFilterBookmarkedStateProvider(
|
||||
isManga: widget
|
||||
.isManga,
|
||||
mangaList:
|
||||
_entries)
|
||||
.notifier)
|
||||
|
|
@ -1170,11 +1247,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
}),
|
||||
Consumer(builder: (context, ref, chil) {
|
||||
final reverse = ref
|
||||
.read(sortLibraryMangaStateProvider
|
||||
.read(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.isReverse();
|
||||
final reverseChapter =
|
||||
ref.watch(sortLibraryMangaStateProvider);
|
||||
final reverseChapter = ref.watch(
|
||||
sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga));
|
||||
return Column(
|
||||
children: [
|
||||
for (var i = 0; i < 7; i++)
|
||||
|
|
@ -1185,7 +1264,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
sortLibraryMangaStateProvider
|
||||
sortLibraryMangaStateProvider(
|
||||
isManga:
|
||||
widget.isManga)
|
||||
.notifier)
|
||||
.set(i);
|
||||
},
|
||||
|
|
@ -1196,22 +1277,31 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
);
|
||||
}),
|
||||
Consumer(builder: (context, ref, chil) {
|
||||
final display = ref
|
||||
.watch(libraryDisplayTypeStateProvider);
|
||||
final display = ref.watch(
|
||||
libraryDisplayTypeStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final displayV = ref.read(
|
||||
libraryDisplayTypeStateProvider.notifier);
|
||||
libraryDisplayTypeStateProvider(
|
||||
isManga: widget.isManga)
|
||||
.notifier);
|
||||
final showCategoryTabs = ref.watch(
|
||||
libraryShowCategoryTabsStateProvider);
|
||||
libraryShowCategoryTabsStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final continueReaderBtn = ref.watch(
|
||||
libraryShowContinueReadingButtonStateProvider);
|
||||
libraryShowContinueReadingButtonStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final showNumbersOfItems = ref.watch(
|
||||
libraryShowNumbersOfItemsStateProvider);
|
||||
libraryShowNumbersOfItemsStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final downloadedChapter = ref.watch(
|
||||
libraryDownloadedChaptersStateProvider);
|
||||
final language =
|
||||
ref.watch(libraryLanguageStateProvider);
|
||||
final localSource = ref
|
||||
.watch(libraryLocalSourceStateProvider);
|
||||
libraryDownloadedChaptersStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final language = ref.watch(
|
||||
libraryLanguageStateProvider(
|
||||
isManga: widget.isManga));
|
||||
final localSource = ref.watch(
|
||||
libraryLocalSourceStateProvider(
|
||||
isManga: widget.isManga));
|
||||
return SingleChildScrollView(
|
||||
physics:
|
||||
const NeverScrollableScrollPhysics(),
|
||||
|
|
@ -1277,9 +1367,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
downloadedChapter ? 1 : 0,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
libraryDownloadedChaptersStateProvider
|
||||
.notifier)
|
||||
.read(libraryDownloadedChaptersStateProvider(
|
||||
isManga: widget
|
||||
.isManga)
|
||||
.notifier)
|
||||
.set(
|
||||
!downloadedChapter);
|
||||
}),
|
||||
|
|
@ -1288,9 +1379,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
type: language ? 1 : 0,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
libraryLanguageStateProvider
|
||||
.notifier)
|
||||
.read(libraryLanguageStateProvider(
|
||||
isManga: widget
|
||||
.isManga)
|
||||
.notifier)
|
||||
.set(!language);
|
||||
}),
|
||||
ListTileChapterFilter(
|
||||
|
|
@ -1298,9 +1390,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
type: localSource ? 1 : 0,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
libraryLocalSourceStateProvider
|
||||
.notifier)
|
||||
.read(libraryLocalSourceStateProvider(
|
||||
isManga: widget
|
||||
.isManga)
|
||||
.notifier)
|
||||
.set(!localSource);
|
||||
}),
|
||||
],
|
||||
|
|
@ -1327,9 +1420,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
showCategoryTabs ? 1 : 0,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
libraryShowCategoryTabsStateProvider
|
||||
.notifier)
|
||||
.read(libraryShowCategoryTabsStateProvider(
|
||||
isManga: widget
|
||||
.isManga)
|
||||
.notifier)
|
||||
.set(!showCategoryTabs);
|
||||
}),
|
||||
ListTileChapterFilter(
|
||||
|
|
@ -1340,9 +1434,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
: 0,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
libraryShowNumbersOfItemsStateProvider
|
||||
.notifier)
|
||||
.read(libraryShowNumbersOfItemsStateProvider(
|
||||
isManga: widget
|
||||
.isManga)
|
||||
.notifier)
|
||||
.set(
|
||||
!showNumbersOfItems);
|
||||
}),
|
||||
|
|
@ -1370,9 +1465,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
continueReaderBtn ? 1 : 0,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
libraryShowContinueReadingButtonStateProvider
|
||||
.notifier)
|
||||
.read(libraryShowContinueReadingButtonStateProvider(
|
||||
isManga: widget
|
||||
.isManga)
|
||||
.notifier)
|
||||
.set(
|
||||
!continueReaderBtn);
|
||||
}),
|
||||
|
|
@ -1420,8 +1516,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
|
||||
final mangaIdsList = ref.watch(mangasListStateProvider);
|
||||
final manga = categoryId == null
|
||||
? ref.watch(getAllMangaWithoutCategoriesStreamProvider)
|
||||
: ref.watch(getAllMangaStreamProvider(categoryId: categoryId));
|
||||
? ref.watch(
|
||||
getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga))
|
||||
: ref.watch(getAllMangaStreamProvider(
|
||||
categoryId: categoryId, isManga: widget.isManga));
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return PreferredSize(
|
||||
preferredSize: Size.fromHeight(AppBar().preferredSize.height),
|
||||
|
|
@ -1490,7 +1588,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
: Row(
|
||||
children: [
|
||||
Text(
|
||||
l10n.library,
|
||||
widget.isManga ? l10n.manga : l10n.anime,
|
||||
style:
|
||||
TextStyle(color: Theme.of(context).hintColor),
|
||||
),
|
||||
|
|
@ -1558,7 +1656,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
return [
|
||||
PopupMenuItem<int>(
|
||||
value: 0, child: Text(l10n.open_random_entry)),
|
||||
PopupMenuItem<int>(value: 1, child: Text(l10n.import)),
|
||||
if (widget.isManga)
|
||||
PopupMenuItem<int>(value: 1, child: Text(l10n.import)),
|
||||
];
|
||||
}, onSelected: (value) {
|
||||
if (value == 0) {
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ part 'isar_providers.g.dart';
|
|||
|
||||
@riverpod
|
||||
Stream<List<Manga>> getAllMangaStream(GetAllMangaStreamRef ref,
|
||||
{required int? categoryId}) async* {
|
||||
{required int? categoryId, required bool? isManga}) async* {
|
||||
yield* categoryId == null
|
||||
? isar.mangas
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.favoriteEqualTo(true)
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.watch(fireImmediately: true)
|
||||
: isar.mangas
|
||||
.filter()
|
||||
|
|
@ -19,21 +21,27 @@ Stream<List<Manga>> getAllMangaStream(GetAllMangaStreamRef ref,
|
|||
.favoriteEqualTo(true)
|
||||
.categoriesIsNotEmpty()
|
||||
.categoriesElementEqualTo(categoryId)
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.watch(fireImmediately: true);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Stream<List<Manga>> getAllMangaWithoutCategoriesStream(
|
||||
GetAllMangaWithoutCategoriesStreamRef ref,
|
||||
) async* {
|
||||
GetAllMangaWithoutCategoriesStreamRef ref,
|
||||
{required bool? isManga}) async* {
|
||||
yield* isar.mangas
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.favoriteEqualTo(true)
|
||||
.categoriesIsEmpty()
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.or()
|
||||
.idIsNotNull()
|
||||
.categoriesIsNull()
|
||||
.favoriteEqualTo(true)
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.watch(fireImmediately: true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'isar_providers.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getAllMangaStreamHash() => r'880357b7617f6592cd453186336b8114982a081b';
|
||||
String _$getAllMangaStreamHash() => r'd06c3a94ba847055746f2d52566cc94db4c28b7e';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -43,9 +43,11 @@ class GetAllMangaStreamFamily extends Family<AsyncValue<List<Manga>>> {
|
|||
/// See also [getAllMangaStream].
|
||||
GetAllMangaStreamProvider call({
|
||||
required int? categoryId,
|
||||
required bool? isManga,
|
||||
}) {
|
||||
return GetAllMangaStreamProvider(
|
||||
categoryId: categoryId,
|
||||
isManga: isManga,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -55,6 +57,7 @@ class GetAllMangaStreamFamily extends Family<AsyncValue<List<Manga>>> {
|
|||
) {
|
||||
return call(
|
||||
categoryId: provider.categoryId,
|
||||
isManga: provider.isManga,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -78,10 +81,12 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
|
|||
/// See also [getAllMangaStream].
|
||||
GetAllMangaStreamProvider({
|
||||
required this.categoryId,
|
||||
required this.isManga,
|
||||
}) : super.internal(
|
||||
(ref) => getAllMangaStream(
|
||||
ref,
|
||||
categoryId: categoryId,
|
||||
isManga: isManga,
|
||||
),
|
||||
from: getAllMangaStreamProvider,
|
||||
name: r'getAllMangaStreamProvider',
|
||||
|
|
@ -95,37 +100,111 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
|
|||
);
|
||||
|
||||
final int? categoryId;
|
||||
final bool? isManga;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is GetAllMangaStreamProvider && other.categoryId == categoryId;
|
||||
return other is GetAllMangaStreamProvider &&
|
||||
other.categoryId == categoryId &&
|
||||
other.isManga == isManga;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, categoryId.hashCode);
|
||||
hash = _SystemHash.combine(hash, isManga.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
String _$getAllMangaWithoutCategoriesStreamHash() =>
|
||||
r'affd1fab4a6ab0e0bbc16b67384a0b17498fe209';
|
||||
r'03581754f330a87894f953f8eaae528642b0afc2';
|
||||
typedef GetAllMangaWithoutCategoriesStreamRef
|
||||
= AutoDisposeStreamProviderRef<List<Manga>>;
|
||||
|
||||
/// See also [getAllMangaWithoutCategoriesStream].
|
||||
@ProviderFor(getAllMangaWithoutCategoriesStream)
|
||||
final getAllMangaWithoutCategoriesStreamProvider =
|
||||
AutoDisposeStreamProvider<List<Manga>>.internal(
|
||||
getAllMangaWithoutCategoriesStream,
|
||||
name: r'getAllMangaWithoutCategoriesStreamProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$getAllMangaWithoutCategoriesStreamHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
const getAllMangaWithoutCategoriesStreamProvider =
|
||||
GetAllMangaWithoutCategoriesStreamFamily();
|
||||
|
||||
typedef GetAllMangaWithoutCategoriesStreamRef
|
||||
= AutoDisposeStreamProviderRef<List<Manga>>;
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
/// See also [getAllMangaWithoutCategoriesStream].
|
||||
class GetAllMangaWithoutCategoriesStreamFamily
|
||||
extends Family<AsyncValue<List<Manga>>> {
|
||||
/// See also [getAllMangaWithoutCategoriesStream].
|
||||
const GetAllMangaWithoutCategoriesStreamFamily();
|
||||
|
||||
/// See also [getAllMangaWithoutCategoriesStream].
|
||||
GetAllMangaWithoutCategoriesStreamProvider call({
|
||||
required bool? isManga,
|
||||
}) {
|
||||
return GetAllMangaWithoutCategoriesStreamProvider(
|
||||
isManga: isManga,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
GetAllMangaWithoutCategoriesStreamProvider getProviderOverride(
|
||||
covariant GetAllMangaWithoutCategoriesStreamProvider provider,
|
||||
) {
|
||||
return call(
|
||||
isManga: provider.isManga,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'getAllMangaWithoutCategoriesStreamProvider';
|
||||
}
|
||||
|
||||
/// See also [getAllMangaWithoutCategoriesStream].
|
||||
class GetAllMangaWithoutCategoriesStreamProvider
|
||||
extends AutoDisposeStreamProvider<List<Manga>> {
|
||||
/// See also [getAllMangaWithoutCategoriesStream].
|
||||
GetAllMangaWithoutCategoriesStreamProvider({
|
||||
required this.isManga,
|
||||
}) : super.internal(
|
||||
(ref) => getAllMangaWithoutCategoriesStream(
|
||||
ref,
|
||||
isManga: isManga,
|
||||
),
|
||||
from: getAllMangaWithoutCategoriesStreamProvider,
|
||||
name: r'getAllMangaWithoutCategoriesStreamProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$getAllMangaWithoutCategoriesStreamHash,
|
||||
dependencies: GetAllMangaWithoutCategoriesStreamFamily._dependencies,
|
||||
allTransitiveDependencies: GetAllMangaWithoutCategoriesStreamFamily
|
||||
._allTransitiveDependencies,
|
||||
);
|
||||
|
||||
final bool? isManga;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is GetAllMangaWithoutCategoriesStreamProvider &&
|
||||
other.isManga == isManga;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, isManga.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@ part 'library_state_provider.g.dart';
|
|||
@riverpod
|
||||
class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
|
||||
@override
|
||||
String build() {
|
||||
return isar.settings.getSync(227)!.displayType.name;
|
||||
String build({required bool isManga}) {
|
||||
return isManga
|
||||
? isar.settings.getSync(227)!.displayType.name
|
||||
: isar.settings.getSync(227)!.animeDisplayType.name;
|
||||
}
|
||||
|
||||
DisplayType getLibraryDisplayTypeValue(String value) {
|
||||
|
|
@ -36,10 +38,16 @@ class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
|
|||
}
|
||||
|
||||
void setLibraryDisplayType(DisplayType displayType) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
Settings settings = isar.settings.getSync(227)!;
|
||||
state = displayType.name;
|
||||
if (isManga) {
|
||||
settings = settings..displayType = displayType;
|
||||
} else {
|
||||
settings = settings..animeDisplayType = displayType;
|
||||
}
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(settings..displayType = displayType);
|
||||
isar.settings.putSync(settings);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -47,19 +55,26 @@ class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
|
|||
@riverpod
|
||||
class MangaFilterDownloadedState extends _$MangaFilterDownloadedState {
|
||||
@override
|
||||
int build({required List<Manga> mangaList}) {
|
||||
int build({required List<Manga> mangaList, required bool isManga}) {
|
||||
state = getType();
|
||||
return getType();
|
||||
}
|
||||
|
||||
int getType() {
|
||||
return isar.settings.getSync(227)!.libraryFilterMangasDownloadType!;
|
||||
return isManga
|
||||
? isar.settings.getSync(227)!.libraryFilterMangasDownloadType!
|
||||
: isar.settings.getSync(227)!.libraryFilterAnimeDownloadType ?? 0;
|
||||
}
|
||||
|
||||
void setType(int type) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
Settings settings = isar.settings.getSync(227)!;
|
||||
if (isManga) {
|
||||
settings = settings..libraryFilterMangasDownloadType = type;
|
||||
} else {
|
||||
settings = settings..libraryFilterAnimeDownloadType = type;
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(settings..libraryFilterMangasDownloadType = type);
|
||||
isar.settings.putSync(settings);
|
||||
});
|
||||
state = type;
|
||||
}
|
||||
|
|
@ -78,19 +93,26 @@ class MangaFilterDownloadedState extends _$MangaFilterDownloadedState {
|
|||
@riverpod
|
||||
class MangaFilterUnreadState extends _$MangaFilterUnreadState {
|
||||
@override
|
||||
int build({required List<Manga> mangaList}) {
|
||||
int build({required List<Manga> mangaList, required bool isManga}) {
|
||||
state = getType();
|
||||
return getType();
|
||||
}
|
||||
|
||||
int getType() {
|
||||
return isar.settings.getSync(227)!.libraryFilterMangasUnreadType!;
|
||||
return isManga
|
||||
? isar.settings.getSync(227)!.libraryFilterMangasUnreadType!
|
||||
: isar.settings.getSync(227)!.libraryFilterAnimeUnreadType ?? 0;
|
||||
}
|
||||
|
||||
void setType(int type) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
Settings settings = isar.settings.getSync(227)!;
|
||||
if (isManga) {
|
||||
settings = settings..libraryFilterMangasUnreadType = type;
|
||||
} else {
|
||||
settings = settings..libraryFilterAnimeUnreadType = type;
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(settings..libraryFilterMangasUnreadType = type);
|
||||
isar.settings.putSync(settings);
|
||||
});
|
||||
state = type;
|
||||
}
|
||||
|
|
@ -158,19 +180,26 @@ class MangaFilterUnreadState extends _$MangaFilterUnreadState {
|
|||
@riverpod
|
||||
class MangaFilterStartedState extends _$MangaFilterStartedState {
|
||||
@override
|
||||
int build({required List<Manga> mangaList}) {
|
||||
int build({required List<Manga> mangaList, required bool isManga}) {
|
||||
state = getType();
|
||||
return getType();
|
||||
}
|
||||
|
||||
int getType() {
|
||||
return isar.settings.getSync(227)!.libraryFilterMangasStartedType!;
|
||||
return isManga
|
||||
? isar.settings.getSync(227)!.libraryFilterMangasStartedType!
|
||||
: isar.settings.getSync(227)!.libraryFilterAnimeStartedType ?? 0;
|
||||
}
|
||||
|
||||
void setType(int type) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
Settings settings = isar.settings.getSync(227)!;
|
||||
if (isManga) {
|
||||
settings = settings..libraryFilterMangasStartedType = type;
|
||||
} else {
|
||||
settings = settings..libraryFilterAnimeStartedType = type;
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(settings..libraryFilterMangasStartedType = type);
|
||||
isar.settings.putSync(settings);
|
||||
});
|
||||
state = type;
|
||||
}
|
||||
|
|
@ -238,19 +267,26 @@ class MangaFilterStartedState extends _$MangaFilterStartedState {
|
|||
@riverpod
|
||||
class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState {
|
||||
@override
|
||||
int build({required List<Manga> mangaList}) {
|
||||
int build({required List<Manga> mangaList, required bool isManga}) {
|
||||
state = getType();
|
||||
return getType();
|
||||
}
|
||||
|
||||
int getType() {
|
||||
return isar.settings.getSync(227)!.libraryFilterMangasBookMarkedType!;
|
||||
return isManga
|
||||
? isar.settings.getSync(227)!.libraryFilterMangasBookMarkedType!
|
||||
: isar.settings.getSync(227)!.libraryFilterAnimeBookMarkedType ?? 0;
|
||||
}
|
||||
|
||||
void setType(int type) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
Settings settings = isar.settings.getSync(227)!;
|
||||
if (isManga) {
|
||||
settings = settings..libraryFilterMangasBookMarkedType = type;
|
||||
} else {
|
||||
settings = settings..libraryFilterAnimeBookMarkedType = type;
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(settings..libraryFilterMangasBookMarkedType = type);
|
||||
isar.settings.putSync(settings);
|
||||
});
|
||||
state = type;
|
||||
}
|
||||
|
|
@ -318,15 +354,15 @@ class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState {
|
|||
@riverpod
|
||||
class MangasFilterResultState extends _$MangasFilterResultState {
|
||||
@override
|
||||
bool build({required List<Manga> mangaList}) {
|
||||
final downloadFilterType =
|
||||
ref.watch(mangaFilterDownloadedStateProvider(mangaList: mangaList));
|
||||
final unreadFilterType =
|
||||
ref.watch(mangaFilterUnreadStateProvider(mangaList: mangaList));
|
||||
final startedFilterType =
|
||||
ref.watch(mangaFilterStartedStateProvider(mangaList: mangaList));
|
||||
final bookmarkedFilterType =
|
||||
ref.watch(mangaFilterBookmarkedStateProvider(mangaList: mangaList));
|
||||
bool build({required List<Manga> mangaList, required bool isManga}) {
|
||||
final downloadFilterType = ref.watch(mangaFilterDownloadedStateProvider(
|
||||
mangaList: mangaList, isManga: isManga));
|
||||
final unreadFilterType = ref.watch(
|
||||
mangaFilterUnreadStateProvider(mangaList: mangaList, isManga: isManga));
|
||||
final startedFilterType = ref.watch(mangaFilterStartedStateProvider(
|
||||
mangaList: mangaList, isManga: isManga));
|
||||
final bookmarkedFilterType = ref.watch(mangaFilterBookmarkedStateProvider(
|
||||
mangaList: mangaList, isManga: isManga));
|
||||
return downloadFilterType == 0 &&
|
||||
unreadFilterType == 0 &&
|
||||
startedFilterType == 0 &&
|
||||
|
|
@ -337,15 +373,22 @@ class MangasFilterResultState extends _$MangasFilterResultState {
|
|||
@riverpod
|
||||
class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
|
||||
@override
|
||||
bool build() {
|
||||
return isar.settings.getSync(227)!.libraryShowCategoryTabs!;
|
||||
bool build({required bool isManga}) {
|
||||
return isManga
|
||||
? isar.settings.getSync(227)!.libraryShowCategoryTabs!
|
||||
: isar.settings.getSync(227)!.animeLibraryShowCategoryTabs ?? false;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
Settings settings = isar.settings.getSync(227)!;
|
||||
if (isManga) {
|
||||
settings = settings..libraryShowCategoryTabs = value;
|
||||
} else {
|
||||
settings = settings..animeLibraryShowCategoryTabs = value;
|
||||
}
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(settings..libraryShowCategoryTabs = value);
|
||||
isar.settings.putSync(settings);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -353,15 +396,22 @@ class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
|
|||
@riverpod
|
||||
class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
|
||||
@override
|
||||
bool build() {
|
||||
return isar.settings.getSync(227)!.libraryDownloadedChapters!;
|
||||
bool build({required bool isManga}) {
|
||||
return isManga
|
||||
? isar.settings.getSync(227)!.libraryDownloadedChapters!
|
||||
: isar.settings.getSync(227)!.animeLibraryDownloadedChapters ?? false;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
Settings settings = isar.settings.getSync(227)!;
|
||||
if (isManga) {
|
||||
settings = settings..libraryDownloadedChapters = value;
|
||||
} else {
|
||||
settings = settings..animeLibraryDownloadedChapters = value;
|
||||
}
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(settings..libraryDownloadedChapters = value);
|
||||
isar.settings.putSync(settings);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -369,15 +419,22 @@ class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
|
|||
@riverpod
|
||||
class LibraryLanguageState extends _$LibraryLanguageState {
|
||||
@override
|
||||
bool build() {
|
||||
return isar.settings.getSync(227)!.libraryShowLanguage!;
|
||||
bool build({required bool isManga}) {
|
||||
return isManga
|
||||
? isar.settings.getSync(227)!.libraryShowLanguage!
|
||||
: isar.settings.getSync(227)!.animeLibraryShowLanguage ?? false;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
Settings settings = isar.settings.getSync(227)!;
|
||||
if (isManga) {
|
||||
settings = settings..libraryShowLanguage = value;
|
||||
} else {
|
||||
settings = settings..animeLibraryShowLanguage = value;
|
||||
}
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(settings..libraryShowLanguage = value);
|
||||
isar.settings.putSync(settings);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -385,15 +442,22 @@ class LibraryLanguageState extends _$LibraryLanguageState {
|
|||
@riverpod
|
||||
class LibraryLocalSourceState extends _$LibraryLocalSourceState {
|
||||
@override
|
||||
bool build() {
|
||||
return isar.settings.getSync(227)!.libraryLocalSource ?? false;
|
||||
bool build({required bool isManga}) {
|
||||
return isManga
|
||||
? isar.settings.getSync(227)!.libraryLocalSource ?? false
|
||||
: isar.settings.getSync(227)!.animeLibraryLocalSource ?? false;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
Settings settings = isar.settings.getSync(227)!;
|
||||
if (isManga) {
|
||||
settings = settings..libraryShowLanguage = value;
|
||||
} else {
|
||||
settings = settings..animeLibraryShowLanguage = value;
|
||||
}
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(settings..libraryShowLanguage = value);
|
||||
isar.settings.putSync(settings);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -401,15 +465,22 @@ class LibraryLocalSourceState extends _$LibraryLocalSourceState {
|
|||
@riverpod
|
||||
class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
|
||||
@override
|
||||
bool build() {
|
||||
return isar.settings.getSync(227)!.libraryShowNumbersOfItems!;
|
||||
bool build({required bool isManga}) {
|
||||
return isManga
|
||||
? isar.settings.getSync(227)!.libraryShowNumbersOfItems!
|
||||
: isar.settings.getSync(227)!.animeLibraryShowNumbersOfItems ?? false;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
Settings settings = isar.settings.getSync(227)!;
|
||||
if (isManga) {
|
||||
settings = settings..libraryShowNumbersOfItems = value;
|
||||
} else {
|
||||
settings = settings..animeLibraryShowNumbersOfItems = value;
|
||||
}
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(settings..libraryShowNumbersOfItems = value);
|
||||
isar.settings.putSync(settings);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -418,15 +489,23 @@ class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
|
|||
class LibraryShowContinueReadingButtonState
|
||||
extends _$LibraryShowContinueReadingButtonState {
|
||||
@override
|
||||
bool build() {
|
||||
return isar.settings.getSync(227)!.libraryShowContinueReadingButton!;
|
||||
bool build({required bool isManga}) {
|
||||
return isManga
|
||||
? isar.settings.getSync(227)!.libraryShowContinueReadingButton!
|
||||
: isar.settings.getSync(227)!.animeLibraryShowContinueReadingButton ??
|
||||
false;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
Settings settings = isar.settings.getSync(227)!;
|
||||
if (isManga) {
|
||||
settings = settings..libraryShowContinueReadingButton = value;
|
||||
} else {
|
||||
settings = settings..animeLibraryShowContinueReadingButton = value;
|
||||
}
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(settings..libraryShowContinueReadingButton = value);
|
||||
isar.settings.putSync(settings);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -434,18 +513,25 @@ class LibraryShowContinueReadingButtonState
|
|||
@riverpod
|
||||
class SortLibraryMangaState extends _$SortLibraryMangaState {
|
||||
@override
|
||||
SortLibraryManga build() {
|
||||
return isar.settings.getSync(227)!.sortLibraryManga ?? SortLibraryManga();
|
||||
SortLibraryManga build({required bool isManga}) {
|
||||
return isManga
|
||||
? isar.settings.getSync(227)!.sortLibraryManga ?? SortLibraryManga()
|
||||
: isar.settings.getSync(227)!.sortLibraryAnime ?? SortLibraryManga();
|
||||
}
|
||||
|
||||
void update(bool reverse, int index) {
|
||||
var value = SortLibraryManga()
|
||||
..index = index
|
||||
..reverse = state.index == index ? !reverse : reverse;
|
||||
|
||||
Settings settings = isar.settings.getSync(227)!;
|
||||
if (isManga) {
|
||||
settings = settings..sortLibraryManga = value;
|
||||
} else {
|
||||
settings = settings..sortLibraryAnime = value;
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
isar.settings.putSync(settings..sortLibraryManga = value);
|
||||
isar.settings.putSync(settings);
|
||||
});
|
||||
state = value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,4 +128,5 @@ class ImportArchivesFromFileProvider
|
|||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member
|
||||
|
|
|
|||
|
|
@ -45,55 +45,48 @@ class LibraryGridViewWidget extends StatelessWidget {
|
|||
childAspectRatio: isComfortableGrid ? 0.642 : 0.69,
|
||||
itemCount: entriesManga.length,
|
||||
itemBuilder: (context, index) {
|
||||
final entry = entriesManga[index];
|
||||
return Consumer(builder: (context, ref, child) {
|
||||
bool isLocalArchive = entriesManga[index].isLocalArchive ?? false;
|
||||
bool isLocalArchive = entry.isLocalArchive ?? false;
|
||||
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(2),
|
||||
child: CoverViewWidget(
|
||||
isLongPressed: mangaIdsList.contains(entriesManga[index].id),
|
||||
isLongPressed: mangaIdsList.contains(entry.id),
|
||||
bottomTextWidget: BottomTextWidget(
|
||||
maxLines: 1,
|
||||
text: entriesManga[index].name!,
|
||||
text: entry.name!,
|
||||
isComfortableGrid: isComfortableGrid,
|
||||
),
|
||||
isComfortableGrid: isComfortableGrid,
|
||||
image: entriesManga[index].customCoverImage != null
|
||||
? MemoryImage(
|
||||
entriesManga[index].customCoverImage as Uint8List)
|
||||
image: entry.customCoverImage != null
|
||||
? MemoryImage(entry.customCoverImage as Uint8List)
|
||||
as ImageProvider
|
||||
: CachedNetworkImageProvider(
|
||||
entriesManga[index].imageUrl!,
|
||||
entry.imageUrl!,
|
||||
headers: ref.watch(headersProvider(
|
||||
source: entriesManga[index].source!,
|
||||
lang: entriesManga[index].lang!)),
|
||||
source: entry.source!, lang: entry.lang!)),
|
||||
),
|
||||
onTap: () {
|
||||
if (isLongPressed) {
|
||||
ref
|
||||
.read(mangasListStateProvider.notifier)
|
||||
.update(entriesManga[index]);
|
||||
ref.read(mangasListStateProvider.notifier).update(entry);
|
||||
} else {
|
||||
pushToMangaReaderDetail(
|
||||
archiveId: isLocalArchive ? entriesManga[index].id : null,
|
||||
archiveId: isLocalArchive ? entry.id : null,
|
||||
context: context,
|
||||
lang: entriesManga[index].lang!,
|
||||
mangaM: entriesManga[index]);
|
||||
lang: entry.lang!,
|
||||
mangaM: entry);
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
if (!isLongPressed) {
|
||||
ref
|
||||
.read(mangasListStateProvider.notifier)
|
||||
.update(entriesManga[index]);
|
||||
ref.read(mangasListStateProvider.notifier).update(entry);
|
||||
|
||||
ref
|
||||
.read(isLongPressedMangaStateProvider.notifier)
|
||||
.update(!isLongPressed);
|
||||
} else {
|
||||
ref
|
||||
.read(mangasListStateProvider.notifier)
|
||||
.update(entriesManga[index]);
|
||||
ref.read(mangasListStateProvider.notifier).update(entry);
|
||||
}
|
||||
},
|
||||
children: [
|
||||
|
|
@ -136,19 +129,14 @@ class LibraryGridViewWidget extends StatelessWidget {
|
|||
List nbrDown = [];
|
||||
isar.txnSync(() {
|
||||
for (var i = 0;
|
||||
i <
|
||||
entriesManga[index]
|
||||
.chapters
|
||||
.length;
|
||||
i < entry.chapters.length;
|
||||
i++) {
|
||||
final entries = isar.downloads
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.chapterIdEqualTo(
|
||||
entriesManga[index]
|
||||
.chapters
|
||||
.toList()[i]
|
||||
.id)
|
||||
.chapterIdEqualTo(entry.chapters
|
||||
.toList()[i]
|
||||
.id)
|
||||
.findAllSync();
|
||||
|
||||
if (entries.isNotEmpty &&
|
||||
|
|
@ -189,10 +177,7 @@ class LibraryGridViewWidget extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(right: 3),
|
||||
child: Text(
|
||||
entriesManga[index]
|
||||
.chapters
|
||||
.length
|
||||
.toString(),
|
||||
entry.chapters.length.toString(),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
|
|
@ -200,7 +185,7 @@ class LibraryGridViewWidget extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
)),
|
||||
if (language && entriesManga[index].lang!.isNotEmpty)
|
||||
if (language && entry.lang!.isNotEmpty)
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
|
|
@ -219,7 +204,7 @@ class LibraryGridViewWidget extends StatelessWidget {
|
|||
padding:
|
||||
const EdgeInsets.only(left: 3, right: 3),
|
||||
child: Text(
|
||||
entriesManga[index].lang!.toUpperCase(),
|
||||
entry.lang!.toUpperCase(),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
|
|
@ -229,7 +214,7 @@ class LibraryGridViewWidget extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
if (!isComfortableGrid && !isCoverOnlyGrid)
|
||||
BottomTextWidget(text: entriesManga[index].name!),
|
||||
BottomTextWidget(text: entry.name!),
|
||||
if (continueReaderBtn)
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
|
|
@ -238,16 +223,16 @@ class LibraryGridViewWidget extends StatelessWidget {
|
|||
padding: const EdgeInsets.all(9),
|
||||
child: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final history =
|
||||
ref.watch(getAllHistoryStreamProvider);
|
||||
final history = ref.watch(
|
||||
getAllHistoryStreamProvider(
|
||||
isManga: entry.isManga!));
|
||||
return history.when(
|
||||
data: (data) {
|
||||
final incognitoMode =
|
||||
ref.watch(incognitoModeStateProvider);
|
||||
final entries = data
|
||||
.where((element) =>
|
||||
element.mangaId ==
|
||||
entriesManga[index].id)
|
||||
element.mangaId == entry.id)
|
||||
.toList();
|
||||
if (entries.isNotEmpty && !incognitoMode) {
|
||||
return GestureDetector(
|
||||
|
|
@ -278,9 +263,7 @@ class LibraryGridViewWidget extends StatelessWidget {
|
|||
onTap: () {
|
||||
pushMangaReaderView(
|
||||
context: context,
|
||||
chapter: entriesManga[index]
|
||||
.chapters
|
||||
.last);
|
||||
chapter: entry.chapters.last);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
return ListViewWidget(
|
||||
itemCount: entriesManga.length,
|
||||
itemBuilder: (context, index) {
|
||||
bool isLocalArchive = entriesManga[index].isLocalArchive ?? false;
|
||||
final entry = entriesManga[index];
|
||||
bool isLocalArchive = entry.isLocalArchive ?? false;
|
||||
return Consumer(builder: (context, ref, child) {
|
||||
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
|
||||
return Material(
|
||||
|
|
@ -48,34 +49,28 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
child: InkWell(
|
||||
onTap: () {
|
||||
if (isLongPressed) {
|
||||
ref
|
||||
.read(mangasListStateProvider.notifier)
|
||||
.update(entriesManga[index]);
|
||||
ref.read(mangasListStateProvider.notifier).update(entry);
|
||||
} else {
|
||||
pushToMangaReaderDetail(
|
||||
archiveId: isLocalArchive ? entriesManga[index].id : null,
|
||||
archiveId: isLocalArchive ? entry.id : null,
|
||||
context: context,
|
||||
lang: entriesManga[index].lang!,
|
||||
mangaM: entriesManga[index]);
|
||||
lang: entry.lang!,
|
||||
mangaM: entry);
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
if (!isLongPressed) {
|
||||
ref
|
||||
.read(mangasListStateProvider.notifier)
|
||||
.update(entriesManga[index]);
|
||||
ref.read(mangasListStateProvider.notifier).update(entry);
|
||||
|
||||
ref
|
||||
.read(isLongPressedMangaStateProvider.notifier)
|
||||
.update(!isLongPressed);
|
||||
} else {
|
||||
ref
|
||||
.read(mangasListStateProvider.notifier)
|
||||
.update(entriesManga[index]);
|
||||
ref.read(mangasListStateProvider.notifier).update(entry);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
color: mangaIdsList.contains(entriesManga[index].id)
|
||||
color: mangaIdsList.contains(entry.id)
|
||||
? primaryColor(context).withOpacity(0.4)
|
||||
: Colors.transparent,
|
||||
child: Padding(
|
||||
|
|
@ -98,24 +93,18 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
fit: BoxFit.cover,
|
||||
width: 40,
|
||||
height: 45,
|
||||
image: entriesManga[index]
|
||||
.customCoverImage !=
|
||||
null
|
||||
? MemoryImage(
|
||||
entriesManga[index].customCoverImage
|
||||
as Uint8List) as ImageProvider
|
||||
image: entry.customCoverImage != null
|
||||
? MemoryImage(entry.customCoverImage
|
||||
as Uint8List) as ImageProvider
|
||||
: CachedNetworkImageProvider(
|
||||
entriesManga[index].imageUrl!,
|
||||
entry.imageUrl!,
|
||||
headers: ref.watch(headersProvider(
|
||||
source:
|
||||
entriesManga[index].source!,
|
||||
lang:
|
||||
entriesManga[index].lang!)),
|
||||
source: entry.source!,
|
||||
lang: entry.lang!)),
|
||||
),
|
||||
child: InkWell(
|
||||
child: Container(
|
||||
color: mangaIdsList
|
||||
.contains(entriesManga[index].id)
|
||||
color: mangaIdsList.contains(entry.id)
|
||||
? primaryColor(context)
|
||||
.withOpacity(0.4)
|
||||
: Colors.transparent,
|
||||
|
|
@ -127,7 +116,7 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10),
|
||||
child: Text(entriesManga[index].name!),
|
||||
child: Text(entry.name!),
|
||||
),
|
||||
)
|
||||
],
|
||||
|
|
@ -168,19 +157,15 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
List nbrDown = [];
|
||||
isar.txnSync(() {
|
||||
for (var i = 0;
|
||||
i <
|
||||
entriesManga[index]
|
||||
.chapters
|
||||
.length;
|
||||
i < entry.chapters.length;
|
||||
i++) {
|
||||
final entries = isar.downloads
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.chapterIdEqualTo(
|
||||
entriesManga[index]
|
||||
.chapters
|
||||
.toList()[i]
|
||||
.id)
|
||||
.chapterIdEqualTo(entry
|
||||
.chapters
|
||||
.toList()[i]
|
||||
.id)
|
||||
.findAllSync();
|
||||
|
||||
if (entries.isNotEmpty &&
|
||||
|
|
@ -220,16 +205,12 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(right: 3),
|
||||
child: Text(
|
||||
entriesManga[index]
|
||||
.chapters
|
||||
.length
|
||||
.toString(),
|
||||
entry.chapters.length.toString(),
|
||||
style:
|
||||
const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
if (language &&
|
||||
entriesManga[index].lang!.isNotEmpty)
|
||||
if (language && entry.lang!.isNotEmpty)
|
||||
Container(
|
||||
color: primaryColor(context),
|
||||
child: Container(
|
||||
|
|
@ -243,9 +224,7 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
padding: const EdgeInsets.only(
|
||||
left: 3, right: 3),
|
||||
child: Text(
|
||||
entriesManga[index]
|
||||
.lang!
|
||||
.toUpperCase(),
|
||||
entry.lang!.toUpperCase(),
|
||||
style: const TextStyle(
|
||||
color: Colors.white),
|
||||
),
|
||||
|
|
@ -260,16 +239,16 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
if (continueReaderBtn)
|
||||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final history =
|
||||
ref.watch(getAllHistoryStreamProvider);
|
||||
final history = ref.watch(
|
||||
getAllHistoryStreamProvider(
|
||||
isManga: entry.isManga!));
|
||||
return history.when(
|
||||
data: (data) {
|
||||
final incognitoMode =
|
||||
ref.watch(incognitoModeStateProvider);
|
||||
final entries = data
|
||||
.where((element) =>
|
||||
element.mangaId ==
|
||||
entriesManga[index].id)
|
||||
element.mangaId == entry.id)
|
||||
.toList();
|
||||
if (entries.isNotEmpty && !incognitoMode) {
|
||||
return GestureDetector(
|
||||
|
|
@ -300,9 +279,7 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
onTap: () {
|
||||
pushMangaReaderView(
|
||||
context: context,
|
||||
chapter: entriesManga[index]
|
||||
.chapters
|
||||
.last);
|
||||
chapter: entry.chapters.last);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ class _MainScreenState extends State<MainScreen> {
|
|||
Widget build(BuildContext context) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
final route = GoRouter.of(context);
|
||||
int currentIndex = route.location == '/library'
|
||||
int currentIndex = route.location == '/MangaLibrary'
|
||||
? 0
|
||||
: route.location == '/updates'
|
||||
: route.location == '/AnimeLibrary'
|
||||
? 1
|
||||
: route.location == '/history'
|
||||
: route.location == '/updates'
|
||||
? 2
|
||||
: route.location == '/browse'
|
||||
? 3
|
||||
|
|
@ -80,9 +80,9 @@ class _MainScreenState extends State<MainScreen> {
|
|||
duration: const Duration(milliseconds: 0),
|
||||
width: isLongPressed
|
||||
? 0
|
||||
: route.location != '/library' &&
|
||||
: route.location != '/MangaLibrary' &&
|
||||
route.location != '/AnimeLibrary' &&
|
||||
route.location != '/updates' &&
|
||||
route.location != '/history' &&
|
||||
route.location != '/browse' &&
|
||||
route.location != '/more'
|
||||
? 0
|
||||
|
|
@ -105,7 +105,18 @@ class _MainScreenState extends State<MainScreen> {
|
|||
),
|
||||
label: Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.library))),
|
||||
child: Text(l10n.manga))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.video_collection,
|
||||
),
|
||||
icon: const Icon(
|
||||
Icons.video_collection_outlined,
|
||||
),
|
||||
label: Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.anime),
|
||||
)),
|
||||
NavigationRailDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.new_releases,
|
||||
|
|
@ -116,17 +127,6 @@ class _MainScreenState extends State<MainScreen> {
|
|||
label: Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.updates))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.history,
|
||||
),
|
||||
icon: const Icon(
|
||||
Icons.history_outlined,
|
||||
),
|
||||
label: Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.history),
|
||||
)),
|
||||
NavigationRailDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.explore,
|
||||
|
|
@ -158,11 +158,11 @@ class _MainScreenState extends State<MainScreen> {
|
|||
});
|
||||
}
|
||||
if (newIndex == 0) {
|
||||
route.go('/library');
|
||||
route.go('/MangaLibrary');
|
||||
} else if (newIndex == 1) {
|
||||
route.go('/updates');
|
||||
route.go('/AnimeLibrary');
|
||||
} else if (newIndex == 2) {
|
||||
route.go('/history');
|
||||
route.go('/updates');
|
||||
} else if (newIndex == 3) {
|
||||
route.go('/browse');
|
||||
} else if (newIndex == 4) {
|
||||
|
|
@ -187,9 +187,9 @@ class _MainScreenState extends State<MainScreen> {
|
|||
width: mediaWidth(context, 1),
|
||||
height: isLongPressed
|
||||
? 0
|
||||
: route.location != '/library' &&
|
||||
: route.location != '/MangaLibrary' &&
|
||||
route.location != '/AnimeLibrary' &&
|
||||
route.location != '/updates' &&
|
||||
route.location != '/history' &&
|
||||
route.location != '/browse' &&
|
||||
route.location != '/more'
|
||||
? 0
|
||||
|
|
@ -211,7 +211,15 @@ class _MainScreenState extends State<MainScreen> {
|
|||
icon: const Icon(
|
||||
Icons.collections_bookmark_outlined,
|
||||
),
|
||||
label: l10n.library),
|
||||
label: l10n.manga),
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.video_collection,
|
||||
),
|
||||
icon: const Icon(
|
||||
Icons.video_collection_outlined,
|
||||
),
|
||||
label: l10n.anime),
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.new_releases,
|
||||
|
|
@ -220,14 +228,6 @@ class _MainScreenState extends State<MainScreen> {
|
|||
Icons.new_releases_outlined,
|
||||
),
|
||||
label: l10n.updates),
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.history,
|
||||
),
|
||||
icon: const Icon(
|
||||
Icons.history_outlined,
|
||||
),
|
||||
label: l10n.history),
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.explore,
|
||||
|
|
@ -252,11 +252,11 @@ class _MainScreenState extends State<MainScreen> {
|
|||
});
|
||||
}
|
||||
if (newIndex == 0) {
|
||||
route.go('/library');
|
||||
route.go('/MangaLibrary');
|
||||
} else if (newIndex == 1) {
|
||||
route.go('/updates');
|
||||
route.go('/AnimeLibrary');
|
||||
} else if (newIndex == 2) {
|
||||
route.go('/history');
|
||||
route.go('/updates');
|
||||
} else if (newIndex == 3) {
|
||||
route.go('/browse');
|
||||
} else if (newIndex == 4) {
|
||||
|
|
|
|||
|
|
@ -373,7 +373,10 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
];
|
||||
}, onSelected: (value) {
|
||||
if (value == 0) {
|
||||
context.push("/categories");
|
||||
context.push("/categories", extra: (
|
||||
true,
|
||||
widget.manga!.isManga! ? 0 : 1
|
||||
));
|
||||
} else if (value == 1) {
|
||||
} else if (value == 2) {
|
||||
final source = getSource(widget.manga!.lang!,
|
||||
|
|
@ -450,8 +453,11 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
.symmetric(
|
||||
horizontal: 8),
|
||||
child: Text(
|
||||
l10n.n_chapters(
|
||||
chapters.length),
|
||||
widget.manga!.isManga!
|
||||
? l10n.n_chapters(
|
||||
chapters.length)
|
||||
: l10n.n_episodes(
|
||||
chapters.length),
|
||||
style: const TextStyle(
|
||||
fontWeight:
|
||||
FontWeight.bold),
|
||||
|
|
@ -1199,7 +1205,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Text(
|
||||
l10n.n_chapters(chapterLength),
|
||||
widget.manga!.isManga!
|
||||
? l10n.n_chapters(chapterLength)
|
||||
: l10n.n_episodes(chapterLength),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
|
|
@ -1656,13 +1664,14 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
mangaId: widget.manga!.id!,
|
||||
trackPreference: entries[index],
|
||||
trackRes: trackRes.first,
|
||||
)
|
||||
isManga: widget.manga!.isManga!)
|
||||
: TrackListile(
|
||||
text: l10nLocalizations(context)!.add_tracker,
|
||||
onTap: () async {
|
||||
final trackSearch =
|
||||
await trackersSearchraggableMenu(
|
||||
context,
|
||||
isManga: widget.manga!.isManga!,
|
||||
track: Track(
|
||||
status: TrackStatus.planToRead,
|
||||
syncId: entries[index].syncId!,
|
||||
|
|
@ -1670,7 +1679,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
) as TrackSearch?;
|
||||
if (trackSearch != null) {
|
||||
await ref
|
||||
.read(trackStateProvider(track: null)
|
||||
.read(trackStateProvider(
|
||||
track: null,
|
||||
isManga: widget.manga!.isManga!)
|
||||
.notifier)
|
||||
.setTrackSearch(
|
||||
trackSearch,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
return Scaffold(
|
||||
floatingActionButton: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final history = ref.watch(getAllHistoryStreamProvider);
|
||||
final history = ref.watch(
|
||||
getAllHistoryStreamProvider(isManga: widget.manga.isManga!));
|
||||
final chaptersList = ref.watch(chaptersListttStateProvider);
|
||||
final isExtended = ref.watch(isExtendedStateProvider);
|
||||
return ref.watch(isLongPressedStateProvider) == true
|
||||
|
|
@ -161,8 +162,12 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
elevation: 0),
|
||||
onPressed: () {
|
||||
final checkCategoryList =
|
||||
isar.categorys.filter().idIsNotNull().isNotEmptySync();
|
||||
final checkCategoryList = isar.categorys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.forMangaEqualTo(widget.manga.isManga)
|
||||
.isNotEmptySync();
|
||||
if (checkCategoryList) {
|
||||
_openCategory(widget.manga);
|
||||
} else {
|
||||
|
|
@ -219,6 +224,8 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
stream: isar.categorys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.forMangaEqualTo(widget.manga.isManga)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
|
||||
|
|
@ -255,7 +262,8 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.push("/categories");
|
||||
context.push("/categories",
|
||||
extra: (true, widget.manga.isManga! ? 0 : 1));
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(l10n.edit)),
|
||||
|
|
|
|||
|
|
@ -193,4 +193,5 @@ class GetChaptersStreamProvider
|
|||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -9,20 +9,34 @@ part 'track_state_providers.g.dart';
|
|||
@riverpod
|
||||
class TrackState extends _$TrackState {
|
||||
@override
|
||||
Track build({Track? track}) {
|
||||
Track build({Track? track, required bool? isManga}) {
|
||||
return track!;
|
||||
}
|
||||
|
||||
Future updateManga() async {
|
||||
Track? updateTrack;
|
||||
if (track!.syncId == 1) {
|
||||
updateTrack = await ref
|
||||
.read(myAnimeListProvider(syncId: track!.syncId!).notifier)
|
||||
.updateManga(track!);
|
||||
updateTrack = isManga!
|
||||
? await ref
|
||||
.read(
|
||||
myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.updateManga(track!)
|
||||
: await ref
|
||||
.read(
|
||||
myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.updateAnime(track!);
|
||||
} else if (track!.syncId == 2) {
|
||||
updateTrack = await ref
|
||||
.read(anilistProvider(syncId: track!.syncId!).notifier)
|
||||
.updateLibManga(track!);
|
||||
updateTrack = isManga!
|
||||
? await ref
|
||||
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.updateLibManga(track!)
|
||||
: await ref
|
||||
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.updateLibAnime(track!);
|
||||
}
|
||||
|
||||
ref
|
||||
|
|
@ -36,7 +50,8 @@ class TrackState extends _$TrackState {
|
|||
maxValue = 10;
|
||||
} else if (track!.syncId == 2) {
|
||||
maxValue = ref
|
||||
.read(anilistProvider(syncId: track!.syncId!).notifier)
|
||||
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.getScoreValue()
|
||||
.$1;
|
||||
}
|
||||
|
|
@ -47,7 +62,7 @@ class TrackState extends _$TrackState {
|
|||
if (track!.syncId == 1) {
|
||||
} else {
|
||||
numberText = ref
|
||||
.read(anilistProvider(syncId: 2).notifier)
|
||||
.read(anilistProvider(syncId: 2, isManga: isManga).notifier)
|
||||
.displayScore(int.parse(numberText));
|
||||
}
|
||||
return numberText;
|
||||
|
|
@ -59,7 +74,8 @@ class TrackState extends _$TrackState {
|
|||
step = 1;
|
||||
} else if (track!.syncId == 2) {
|
||||
step = ref
|
||||
.read(anilistProvider(syncId: track!.syncId!).notifier)
|
||||
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.getScoreValue()
|
||||
.$2;
|
||||
}
|
||||
|
|
@ -71,8 +87,9 @@ class TrackState extends _$TrackState {
|
|||
if (track!.syncId == 1) {
|
||||
result = score.toString();
|
||||
} else {
|
||||
result =
|
||||
ref.read(anilistProvider(syncId: 2).notifier).displayScore(score);
|
||||
result = ref
|
||||
.read(anilistProvider(syncId: 2, isManga: isManga).notifier)
|
||||
.displayScore(score);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -94,19 +111,35 @@ class TrackState extends _$TrackState {
|
|||
finishedReadingDate: 0);
|
||||
if (syncId == 1) {
|
||||
findManga = await ref
|
||||
.read(myAnimeListProvider(syncId: syncId).notifier)
|
||||
.read(myAnimeListProvider(syncId: syncId, isManga: isManga).notifier)
|
||||
.findManga(track);
|
||||
} else if (syncId == 2) {
|
||||
findManga = findManga = await ref
|
||||
.read(anilistProvider(syncId: syncId).notifier)
|
||||
.findLibManga(track);
|
||||
findManga = isManga!
|
||||
? await ref
|
||||
.read(anilistProvider(syncId: syncId, isManga: isManga).notifier)
|
||||
.findLibManga(track)
|
||||
: await ref
|
||||
.read(anilistProvider(syncId: syncId, isManga: isManga).notifier)
|
||||
.findLibAnime(track);
|
||||
if (findManga == null) {
|
||||
await ref
|
||||
.read(anilistProvider(syncId: syncId).notifier)
|
||||
.addLibManga(track);
|
||||
findManga = await ref
|
||||
.read(anilistProvider(syncId: syncId).notifier)
|
||||
.findLibManga(track);
|
||||
findManga = isManga!
|
||||
? await ref
|
||||
.read(
|
||||
anilistProvider(syncId: syncId, isManga: isManga).notifier)
|
||||
.addLibManga(track)
|
||||
: await ref
|
||||
.read(
|
||||
anilistProvider(syncId: syncId, isManga: isManga).notifier)
|
||||
.addLibAnime(track);
|
||||
findManga = isManga!
|
||||
? await ref
|
||||
.read(
|
||||
anilistProvider(syncId: syncId, isManga: isManga).notifier)
|
||||
.findLibManga(track)
|
||||
: await ref
|
||||
.read(
|
||||
anilistProvider(syncId: syncId, isManga: isManga).notifier)
|
||||
.findLibAnime(track);
|
||||
}
|
||||
}
|
||||
ref
|
||||
|
|
@ -118,13 +151,27 @@ class TrackState extends _$TrackState {
|
|||
List<TrackStatus> statusList = [];
|
||||
List<TrackStatus> list = [];
|
||||
if (track!.syncId == 1) {
|
||||
statusList = ref
|
||||
.read(myAnimeListProvider(syncId: track!.syncId!).notifier)
|
||||
.myAnimeListStatusList;
|
||||
statusList = isManga!
|
||||
? ref
|
||||
.read(
|
||||
myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.myAnimeListStatusListManga
|
||||
: ref
|
||||
.read(
|
||||
myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.myAnimeListStatusListAnime;
|
||||
} else if (track!.syncId == 2) {
|
||||
statusList = ref
|
||||
.read(anilistProvider(syncId: track!.syncId!).notifier)
|
||||
.aniListStatusList;
|
||||
statusList = isManga!
|
||||
? ref
|
||||
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.aniListStatusListManga
|
||||
: ref
|
||||
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.aniListStatusListAnime;
|
||||
}
|
||||
for (var element in TrackStatus.values) {
|
||||
if (statusList.contains(element)) {
|
||||
|
|
@ -138,12 +185,19 @@ class TrackState extends _$TrackState {
|
|||
Track? findManga;
|
||||
if (track!.syncId == 1) {
|
||||
findManga = await ref
|
||||
.read(myAnimeListProvider(syncId: track!.syncId!).notifier)
|
||||
.read(myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.findManga(track!);
|
||||
} else if (track!.syncId == 2) {
|
||||
findManga = findManga = await ref
|
||||
.read(anilistProvider(syncId: track!.syncId!).notifier)
|
||||
.findLibManga(track!);
|
||||
findManga = isManga!
|
||||
? await ref
|
||||
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.findLibManga(track!)
|
||||
: await ref
|
||||
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.findLibAnime(track!);
|
||||
}
|
||||
return findManga;
|
||||
}
|
||||
|
|
@ -152,12 +206,19 @@ class TrackState extends _$TrackState {
|
|||
List<TrackSearch>? tracks;
|
||||
if (track!.syncId == 1) {
|
||||
tracks = await ref
|
||||
.read(myAnimeListProvider(syncId: track!.syncId!).notifier)
|
||||
.read(myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.search(query);
|
||||
} else if (track!.syncId == 2) {
|
||||
tracks = await ref
|
||||
.read(anilistProvider(syncId: track!.syncId!).notifier)
|
||||
.search(query);
|
||||
tracks = isManga!
|
||||
? await ref
|
||||
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.search(query)
|
||||
: await ref
|
||||
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
|
||||
.notifier)
|
||||
.searchAnime(query);
|
||||
}
|
||||
return tracks;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'track_state_providers.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$trackStateHash() => r'7004528230213b458c7db417947eecfc700d44d7';
|
||||
String _$trackStateHash() => r'eeca421125ff52ccf671d434c41e0198bb7b6fea';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -31,9 +31,11 @@ class _SystemHash {
|
|||
|
||||
abstract class _$TrackState extends BuildlessAutoDisposeNotifier<Track> {
|
||||
late final Track? track;
|
||||
late final bool? isManga;
|
||||
|
||||
Track build({
|
||||
Track? track,
|
||||
required bool? isManga,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -49,9 +51,11 @@ class TrackStateFamily extends Family<Track> {
|
|||
/// See also [TrackState].
|
||||
TrackStateProvider call({
|
||||
Track? track,
|
||||
required bool? isManga,
|
||||
}) {
|
||||
return TrackStateProvider(
|
||||
track: track,
|
||||
isManga: isManga,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +65,7 @@ class TrackStateFamily extends Family<Track> {
|
|||
) {
|
||||
return call(
|
||||
track: provider.track,
|
||||
isManga: provider.isManga,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -85,8 +90,11 @@ class TrackStateProvider
|
|||
/// See also [TrackState].
|
||||
TrackStateProvider({
|
||||
this.track,
|
||||
required this.isManga,
|
||||
}) : super.internal(
|
||||
() => TrackState()..track = track,
|
||||
() => TrackState()
|
||||
..track = track
|
||||
..isManga = isManga,
|
||||
from: trackStateProvider,
|
||||
name: r'trackStateProvider',
|
||||
debugGetCreateSourceHash:
|
||||
|
|
@ -99,16 +107,20 @@ class TrackStateProvider
|
|||
);
|
||||
|
||||
final Track? track;
|
||||
final bool? isManga;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is TrackStateProvider && other.track == track;
|
||||
return other is TrackStateProvider &&
|
||||
other.track == track &&
|
||||
other.isManga == isManga;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, track.hashCode);
|
||||
hash = _SystemHash.combine(hash, isManga.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
|
@ -119,7 +131,9 @@ class TrackStateProvider
|
|||
) {
|
||||
return notifier.build(
|
||||
track: track,
|
||||
isManga: isManga,
|
||||
);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
|
|||
dateFormatLocale: source.dateFormatLocale);
|
||||
final getManga = await ref
|
||||
.watch(getMangaDetailProvider(manga: mangaS, source: source).future);
|
||||
|
||||
final imageUrl = getManga.imageUrl != null && getManga.imageUrl!.isNotEmpty
|
||||
? getManga.imageUrl
|
||||
: manga.imageUrl ?? "";
|
||||
|
|
@ -39,6 +40,7 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
|
|||
.toSet()
|
||||
.toList()
|
||||
: manga.genre ?? [];
|
||||
|
||||
final author = getManga.author != null && getManga.author!.isNotEmpty
|
||||
? getManga.author!.trim().trimLeft().trimRight()
|
||||
: manga.author ?? "";
|
||||
|
|
@ -72,6 +74,7 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
|
|||
..link = link
|
||||
..source = sourceA
|
||||
..lang = lang
|
||||
..isManga = source.isManga
|
||||
..lastUpdate = DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
|
|
@ -99,7 +102,9 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
|
|||
final chapters = Chapter(
|
||||
name: title,
|
||||
url: getManga.urls![i].trim().trimLeft().trimRight(),
|
||||
dateUpload: getManga.chaptersDateUploads![i],
|
||||
dateUpload: getManga.chaptersDateUploads!.isEmpty
|
||||
? null
|
||||
: getManga.chaptersDateUploads![i],
|
||||
scanlator: scanlator,
|
||||
)..manga.value = manga;
|
||||
isar.chapters.putSync(chapters);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'update_manga_detail_providers.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$updateMangaDetailHash() => r'7c8e4cae20be71b2cab42f7d784888fb4037aa00';
|
||||
String _$updateMangaDetailHash() => r'143fc36898ba2d83ee6d42d71b01077ce33dcb19';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -118,4 +118,5 @@ class UpdateMangaDetailProvider extends AutoDisposeFutureProvider<dynamic> {
|
|||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/services/anime_servers/gogo_cdn_extractor.dart';
|
||||
import 'package:mangayomi/utils/date.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
|
||||
import 'package:mangayomi/utils/colors.dart';
|
||||
|
|
@ -74,7 +75,12 @@ class ChapterListTileWidget extends ConsumerWidget {
|
|||
children: [
|
||||
if ((chapter.manga.value!.isLocalArchive ?? false) == false)
|
||||
Text(
|
||||
dateFormat(chapter.dateUpload!, ref: ref, context: context),
|
||||
dateFormat(
|
||||
!chapter.manga.value!.isManga!
|
||||
? DateTime.now().millisecondsSinceEpoch.toString()
|
||||
: chapter.dateUpload!,
|
||||
ref: ref,
|
||||
context: context),
|
||||
style: const TextStyle(fontSize: 11),
|
||||
),
|
||||
if (!chapter.isRead!)
|
||||
|
|
@ -84,7 +90,13 @@ class ChapterListTileWidget extends ConsumerWidget {
|
|||
children: [
|
||||
const Text(' • '),
|
||||
Text(
|
||||
l10n.page(chapter.lastPageRead!),
|
||||
!chapter.manga.value!.isManga!
|
||||
? l10n.episode_progress(Duration(
|
||||
milliseconds:
|
||||
int.parse(chapter.lastPageRead!))
|
||||
.toString()
|
||||
.substringBefore("."))
|
||||
: l10n.page(chapter.lastPageRead!),
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: isLight(context)
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@ import 'package:mangayomi/utils/colors.dart';
|
|||
import 'package:mangayomi/utils/media_query.dart';
|
||||
|
||||
class TrackerWidgetSearch extends ConsumerStatefulWidget {
|
||||
final bool isManga;
|
||||
final Track track;
|
||||
const TrackerWidgetSearch({required this.track, super.key});
|
||||
const TrackerWidgetSearch(
|
||||
{required this.isManga, required this.track, super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<TrackerWidgetSearch> createState() =>
|
||||
|
|
@ -30,7 +32,8 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
|
|||
_init() async {
|
||||
await Future.delayed(const Duration(microseconds: 100));
|
||||
tracks = await ref
|
||||
.read(trackStateProvider(track: widget.track).notifier)
|
||||
.read(trackStateProvider(track: widget.track, isManga: widget.isManga)
|
||||
.notifier)
|
||||
.search(query);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
|
|
@ -169,7 +172,9 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
|
|||
_isLoading = true;
|
||||
});
|
||||
tracks = await ref
|
||||
.read(trackStateProvider(track: widget.track)
|
||||
.read(trackStateProvider(
|
||||
track: widget.track,
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.search(d.trim());
|
||||
if (mounted) {
|
||||
|
|
@ -210,7 +215,8 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
|
|||
}
|
||||
}
|
||||
|
||||
trackersSearchraggableMenu(BuildContext context, {required Track track}) async {
|
||||
trackersSearchraggableMenu(BuildContext context,
|
||||
{required Track track, required bool isManga}) async {
|
||||
return await DraggableMenu.open(
|
||||
context,
|
||||
DraggableMenu(
|
||||
|
|
@ -240,5 +246,6 @@ trackersSearchraggableMenu(BuildContext context, {required Track track}) async {
|
|||
maxHeight: mediaHeight(context, 0.9),
|
||||
child: TrackerWidgetSearch(
|
||||
track: track,
|
||||
isManga: isManga,
|
||||
)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,11 +15,13 @@ import 'package:mangayomi/utils/utils.dart';
|
|||
import 'package:numberpicker/numberpicker.dart';
|
||||
|
||||
class TrackerWidget extends ConsumerStatefulWidget {
|
||||
final bool isManga;
|
||||
final Track trackRes;
|
||||
final int mangaId;
|
||||
final TrackPreference trackPreference;
|
||||
const TrackerWidget(
|
||||
{super.key,
|
||||
required this.isManga,
|
||||
required this.trackPreference,
|
||||
required this.trackRes,
|
||||
required this.mangaId});
|
||||
|
|
@ -38,7 +40,9 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
|
|||
_init() async {
|
||||
await Future.delayed(const Duration(microseconds: 100));
|
||||
final findManga = await ref
|
||||
.read(trackStateProvider(track: widget.trackRes).notifier)
|
||||
.read(
|
||||
trackStateProvider(track: widget.trackRes, isManga: widget.isManga)
|
||||
.notifier)
|
||||
.findManga();
|
||||
if (mounted) {
|
||||
ref
|
||||
|
|
@ -83,10 +87,13 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
|
|||
onPressed: () async {
|
||||
final trackSearch = await trackersSearchraggableMenu(
|
||||
context,
|
||||
isManga: widget.isManga,
|
||||
track: widget.trackRes) as TrackSearch?;
|
||||
if (trackSearch != null) {
|
||||
await ref
|
||||
.read(trackStateProvider(track: null).notifier)
|
||||
.read(trackStateProvider(
|
||||
track: null, isManga: widget.isManga)
|
||||
.notifier)
|
||||
.setTrackSearch(trackSearch, widget.mangaId,
|
||||
widget.trackPreference.syncId!);
|
||||
}
|
||||
|
|
@ -142,26 +149,33 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
|
|||
shrinkWrap: true,
|
||||
itemCount: ref
|
||||
.read(trackStateProvider(
|
||||
track: widget.trackRes)
|
||||
track: widget.trackRes,
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.getStatusList()
|
||||
.length,
|
||||
itemBuilder: (context, index) {
|
||||
final status = ref
|
||||
.read(trackStateProvider(
|
||||
track: widget.trackRes)
|
||||
track: widget.trackRes,
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.getStatusList()[index];
|
||||
print(status);
|
||||
return RadioListTile(
|
||||
dense: true,
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
value: status,
|
||||
groupValue: widget.trackRes.status,
|
||||
groupValue: toStatus(
|
||||
widget.trackRes.status,
|
||||
widget.isManga,
|
||||
widget.trackRes.syncId!),
|
||||
onChanged: (value) {
|
||||
ref
|
||||
.read(trackStateProvider(
|
||||
track: widget.trackRes
|
||||
..status = status)
|
||||
..status = status,
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.updateManga();
|
||||
Navigator.pop(context);
|
||||
|
|
@ -189,7 +203,11 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
|
|||
],
|
||||
);
|
||||
});
|
||||
}, text: getTrackStatus(widget.trackRes.status, context)),
|
||||
},
|
||||
text: getTrackStatus(
|
||||
toStatus(widget.trackRes.status, widget.isManga,
|
||||
widget.trackRes.syncId!),
|
||||
context)),
|
||||
),
|
||||
Expanded(
|
||||
child: _elevatedButton(context, onPressed: () {
|
||||
|
|
@ -241,7 +259,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
|
|||
.read(trackStateProvider(
|
||||
track: widget.trackRes
|
||||
..lastChapterRead =
|
||||
currentIntValue)
|
||||
currentIntValue,
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.updateManga();
|
||||
Navigator.pop(context);
|
||||
|
|
@ -282,19 +301,22 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
|
|||
minValue: 0,
|
||||
maxValue: ref
|
||||
.read(trackStateProvider(
|
||||
track: widget.trackRes)
|
||||
track: widget.trackRes,
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.getScoreMaxValue(),
|
||||
textMapper: (numberText) {
|
||||
return ref
|
||||
.read(trackStateProvider(
|
||||
track: widget.trackRes)
|
||||
track: widget.trackRes,
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.getTextMapper(numberText);
|
||||
},
|
||||
step: ref
|
||||
.read(trackStateProvider(
|
||||
track: widget.trackRes)
|
||||
track: widget.trackRes,
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.getScoreStep(),
|
||||
haptics: true,
|
||||
|
|
@ -323,7 +345,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
|
|||
ref
|
||||
.read(trackStateProvider(
|
||||
track: widget.trackRes
|
||||
..score = currentIntValue)
|
||||
..score = currentIntValue,
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.updateManga();
|
||||
Navigator.pop(context);
|
||||
|
|
@ -341,7 +364,9 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
|
|||
},
|
||||
text: widget.trackRes.score != 0
|
||||
? ref
|
||||
.read(trackStateProvider(track: widget.trackRes)
|
||||
.read(trackStateProvider(
|
||||
track: widget.trackRes,
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.displayScore(widget.trackRes.score!)
|
||||
: l10n!.score),
|
||||
|
|
@ -366,7 +391,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
|
|||
.read(trackStateProvider(
|
||||
track: widget.trackRes
|
||||
..startedReadingDate =
|
||||
newDate.millisecondsSinceEpoch)
|
||||
newDate.millisecondsSinceEpoch,
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.updateManga();
|
||||
},
|
||||
|
|
@ -396,7 +422,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
|
|||
.read(trackStateProvider(
|
||||
track: widget.trackRes
|
||||
..finishedReadingDate =
|
||||
newDate.millisecondsSinceEpoch)
|
||||
newDate.millisecondsSinceEpoch,
|
||||
isManga: widget.isManga)
|
||||
.notifier)
|
||||
.updateManga();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -134,4 +134,5 @@ class ConvertToCBZProvider extends AutoDisposeFutureProvider<List<String>> {
|
|||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member
|
||||
|
|
|
|||
|
|
@ -29,8 +29,7 @@ Future<List<String>> downloadChapter(
|
|||
bool onlyOnWifi = useWifi ?? ref.watch(onlyOnWifiStateProvider);
|
||||
Directory? path;
|
||||
final getDownloadLocation = ref.watch(downloadLocationStateProvider).$2;
|
||||
final desktopCustomDownloadLocation =
|
||||
Platform.isWindows && getDownloadLocation.isNotEmpty;
|
||||
final customDownloadLocation = getDownloadLocation.isNotEmpty;
|
||||
bool isOk = false;
|
||||
final manga = chapter.manga.value!;
|
||||
final path1 = await storageProvider.getDirectory();
|
||||
|
|
@ -99,10 +98,9 @@ Future<List<String>> downloadChapter(
|
|||
headersProvider(source: manga.source!, lang: manga.lang!)),
|
||||
url: pageUrls[index].trim().trimLeft().trimRight(),
|
||||
filename: "${padIndex(index + 1)}.jpg",
|
||||
baseDirectory:
|
||||
Platform.isAndroid || desktopCustomDownloadLocation
|
||||
? BaseDirectory.temporary
|
||||
: BaseDirectory.applicationDocuments,
|
||||
baseDirectory: customDownloadLocation
|
||||
? BaseDirectory.temporary
|
||||
: BaseDirectory.applicationDocuments,
|
||||
directory: 'Mangayomi/$finalPath',
|
||||
updates: Updates.statusAndProgress,
|
||||
allowPause: true,
|
||||
|
|
@ -119,10 +117,9 @@ Future<List<String>> downloadChapter(
|
|||
headersProvider(source: manga.source!, lang: manga.lang!)),
|
||||
url: pageUrls[index].trim().trimLeft().trimRight(),
|
||||
filename: "${padIndex(index + 1)}.jpg",
|
||||
baseDirectory:
|
||||
Platform.isAndroid || desktopCustomDownloadLocation
|
||||
? BaseDirectory.temporary
|
||||
: BaseDirectory.applicationDocuments,
|
||||
baseDirectory: customDownloadLocation
|
||||
? BaseDirectory.temporary
|
||||
: BaseDirectory.applicationDocuments,
|
||||
directory: 'Mangayomi/$finalPath',
|
||||
updates: Updates.statusAndProgress,
|
||||
allowPause: true,
|
||||
|
|
@ -188,7 +185,7 @@ Future<List<String>> downloadChapter(
|
|||
},
|
||||
taskProgressCallback: (taskProgress) async {
|
||||
if (taskProgress.progress == 1.0) {
|
||||
if (Platform.isAndroid || desktopCustomDownloadLocation) {
|
||||
if (customDownloadLocation) {
|
||||
await File(
|
||||
"${tempDir.path}/${taskProgress.task.directory}/${taskProgress.task.filename}")
|
||||
.copy("${path!.path}/${taskProgress.task.filename}");
|
||||
|
|
|
|||
|
|
@ -118,4 +118,5 @@ class DownloadChapterProvider extends AutoDisposeFutureProvider<List<String>> {
|
|||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member
|
||||
|
|
|
|||
|
|
@ -390,6 +390,7 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
|
|||
return buildProgressIndicator();
|
||||
}
|
||||
return MangaHomeImageCard(
|
||||
isManga: widget.source.isManga ?? true,
|
||||
manga: data[index]!,
|
||||
source: widget.source,
|
||||
);
|
||||
|
|
@ -409,11 +410,13 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
|
|||
|
||||
class MangaHomeImageCard extends ConsumerStatefulWidget {
|
||||
final MangaModel manga;
|
||||
final bool isManga;
|
||||
final Source source;
|
||||
const MangaHomeImageCard({
|
||||
super.key,
|
||||
required this.manga,
|
||||
required this.source,
|
||||
required this.isManga,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -431,6 +434,7 @@ class _MangaHomeImageCardState extends ConsumerState<MangaHomeImageCard>
|
|||
..lang = widget.source.lang
|
||||
..source = widget.source.name,
|
||||
lang: widget.source.lang!,
|
||||
isManga: widget.isManga,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class SearchResultScreen extends ConsumerWidget {
|
|||
return MangaHomeImageCard(
|
||||
manga: data[index]!,
|
||||
source: source,
|
||||
isManga: source.isManga ?? true,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -86,86 +86,86 @@ class CropBorderClass {
|
|||
|
||||
void _autocropImageIsolate(CropBorderClass cropData) async {
|
||||
Image? croppedImage;
|
||||
Image? image = decodeImage(cropData.image!);
|
||||
final old = image;
|
||||
image = copyCrop(image!, 0, 0, image.width, image.height);
|
||||
// // Image? image = decodeImage(cropData.image!);
|
||||
// // final old = image;
|
||||
// // image = copyCrop(image!, 0, 0, image.width, image.height);
|
||||
|
||||
int left = 0;
|
||||
int top = 0;
|
||||
int right = image.width - 1;
|
||||
int bottom = image.height - 1;
|
||||
// // int left = 0;
|
||||
// // int top = 0;
|
||||
// // int right = image.width - 1;
|
||||
// // int bottom = image.height - 1;
|
||||
|
||||
// Find left coordinate
|
||||
for (int x = 0; x < image.width; x++) {
|
||||
bool stop = false;
|
||||
for (int y = 0; y < image.height; y++) {
|
||||
if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (stop) {
|
||||
left = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// // // Find left coordinate
|
||||
// // for (int x = 0; x < image.width; x++) {
|
||||
// // bool stop = false;
|
||||
// // for (int y = 0; y < image.height; y++) {
|
||||
// // if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
|
||||
// // stop = true;
|
||||
// // break;
|
||||
// // }
|
||||
// // }
|
||||
// // if (stop) {
|
||||
// // left = x;
|
||||
// // break;
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// Find top coordinate
|
||||
for (int y = 0; y < image.height; y++) {
|
||||
bool stop = false;
|
||||
for (int x = 0; x < image.width; x++) {
|
||||
if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (stop) {
|
||||
top = y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// // // Find top coordinate
|
||||
// // for (int y = 0; y < image.height; y++) {
|
||||
// // bool stop = false;
|
||||
// // for (int x = 0; x < image.width; x++) {
|
||||
// // if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
|
||||
// // stop = true;
|
||||
// // break;
|
||||
// // }
|
||||
// // }
|
||||
// // if (stop) {
|
||||
// // top = y;
|
||||
// // break;
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// Find right coordinate
|
||||
for (int x = image.width - 1; x >= 0; x--) {
|
||||
bool stop = false;
|
||||
for (int y = 0; y < image.height; y++) {
|
||||
if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (stop) {
|
||||
right = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// // // Find right coordinate
|
||||
// // for (int x = image.width - 1; x >= 0; x--) {
|
||||
// // bool stop = false;
|
||||
// // for (int y = 0; y < image.height; y++) {
|
||||
// // if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
|
||||
// // stop = true;
|
||||
// // break;
|
||||
// // }
|
||||
// // }
|
||||
// // if (stop) {
|
||||
// // right = x;
|
||||
// // break;
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// Find bottom coordinate
|
||||
for (int y = image.height - 1; y >= 0; y--) {
|
||||
bool stop = false;
|
||||
for (int x = 0; x < image.width; x++) {
|
||||
if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (stop) {
|
||||
bottom = y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// // // Find bottom coordinate
|
||||
// // for (int y = image.height - 1; y >= 0; y--) {
|
||||
// // bool stop = false;
|
||||
// // for (int x = 0; x < image.width; x++) {
|
||||
// // if (image.getPixel(x, y) != getColor(255, 255, 255, 255)) {
|
||||
// // stop = true;
|
||||
// // break;
|
||||
// // }
|
||||
// // }
|
||||
// // if (stop) {
|
||||
// // bottom = y;
|
||||
// // break;
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// Crop the image
|
||||
croppedImage = copyCrop(
|
||||
image,
|
||||
left,
|
||||
top,
|
||||
right - left + 1,
|
||||
bottom - top + 1,
|
||||
);
|
||||
if (old != croppedImage) {
|
||||
cropData.sendPort.send(encodeJpg(croppedImage) as Uint8List);
|
||||
} else {
|
||||
cropData.sendPort.send(null);
|
||||
}
|
||||
// // // Crop the image
|
||||
// // croppedImage = copyCrop(
|
||||
// // image,
|
||||
// // left,
|
||||
// // top,
|
||||
// // right - left + 1,
|
||||
// // bottom - top + 1,
|
||||
// // );
|
||||
// if (old != croppedImage) {
|
||||
// cropData.sendPort.send(encodeJpg(croppedImage) as Uint8List);
|
||||
// } else {
|
||||
// cropData.sendPort.send(null);
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,4 +135,5 @@ class AutoCropBorderProvider
|
|||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member
|
||||
|
|
|
|||
|
|
@ -6,7 +6,14 @@ pushMangaReaderView({
|
|||
required BuildContext context,
|
||||
required Chapter chapter,
|
||||
}) {
|
||||
context.push('/mangareaderview', extra: chapter);
|
||||
print(chapter.manga.value!.isManga!);
|
||||
if (chapter.manga.value!.isManga!) {
|
||||
print("aaz");
|
||||
context.pushReplacement('/mangareaderview', extra: chapter);
|
||||
} else {
|
||||
print("object");
|
||||
context.push('/animestreamview', extra: chapter);
|
||||
}
|
||||
}
|
||||
|
||||
pushReplacementMangaReaderView({
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -2,28 +2,82 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/category.dart';
|
||||
import 'package:mangayomi/modules/more/categoties/providers/isar_providers.dart';
|
||||
import 'package:mangayomi/modules/more/categoties/widgets/custom_textfield.dart';
|
||||
import 'package:mangayomi/modules/more/categories/providers/isar_providers.dart';
|
||||
import 'package:mangayomi/modules/more/categories/widgets/custom_textfield.dart';
|
||||
import 'package:mangayomi/modules/widgets/progress_center.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
|
||||
class CategoriesScreen extends ConsumerStatefulWidget {
|
||||
const CategoriesScreen({super.key});
|
||||
final (bool, int) data;
|
||||
const CategoriesScreen({required this.data, super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<CategoriesScreen> createState() => _CategoriesScreenState();
|
||||
}
|
||||
|
||||
class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
||||
class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
|
||||
with TickerProviderStateMixin {
|
||||
late TabController _tabBarController;
|
||||
@override
|
||||
void initState() {
|
||||
_tabBarController = TabController(length: 2, vsync: this);
|
||||
_tabBarController.animateTo(widget.data.$2);
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return DefaultTabController(
|
||||
animationDuration: Duration.zero,
|
||||
length: 2,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
title: Text(
|
||||
widget.data.$1 ? l10n.edit_categories : l10n.categories,
|
||||
style: TextStyle(color: Theme.of(context).hintColor),
|
||||
),
|
||||
bottom: TabBar(
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
controller: _tabBarController,
|
||||
tabs: [
|
||||
Tab(text: l10n.manga),
|
||||
Tab(text: l10n.anime),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: TabBarView(controller: _tabBarController, children: const [
|
||||
CategoriesTab(
|
||||
isManga: true,
|
||||
),
|
||||
CategoriesTab(
|
||||
isManga: false,
|
||||
)
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CategoriesTab extends ConsumerStatefulWidget {
|
||||
final bool isManga;
|
||||
const CategoriesTab({required this.isManga, super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<CategoriesTab> createState() => _CategoriesTabState();
|
||||
}
|
||||
|
||||
class _CategoriesTabState extends ConsumerState<CategoriesTab> {
|
||||
List<Category> _entries = [];
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = l10nLocalizations(context);
|
||||
final categories = ref.watch(getMangaCategorieStreamProvider);
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
final categories =
|
||||
ref.watch(getMangaCategorieStreamProvider(isManga: widget.isManga));
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(l10n!.edit_categories),
|
||||
),
|
||||
body: categories.when(
|
||||
data: (data) {
|
||||
if (data.isEmpty) {
|
||||
|
|
@ -215,6 +269,7 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
|||
: () async {
|
||||
await isar.writeTxn(() async {
|
||||
await isar.categorys.put(Category(
|
||||
forManga: widget.isManga,
|
||||
name: controller.text,
|
||||
));
|
||||
});
|
||||
|
|
@ -5,11 +5,12 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|||
part 'isar_providers.g.dart';
|
||||
|
||||
@riverpod
|
||||
Stream<List<Category>> getMangaCategorieStream(
|
||||
GetMangaCategorieStreamRef ref,
|
||||
) async* {
|
||||
Stream<List<Category>> getMangaCategorieStream(GetMangaCategorieStreamRef ref,
|
||||
{required bool isManga}) async* {
|
||||
yield* isar.categorys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.forMangaEqualTo(isManga)
|
||||
.watch(fireImmediately: true);
|
||||
}
|
||||