diff --git a/epubx/.gitignore b/epubx/.gitignore new file mode 100644 index 00000000..8aa52235 --- /dev/null +++ b/epubx/.gitignore @@ -0,0 +1,31 @@ +# See https://www.dartlang.org/tools/private-files.html + +# Files and directories created by pub +.buildlog +.packages +.project +.pub/ +build/ +**/packages/ +.dart_tool/ + +# Files created by dart2js +# (Most Dart developers will use pub build to compile Dart, use/modify these +# rules if you intend to use dart2js directly +# Convention is to use extension '.dart.js' for Dart compiled to Javascript to +# differentiate from explicit Javascript files) +*.dart.js +*.part.js +*.js.deps +*.js.map +*.info.json + +# Directory created by dartdoc +doc/api/ + +# Don't commit pubspec lock file +# (Library packages only! Remove pattern if developing an application package) +pubspec.lock + +#Ignore VSCode Directory +.vscode/ diff --git a/epubx/.travis.yml b/epubx/.travis.yml new file mode 100644 index 00000000..03f0c4c3 --- /dev/null +++ b/epubx/.travis.yml @@ -0,0 +1,16 @@ +language: dart +dart: + - stable +sudo: false +before_script: + - chmod +x ./tool/travis.sh + - chmod +x ./tool/publish.sh + - pub get +script: ./tool/travis.sh +deploy: + provider: script + script: ./tool/publish.sh + skip_cleanup: true + on: + branch: master + dart: stable \ No newline at end of file diff --git a/epubx/CHANGELOG.md b/epubx/CHANGELOG.md new file mode 100644 index 00000000..63c3d9a1 --- /dev/null +++ b/epubx/CHANGELOG.md @@ -0,0 +1,148 @@ +## 4.0.0 + +- Merge all pull requests + +## 3.0.0 +### Changed +- `metadata` file now saves as `mimetype` [pull#1](https://github.com/rbcprolabs/epubx.dart/pull/1) +### Added +- Epub v3 support [dart-epub | pull#76](https://github.com/orthros/dart-epub/pull/76) +- Doc comment [dart-epub | pull#80](https://github.com/orthros/dart-epub/pull/80) + +## 3.0.0-dev.3 +### Changed +- At `EpubReader.{openBook, readBook}` first argument can be future (not before) + +## 3.0.0-dev.2 +### Fixed +- Fixed null-safety bug + +## 3.0.0-dev.1 +### Added +- Null-safety migration +### Changed +- Upgrade all dependencies + +## 2.1.0 +### Fixed +- Version 3 EPUB's can have a null Table of Contents +- Updated `pedantic` analysis options + +## 2.0.7 +### Added +- Added example of using `epub` in a web page: `examples/web_ex` +### Fixed +- Fixed errors from pedantic analysis +### Changed +- Added pedantic analysis options + +## 2.0.6 +### Fixed +- Fixed Issue #35: File cannot be opened if its path is url-encoded in the manifest +- Updated `examples/dart_ex` to have a README as well as use a locally stored file. + +## 2.0.5 +### Changed +- Exposed `EpubChapterRef` to consumers. + +## 2.0.4 +### Fixed +- Merged pull request #45 + - Fixes pana hits to make code more readable + +## 2.0.3 +### Changed +- Raised `sdk` version constraint to 2.0.0 +- Raised constraint on `async` to 3.0.0 +### Fixed +- Merged pull request #40 by vblago. + - Fixes Undefined class 'XmlBuilder' + +## 2.0.2 +### Changed +- Lowered sdk version constraint to 2.0.0-dev.61.0 + +## 2.0.1 +### Changed +- Formatted documents + +## 2.0.0 +### Added +- Added support for writing Epubs back to Byte Arrays +- Tests for writing Epubs + +### Changed +- Epub Readers and Writers now have their == operator and hashCode get-er overridden + +### Fixed +- Fixed an issue when reading EpubContentFileRef + +## 1.3.2 +### Changed +- Updates to Travis configuration and publishing + +## 1.3.1 +### Changed +- Updates to Travis configuration and publishing +### Removed +- Removed unused variable `FilePath` from `EpubBook` and `EpubBookRef` + +## 1.3.0 +### Added +- Package now supports Dart 2! +### Removed +- Removed support for Dart 1.2.21 + +## 1.2.10 +### Fixed +- Merged pull request #15 from ShadowJonathan/dev. + - Fixes issue with parsing schema by removing `opf:` namespace + +## 1.2.9 +### Changed +- Ran code through `dartfmt` as per analysis by `pana` + +## 1.2.8 +### Added +- Added unit tests for Images +### Changed +- Updated dependencies + +## 1.2.7 +### Added +- Added upper limit of Dart version to 2.0.1 + +## 1.2.6 +### Added +- Added Support for Dart 2.0 + +## 1.2.5 +### Added +- A publish step in the travis deploy + +## 1.2.4 +### Changed +- EnumFromString no longer uses the `mirrors` package to make this Flutter compatible by @MostafaAyesh + +## 1.2.3 +### Added +- This Changelog! + +### Changed +- Author email + +## 1.2.2 +### Changed +- Dependencies were updated to more permissive versions by @jarontai + +### Added +- Example by @jarontai +- More Entities and types are exported by @jarontai + +### Fixed +- Issue with case sensitivity in switch statements from @jarontai +- Issue with Async Loops from @jarontai + +## 1.2.1 +### Fixed +- Made code in line with Dart styleguide diff --git a/epubx/CODE_OF_CONDUCT.md b/epubx/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..71f7a430 --- /dev/null +++ b/epubx/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at colin@ifdevthentalk.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/epubx/LICENSE b/epubx/LICENSE new file mode 100644 index 00000000..d9ec56f2 --- /dev/null +++ b/epubx/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Colin Nelson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/epubx/README.md b/epubx/README.md new file mode 100644 index 00000000..42fc9053 --- /dev/null +++ b/epubx/README.md @@ -0,0 +1,134 @@ +# epubx + +It package is [dart-epub](https://github.com/orthros/dart-epub) fork + +[Flutter UI implementation](https://pub.dev/packages/epub_view) + +Epub Reader and Writer for Dart inspired by [this fantastic C# Epub Reader](https://github.com/versfx/EpubReader) + +This does not rely on the ```dart:io``` package in any way, so it is avilable for both desktop and web-based implementations + +[![pub package](https://img.shields.io/pub/v/epubx.svg)](https://pub.dartlang.org/packages/epubx) +## Installing +Add the package to the ```dependencies``` section of your pubspec.yaml +``` +dependencies: + epubx: any +``` + +## Example +```dart + +//Get the epub into memory somehow +String fileName = 'sample.epub'; +String fullPath = path.join(io.Directory.current.path, fileName); +var targetFile = new io.File(fullPath); +List bytes = await targetFile.readAsBytes(); + + +// Opens a book and reads all of its content into memory +EpubBook epubBook = await EpubReader.readBook(bytes); + +// COMMON PROPERTIES + +// Book's title +String title = epubBook.Title; + +// Book's authors (comma separated list) +String author = epubBook.Author; + +// Book's authors (list of authors names) +List authors = epubBook.AuthorList; + +// Book's cover image (null if there is no cover) +Image coverImage = epubBook.CoverImage; + + +// CHAPTERS + +// Enumerating chapters +epubBook.Chapters.forEach((EpubChapter chapter) { + // Title of chapter + String chapterTitle = chapter.Title; + + // HTML content of current chapter + String chapterHtmlContent = chapter.HtmlContent; + + // Nested chapters + List subChapters = chapter.SubChapters; +}); + + +// CONTENT + +// Book's content (HTML files, stylesheets, images, fonts, etc.) +EpubContent bookContent = epubBook.Content; + + +// IMAGES + +// All images in the book (file name is the key) +Map images = bookContent.Images; + +EpubByteContentFile firstImage = images.values.first; + +// Content type (e.g. EpubContentType.IMAGE_JPEG, EpubContentType.IMAGE_PNG) +EpubContentType contentType = firstImage.ContentType; + +// MIME type (e.g. "image/jpeg", "image/png") +String mimeContentType = firstImage.ContentMimeType; + +// HTML & CSS + +// All XHTML files in the book (file name is the key) +Map htmlFiles = bookContent.Html; + +// All CSS files in the book (file name is the key) +Map cssFiles = bookContent.Css; + +// Entire HTML content of the book +htmlFiles.values.forEach((EpubTextContentFile htmlFile) { + String htmlContent = htmlFile.Content; +}); + +// All CSS content in the book +cssFiles.values.forEach((EpubTextContentFile cssFile){ + String cssContent = cssFile.Content; +}); + + +// OTHER CONTENT + +// All fonts in the book (file name is the key) +Map fonts = bookContent.Fonts; + +// All files in the book (including HTML, CSS, images, fonts, and other types of files) +Map allFiles = bookContent.AllFiles; + + +// ACCESSING RAW SCHEMA INFORMATION + +// EPUB OPF data +EpubPackage package = epubBook.Schema.Package; + +// Enumerating book's contributors +package.Metadata.Contributors.forEach((EpubMetadataContributor contributor){ + String contributorName = contributor.Contributor; + String contributorRole = contributor.Role; +}); + +// EPUB NCX data +EpubNavigation navigation = epubBook.Schema.Navigation; + +// Enumerating NCX metadata +navigation.Head.Metadata.forEach((EpubNavigationHeadMeta meta){ + String metadataItemName = meta.Name; + String metadataItemContent = meta.Content; +}); + +// Writing Data +var written = await EpubWriter.writeBook(epubBook); + +// You can even re-read the book into a new object! +var bookRoundTrip = await EpubReader.readBook(written); +``` \ No newline at end of file diff --git a/epubx/analysis_options.yaml b/epubx/analysis_options.yaml new file mode 100644 index 00000000..1728f8db --- /dev/null +++ b/epubx/analysis_options.yaml @@ -0,0 +1,15 @@ +# Defines a default set of lint rules enforced for +# projects at Google. For details and rationale, +# see https://github.com/dart-lang/pedantic#enabled-lints. +include: package:pedantic/analysis_options.yaml + +# For lint rules and documentation, see http://dart-lang.github.io/linter/lints. +# Uncomment to specify additional rules. +# linter: +# rules: +# - camel_case_types + +analyzer: + exclude: + - example/** + - test/** diff --git a/epubx/example/README.md b/epubx/example/README.md new file mode 100644 index 00000000..160c373e --- /dev/null +++ b/epubx/example/README.md @@ -0,0 +1,9 @@ +# Examples + +## dart_ex + +This example reads an EPUB from disk and logs various information about it. + +## flutter_ex + +This example fetches an EPUB from a user-inputted URL and displays the Title and Author. \ No newline at end of file diff --git a/epubx/example/dart_ex/README.md b/epubx/example/dart_ex/README.md new file mode 100644 index 00000000..b785e80b --- /dev/null +++ b/epubx/example/dart_ex/README.md @@ -0,0 +1,9 @@ +# dart_ex + +An example of using the `epub` library in a "standard" command line application. + +## To Run + +```shell +dart bin/main.dart +``` \ No newline at end of file diff --git a/epubx/example/dart_ex/alicesAdventuresUnderGround.epub b/epubx/example/dart_ex/alicesAdventuresUnderGround.epub new file mode 100644 index 00000000..48af8a2c Binary files /dev/null and b/epubx/example/dart_ex/alicesAdventuresUnderGround.epub differ diff --git a/epubx/example/dart_ex/bin/main.dart b/epubx/example/dart_ex/bin/main.dart new file mode 100644 index 00000000..634763d1 --- /dev/null +++ b/epubx/example/dart_ex/bin/main.dart @@ -0,0 +1,113 @@ +import 'dart:io' as io; + +import 'package:path/path.dart' as path; +import 'package:epubx/epubx.dart'; + +main(List args) async { + //Get the epub into memory somehow + String fileName = "alicesAdventuresUnderGround.epub"; + String fullPath = path.join(io.Directory.current.path, fileName); + var targetFile = new io.File(fullPath); + List bytes = await targetFile.readAsBytes(); + +// Opens a book and reads all of its content into the memory + EpubBook epubBook = await EpubReader.readBook(bytes); + +// COMMON PROPERTIES + +// Book's title + String? title = epubBook.Title; + +// Book's authors (comma separated list) + String? author = epubBook.Author; + +// Book's authors (list of authors names) + List? authors = epubBook.AuthorList; + +// Book's cover image (null if there is no cover) + Image? coverImage = epubBook.CoverImage; + +// CHAPTERS + +// Enumerating chapters + epubBook.Chapters!.forEach((EpubChapter chapter) { + // Title of chapter + String chapterTitle = chapter.Title!; + + // HTML content of current chapter + String chapterHtmlContent = chapter.HtmlContent!; + + // Nested chapters + List subChapters = chapter.SubChapters!; + }); + +// CONTENT + +// Book's content (HTML files, stlylesheets, images, fonts, etc.) + EpubContent bookContent = epubBook.Content!; + +// IMAGES + +// All images in the book (file name is the key) + Map images = bookContent.Images!; + + EpubByteContentFile? firstImage = + images.isNotEmpty ? images.values.first : null; + +// Content type (e.g. EpubContentType.IMAGE_JPEG, EpubContentType.IMAGE_PNG) + EpubContentType contentType = firstImage!.ContentType!; + +// MIME type (e.g. "image/jpeg", "image/png") + String mimeContentType = firstImage.ContentMimeType!; + +// HTML & CSS + +// All XHTML files in the book (file name is the key) + Map htmlFiles = bookContent.Html!; + +// All CSS files in the book (file name is the key) + Map cssFiles = bookContent.Css!; + +// Entire HTML content of the book + htmlFiles.values.forEach((EpubTextContentFile htmlFile) { + String htmlContent = htmlFile.Content!; + }); + +// All CSS content in the book + cssFiles.values.forEach((EpubTextContentFile cssFile) { + String cssContent = cssFile.Content!; + }); + +// OTHER CONTENT + +// All fonts in the book (file name is the key) + Map fonts = bookContent.Fonts!; + +// All files in the book (including HTML, CSS, images, fonts, and other types of files) + Map allFiles = bookContent.AllFiles!; + +// ACCESSING RAW SCHEMA INFORMATION + +// EPUB OPF data + EpubPackage package = epubBook.Schema!.Package!; + +// Enumerating book's contributors + package.Metadata!.Contributors!.forEach((contributor) { + String contributorName = contributor.Contributor!; + String contributorRole = contributor.Role!; + }); + +// EPUB NCX data + EpubNavigation navigation = epubBook.Schema!.Navigation!; + +// Enumerating NCX metadata + navigation.Head!.Metadata!.forEach((meta) { + String metadataItemName = meta.Name!; + String metadataItemContent = meta.Content!; + }); + + // Write the Book + var written = EpubWriter.writeBook(epubBook); + // Read the book into a new object! + var newBook = await EpubReader.readBook(written!); +} diff --git a/epubx/example/dart_ex/pubspec.yaml b/epubx/example/dart_ex/pubspec.yaml new file mode 100644 index 00000000..7a6837b6 --- /dev/null +++ b/epubx/example/dart_ex/pubspec.yaml @@ -0,0 +1,11 @@ +name: dart_ex +description: Example dart project +version: 1.0.0+1 + +environment: + sdk: '>=2.12.0 <3.0.0' + +dependencies: + # Epub + epubx: + path: ../../ diff --git a/epubx/example/flutter_ex/.gitignore b/epubx/example/flutter_ex/.gitignore new file mode 100644 index 00000000..3132dc5f --- /dev/null +++ b/epubx/example/flutter_ex/.gitignore @@ -0,0 +1,73 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/epubx/example/flutter_ex/.metadata b/epubx/example/flutter_ex/.metadata new file mode 100644 index 00000000..033ad2af --- /dev/null +++ b/epubx/example/flutter_ex/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b + channel: stable + +project_type: app diff --git a/epubx/example/flutter_ex/README.md b/epubx/example/flutter_ex/README.md new file mode 100644 index 00000000..49ef7495 --- /dev/null +++ b/epubx/example/flutter_ex/README.md @@ -0,0 +1,13 @@ +# flutter_ex + +A sample application that fetches an epub from a given URL and displays the Title and Author + +Place a URL in the text box (e.g. https://www.gutenberg.org/ebooks/11.epub.images), hit the "Inspect Book" button and watch the application download the book and extract some relevant information. + +## Examples + +### With Cover Image +![](examplewithcover.png) + +### Without Cover Image +![](example.png) diff --git a/epubx/example/flutter_ex/analysis_options.yaml b/epubx/example/flutter_ex/analysis_options.yaml new file mode 100644 index 00000000..61b6c4de --- /dev/null +++ b/epubx/example/flutter_ex/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/epubx/example/flutter_ex/android/.gitignore b/epubx/example/flutter_ex/android/.gitignore new file mode 100644 index 00000000..6f568019 --- /dev/null +++ b/epubx/example/flutter_ex/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/epubx/example/flutter_ex/android/app/build.gradle b/epubx/example/flutter_ex/android/app/build.gradle new file mode 100644 index 00000000..a19fe6c5 --- /dev/null +++ b/epubx/example/flutter_ex/android/app/build.gradle @@ -0,0 +1,68 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 30 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.flutter_ex" + minSdkVersion 16 + targetSdkVersion 30 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/epubx/example/flutter_ex/android/app/src/debug/AndroidManifest.xml b/epubx/example/flutter_ex/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..9a86d921 --- /dev/null +++ b/epubx/example/flutter_ex/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/epubx/example/flutter_ex/android/app/src/main/AndroidManifest.xml b/epubx/example/flutter_ex/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..d39d75c0 --- /dev/null +++ b/epubx/example/flutter_ex/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + diff --git a/epubx/example/flutter_ex/android/app/src/main/kotlin/com/example/flutter_ex/MainActivity.kt b/epubx/example/flutter_ex/android/app/src/main/kotlin/com/example/flutter_ex/MainActivity.kt new file mode 100644 index 00000000..d1b63010 --- /dev/null +++ b/epubx/example/flutter_ex/android/app/src/main/kotlin/com/example/flutter_ex/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.flutter_ex + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/epubx/example/flutter_ex/android/app/src/main/res/drawable-v21/launch_background.xml b/epubx/example/flutter_ex/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/epubx/example/flutter_ex/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/epubx/example/flutter_ex/android/app/src/main/res/drawable/launch_background.xml b/epubx/example/flutter_ex/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/epubx/example/flutter_ex/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/epubx/example/flutter_ex/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/epubx/example/flutter_ex/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..db77bb4b Binary files /dev/null and b/epubx/example/flutter_ex/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/epubx/example/flutter_ex/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/epubx/example/flutter_ex/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..17987b79 Binary files /dev/null and b/epubx/example/flutter_ex/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/epubx/example/flutter_ex/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/epubx/example/flutter_ex/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..09d43914 Binary files /dev/null and b/epubx/example/flutter_ex/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/epubx/example/flutter_ex/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/epubx/example/flutter_ex/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..d5f1c8d3 Binary files /dev/null and b/epubx/example/flutter_ex/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/epubx/example/flutter_ex/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/epubx/example/flutter_ex/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..4d6372ee Binary files /dev/null and b/epubx/example/flutter_ex/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/epubx/example/flutter_ex/android/app/src/main/res/values-night/styles.xml b/epubx/example/flutter_ex/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..449a9f93 --- /dev/null +++ b/epubx/example/flutter_ex/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/epubx/example/flutter_ex/android/app/src/main/res/values/styles.xml b/epubx/example/flutter_ex/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..d74aa35c --- /dev/null +++ b/epubx/example/flutter_ex/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/epubx/example/flutter_ex/android/app/src/profile/AndroidManifest.xml b/epubx/example/flutter_ex/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..9a86d921 --- /dev/null +++ b/epubx/example/flutter_ex/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/epubx/example/flutter_ex/android/build.gradle b/epubx/example/flutter_ex/android/build.gradle new file mode 100644 index 00000000..ed45c658 --- /dev/null +++ b/epubx/example/flutter_ex/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/epubx/example/flutter_ex/android/gradle.properties b/epubx/example/flutter_ex/android/gradle.properties new file mode 100644 index 00000000..94adc3a3 --- /dev/null +++ b/epubx/example/flutter_ex/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/epubx/example/flutter_ex/android/gradle/wrapper/gradle-wrapper.properties b/epubx/example/flutter_ex/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..bc6a58af --- /dev/null +++ b/epubx/example/flutter_ex/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/epubx/example/flutter_ex/android/settings.gradle b/epubx/example/flutter_ex/android/settings.gradle new file mode 100644 index 00000000..44e62bcf --- /dev/null +++ b/epubx/example/flutter_ex/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/epubx/example/flutter_ex/example.png b/epubx/example/flutter_ex/example.png new file mode 100644 index 00000000..501461e0 Binary files /dev/null and b/epubx/example/flutter_ex/example.png differ diff --git a/epubx/example/flutter_ex/examplewithcover.png b/epubx/example/flutter_ex/examplewithcover.png new file mode 100644 index 00000000..0b6ad677 Binary files /dev/null and b/epubx/example/flutter_ex/examplewithcover.png differ diff --git a/epubx/example/flutter_ex/ios/.gitignore b/epubx/example/flutter_ex/ios/.gitignore new file mode 100644 index 00000000..7a7f9873 --- /dev/null +++ b/epubx/example/flutter_ex/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/epubx/example/flutter_ex/ios/Flutter/AppFrameworkInfo.plist b/epubx/example/flutter_ex/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..9625e105 --- /dev/null +++ b/epubx/example/flutter_ex/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/epubx/example/flutter_ex/ios/Flutter/Debug.xcconfig b/epubx/example/flutter_ex/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..592ceee8 --- /dev/null +++ b/epubx/example/flutter_ex/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/epubx/example/flutter_ex/ios/Flutter/Release.xcconfig b/epubx/example/flutter_ex/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..592ceee8 --- /dev/null +++ b/epubx/example/flutter_ex/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/epubx/example/flutter_ex/ios/Runner.xcodeproj/project.pbxproj b/epubx/example/flutter_ex/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..1978b7aa --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,474 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterEx; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterEx; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterEx; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/epubx/example/flutter_ex/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/epubx/example/flutter_ex/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/epubx/example/flutter_ex/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/epubx/example/flutter_ex/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/epubx/example/flutter_ex/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/epubx/example/flutter_ex/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/epubx/example/flutter_ex/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/epubx/example/flutter_ex/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..3db53b6e --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/epubx/example/flutter_ex/ios/Runner.xcworkspace/contents.xcworkspacedata b/epubx/example/flutter_ex/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/epubx/example/flutter_ex/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/epubx/example/flutter_ex/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/epubx/example/flutter_ex/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/epubx/example/flutter_ex/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/epubx/example/flutter_ex/ios/Runner/AppDelegate.swift b/epubx/example/flutter_ex/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..70693e4a --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 00000000..28c6bf03 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 00000000..2ccbfd96 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 00000000..f091b6b0 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 00000000..4cde1211 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 00000000..d0ef06e7 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 00000000..dcdc2306 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 00000000..2ccbfd96 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 00000000..c8f9ed8f Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 00000000..a6d6b860 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 00000000..a6d6b860 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 00000000..75b2d164 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 00000000..c4df70d3 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 00000000..6a84f41e Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 00000000..d0e1f585 Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 00000000..0bedcf2f --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/epubx/example/flutter_ex/ios/Runner/Base.lproj/LaunchScreen.storyboard b/epubx/example/flutter_ex/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/epubx/example/flutter_ex/ios/Runner/Base.lproj/Main.storyboard b/epubx/example/flutter_ex/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/epubx/example/flutter_ex/ios/Runner/Info.plist b/epubx/example/flutter_ex/ios/Runner/Info.plist new file mode 100644 index 00000000..fbb4acca --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + flutter_ex + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/epubx/example/flutter_ex/ios/Runner/Runner-Bridging-Header.h b/epubx/example/flutter_ex/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/epubx/example/flutter_ex/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/epubx/example/flutter_ex/lib/main.dart b/epubx/example/flutter_ex/lib/main.dart new file mode 100644 index 00000000..b3ae1ee7 --- /dev/null +++ b/epubx/example/flutter_ex/lib/main.dart @@ -0,0 +1,233 @@ +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:epubx/epubx.dart' as epub; +import 'package:image/image.dart' as image; + +void main() => runApp(EpubWidget()); + +class EpubWidget extends StatefulWidget { + @override + State createState() => EpubState(); +} + +class EpubState extends State { + Future? book; + + final _urlController = TextEditingController(); + + void fetchBookButton() { + setState(() { + book = fetchBook(_urlController.text); + }); + } + + void fetchBookPresets(String link) { + setState(() { + book = fetchBook(link); + }); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Fetch Epub Example", + theme: ThemeData.light(), + darkTheme: ThemeData.dark(), + home: SingleChildScrollView( + padding: const EdgeInsets.all(32.0), + child: Material( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + Padding(padding: EdgeInsets.only(top: 16.0)), + Text( + 'Epub Inspector', + style: TextStyle(fontSize: 25.0), + ), + Padding(padding: EdgeInsets.only(top: 50.0)), + Text( + 'Enter the Url of an Epub to view some of it\'s metadata.', + style: TextStyle(fontSize: 18.0), + textAlign: TextAlign.center, + ), + Padding(padding: EdgeInsets.only(top: 20.0)), + TextFormField( + decoration: InputDecoration( + labelText: "Enter Url", + fillColor: Colors.white, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(25.0), + borderSide: BorderSide(), + ), + ), + validator: (val) { + if (val!.length == 0) { + return "Url cannot be empty"; + } else { + return null; + } + }, + controller: _urlController, + keyboardType: TextInputType.url, + style: TextStyle( + fontFamily: "Poppins", + ), + ), + Padding( + padding: EdgeInsets.only(top: 20.0), + ), + ElevatedButton( + onPressed: fetchBookButton, + style: ButtonStyle( + padding: MaterialStateProperty.all( + EdgeInsets.all(8.0)), + textStyle: MaterialStateProperty.all(TextStyle( + color: Colors.white, + )), + backgroundColor: + MaterialStateProperty.all(Colors.blue), + ), + child: Text("Inspect Book"), + ), + Padding(padding: EdgeInsets.only(top: 25.0)), + Text( + 'Or select available links:', + style: TextStyle(fontSize: 18.0), + textAlign: TextAlign.center, + ), + Padding(padding: EdgeInsets.only(top: 12.0)), + Column( + children: [ + ...[ + 'https://filesamples.com/samples/ebook/epub/Around%20the%20World%20in%2028%20Languages.epub', + 'https://filesamples.com/samples/ebook/epub/Sway.epub', + 'https://filesamples.com/samples/ebook/epub/Alices%20Adventures%20in%20Wonderland.epub', + 'https://filesamples.com/samples/ebook/epub/sample1.epub', + ] + .map((link) => TextButton( + child: Text(link), + onPressed: () => fetchBookPresets(link), + )) + .cast() + .toList(), + ], + ), + Padding(padding: EdgeInsets.only(top: 25.0)), + Center( + child: FutureBuilder( + future: book, + builder: (context, snapshot) { + if (snapshot.hasData) { + return Material( + color: Colors.white, + child: buildEpubWidget(snapshot.data!), + ); + } else if (snapshot.hasError) { + return Text("${snapshot.error}"); + } + // By default, show a loading spinner + // return CircularProgressIndicator(); + + // By default, show just empty. + return Container(); + }, + ), + ), + ], + ), + ), + ), + ), + ); + } +} + +Widget buildEpubWidget(epub.EpubBookRef book) { + var chapters = book.getChapters(); + var cover = book.readCover(); + return Container( + child: Column( + children: [ + Text( + "Title", + style: TextStyle(fontSize: 20.0), + ), + Text( + book.Title!, + style: TextStyle(fontSize: 15.0), + ), + Padding( + padding: EdgeInsets.only(top: 15.0), + ), + Text( + "Author", + style: TextStyle(fontSize: 20.0), + ), + Text( + book.Author!, + style: TextStyle(fontSize: 15.0), + ), + Padding( + padding: EdgeInsets.only(top: 15.0), + ), + FutureBuilder>( + future: chapters, + builder: (context, snapshot) { + if (snapshot.hasData) { + return Column( + children: [ + Text("Chapters", style: TextStyle(fontSize: 20.0)), + Text( + snapshot.data!.length.toString(), + style: TextStyle(fontSize: 15.0), + ) + ], + ); + } else if (snapshot.hasError) { + return Text("${snapshot.error}"); + } + return Container(); + }), + Padding( + padding: EdgeInsets.only(top: 15.0), + ), + FutureBuilder( + future: cover, + builder: (context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return Column( + children: [ + Text("Cover", style: TextStyle(fontSize: 20.0)), + Image.memory( + Uint8List.fromList(image.encodePng(snapshot.data!))), + ], + ); + } else if (snapshot.hasError) { + return Text("${snapshot.error}"); + } + return Container(); + }, + ), + ], + )); +} + +// Needs a url to a valid url to an epub such as +// https://www.gutenberg.org/ebooks/11.epub.images +// or +// https://www.gutenberg.org/ebooks/19002.epub.images +Future fetchBook(String url) async { + // Hard coded to Alice Adventures In Wonderland in Project Gutenberb + final response = await http.get(Uri.parse(url)); + + if (response.statusCode == 200) { + // If server returns an OK response, parse the EPUB + return epub.EpubReader.openBook(response.bodyBytes); + } else { + // If that response was not OK, throw an error. + throw Exception('Failed to load epub'); + } +} diff --git a/epubx/example/flutter_ex/macos/.gitignore b/epubx/example/flutter_ex/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/epubx/example/flutter_ex/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/epubx/example/flutter_ex/macos/Flutter/Flutter-Debug.xcconfig b/epubx/example/flutter_ex/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..c2efd0b6 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/epubx/example/flutter_ex/macos/Flutter/Flutter-Release.xcconfig b/epubx/example/flutter_ex/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..c2efd0b6 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/epubx/example/flutter_ex/macos/Flutter/GeneratedPluginRegistrant.swift b/epubx/example/flutter_ex/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..cccf817a --- /dev/null +++ b/epubx/example/flutter_ex/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,10 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { +} diff --git a/epubx/example/flutter_ex/macos/Runner.xcodeproj/project.pbxproj b/epubx/example/flutter_ex/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..2729429f --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,572 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* flutter_ex.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "flutter_ex.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* flutter_ex.app */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* flutter_ex.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 0930; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/epubx/example/flutter_ex/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/epubx/example/flutter_ex/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/epubx/example/flutter_ex/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/epubx/example/flutter_ex/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..674b8f4e --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/epubx/example/flutter_ex/macos/Runner.xcworkspace/contents.xcworkspacedata b/epubx/example/flutter_ex/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/epubx/example/flutter_ex/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/epubx/example/flutter_ex/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/epubx/example/flutter_ex/macos/Runner/AppDelegate.swift b/epubx/example/flutter_ex/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..d53ef643 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..3c4935a7 Binary files /dev/null and b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..ed4cc164 Binary files /dev/null and b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..483be613 Binary files /dev/null and b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bcbf36df Binary files /dev/null and b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..9c0a6528 Binary files /dev/null and b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..e71a7261 Binary files /dev/null and b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..8a31fe2d Binary files /dev/null and b/epubx/example/flutter_ex/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/epubx/example/flutter_ex/macos/Runner/Base.lproj/MainMenu.xib b/epubx/example/flutter_ex/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..537341ab --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/epubx/example/flutter_ex/macos/Runner/Configs/AppInfo.xcconfig b/epubx/example/flutter_ex/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..f422d827 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = flutter_ex + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterEx + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2021 com.example. All rights reserved. diff --git a/epubx/example/flutter_ex/macos/Runner/Configs/Debug.xcconfig b/epubx/example/flutter_ex/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/epubx/example/flutter_ex/macos/Runner/Configs/Release.xcconfig b/epubx/example/flutter_ex/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/epubx/example/flutter_ex/macos/Runner/Configs/Warnings.xcconfig b/epubx/example/flutter_ex/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/epubx/example/flutter_ex/macos/Runner/DebugProfile.entitlements b/epubx/example/flutter_ex/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..3ba6c126 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.client + + com.apple.security.network.server + + + diff --git a/epubx/example/flutter_ex/macos/Runner/Info.plist b/epubx/example/flutter_ex/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/epubx/example/flutter_ex/macos/Runner/MainFlutterWindow.swift b/epubx/example/flutter_ex/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..2722837e --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController.init() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/epubx/example/flutter_ex/macos/Runner/Release.entitlements b/epubx/example/flutter_ex/macos/Runner/Release.entitlements new file mode 100644 index 00000000..7a2230dc --- /dev/null +++ b/epubx/example/flutter_ex/macos/Runner/Release.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.network.client + + com.apple.security.network.server + + + diff --git a/epubx/example/flutter_ex/pubspec.yaml b/epubx/example/flutter_ex/pubspec.yaml new file mode 100644 index 00000000..c215fd3e --- /dev/null +++ b/epubx/example/flutter_ex/pubspec.yaml @@ -0,0 +1,28 @@ +name: flutter_ex +description: A new Flutter project. +publish_to: none +version: 1.0.0+1 + +environment: + sdk: ">=2.12.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + # Epub + epubx: + path: ../../ + # To get the epub from the internet + http: ^0.13.4 + image: ^3.0.8 + +dev_dependencies: + flutter_test: + sdk: flutter + +# The following section is specific to Flutter. +flutter: + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true diff --git a/epubx/example/flutter_ex/web/favicon.png b/epubx/example/flutter_ex/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/epubx/example/flutter_ex/web/favicon.png differ diff --git a/epubx/example/flutter_ex/web/icons/Icon-192.png b/epubx/example/flutter_ex/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/epubx/example/flutter_ex/web/icons/Icon-192.png differ diff --git a/epubx/example/flutter_ex/web/icons/Icon-512.png b/epubx/example/flutter_ex/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/epubx/example/flutter_ex/web/icons/Icon-512.png differ diff --git a/epubx/example/flutter_ex/web/icons/Icon-maskable-192.png b/epubx/example/flutter_ex/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/epubx/example/flutter_ex/web/icons/Icon-maskable-192.png differ diff --git a/epubx/example/flutter_ex/web/icons/Icon-maskable-512.png b/epubx/example/flutter_ex/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/epubx/example/flutter_ex/web/icons/Icon-maskable-512.png differ diff --git a/epubx/example/flutter_ex/web/index.html b/epubx/example/flutter_ex/web/index.html new file mode 100644 index 00000000..c69f338e --- /dev/null +++ b/epubx/example/flutter_ex/web/index.html @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + flutter_ex + + + + + + + diff --git a/epubx/example/flutter_ex/web/manifest.json b/epubx/example/flutter_ex/web/manifest.json new file mode 100644 index 00000000..841e3f67 --- /dev/null +++ b/epubx/example/flutter_ex/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "flutter_ex", + "short_name": "flutter_ex", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/epubx/example/web_ex/.gitignore b/epubx/example/web_ex/.gitignore new file mode 100644 index 00000000..50602ac6 --- /dev/null +++ b/epubx/example/web_ex/.gitignore @@ -0,0 +1,11 @@ +# Files and directories created by pub +.dart_tool/ +.packages +# Remove the following pattern if you wish to check in your lock file +pubspec.lock + +# Conventional directory for build outputs +build/ + +# Directory created by dartdoc +doc/api/ diff --git a/epubx/example/web_ex/README.md b/epubx/example/web_ex/README.md new file mode 100644 index 00000000..eaf7c672 --- /dev/null +++ b/epubx/example/web_ex/README.md @@ -0,0 +1,27 @@ +# web_ex + +An absolute bare-bones web app which uses the epub package. + +## To run + +Install webdev +```bash +pub global activate webdev +``` + +Get dependencies +```bash +pub get +``` + +Run the application +```bash +webdev serve +``` + +Browse to `localhost:8080` + + +## Notices +Created from templates made available by Stagehand under a BSD-style +[license](https://github.com/dart-lang/stagehand/blob/master/LICENSE). diff --git a/epubx/example/web_ex/analysis_options.yaml b/epubx/example/web_ex/analysis_options.yaml new file mode 100644 index 00000000..a686c1b4 --- /dev/null +++ b/epubx/example/web_ex/analysis_options.yaml @@ -0,0 +1,14 @@ +# Defines a default set of lint rules enforced for +# projects at Google. For details and rationale, +# see https://github.com/dart-lang/pedantic#enabled-lints. +include: package:pedantic/analysis_options.yaml + +# For lint rules and documentation, see http://dart-lang.github.io/linter/lints. +# Uncomment to specify additional rules. +# linter: +# rules: +# - camel_case_types + +analyzer: +# exclude: +# - path/to/excluded/files/** diff --git a/epubx/example/web_ex/pubspec.yaml b/epubx/example/web_ex/pubspec.yaml new file mode 100644 index 00000000..bb6bd5aa --- /dev/null +++ b/epubx/example/web_ex/pubspec.yaml @@ -0,0 +1,18 @@ +name: web_ex +description: An absolute bare-bones web app. +# version: 1.0.0 +#homepage: https://www.example.com +#author: Colin Nelson + +environment: + sdk: '>=2.2.0 <3.0.0' + +dependencies: +# path: ^1.4.1 + http: ^0.12.0+2 + epub: ^2.0.6 + +dev_dependencies: + build_runner: ^1.1.2 + build_web_compilers: ^1.0.0 + pedantic: ^1.0.0 diff --git a/epubx/example/web_ex/web/alicesAdventuresUnderGround.epub b/epubx/example/web_ex/web/alicesAdventuresUnderGround.epub new file mode 100644 index 00000000..48af8a2c Binary files /dev/null and b/epubx/example/web_ex/web/alicesAdventuresUnderGround.epub differ diff --git a/epubx/example/web_ex/web/favicon.ico b/epubx/example/web_ex/web/favicon.ico new file mode 100644 index 00000000..7ba349b3 Binary files /dev/null and b/epubx/example/web_ex/web/favicon.ico differ diff --git a/epubx/example/web_ex/web/index.html b/epubx/example/web_ex/web/index.html new file mode 100644 index 00000000..54effe28 --- /dev/null +++ b/epubx/example/web_ex/web/index.html @@ -0,0 +1,27 @@ + + + + + + + + + + web_ex + + + + + + + +
+

Title

+
+

Author

+
+

Number of Chapters

+
+ + + \ No newline at end of file diff --git a/epubx/example/web_ex/web/main.dart b/epubx/example/web_ex/web/main.dart new file mode 100644 index 00000000..eaf36e9a --- /dev/null +++ b/epubx/example/web_ex/web/main.dart @@ -0,0 +1,17 @@ +import 'dart:html'; +import 'package:http/http.dart' as http; +import 'package:epubx/epub.dart' as epub; + +void main() async { + querySelector('#output').text = 'Your Dart app is running.'; + + var epubRes = await http.get('alicesAdventuresUnderGround.epub'); + if (epubRes.statusCode == 200) { + var book = await epub.EpubReader.openBook(epubRes.bodyBytes); + querySelector('#title').text = book.Title; + querySelector('#author').text = book.Author; + var chapters = await book.getChapters(); + querySelector('#nchapters').text = chapters.length.toString(); + querySelectorAll('h2').style.visibility = 'visible'; + } +} diff --git a/epubx/example/web_ex/web/styles.css b/epubx/example/web_ex/web/styles.css new file mode 100644 index 00000000..1eb12b31 --- /dev/null +++ b/epubx/example/web_ex/web/styles.css @@ -0,0 +1,18 @@ +@import url(https://fonts.googleapis.com/css?family=Roboto); + +html, body { + width: 100%; + height: 100%; + margin: 0; + padding: 0; + font-family: 'Roboto', sans-serif; +} + +div, h2 { + padding: 20px; + text-align: center; +} + +h2{ + visibility: hidden +} diff --git a/epubx/lib/epubx.dart b/epubx/lib/epubx.dart new file mode 100644 index 00000000..c5127f2c --- /dev/null +++ b/epubx/lib/epubx.dart @@ -0,0 +1,36 @@ +library epubx; + +export 'src/utils/enum_from_string.dart'; + +export 'src/epub_reader.dart'; +export 'src/epub_writer.dart'; +export 'src/ref_entities/epub_book_ref.dart'; +export 'src/ref_entities/epub_chapter_ref.dart'; +export 'src/entities/epub_book.dart'; +export 'src/entities/epub_chapter.dart'; +export 'src/entities/epub_content.dart'; +export 'src/entities/epub_content_type.dart'; +export 'src/entities/epub_byte_content_file.dart'; +export 'src/entities/epub_content_file.dart'; +export 'src/entities/epub_text_content_file.dart'; +export 'src/entities/epub_schema.dart'; +export 'src/schema/opf/epub_guide.dart'; +export 'src/schema/opf/epub_guide_reference.dart'; +export 'src/schema/opf/epub_spine.dart'; +export 'src/schema/opf/epub_spine_item_ref.dart'; +export 'src/schema/opf/epub_manifest.dart'; +export 'src/schema/opf/epub_manifest_item.dart'; +export 'src/schema/opf/epub_metadata.dart'; +export 'src/schema/opf/epub_metadata_creator.dart'; +export 'src/schema/opf/epub_package.dart'; +export 'src/schema/opf/epub_version.dart'; +export 'src/schema/navigation/epub_metadata.dart'; +export 'src/schema/navigation/epub_navigation.dart'; +export 'src/schema/navigation/epub_navigation_head.dart'; +export 'src/schema/navigation/epub_navigation_doc_author.dart'; +export 'src/schema/navigation/epub_navigation_doc_title.dart'; +export 'src/schema/navigation/epub_navigation_head_meta.dart'; +export 'src/schema/navigation/epub_navigation_label.dart'; +export 'src/schema/navigation/epub_navigation_map.dart'; +export 'src/schema/navigation/epub_navigation_point.dart'; +export 'package:image/image.dart' show Image; diff --git a/epubx/lib/src/entities/epub_book.dart b/epubx/lib/src/entities/epub_book.dart new file mode 100644 index 00000000..b87aeceb --- /dev/null +++ b/epubx/lib/src/entities/epub_book.dart @@ -0,0 +1,48 @@ +import 'package:image/image.dart'; +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_chapter.dart'; +import 'epub_content.dart'; +import 'epub_schema.dart'; + +class EpubBook { + String? Title; + String? Author; + List? AuthorList; + EpubSchema? Schema; + EpubContent? Content; + Image? CoverImage; + List? Chapters; + + @override + int get hashCode { + var objects = [ + Title.hashCode, + Author.hashCode, + Schema.hashCode, + Content.hashCode, + ...CoverImage?.getBytes().map((byte) => byte.hashCode) ?? [0], + ...AuthorList?.map((author) => author.hashCode) ?? [0], + ...Chapters?.map((chapter) => chapter.hashCode) ?? [0], + ]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + if (!(other is EpubBook)) { + return false; + } + + return Title == other.Title && + Author == other.Author && + collections.listsEqual(AuthorList, other.AuthorList) && + Schema == other.Schema && + Content == other.Content && + ((CoverImage == null && other.CoverImage == null) || + (collections.listsEqual( + CoverImage!.getBytes(), other.CoverImage!.getBytes()))) && + collections.listsEqual(Chapters, other.Chapters); + } +} diff --git a/epubx/lib/src/entities/epub_byte_content_file.dart b/epubx/lib/src/entities/epub_byte_content_file.dart new file mode 100644 index 00000000..8bf868f5 --- /dev/null +++ b/epubx/lib/src/entities/epub_byte_content_file.dart @@ -0,0 +1,30 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_content_file.dart'; + +class EpubByteContentFile extends EpubContentFile { + List? Content; + + @override + int get hashCode { + var objects = [ + ContentMimeType.hashCode, + ContentType.hashCode, + FileName.hashCode, + ...Content?.map((content) => content.hashCode) ?? [0], + ]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + if (!(other is EpubByteContentFile)) { + return false; + } + return collections.listsEqual(Content, other.Content) && + ContentMimeType == other.ContentMimeType && + ContentType == other.ContentType && + FileName == other.FileName; + } +} diff --git a/epubx/lib/src/entities/epub_chapter.dart b/epubx/lib/src/entities/epub_chapter.dart new file mode 100644 index 00000000..7a7d6b6c --- /dev/null +++ b/epubx/lib/src/entities/epub_chapter.dart @@ -0,0 +1,42 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +class EpubChapter { + String? Title; + String? ContentFileName; + String? Anchor; + String? HtmlContent; + List? SubChapters; + List OtherContentFileNames = []; + + @override + int get hashCode { + var objects = [ + Title.hashCode, + ContentFileName.hashCode, + OtherContentFileNames.hashCode, + Anchor.hashCode, + HtmlContent.hashCode, + ...SubChapters?.map((subChapter) => subChapter.hashCode) ?? [0], + ]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + if (!(other is EpubChapter)) { + return false; + } + return Title == other.Title && + ContentFileName == other.ContentFileName && + OtherContentFileNames == other.OtherContentFileNames && + Anchor == other.Anchor && + HtmlContent == other.HtmlContent && + collections.listsEqual(SubChapters, other.SubChapters); + } + + @override + String toString() { + return 'Title: $Title, Subchapter count: ${SubChapters!.length}'; + } +} diff --git a/epubx/lib/src/entities/epub_content.dart b/epubx/lib/src/entities/epub_content.dart new file mode 100644 index 00000000..e30b22de --- /dev/null +++ b/epubx/lib/src/entities/epub_content.dart @@ -0,0 +1,52 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_byte_content_file.dart'; +import 'epub_content_file.dart'; +import 'epub_text_content_file.dart'; + +class EpubContent { + Map? Html; + Map? Css; + Map? Images; + Map? Fonts; + Map? AllFiles; + + EpubContent() { + Html = {}; + Css = {}; + Images = {}; + Fonts = {}; + AllFiles = {}; + } + + @override + int get hashCode { + var objects = [ + ...Html!.keys.map((key) => key.hashCode), + ...Html!.values.map((value) => value.hashCode), + ...Css!.keys.map((key) => key.hashCode), + ...Css!.values.map((value) => value.hashCode), + ...Images!.keys.map((key) => key.hashCode), + ...Images!.values.map((value) => value.hashCode), + ...Fonts!.keys.map((key) => key.hashCode), + ...Fonts!.values.map((value) => value.hashCode), + ...AllFiles!.keys.map((key) => key.hashCode), + ...AllFiles!.values.map((value) => value.hashCode), + ]; + + return hashObjects(objects); + } + + @override + bool operator ==(other) { + if (!(other is EpubContent)) { + return false; + } + return collections.mapsEqual(Html, other.Html) && + collections.mapsEqual(Css, other.Css) && + collections.mapsEqual(Images, other.Images) && + collections.mapsEqual(Fonts, other.Fonts) && + collections.mapsEqual(AllFiles, other.AllFiles); + } +} diff --git a/epubx/lib/src/entities/epub_content_file.dart b/epubx/lib/src/entities/epub_content_file.dart new file mode 100644 index 00000000..d43801c4 --- /dev/null +++ b/epubx/lib/src/entities/epub_content_file.dart @@ -0,0 +1,23 @@ +import 'package:quiver/core.dart'; + +import 'epub_content_type.dart'; + +abstract class EpubContentFile { + String? FileName; + EpubContentType? ContentType; + String? ContentMimeType; + + @override + int get hashCode => + hash3(FileName.hashCode, ContentType.hashCode, ContentMimeType.hashCode); + + @override + bool operator ==(other) { + if (!(other is EpubContentFile)) { + return false; + } + return FileName == other.FileName && + ContentType == other.ContentType && + ContentMimeType == other.ContentMimeType; + } +} diff --git a/epubx/lib/src/entities/epub_content_type.dart b/epubx/lib/src/entities/epub_content_type.dart new file mode 100644 index 00000000..b1c0e075 --- /dev/null +++ b/epubx/lib/src/entities/epub_content_type.dart @@ -0,0 +1,17 @@ +enum EpubContentType { + XHTML_1_1, + DTBOOK, + DTBOOK_NCX, + OEB1_DOCUMENT, + XML, + CSS, + OEB1_CSS, + IMAGE_GIF, + IMAGE_JPEG, + IMAGE_PNG, + IMAGE_SVG, + IMAGE_BMP, + FONT_TRUETYPE, + FONT_OPENTYPE, + OTHER +} diff --git a/epubx/lib/src/entities/epub_schema.dart b/epubx/lib/src/entities/epub_schema.dart new file mode 100644 index 00000000..c34d190d --- /dev/null +++ b/epubx/lib/src/entities/epub_schema.dart @@ -0,0 +1,25 @@ +import 'package:quiver/core.dart'; + +import '../schema/navigation/epub_navigation.dart'; +import '../schema/opf/epub_package.dart'; + +class EpubSchema { + EpubPackage? Package; + EpubNavigation? Navigation; + String? ContentDirectoryPath; + + @override + int get hashCode => hash3( + Package.hashCode, Navigation.hashCode, ContentDirectoryPath.hashCode); + + @override + bool operator ==(other) { + if (!(other is EpubSchema)) { + return false; + } + + return Package == other.Package && + Navigation == other.Navigation && + ContentDirectoryPath == other.ContentDirectoryPath; + } +} diff --git a/epubx/lib/src/entities/epub_text_content_file.dart b/epubx/lib/src/entities/epub_text_content_file.dart new file mode 100644 index 00000000..a378074c --- /dev/null +++ b/epubx/lib/src/entities/epub_text_content_file.dart @@ -0,0 +1,22 @@ +import 'package:quiver/core.dart'; + +import 'epub_content_file.dart'; + +class EpubTextContentFile extends EpubContentFile { + String? Content; + + @override + int get hashCode => hash4(Content, ContentMimeType, ContentType, FileName); + + @override + bool operator ==(other) { + if (!(other is EpubTextContentFile)) { + return false; + } + + return Content == other.Content && + ContentMimeType == other.ContentMimeType && + ContentType == other.ContentType && + FileName == other.FileName; + } +} diff --git a/epubx/lib/src/epub_reader.dart b/epubx/lib/src/epub_reader.dart new file mode 100644 index 00000000..0835fb31 --- /dev/null +++ b/epubx/lib/src/epub_reader.dart @@ -0,0 +1,183 @@ +import 'dart:async'; + +import 'package:archive/archive.dart'; + +import 'entities/epub_book.dart'; +import 'entities/epub_byte_content_file.dart'; +import 'entities/epub_chapter.dart'; +import 'entities/epub_content.dart'; +import 'entities/epub_content_file.dart'; +import 'entities/epub_text_content_file.dart'; +import 'readers/content_reader.dart'; +import 'readers/schema_reader.dart'; +import 'ref_entities/epub_book_ref.dart'; +import 'ref_entities/epub_byte_content_file_ref.dart'; +import 'ref_entities/epub_chapter_ref.dart'; +import 'ref_entities/epub_content_file_ref.dart'; +import 'ref_entities/epub_content_ref.dart'; +import 'ref_entities/epub_text_content_file_ref.dart'; +import 'schema/opf/epub_metadata_creator.dart'; + +/// A class that provides the primary interface to read Epub files. +/// +/// To open an Epub and load all data at once use the [readBook()] method. +/// +/// To open an Epub and load only basic metadata use the [openBook()] method. +/// This is a good option to quickly load text-based metadata, while leaving the +/// heavier lifting of loading images and main content for subsequent operations. +/// +/// ## Example +/// ```dart +/// // Read the basic metadata. +/// EpubBookRef epub = await EpubReader.openBook(epubFileBytes); +/// // Extract values of interest. +/// String title = epub.Title; +/// String author = epub.Author; +/// var metadata = epub.Schema.Package.Metadata; +/// String genres = metadata.Subjects.join(', '); +/// ``` +class EpubReader { + /// Loads basics metadata. + /// + /// Opens the book asynchronously without reading its main content. + /// Holds the handle to the EPUB file. + /// + /// Argument [bytes] should be the bytes of + /// the epub file you have loaded with something like the [dart:io] package's + /// [readAsBytes()]. + /// + /// This is a fast and convenient way to get the most important information + /// about the book, notably the [Title], [Author] and [AuthorList]. + /// Additional information is loaded in the [Schema] property such as the + /// Epub version, Publishers, Languages and more. + static Future openBook(FutureOr> bytes) async { + List loadedBytes; + if (bytes is Future) { + loadedBytes = await bytes; + } else { + loadedBytes = bytes; + } + + var epubArchive = ZipDecoder().decodeBytes(loadedBytes); + + var bookRef = EpubBookRef(epubArchive); + bookRef.Schema = await SchemaReader.readSchema(epubArchive); + bookRef.Title = bookRef.Schema!.Package!.Metadata!.Titles! + .firstWhere((String name) => true, orElse: () => ''); + bookRef.AuthorList = bookRef.Schema!.Package!.Metadata!.Creators! + .map((EpubMetadataCreator creator) => creator.Creator) + .toList(); + bookRef.Author = bookRef.AuthorList!.join(', '); + bookRef.Content = ContentReader.parseContentMap(bookRef); + return bookRef; + } + + /// Opens the book asynchronously and reads all of its content into the memory. Does not hold the handle to the EPUB file. + static Future readBook(FutureOr> bytes) async { + var result = EpubBook(); + List loadedBytes; + if (bytes is Future) { + loadedBytes = await bytes; + } else { + loadedBytes = bytes; + } + + var epubBookRef = await openBook(loadedBytes); + result.Schema = epubBookRef.Schema; + result.Title = epubBookRef.Title; + result.AuthorList = epubBookRef.AuthorList; + result.Author = epubBookRef.Author; + result.Content = await readContent(epubBookRef.Content!); + result.CoverImage = await epubBookRef.readCover(); + var chapterRefs = await epubBookRef.getChapters(); + result.Chapters = await readChapters(chapterRefs); + + return result; + } + + static Future readContent(EpubContentRef contentRef) async { + var result = EpubContent(); + result.Html = await readTextContentFiles(contentRef.Html!); + result.Css = await readTextContentFiles(contentRef.Css!); + result.Images = await readByteContentFiles(contentRef.Images!); + result.Fonts = await readByteContentFiles(contentRef.Fonts!); + result.AllFiles = {}; + + result.Html!.forEach((String? key, EpubTextContentFile value) { + result.AllFiles![key!] = value; + }); + result.Css!.forEach((String? key, EpubTextContentFile value) { + result.AllFiles![key!] = value; + }); + + result.Images!.forEach((String? key, EpubByteContentFile value) { + result.AllFiles![key!] = value; + }); + result.Fonts!.forEach((String? key, EpubByteContentFile value) { + result.AllFiles![key!] = value; + }); + + await Future.forEach(contentRef.AllFiles!.keys, (dynamic key) async { + if (!result.AllFiles!.containsKey(key)) { + result.AllFiles![key] = + await readByteContentFile(contentRef.AllFiles![key]!); + } + }); + + return result; + } + + static Future> readTextContentFiles( + Map textContentFileRefs) async { + var result = {}; + + await Future.forEach(textContentFileRefs.keys, (dynamic key) async { + EpubContentFileRef value = textContentFileRefs[key]!; + var textContentFile = EpubTextContentFile(); + textContentFile.FileName = value.FileName; + textContentFile.ContentType = value.ContentType; + textContentFile.ContentMimeType = value.ContentMimeType; + textContentFile.Content = await value.readContentAsText(); + result[key] = textContentFile; + }); + return result; + } + + static Future> readByteContentFiles( + Map byteContentFileRefs) async { + var result = {}; + await Future.forEach(byteContentFileRefs.keys, (dynamic key) async { + result[key] = await readByteContentFile(byteContentFileRefs[key]!); + }); + return result; + } + + static Future readByteContentFile( + EpubContentFileRef contentFileRef) async { + var result = EpubByteContentFile(); + + result.FileName = contentFileRef.FileName; + result.ContentType = contentFileRef.ContentType; + result.ContentMimeType = contentFileRef.ContentMimeType; + result.Content = await contentFileRef.readContentAsBytes(); + + return result; + } + + static Future> readChapters( + List chapterRefs) async { + var result = []; + await Future.forEach(chapterRefs, (EpubChapterRef chapterRef) async { + var chapter = EpubChapter(); + + chapter.Title = chapterRef.Title; + chapter.ContentFileName = chapterRef.ContentFileName; + chapter.Anchor = chapterRef.Anchor; + chapter.HtmlContent = await chapterRef.readHtmlContent(); + chapter.SubChapters = await readChapters(chapterRef.SubChapters!); + + result.add(chapter); + }); + return result; + } +} diff --git a/epubx/lib/src/epub_writer.dart b/epubx/lib/src/epub_writer.dart new file mode 100644 index 00000000..7c9caa52 --- /dev/null +++ b/epubx/lib/src/epub_writer.dart @@ -0,0 +1,59 @@ +import 'package:archive/archive.dart'; +import 'dart:convert' as convert; +import 'package:epubx/src/utils/zip_path_utils.dart'; +import 'package:epubx/src/writers/epub_package_writer.dart'; + +import 'entities/epub_book.dart'; +import 'entities/epub_byte_content_file.dart'; +import 'entities/epub_text_content_file.dart'; + +class EpubWriter { + static const _container_file = + ''; + + // Creates a Zip Archive of an EpubBook + static Archive _createArchive(EpubBook book) { + var arch = Archive(); + + // Add simple metadata + arch.addFile(ArchiveFile.noCompress( + 'mimetype', 20, convert.utf8.encode('application/epub+zip'))); + + // Add Container file + arch.addFile(ArchiveFile('META-INF/container.xml', _container_file.length, + convert.utf8.encode(_container_file))); + + // Add all content to the archive + book.Content!.AllFiles!.forEach((name, file) { + List? content; + + if (file is EpubByteContentFile) { + content = file.Content; + } else if (file is EpubTextContentFile) { + content = convert.utf8.encode(file.Content!); + } + + arch.addFile(ArchiveFile( + ZipPathUtils.combine(book.Schema!.ContentDirectoryPath, name)!, + content!.length, + content)); + }); + + // Generate the content.opf file and add it to the Archive + var contentopf = EpubPackageWriter.writeContent(book.Schema!.Package!); + + arch.addFile(ArchiveFile( + ZipPathUtils.combine(book.Schema!.ContentDirectoryPath, 'content.opf')!, + contentopf.length, + convert.utf8.encode(contentopf))); + + return arch; + } + + // Serializes the EpubBook into a byte array + static List? writeBook(EpubBook book) { + var arch = _createArchive(book); + + return ZipEncoder().encode(arch); + } +} diff --git a/epubx/lib/src/readers/book_cover_reader.dart b/epubx/lib/src/readers/book_cover_reader.dart new file mode 100644 index 00000000..abebf642 --- /dev/null +++ b/epubx/lib/src/readers/book_cover_reader.dart @@ -0,0 +1,54 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:collection/collection.dart' show IterableExtension; +import 'package:image/image.dart' as images; + +import '../ref_entities/epub_book_ref.dart'; +import '../ref_entities/epub_byte_content_file_ref.dart'; +import '../schema/opf/epub_manifest_item.dart'; +import '../schema/opf/epub_metadata_meta.dart'; + +class BookCoverReader { + static Future readBookCover(EpubBookRef bookRef) async { + EpubManifestItem? coverManifestItem = + bookRef.Schema!.Package!.Manifest!.Items!.firstWhereOrNull( + (i) => i.Properties == "cover-image", + ); + + if (coverManifestItem == null) { + var metaItems = bookRef.Schema!.Package!.Metadata!.MetaItems; + if (metaItems == null || metaItems.isEmpty) return null; + + var coverMetaItem = metaItems.firstWhereOrNull( + (EpubMetadataMeta metaItem) => + metaItem.Name != null && metaItem.Name!.toLowerCase() == 'cover'); + if (coverMetaItem == null) return null; + if (coverMetaItem.Content == null || coverMetaItem.Content!.isEmpty) { + throw Exception( + 'Incorrect EPUB metadata: cover item content is missing.'); + } + + coverManifestItem = bookRef.Schema!.Package!.Manifest!.Items! + .firstWhereOrNull((EpubManifestItem manifestItem) => + manifestItem.Id!.toLowerCase() == + coverMetaItem.Content!.toLowerCase()); + } + + if (coverManifestItem == null) { + throw Exception('Incorrect EPUB manifest'); + } + + EpubByteContentFileRef? coverImageContentFileRef; + if (!bookRef.Content!.Images!.containsKey(coverManifestItem.Href)) { + throw Exception( + 'Incorrect EPUB manifest: item with href = \"${coverManifestItem.Href}\" is missing.'); + } + + coverImageContentFileRef = bookRef.Content!.Images![coverManifestItem.Href]; + var coverImageContent = + await coverImageContentFileRef!.readContentAsBytes(); + var retval = images.decodeImage(Uint8List.fromList(coverImageContent)); + return retval; + } +} diff --git a/epubx/lib/src/readers/chapter_reader.dart b/epubx/lib/src/readers/chapter_reader.dart new file mode 100644 index 00000000..e515ef69 --- /dev/null +++ b/epubx/lib/src/readers/chapter_reader.dart @@ -0,0 +1,67 @@ +import '../ref_entities/epub_book_ref.dart'; +import '../ref_entities/epub_chapter_ref.dart'; +import '../ref_entities/epub_text_content_file_ref.dart'; +import '../schema/navigation/epub_navigation_point.dart'; + +class ChapterReader { + static List getChapters(EpubBookRef bookRef) { + if (bookRef.Schema!.Navigation == null) { + return []; + } + return getChaptersImpl( + bookRef, bookRef.Schema!.Navigation!.NavMap!.Points!); + } + + static List getChaptersImpl( + EpubBookRef bookRef, List navigationPoints) { + var result = []; + // navigationPoints.forEach((EpubNavigationPoint navigationPoint) { + for (var navigationPoint in navigationPoints) { + String? contentFileName; + String? anchor; + if (navigationPoint.Content?.Source == null) continue; + var contentSourceAnchorCharIndex = + navigationPoint.Content!.Source!.indexOf('#'); + if (contentSourceAnchorCharIndex == -1) { + contentFileName = navigationPoint.Content!.Source; + anchor = null; + } else { + contentFileName = navigationPoint.Content!.Source! + .substring(0, contentSourceAnchorCharIndex); + anchor = navigationPoint.Content!.Source! + .substring(contentSourceAnchorCharIndex + 1); + } + contentFileName = Uri.decodeFull(contentFileName!).replaceAll("\\", "/"); + EpubTextContentFileRef? htmlContentFileRef; + if (!bookRef.Content!.Html!.containsKey(contentFileName)) { + throw Exception( + 'Incorrect EPUB manifest: item with href = \"$contentFileName\" is missing.'); + } + + htmlContentFileRef = bookRef.Content!.Html![contentFileName]; + var chapterRef = EpubChapterRef(htmlContentFileRef); + chapterRef.ContentFileName = contentFileName; + chapterRef.Anchor = anchor; + chapterRef.Title = navigationPoint.NavigationLabels!.first.Text; + chapterRef.SubChapters = + getChaptersImpl(bookRef, navigationPoint.ChildNavigationPoints!); + if (chapterRef.ContentFileName!.contains('_split_')) { + var fileNamePart = chapterRef.ContentFileName!.split('_split_')[0]; + for (var fileName in bookRef.Content!.Html!.keys) { + if (fileName.contains(fileNamePart)) { + if (fileName == contentFileName) { + continue; + } + chapterRef.otherTextContentFileRefs + .add(bookRef.Content!.Html![fileName]!); + chapterRef.OtherContentFileNames.add(fileName); + } + } + } + + result.add(chapterRef); + } + ; + return result; + } +} diff --git a/epubx/lib/src/readers/content_reader.dart b/epubx/lib/src/readers/content_reader.dart new file mode 100644 index 00000000..78d0e7cf --- /dev/null +++ b/epubx/lib/src/readers/content_reader.dart @@ -0,0 +1,137 @@ +import '../entities/epub_content_type.dart'; +import '../ref_entities/epub_book_ref.dart'; +import '../ref_entities/epub_byte_content_file_ref.dart'; +import '../ref_entities/epub_content_file_ref.dart'; +import '../ref_entities/epub_content_ref.dart'; +import '../ref_entities/epub_text_content_file_ref.dart'; +import '../schema/opf/epub_manifest_item.dart'; + +class ContentReader { + static EpubContentRef parseContentMap(EpubBookRef bookRef) { + var result = EpubContentRef(); + result.Html = {}; + result.Css = {}; + result.Images = {}; + result.Fonts = {}; + result.AllFiles = {}; + + bookRef.Schema!.Package!.Manifest!.Items! + .forEach((EpubManifestItem manifestItem) { + var fileName = manifestItem.Href; + var contentMimeType = manifestItem.MediaType!; + var contentType = getContentTypeByContentMimeType(contentMimeType); + switch (contentType) { + case EpubContentType.XHTML_1_1: + case EpubContentType.CSS: + case EpubContentType.OEB1_DOCUMENT: + case EpubContentType.OEB1_CSS: + case EpubContentType.XML: + case EpubContentType.DTBOOK: + case EpubContentType.DTBOOK_NCX: + var epubTextContentFile = EpubTextContentFileRef(bookRef); + { + epubTextContentFile.FileName = Uri.decodeFull(fileName!); + epubTextContentFile.ContentMimeType = contentMimeType; + epubTextContentFile.ContentType = contentType; + } + ; + switch (contentType) { + case EpubContentType.XHTML_1_1: + result.Html![fileName] = epubTextContentFile; + break; + case EpubContentType.CSS: + result.Css![fileName] = epubTextContentFile; + break; + case EpubContentType.DTBOOK: + case EpubContentType.DTBOOK_NCX: + case EpubContentType.OEB1_DOCUMENT: + case EpubContentType.XML: + case EpubContentType.OEB1_CSS: + case EpubContentType.IMAGE_GIF: + case EpubContentType.IMAGE_JPEG: + case EpubContentType.IMAGE_PNG: + case EpubContentType.IMAGE_SVG: + case EpubContentType.IMAGE_BMP: + case EpubContentType.FONT_TRUETYPE: + case EpubContentType.FONT_OPENTYPE: + case EpubContentType.OTHER: + break; + } + result.AllFiles![fileName] = epubTextContentFile; + break; + default: + var epubByteContentFile = EpubByteContentFileRef(bookRef); + { + epubByteContentFile.FileName = Uri.decodeFull(fileName!); + epubByteContentFile.ContentMimeType = contentMimeType; + epubByteContentFile.ContentType = contentType; + } + ; + switch (contentType) { + case EpubContentType.IMAGE_GIF: + case EpubContentType.IMAGE_JPEG: + case EpubContentType.IMAGE_PNG: + case EpubContentType.IMAGE_SVG: + case EpubContentType.IMAGE_BMP: + result.Images![fileName] = epubByteContentFile; + break; + case EpubContentType.FONT_TRUETYPE: + case EpubContentType.FONT_OPENTYPE: + result.Fonts![fileName] = epubByteContentFile; + break; + case EpubContentType.CSS: + case EpubContentType.XHTML_1_1: + case EpubContentType.DTBOOK: + case EpubContentType.DTBOOK_NCX: + case EpubContentType.OEB1_DOCUMENT: + case EpubContentType.XML: + case EpubContentType.OEB1_CSS: + case EpubContentType.OTHER: + break; + } + result.AllFiles![fileName] = epubByteContentFile; + break; + } + }); + return result; + } + + static EpubContentType getContentTypeByContentMimeType( + String contentMimeType) { + switch (contentMimeType.toLowerCase()) { + case 'application/xhtml+xml': + case 'text/html': + return EpubContentType.XHTML_1_1; + case 'application/x-dtbook+xml': + return EpubContentType.DTBOOK; + case 'application/x-dtbncx+xml': + return EpubContentType.DTBOOK_NCX; + case 'text/x-oeb1-document': + return EpubContentType.OEB1_DOCUMENT; + case 'application/xml': + return EpubContentType.XML; + case 'text/css': + return EpubContentType.CSS; + case 'text/x-oeb1-css': + return EpubContentType.OEB1_CSS; + case 'image/gif': + return EpubContentType.IMAGE_GIF; + case 'image/jpeg': + return EpubContentType.IMAGE_JPEG; + case 'image/png': + return EpubContentType.IMAGE_PNG; + case 'image/svg+xml': + return EpubContentType.IMAGE_SVG; + case 'image/bmp': + return EpubContentType.IMAGE_BMP; + case 'font/truetype': + return EpubContentType.FONT_TRUETYPE; + case 'font/opentype': + return EpubContentType.FONT_OPENTYPE; + case 'application/vnd.ms-opentype': + return EpubContentType.FONT_OPENTYPE; + default: + return EpubContentType.OTHER; + } + } +} diff --git a/epubx/lib/src/readers/navigation_reader.dart b/epubx/lib/src/readers/navigation_reader.dart new file mode 100644 index 00000000..67f073b5 --- /dev/null +++ b/epubx/lib/src/readers/navigation_reader.dart @@ -0,0 +1,559 @@ +import 'dart:async'; + +import 'package:archive/archive.dart'; +import 'dart:convert' as convert; +import 'package:collection/collection.dart' show IterableExtension; +import 'package:epubx/src/schema/opf/epub_version.dart'; +import 'package:xml/xml.dart' as xml; +import 'package:path/path.dart' as path; + +import '../schema/navigation/epub_metadata.dart'; +import '../schema/navigation/epub_navigation.dart'; +import '../schema/navigation/epub_navigation_doc_author.dart'; +import '../schema/navigation/epub_navigation_doc_title.dart'; +import '../schema/navigation/epub_navigation_head.dart'; +import '../schema/navigation/epub_navigation_head_meta.dart'; +import '../schema/navigation/epub_navigation_label.dart'; +import '../schema/navigation/epub_navigation_list.dart'; +import '../schema/navigation/epub_navigation_map.dart'; +import '../schema/navigation/epub_navigation_page_list.dart'; +import '../schema/navigation/epub_navigation_page_target.dart'; +import '../schema/navigation/epub_navigation_page_target_type.dart'; +import '../schema/navigation/epub_navigation_point.dart'; +import '../schema/navigation/epub_navigation_target.dart'; +import '../schema/opf/epub_manifest_item.dart'; +import '../schema/opf/epub_package.dart'; +import '../utils/enum_from_string.dart'; +import '../utils/zip_path_utils.dart'; + +// ignore: omit_local_variable_types + +class NavigationReader { + static String? _tocFileEntryPath; + + static Future readNavigation( + Archive epubArchive, String contentDirectoryPath, EpubPackage package) async { + var result = EpubNavigation(); + if (package.Version == EpubVersion.Epub2) { + var tocId = package.Spine!.TableOfContents; + if (tocId == null || tocId.isEmpty) { + throw Exception('EPUB parsing error: TOC ID is empty.'); + } + + var tocManifestItem = package.Manifest!.Items!.cast().firstWhere( + (EpubManifestItem? item) => item!.Id!.toLowerCase() == tocId.toLowerCase(), + orElse: () => null, + ); + if (tocManifestItem == null) { + throw Exception('EPUB parsing error: TOC item $tocId not found in EPUB manifest.'); + } + + _tocFileEntryPath = ZipPathUtils.combine(contentDirectoryPath, tocManifestItem.Href); + var tocFileEntry = epubArchive.files.cast().firstWhere( + (ArchiveFile? file) => file!.name.toLowerCase() == _tocFileEntryPath!.toLowerCase(), + orElse: () => null); + if (tocFileEntry == null) { + throw Exception('EPUB parsing error: TOC file $_tocFileEntryPath not found in archive.'); + } + + var containerDocument = xml.XmlDocument.parse(convert.utf8.decode(tocFileEntry.content)); + + var ncxNamespace = 'http://www.daisy.org/z3986/2005/ncx/'; + var ncxNode = containerDocument + .findAllElements('ncx', namespace: ncxNamespace) + .cast() + .firstWhere((xml.XmlElement? elem) => elem != null, orElse: () => null); + if (ncxNode == null) { + throw Exception('EPUB parsing error: TOC file does not contain ncx element.'); + } + + var headNode = ncxNode + .findAllElements('head', namespace: ncxNamespace) + .cast() + .firstWhere((xml.XmlElement? elem) => elem != null, orElse: () => null); + if (headNode == null) { + throw Exception('EPUB parsing error: TOC file does not contain head element.'); + } + + var navigationHead = readNavigationHead(headNode); + result.Head = navigationHead; + var docTitleNode = ncxNode + .findElements('docTitle', namespace: ncxNamespace) + .cast() + .firstWhere((xml.XmlElement? elem) => elem != null, orElse: () => null); + if (docTitleNode == null) { + throw Exception('EPUB parsing error: TOC file does not contain docTitle element.'); + } + + var navigationDocTitle = readNavigationDocTitle(docTitleNode); + result.DocTitle = navigationDocTitle; + result.DocAuthors = []; + ncxNode.findElements('docAuthor', namespace: ncxNamespace).forEach((xml.XmlElement docAuthorNode) { + var navigationDocAuthor = readNavigationDocAuthor(docAuthorNode); + result.DocAuthors!.add(navigationDocAuthor); + }); + + var navMapNode = ncxNode + .findElements('navMap', namespace: ncxNamespace) + .cast() + .firstWhere((xml.XmlElement? elem) => elem != null, orElse: () => null); + if (navMapNode == null) { + throw Exception('EPUB parsing error: TOC file does not contain navMap element.'); + } + + var navMap = readNavigationMap(navMapNode); + result.NavMap = navMap; + var pageListNode = ncxNode + .findElements('pageList', namespace: ncxNamespace) + .cast() + .firstWhere((xml.XmlElement? elem) => elem != null, orElse: () => null); + if (pageListNode != null) { + var pageList = readNavigationPageList(pageListNode); + result.PageList = pageList; + } + + result.NavLists = []; + ncxNode.findElements('navList', namespace: ncxNamespace).forEach((xml.XmlElement navigationListNode) { + var navigationList = readNavigationList(navigationListNode); + result.NavLists!.add(navigationList); + }); + } else { + //Version 3 + + var tocManifestItem = package.Manifest!.Items! + .cast() + .firstWhere((element) => element!.Properties == 'nav', orElse: () => null); + if (tocManifestItem == null) { + throw Exception('EPUB parsing error: TOC item, not found in EPUB manifest.'); + } + + _tocFileEntryPath = ZipPathUtils.combine(contentDirectoryPath, tocManifestItem.Href); + var tocFileEntry = epubArchive.files.cast().firstWhere( + (ArchiveFile? file) => file!.name.toLowerCase() == _tocFileEntryPath!.toLowerCase(), + orElse: () => null); + if (tocFileEntry == null) { + throw Exception('EPUB parsing error: TOC file $_tocFileEntryPath not found in archive.'); + } + //Get relative toc file path + _tocFileEntryPath = ((_tocFileEntryPath!.split('/')..removeLast())..removeAt(0)).join('/') + '/'; + + var containerDocument = xml.XmlDocument.parse(convert.utf8.decode(tocFileEntry.content)); + + var headNode = containerDocument + .findAllElements('head') + .cast() + .firstWhere((xml.XmlElement? elem) => elem != null, orElse: () => null); + if (headNode == null) { + throw Exception('EPUB parsing error: TOC file does not contain head element.'); + } + + result.DocTitle = EpubNavigationDocTitle(); + result.DocTitle!.Titles = package.Metadata!.Titles; +// result.DocTitle.Titles.add(headNode.findAllElements("title").firstWhere((element) => element != null, orElse: () => null).text.trim()); + + result.DocAuthors = []; + + var navNode = containerDocument + .findAllElements('nav') + .cast() + .firstWhere((xml.XmlElement? elem) => elem != null, orElse: () => null); + if (navNode == null) { + throw Exception('EPUB parsing error: TOC file does not contain head element.'); + } + var navMapNode = navNode.findElements('ol').single; + + var navMap = readNavigationMapV3(navMapNode); + result.NavMap = navMap; + + //TODO : Implement pagesLists +// xml.XmlElement pageListNode = ncxNode +// .findElements("pageList", namespace: ncxNamespace) +// .firstWhere((xml.XmlElement elem) => elem != null, +// orElse: () => null); +// if (pageListNode != null) { +// EpubNavigationPageList pageList = readNavigationPageList(pageListNode); +// result.PageList = pageList; +// } + } + + return result; + } + + static EpubNavigationContent readNavigationContent(xml.XmlElement navigationContentNode) { + var result = EpubNavigationContent(); + navigationContentNode.attributes.forEach((xml.XmlAttribute navigationContentNodeAttribute) { + var attributeValue = navigationContentNodeAttribute.value; + switch (navigationContentNodeAttribute.name.local.toLowerCase()) { + case 'id': + result.Id = attributeValue; + break; + case 'src': + result.Source = attributeValue; + break; + } + }); + if (result.Source == null || result.Source!.isEmpty) { + throw Exception('Incorrect EPUB navigation content: content source is missing.'); + } + + return result; + } + + static EpubNavigationContent readNavigationContentV3(xml.XmlElement navigationContentNode) { + var result = EpubNavigationContent(); + navigationContentNode.attributes.forEach((xml.XmlAttribute navigationContentNodeAttribute) { + var attributeValue = navigationContentNodeAttribute.value; + switch (navigationContentNodeAttribute.name.local.toLowerCase()) { + case 'id': + result.Id = attributeValue; + break; + case 'href': + if (_tocFileEntryPath!.length < 2 || + attributeValue.startsWith(_tocFileEntryPath!)) { + result.Source = attributeValue; + } else { + result.Source = path.normalize(_tocFileEntryPath! + attributeValue); + } + + break; + } + }); + // element with span, the content will be null; + // if (result.Source == null || result.Source!.isEmpty) { + // throw Exception( + // 'Incorrect EPUB navigation content: content source is missing.'); + // } + return result; + } + + static String extractContentPath(String _tocFileEntryPath, String ref) { + if (!_tocFileEntryPath.endsWith('/')) _tocFileEntryPath = _tocFileEntryPath + '/'; + var r = _tocFileEntryPath + ref; + r = r.replaceAll('/\./', '/'); + r = r.replaceAll(RegExp(r'/[^/]+/\.\./'), '/'); + r = r.replaceAll(RegExp(r'^[^/]+/\.\./'), ''); + return r; + } + + static EpubNavigationDocAuthor readNavigationDocAuthor(xml.XmlElement docAuthorNode) { + var result = EpubNavigationDocAuthor(); + result.Authors = []; + docAuthorNode.children.whereType().forEach((xml.XmlElement textNode) { + if (textNode.name.local.toLowerCase() == 'text') { + result.Authors!.add(textNode.text); + } + }); + return result; + } + + static EpubNavigationDocTitle readNavigationDocTitle(xml.XmlElement docTitleNode) { + var result = EpubNavigationDocTitle(); + result.Titles = []; + docTitleNode.children.whereType().forEach((xml.XmlElement textNode) { + if (textNode.name.local.toLowerCase() == 'text') { + result.Titles!.add(textNode.text); + } + }); + return result; + } + + static EpubNavigationHead readNavigationHead(xml.XmlElement headNode) { + var result = EpubNavigationHead(); + result.Metadata = []; + + headNode.children.whereType().forEach((xml.XmlElement metaNode) { + if (metaNode.name.local.toLowerCase() == 'meta') { + var meta = EpubNavigationHeadMeta(); + metaNode.attributes.forEach((xml.XmlAttribute metaNodeAttribute) { + var attributeValue = metaNodeAttribute.value; + switch (metaNodeAttribute.name.local.toLowerCase()) { + case 'name': + meta.Name = attributeValue; + break; + case 'content': + meta.Content = attributeValue; + break; + case 'scheme': + meta.Scheme = attributeValue; + break; + } + }); + + if (meta.Name == null || meta.Name!.isEmpty) { + throw Exception('Incorrect EPUB navigation meta: meta name is missing.'); + } + if (meta.Content == null) { + throw Exception('Incorrect EPUB navigation meta: meta content is missing.'); + } + + result.Metadata!.add(meta); + } + }); + return result; + } + + static EpubNavigationLabel readNavigationLabel(xml.XmlElement navigationLabelNode) { + var result = EpubNavigationLabel(); + + var navigationLabelTextNode = navigationLabelNode + .findElements('text', namespace: navigationLabelNode.name.namespaceUri) + .firstWhereOrNull((xml.XmlElement? elem) => elem != null); + if (navigationLabelTextNode == null) { + throw Exception('Incorrect EPUB navigation label: label text element is missing.'); + } + + result.Text = navigationLabelTextNode.text; + + return result; + } + + static EpubNavigationLabel readNavigationLabelV3(xml.XmlElement navigationLabelNode) { + var result = EpubNavigationLabel(); + result.Text = navigationLabelNode.text.trim(); + return result; + } + + static EpubNavigationList readNavigationList(xml.XmlElement navigationListNode) { + var result = EpubNavigationList(); + navigationListNode.attributes.forEach((xml.XmlAttribute navigationListNodeAttribute) { + var attributeValue = navigationListNodeAttribute.value; + switch (navigationListNodeAttribute.name.local.toLowerCase()) { + case 'id': + result.Id = attributeValue; + break; + case 'class': + result.Class = attributeValue; + break; + } + }); + navigationListNode.children.whereType().forEach((xml.XmlElement navigationListChildNode) { + switch (navigationListChildNode.name.local.toLowerCase()) { + case 'navlabel': + var navigationLabel = readNavigationLabel(navigationListChildNode); + result.NavigationLabels!.add(navigationLabel); + break; + case 'navtarget': + var navigationTarget = readNavigationTarget(navigationListChildNode); + result.NavigationTargets!.add(navigationTarget); + break; + } + }); + // if (result.NavigationLabels!.isEmpty) { + // throw Exception( + // 'Incorrect EPUB navigation page target: at least one navLabel element is required.'); + // } + return result; + } + + static EpubNavigationMap readNavigationMap(xml.XmlElement navigationMapNode) { + var result = EpubNavigationMap(); + result.Points = []; + navigationMapNode.children.whereType().forEach((xml.XmlElement navigationPointNode) { + if (navigationPointNode.name.local.toLowerCase() == 'navpoint') { + var navigationPoint = readNavigationPoint(navigationPointNode); + result.Points!.add(navigationPoint); + } + }); + return result; + } + + static EpubNavigationMap readNavigationMapV3(xml.XmlElement navigationMapNode) { + var result = EpubNavigationMap(); + result.Points = []; + navigationMapNode.children.whereType().forEach((xml.XmlElement navigationPointNode) { + if (navigationPointNode.name.local.toLowerCase() == 'li') { + var navigationPoint = readNavigationPointV3(navigationPointNode); + result.Points!.add(navigationPoint); + } + }); + return result; + } + + static EpubNavigationPageList readNavigationPageList(xml.XmlElement navigationPageListNode) { + var result = EpubNavigationPageList(); + result.Targets = []; + navigationPageListNode.children.whereType().forEach((xml.XmlElement pageTargetNode) { + if (pageTargetNode.name.local == 'pageTarget') { + var pageTarget = readNavigationPageTarget(pageTargetNode); + result.Targets!.add(pageTarget); + } + }); + + return result; + } + + static EpubNavigationPageTarget readNavigationPageTarget(xml.XmlElement navigationPageTargetNode) { + var result = EpubNavigationPageTarget(); + result.NavigationLabels = []; + navigationPageTargetNode.attributes.forEach((xml.XmlAttribute navigationPageTargetNodeAttribute) { + var attributeValue = navigationPageTargetNodeAttribute.value; + switch (navigationPageTargetNodeAttribute.name.local.toLowerCase()) { + case 'id': + result.Id = attributeValue; + break; + case 'value': + result.Value = attributeValue; + break; + case 'type': + var converter = EnumFromString(EpubNavigationPageTargetType.values); + var type = converter.get(attributeValue); + result.Type = type; + break; + case 'class': + result.Class = attributeValue; + break; + case 'playorder': + result.PlayOrder = attributeValue; + break; + } + }); + if (result.Type == EpubNavigationPageTargetType.UNDEFINED) { + throw Exception('Incorrect EPUB navigation page target: page target type is missing.'); + } + + navigationPageTargetNode.children + .whereType() + .forEach((xml.XmlElement navigationPageTargetChildNode) { + switch (navigationPageTargetChildNode.name.local.toLowerCase()) { + case 'navlabel': + var navigationLabel = readNavigationLabel(navigationPageTargetChildNode); + result.NavigationLabels!.add(navigationLabel); + break; + case 'content': + var content = readNavigationContent(navigationPageTargetChildNode); + result.Content = content; + break; + } + }); + if (result.NavigationLabels!.isEmpty) { + throw Exception('Incorrect EPUB navigation page target: at least one navLabel element is required.'); + } + + return result; + } + + static EpubNavigationPoint readNavigationPoint(xml.XmlElement navigationPointNode) { + var result = EpubNavigationPoint(); + navigationPointNode.attributes.forEach((xml.XmlAttribute navigationPointNodeAttribute) { + var attributeValue = navigationPointNodeAttribute.value; + switch (navigationPointNodeAttribute.name.local.toLowerCase()) { + case 'id': + result.Id = attributeValue; + break; + case 'class': + result.Class = attributeValue; + break; + case 'playorder': + result.PlayOrder = attributeValue; + break; + } + }); + if (result.Id == null || result.Id!.isEmpty) { + throw Exception('Incorrect EPUB navigation point: point ID is missing.'); + } + + result.NavigationLabels = []; + result.ChildNavigationPoints = []; + navigationPointNode.children.whereType().forEach((xml.XmlElement navigationPointChildNode) { + switch (navigationPointChildNode.name.local.toLowerCase()) { + case 'navlabel': + var navigationLabel = readNavigationLabel(navigationPointChildNode); + result.NavigationLabels!.add(navigationLabel); + break; + case 'content': + var content = readNavigationContent(navigationPointChildNode); + result.Content = content; + break; + case 'navpoint': + var childNavigationPoint = readNavigationPoint(navigationPointChildNode); + result.ChildNavigationPoints!.add(childNavigationPoint); + break; + } + }); + + if (result.NavigationLabels!.isEmpty) { + throw Exception( + 'EPUB parsing error: navigation point ${result.Id} should contain at least one navigation label.'); + } + if (result.Content == null) { + throw Exception('EPUB parsing error: navigation point ${result.Id} should contain content.'); + } + + return result; + } + + static EpubNavigationPoint readNavigationPointV3(xml.XmlElement navigationPointNode) { + var result = EpubNavigationPoint(); + + result.NavigationLabels = []; + result.ChildNavigationPoints = []; + navigationPointNode.children.whereType().forEach((xml.XmlElement navigationPointChildNode) { + switch (navigationPointChildNode.name.local.toLowerCase()) { + case 'a': + case 'span': + var navigationLabel = readNavigationLabelV3(navigationPointChildNode); + result.NavigationLabels!.add(navigationLabel); + var content = readNavigationContentV3(navigationPointChildNode); + result.Content = content; + break; + case 'ol': + readNavigationMapV3(navigationPointChildNode).Points!.forEach((point) { + result.ChildNavigationPoints!.add(point); + }); + break; + } + }); + + if (result.NavigationLabels!.isEmpty) { + throw Exception( + 'EPUB parsing error: navigation point ${result.Id} should contain at least one navigation label.'); + } + if (result.Content == null) { + throw Exception('EPUB parsing error: navigation point ${result.Id} should contain content.'); + } + + return result; + } + + static EpubNavigationTarget readNavigationTarget(xml.XmlElement navigationTargetNode) { + var result = EpubNavigationTarget(); + navigationTargetNode.attributes.forEach((xml.XmlAttribute navigationPageTargetNodeAttribute) { + var attributeValue = navigationPageTargetNodeAttribute.value; + switch (navigationPageTargetNodeAttribute.name.local.toLowerCase()) { + case 'id': + result.Id = attributeValue; + break; + case 'value': + result.Value = attributeValue; + break; + case 'class': + result.Class = attributeValue; + break; + case 'playorder': + result.PlayOrder = attributeValue; + break; + } + }); + if (result.Id == null || result.Id!.isEmpty) { + throw Exception('Incorrect EPUB navigation target: navigation target ID is missing.'); + } + + navigationTargetNode.children.whereType().forEach((xml.XmlElement navigationTargetChildNode) { + switch (navigationTargetChildNode.name.local.toLowerCase()) { + case 'navlabel': + var navigationLabel = readNavigationLabel(navigationTargetChildNode); + result.NavigationLabels!.add(navigationLabel); + break; + case 'content': + var content = readNavigationContent(navigationTargetChildNode); + result.Content = content; + break; + } + }); + if (result.NavigationLabels!.isEmpty) { + throw Exception('Incorrect EPUB navigation target: at least one navLabel element is required.'); + } + + return result; + } +} diff --git a/epubx/lib/src/readers/package_reader.dart b/epubx/lib/src/readers/package_reader.dart new file mode 100644 index 00000000..6df17f39 --- /dev/null +++ b/epubx/lib/src/readers/package_reader.dart @@ -0,0 +1,409 @@ +import 'dart:async'; + +import 'package:archive/archive.dart'; +import 'dart:convert' as convert; +import 'package:collection/collection.dart' show IterableExtension; +import 'package:xml/xml.dart'; + +import '../schema/opf/epub_guide.dart'; +import '../schema/opf/epub_guide_reference.dart'; +import '../schema/opf/epub_manifest.dart'; +import '../schema/opf/epub_manifest_item.dart'; +import '../schema/opf/epub_metadata.dart'; +import '../schema/opf/epub_metadata_contributor.dart'; +import '../schema/opf/epub_metadata_creator.dart'; +import '../schema/opf/epub_metadata_date.dart'; +import '../schema/opf/epub_metadata_identifier.dart'; +import '../schema/opf/epub_metadata_meta.dart'; +import '../schema/opf/epub_package.dart'; +import '../schema/opf/epub_spine.dart'; +import '../schema/opf/epub_spine_item_ref.dart'; +import '../schema/opf/epub_version.dart'; + +class PackageReader { + static EpubGuide readGuide(XmlElement guideNode) { + var result = EpubGuide(); + result.Items = []; + guideNode.children + .whereType() + .forEach((XmlElement guideReferenceNode) { + if (guideReferenceNode.name.local.toLowerCase() == 'reference') { + var guideReference = EpubGuideReference(); + guideReferenceNode.attributes + .forEach((XmlAttribute guideReferenceNodeAttribute) { + var attributeValue = guideReferenceNodeAttribute.value; + switch (guideReferenceNodeAttribute.name.local.toLowerCase()) { + case 'type': + guideReference.Type = attributeValue; + break; + case 'title': + guideReference.Title = attributeValue; + break; + case 'href': + guideReference.Href = attributeValue; + break; + } + }); + if (guideReference.Type == null || guideReference.Type!.isEmpty) { + throw Exception('Incorrect EPUB guide: item type is missing'); + } + if (guideReference.Href == null || guideReference.Href!.isEmpty) { + throw Exception('Incorrect EPUB guide: item href is missing'); + } + result.Items!.add(guideReference); + } + }); + return result; + } + + static EpubManifest readManifest(XmlElement manifestNode) { + var result = EpubManifest(); + result.Items = []; + manifestNode.children + .whereType() + .forEach((XmlElement manifestItemNode) { + if (manifestItemNode.name.local.toLowerCase() == 'item') { + var manifestItem = EpubManifestItem(); + manifestItemNode.attributes + .forEach((XmlAttribute manifestItemNodeAttribute) { + var attributeValue = manifestItemNodeAttribute.value; + switch (manifestItemNodeAttribute.name.local.toLowerCase()) { + case 'id': + manifestItem.Id = attributeValue; + break; + case 'href': + manifestItem.Href = attributeValue; + break; + case 'media-type': + manifestItem.MediaType = attributeValue; + break; + case 'media-overlay': + manifestItem.MediaOverlay = attributeValue; + break; + case 'required-namespace': + manifestItem.RequiredNamespace = attributeValue; + break; + case 'required-modules': + manifestItem.RequiredModules = attributeValue; + break; + case 'fallback': + manifestItem.Fallback = attributeValue; + break; + case 'fallback-style': + manifestItem.FallbackStyle = attributeValue; + break; + case 'properties': + manifestItem.Properties = attributeValue; + break; + } + }); + + if (manifestItem.Id == null || manifestItem.Id!.isEmpty) { + throw Exception('Incorrect EPUB manifest: item ID is missing'); + } + if (manifestItem.Href == null || manifestItem.Href!.isEmpty) { + throw Exception('Incorrect EPUB manifest: item href is missing'); + } + if (manifestItem.MediaType == null || manifestItem.MediaType!.isEmpty) { + throw Exception( + 'Incorrect EPUB manifest: item media type is missing'); + } + result.Items!.add(manifestItem); + } + }); + return result; + } + + static EpubMetadata readMetadata( + XmlElement metadataNode, EpubVersion? epubVersion) { + var result = EpubMetadata(); + result.Titles = []; + result.Creators = []; + result.Subjects = []; + result.Publishers = []; + result.Contributors = []; + result.Dates = []; + result.Types = []; + result.Formats = []; + result.Identifiers = []; + result.Sources = []; + result.Languages = []; + result.Relations = []; + result.Coverages = []; + result.Rights = []; + result.MetaItems = []; + metadataNode.children + .whereType() + .forEach((XmlElement metadataItemNode) { + var innerText = metadataItemNode.text; + switch (metadataItemNode.name.local.toLowerCase()) { + case 'title': + result.Titles!.add(innerText); + break; + case 'creator': + var creator = readMetadataCreator(metadataItemNode); + result.Creators!.add(creator); + break; + case 'subject': + result.Subjects!.add(innerText); + break; + case 'description': + result.Description = innerText; + break; + case 'publisher': + result.Publishers!.add(innerText); + break; + case 'contributor': + var contributor = readMetadataContributor(metadataItemNode); + result.Contributors!.add(contributor); + break; + case 'date': + var date = readMetadataDate(metadataItemNode); + result.Dates!.add(date); + break; + case 'type': + result.Types!.add(innerText); + break; + case 'format': + result.Formats!.add(innerText); + break; + case 'identifier': + var identifier = readMetadataIdentifier(metadataItemNode); + result.Identifiers!.add(identifier); + break; + case 'source': + result.Sources!.add(innerText); + break; + case 'language': + result.Languages!.add(innerText); + break; + case 'relation': + result.Relations!.add(innerText); + break; + case 'coverage': + result.Coverages!.add(innerText); + break; + case 'rights': + result.Rights!.add(innerText); + break; + case 'meta': + if (epubVersion == EpubVersion.Epub2) { + var meta = readMetadataMetaVersion2(metadataItemNode); + result.MetaItems!.add(meta); + } else if (epubVersion == EpubVersion.Epub3) { + var meta = readMetadataMetaVersion3(metadataItemNode); + result.MetaItems!.add(meta); + } + break; + } + }); + return result; + } + + static EpubMetadataContributor readMetadataContributor( + XmlElement metadataContributorNode) { + var result = EpubMetadataContributor(); + metadataContributorNode.attributes + .forEach((XmlAttribute metadataContributorNodeAttribute) { + var attributeValue = metadataContributorNodeAttribute.value; + switch (metadataContributorNodeAttribute.name.local.toLowerCase()) { + case 'role': + result.Role = attributeValue; + break; + case 'file-as': + result.FileAs = attributeValue; + break; + } + }); + result.Contributor = metadataContributorNode.text; + return result; + } + + static EpubMetadataCreator readMetadataCreator( + XmlElement metadataCreatorNode) { + var result = EpubMetadataCreator(); + metadataCreatorNode.attributes + .forEach((XmlAttribute metadataCreatorNodeAttribute) { + var attributeValue = metadataCreatorNodeAttribute.value; + switch (metadataCreatorNodeAttribute.name.local.toLowerCase()) { + case 'role': + result.Role = attributeValue; + break; + case 'file-as': + result.FileAs = attributeValue; + break; + } + }); + result.Creator = metadataCreatorNode.text; + return result; + } + + static EpubMetadataDate readMetadataDate(XmlElement metadataDateNode) { + var result = EpubMetadataDate(); + var eventAttribute = metadataDateNode.getAttribute('event', + namespace: metadataDateNode.name.namespaceUri); + if (eventAttribute != null && eventAttribute.isNotEmpty) { + result.Event = eventAttribute; + } + result.Date = metadataDateNode.text; + return result; + } + + static EpubMetadataIdentifier readMetadataIdentifier( + XmlElement metadataIdentifierNode) { + var result = EpubMetadataIdentifier(); + metadataIdentifierNode.attributes + .forEach((XmlAttribute metadataIdentifierNodeAttribute) { + var attributeValue = metadataIdentifierNodeAttribute.value; + switch (metadataIdentifierNodeAttribute.name.local.toLowerCase()) { + case 'id': + result.Id = attributeValue; + break; + case 'scheme': + result.Scheme = attributeValue; + break; + } + }); + result.Identifier = metadataIdentifierNode.text; + return result; + } + + static EpubMetadataMeta readMetadataMetaVersion2( + XmlElement metadataMetaNode) { + var result = EpubMetadataMeta(); + metadataMetaNode.attributes + .forEach((XmlAttribute metadataMetaNodeAttribute) { + var attributeValue = metadataMetaNodeAttribute.value; + switch (metadataMetaNodeAttribute.name.local.toLowerCase()) { + case 'name': + result.Name = attributeValue; + break; + case 'content': + result.Content = attributeValue; + break; + } + }); + return result; + } + + static EpubMetadataMeta readMetadataMetaVersion3( + XmlElement metadataMetaNode) { + var result = EpubMetadataMeta(); + result.Attributes = {}; + metadataMetaNode.attributes + .forEach((XmlAttribute metadataMetaNodeAttribute) { + var attributeValue = metadataMetaNodeAttribute.value; + result.Attributes![metadataMetaNodeAttribute.name.local.toLowerCase()] = + attributeValue; + switch (metadataMetaNodeAttribute.name.local.toLowerCase()) { + case 'id': + result.Id = attributeValue; + break; + case 'refines': + result.Refines = attributeValue; + break; + case 'property': + result.Property = attributeValue; + break; + case 'scheme': + result.Scheme = attributeValue; + break; + case 'content': + result.Content = attributeValue; + break; + case 'name': + result.Name = attributeValue; + break; + } + }); + result.Content = result.Content ?? metadataMetaNode.text; + return result; + } + + static Future readPackage( + Archive epubArchive, String rootFilePath) async { + var rootFileEntry = epubArchive.files.firstWhereOrNull( + (ArchiveFile testFile) => testFile.name == rootFilePath); + if (rootFileEntry == null) { + throw Exception('EPUB parsing error: root file not found in archive.'); + } + var containerDocument = + XmlDocument.parse(convert.utf8.decode(rootFileEntry.content)); + var opfNamespace = 'http://www.idpf.org/2007/opf'; + var packageNode = containerDocument + .findElements('package', namespace: opfNamespace) + .firstWhere((XmlElement? elem) => elem != null); + var result = EpubPackage(); + var epubVersionValue = packageNode.getAttribute('version'); + if (epubVersionValue == '2.0') { + result.Version = EpubVersion.Epub2; + } else if (epubVersionValue == '3.0') { + result.Version = EpubVersion.Epub3; + } else { + throw Exception('Unsupported EPUB version: $epubVersionValue.'); + } + var metadataNode = packageNode + .findElements('metadata', namespace: opfNamespace) + .cast() + .firstWhere((XmlElement? elem) => elem != null); + if (metadataNode == null) { + throw Exception('EPUB parsing error: metadata not found in the package.'); + } + var metadata = readMetadata(metadataNode, result.Version); + result.Metadata = metadata; + var manifestNode = packageNode + .findElements('manifest', namespace: opfNamespace) + .cast() + .firstWhere((XmlElement? elem) => elem != null); + if (manifestNode == null) { + throw Exception('EPUB parsing error: manifest not found in the package.'); + } + var manifest = readManifest(manifestNode); + result.Manifest = manifest; + + var spineNode = packageNode + .findElements('spine', namespace: opfNamespace) + .cast() + .firstWhere((XmlElement? elem) => elem != null); + if (spineNode == null) { + throw Exception('EPUB parsing error: spine not found in the package.'); + } + var spine = readSpine(spineNode); + result.Spine = spine; + var guideNode = packageNode + .findElements('guide', namespace: opfNamespace) + .firstWhereOrNull((XmlElement? elem) => elem != null); + if (guideNode != null) { + var guide = readGuide(guideNode); + result.Guide = guide; + } + return result; + } + + static EpubSpine readSpine(XmlElement spineNode) { + var result = EpubSpine(); + result.Items = []; + var tocAttribute = spineNode.getAttribute('toc'); + result.TableOfContents = tocAttribute; + var pageProgression = spineNode.getAttribute('page-progression-direction'); + result.ltr = + ((pageProgression == null) || pageProgression.toLowerCase() == 'ltr'); + spineNode.children + .whereType() + .forEach((XmlElement spineItemNode) { + if (spineItemNode.name.local.toLowerCase() == 'itemref') { + var spineItemRef = EpubSpineItemRef(); + var idRefAttribute = spineItemNode.getAttribute('idref'); + if (idRefAttribute == null || idRefAttribute.isEmpty) { + throw Exception('Incorrect EPUB spine: item ID ref is missing'); + } + spineItemRef.IdRef = idRefAttribute; + var linearAttribute = spineItemNode.getAttribute('linear'); + spineItemRef.IsLinear = + linearAttribute == null || (linearAttribute.toLowerCase() == 'no'); + result.Items!.add(spineItemRef); + } + }); + return result; + } +} diff --git a/epubx/lib/src/readers/root_file_path_reader.dart b/epubx/lib/src/readers/root_file_path_reader.dart new file mode 100644 index 00000000..0110414f --- /dev/null +++ b/epubx/lib/src/readers/root_file_path_reader.dart @@ -0,0 +1,36 @@ +import 'dart:async'; + +import 'package:archive/archive.dart'; +import 'dart:convert' as convert; +import 'package:collection/collection.dart' show IterableExtension; +import 'package:xml/xml.dart' as xml; + +class RootFilePathReader { + static Future getRootFilePath(Archive epubArchive) async { + const EPUB_CONTAINER_FILE_PATH = 'META-INF/container.xml'; + + var containerFileEntry = epubArchive.files.firstWhereOrNull( + (ArchiveFile file) => file.name == EPUB_CONTAINER_FILE_PATH); + if (containerFileEntry == null) { + throw Exception( + 'EPUB parsing error: $EPUB_CONTAINER_FILE_PATH file not found in archive.'); + } + + var containerDocument = + xml.XmlDocument.parse(convert.utf8.decode(containerFileEntry.content)); + var packageElement = containerDocument + .findAllElements('container', + namespace: 'urn:oasis:names:tc:opendocument:xmlns:container') + .firstWhereOrNull((xml.XmlElement? elem) => elem != null); + if (packageElement == null) { + throw Exception('EPUB parsing error: Invalid epub container'); + } + + var rootFileElement = packageElement.descendants.firstWhereOrNull( + (xml.XmlNode testElem) => + (testElem is xml.XmlElement) && + 'rootfile' == testElem.name.local) as xml.XmlElement; + + return rootFileElement.getAttribute('full-path'); + } +} diff --git a/epubx/lib/src/readers/schema_reader.dart b/epubx/lib/src/readers/schema_reader.dart new file mode 100644 index 00000000..d931c0a8 --- /dev/null +++ b/epubx/lib/src/readers/schema_reader.dart @@ -0,0 +1,28 @@ +import 'dart:async'; + +import 'package:archive/archive.dart'; + +import '../entities/epub_schema.dart'; +import '../utils/zip_path_utils.dart'; +import 'navigation_reader.dart'; +import 'package_reader.dart'; +import 'root_file_path_reader.dart'; + +class SchemaReader { + static Future readSchema(Archive epubArchive) async { + var result = EpubSchema(); + + var rootFilePath = (await RootFilePathReader.getRootFilePath(epubArchive))!; + var contentDirectoryPath = ZipPathUtils.getDirectoryPath(rootFilePath); + result.ContentDirectoryPath = contentDirectoryPath; + + var package = await PackageReader.readPackage(epubArchive, rootFilePath); + result.Package = package; + + var navigation = await NavigationReader.readNavigation( + epubArchive, contentDirectoryPath, package); + result.Navigation = navigation; + + return result; + } +} diff --git a/epubx/lib/src/ref_entities/epub_book_ref.dart b/epubx/lib/src/ref_entities/epub_book_ref.dart new file mode 100644 index 00000000..7ddd4b1a --- /dev/null +++ b/epubx/lib/src/ref_entities/epub_book_ref.dart @@ -0,0 +1,62 @@ +import 'dart:async'; + +import 'package:archive/archive.dart'; +import 'package:image/image.dart'; +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import '../entities/epub_schema.dart'; +import '../readers/book_cover_reader.dart'; +import '../readers/chapter_reader.dart'; +import 'epub_chapter_ref.dart'; +import 'epub_content_ref.dart'; + +class EpubBookRef { + Archive? _epubArchive; + + String? Title; + String? Author; + List? AuthorList; + EpubSchema? Schema; + EpubContentRef? Content; + EpubBookRef(Archive epubArchive) { + _epubArchive = epubArchive; + } + + @override + int get hashCode { + var objects = [ + Title.hashCode, + Author.hashCode, + Schema.hashCode, + Content.hashCode, + ...AuthorList?.map((author) => author.hashCode) ?? [0], + ]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + if (!(other is EpubBookRef)) { + return false; + } + + return Title == other.Title && + Author == other.Author && + Schema == other.Schema && + Content == other.Content && + collections.listsEqual(AuthorList, other.AuthorList); + } + + Archive? EpubArchive() { + return _epubArchive; + } + + Future> getChapters() async { + return ChapterReader.getChapters(this); + } + + Future readCover() async { + return await BookCoverReader.readBookCover(this); + } +} diff --git a/epubx/lib/src/ref_entities/epub_byte_content_file_ref.dart b/epubx/lib/src/ref_entities/epub_byte_content_file_ref.dart new file mode 100644 index 00000000..85a2792d --- /dev/null +++ b/epubx/lib/src/ref_entities/epub_byte_content_file_ref.dart @@ -0,0 +1,12 @@ +import 'dart:async'; + +import 'epub_book_ref.dart'; +import 'epub_content_file_ref.dart'; + +class EpubByteContentFileRef extends EpubContentFileRef { + EpubByteContentFileRef(EpubBookRef epubBookRef) : super(epubBookRef); + + Future> readContent() { + return readContentAsBytes(); + } +} diff --git a/epubx/lib/src/ref_entities/epub_chapter_ref.dart b/epubx/lib/src/ref_entities/epub_chapter_ref.dart new file mode 100644 index 00000000..5e68e8af --- /dev/null +++ b/epubx/lib/src/ref_entities/epub_chapter_ref.dart @@ -0,0 +1,72 @@ +import 'dart:async'; + +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_text_content_file_ref.dart'; + +class EpubChapterRef { + // Referece to Text content reader. + EpubTextContentFileRef? epubTextContentFileRef; + // If the chapter is split into multiple files, this list contains the references to content readers of the other files. + List otherTextContentFileRefs = []; + + String? Title; + String? ContentFileName; + String? Anchor; + List? SubChapters; + // If the chapter is split into multiple files, this list contains the names of the other files. + List OtherContentFileNames = []; + + EpubChapterRef(EpubTextContentFileRef? epubTextContentFileRef) { + this.epubTextContentFileRef = epubTextContentFileRef; + } + + @override + int get hashCode { + var objects = [ + Title.hashCode, + ContentFileName.hashCode, + OtherContentFileNames.hashCode, + Anchor.hashCode, + epubTextContentFileRef.hashCode, + otherTextContentFileRefs.hashCode, + ...SubChapters?.map((subChapter) => subChapter.hashCode) ?? [0], + ]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + if (!(other is EpubChapterRef)) { + return false; + } + return Title == other.Title && + ContentFileName == other.ContentFileName && + OtherContentFileNames == other.OtherContentFileNames && + Anchor == other.Anchor && + epubTextContentFileRef == other.epubTextContentFileRef && + otherTextContentFileRefs == other.otherTextContentFileRefs && + collections.listsEqual(SubChapters, other.SubChapters); + } + + Future readHtmlContent() async { + var contentFuture = epubTextContentFileRef!.readContentAsText(); + if (OtherContentFileNames.isNotEmpty) { + var allContentFutures = >[contentFuture]; + for (var otherContentFileRef in otherTextContentFileRefs) { + allContentFutures.add(otherContentFileRef.readContentAsText()); + } + return Future.wait(allContentFutures).then((List contents) { + return contents.join(''); + }); + } else { + return contentFuture; + } + } + + @override + String toString() { + return 'Title: $Title, Subchapter count: ${SubChapters!.length}'; + } +} diff --git a/epubx/lib/src/ref_entities/epub_content_file_ref.dart b/epubx/lib/src/ref_entities/epub_content_file_ref.dart new file mode 100644 index 00000000..7c20f47e --- /dev/null +++ b/epubx/lib/src/ref_entities/epub_content_file_ref.dart @@ -0,0 +1,85 @@ +import 'dart:async'; +import 'dart:convert' as convert; +import 'dart:typed_data'; + +import 'package:archive/archive.dart'; +import 'package:collection/collection.dart' show IterableExtension; +import 'package:quiver/core.dart'; + +import '../entities/epub_content_type.dart'; +import '../utils/zip_path_utils.dart'; +import 'epub_book_ref.dart'; + +abstract class EpubContentFileRef { + late EpubBookRef epubBookRef; + + String? FileName; + + EpubContentType? ContentType; + String? ContentMimeType; + EpubContentFileRef(EpubBookRef epubBookRef) { + this.epubBookRef = epubBookRef; + } + + @override + int get hashCode => + hash3(FileName.hashCode, ContentMimeType.hashCode, ContentType.hashCode); + + @override + bool operator ==(other) { + if (!(other is EpubContentFileRef)) { + return false; + } + + return (other.FileName == FileName && + other.ContentMimeType == ContentMimeType && + other.ContentType == ContentType); + } + + ArchiveFile getContentFileEntry() { + var contentFilePath = ZipPathUtils.combine( + epubBookRef.Schema!.ContentDirectoryPath, FileName); + var contentFileEntry = epubBookRef.EpubArchive()! + .files + .firstWhereOrNull((ArchiveFile x) => x.name == contentFilePath); + if (contentFileEntry == null) { + throw Exception( + 'EPUB parsing error: file $contentFilePath not found in archive.'); + } + return contentFileEntry; + } + + List getContentStream() { + return openContentStream(getContentFileEntry()); + } + + List openContentStream(ArchiveFile contentFileEntry) { + var contentStream = []; + if (contentFileEntry.content == null) { + throw Exception( + 'Incorrect EPUB file: content file \"$FileName\" specified in manifest is not found.'); + } + contentStream.addAll(contentFileEntry.content); + return contentStream; + } + + Future readContentAsBytes() async { + try { + var contentFileEntry = getContentFileEntry(); + var content = openContentStream(contentFileEntry); + return Uint8List.fromList(content); + } catch (_) { + return Uint8List.fromList([]); + } + } + + Future readContentAsText() async { + try { + var contentStream = getContentStream(); + var result = convert.utf8.decode(contentStream); + return result; + } catch (_) { + return ""; + } + } +} diff --git a/epubx/lib/src/ref_entities/epub_content_ref.dart b/epubx/lib/src/ref_entities/epub_content_ref.dart new file mode 100644 index 00000000..287a6ed1 --- /dev/null +++ b/epubx/lib/src/ref_entities/epub_content_ref.dart @@ -0,0 +1,53 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_byte_content_file_ref.dart'; +import 'epub_content_file_ref.dart'; +import 'epub_text_content_file_ref.dart'; + +class EpubContentRef { + Map? Html; + Map? Css; + Map? Images; + Map? Fonts; + Map? AllFiles; + + EpubContentRef() { + Html = {}; + Css = {}; + Images = {}; + Fonts = {}; + AllFiles = {}; + } + + @override + int get hashCode { + var objects = [ + ...Html!.keys.map((key) => key.hashCode), + ...Html!.values.map((value) => value.hashCode), + ...Css!.keys.map((key) => key.hashCode), + ...Css!.values.map((value) => value.hashCode), + ...Images!.keys.map((key) => key.hashCode), + ...Images!.values.map((value) => value.hashCode), + ...Fonts!.keys.map((key) => key.hashCode), + ...Fonts!.values.map((value) => value.hashCode), + ...AllFiles!.keys.map((key) => key.hashCode), + ...AllFiles!.values.map((value) => value.hashCode) + ]; + + return hashObjects(objects); + } + + @override + bool operator ==(other) { + if (!(other is EpubContentRef)) { + return false; + } + + return collections.mapsEqual(Html, other.Html) && + collections.mapsEqual(Css, other.Css) && + collections.mapsEqual(Images, other.Images) && + collections.mapsEqual(Fonts, other.Fonts) && + collections.mapsEqual(AllFiles, other.AllFiles); + } +} diff --git a/epubx/lib/src/ref_entities/epub_text_content_file_ref.dart b/epubx/lib/src/ref_entities/epub_text_content_file_ref.dart new file mode 100644 index 00000000..647458cf --- /dev/null +++ b/epubx/lib/src/ref_entities/epub_text_content_file_ref.dart @@ -0,0 +1,12 @@ +import 'dart:async'; + +import 'epub_book_ref.dart'; +import 'epub_content_file_ref.dart'; + +class EpubTextContentFileRef extends EpubContentFileRef { + EpubTextContentFileRef(EpubBookRef epubBookRef) : super(epubBookRef); + + Future ReadContentAsync() async { + return readContentAsText(); + } +} diff --git a/epubx/lib/src/schema/navigation/epub_metadata.dart b/epubx/lib/src/schema/navigation/epub_metadata.dart new file mode 100644 index 00000000..b27ae3e4 --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_metadata.dart @@ -0,0 +1,22 @@ +import 'package:quiver/core.dart'; + +class EpubNavigationContent { + String? Id; + String? Source; + + @override + int get hashCode => hash2(Id.hashCode, Source.hashCode); + + @override + bool operator ==(other) { + if (!(other is EpubNavigationContent)) { + return false; + } + return Id == other.Id && Source == other.Source; + } + + @override + String toString() { + return 'Source: $Source'; + } +} diff --git a/epubx/lib/src/schema/navigation/epub_navigation.dart b/epubx/lib/src/schema/navigation/epub_navigation.dart new file mode 100644 index 00000000..f6fc5e3c --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation.dart @@ -0,0 +1,51 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_navigation_doc_author.dart'; +import 'epub_navigation_doc_title.dart'; +import 'epub_navigation_head.dart'; +import 'epub_navigation_list.dart'; +import 'epub_navigation_map.dart'; +import 'epub_navigation_page_list.dart'; + +class EpubNavigation { + EpubNavigationHead? Head; + EpubNavigationDocTitle? DocTitle; + List? DocAuthors; + EpubNavigationMap? NavMap; + EpubNavigationPageList? PageList; + List? NavLists; + + @override + int get hashCode { + var objects = [ + Head.hashCode, + DocTitle.hashCode, + NavMap.hashCode, + PageList.hashCode, + ...DocAuthors?.map((author) => author.hashCode) ?? [0], + ...NavLists?.map((navList) => navList.hashCode) ?? [0] + ]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubNavigation?; + if (otherAs == null) { + return false; + } + + if (!collections.listsEqual(DocAuthors, otherAs.DocAuthors)) { + return false; + } + if (!collections.listsEqual(NavLists, otherAs.NavLists)) { + return false; + } + + return Head == otherAs.Head && + DocTitle == otherAs.DocTitle && + NavMap == otherAs.NavMap && + PageList == otherAs.PageList; + } +} diff --git a/epubx/lib/src/schema/navigation/epub_navigation_doc_author.dart b/epubx/lib/src/schema/navigation/epub_navigation_doc_author.dart new file mode 100644 index 00000000..b5275fe8 --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation_doc_author.dart @@ -0,0 +1,24 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +class EpubNavigationDocAuthor { + List? Authors; + + EpubNavigationDocAuthor() { + Authors = []; + } + + @override + int get hashCode { + var objects = [...Authors!.map((author) => author.hashCode)]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubNavigationDocAuthor?; + if (otherAs == null) return false; + + return collections.listsEqual(Authors, otherAs.Authors); + } +} diff --git a/epubx/lib/src/schema/navigation/epub_navigation_doc_title.dart b/epubx/lib/src/schema/navigation/epub_navigation_doc_title.dart new file mode 100644 index 00000000..3e48cfc3 --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation_doc_title.dart @@ -0,0 +1,24 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +class EpubNavigationDocTitle { + List? Titles; + + EpubNavigationDocTitle() { + Titles = []; + } + + @override + int get hashCode { + var objects = [...Titles!.map((title) => title.hashCode)]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubNavigationDocTitle?; + if (otherAs == null) return false; + + return collections.listsEqual(Titles, otherAs.Titles); + } +} diff --git a/epubx/lib/src/schema/navigation/epub_navigation_head.dart b/epubx/lib/src/schema/navigation/epub_navigation_head.dart new file mode 100644 index 00000000..4b2e2e09 --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation_head.dart @@ -0,0 +1,28 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_navigation_head_meta.dart'; + +class EpubNavigationHead { + List? Metadata; + + EpubNavigationHead() { + Metadata = []; + } + + @override + int get hashCode { + var objects = [...Metadata!.map((meta) => meta.hashCode)]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubNavigationHead?; + if (otherAs == null) { + return false; + } + + return collections.listsEqual(Metadata, otherAs.Metadata); + } +} diff --git a/epubx/lib/src/schema/navigation/epub_navigation_head_meta.dart b/epubx/lib/src/schema/navigation/epub_navigation_head_meta.dart new file mode 100644 index 00000000..a9e3bb27 --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation_head_meta.dart @@ -0,0 +1,22 @@ +import 'package:quiver/core.dart'; + +class EpubNavigationHeadMeta { + String? Name; + String? Content; + String? Scheme; + + @override + int get hashCode => hash3(Name.hashCode, Content.hashCode, Scheme.hashCode); + + @override + bool operator ==(other) { + var otherAs = other as EpubNavigationHeadMeta?; + if (otherAs == null) { + return false; + } + + return Name == otherAs.Name && + Content == otherAs.Content && + Scheme == otherAs.Scheme; + } +} diff --git a/epubx/lib/src/schema/navigation/epub_navigation_label.dart b/epubx/lib/src/schema/navigation/epub_navigation_label.dart new file mode 100644 index 00000000..910a1d53 --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation_label.dart @@ -0,0 +1,18 @@ +class EpubNavigationLabel { + String? Text; + + @override + int get hashCode => Text.hashCode; + + @override + bool operator ==(other) { + var otherAs = other as EpubNavigationLabel?; + if (otherAs == null) return false; + return Text == otherAs.Text; + } + + @override + String toString() { + return Text!; + } +} diff --git a/epubx/lib/src/schema/navigation/epub_navigation_list.dart b/epubx/lib/src/schema/navigation/epub_navigation_list.dart new file mode 100644 index 00000000..60c55048 --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation_list.dart @@ -0,0 +1,41 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_navigation_label.dart'; +import 'epub_navigation_target.dart'; + +class EpubNavigationList { + String? Id; + String? Class; + List? NavigationLabels; + List? NavigationTargets; + + @override + int get hashCode { + var objects = [ + Id.hashCode, + Class.hashCode, + ...NavigationLabels?.map((label) => label.hashCode) ?? [0], + ...NavigationTargets?.map((target) => target.hashCode) ?? [0] + ]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubNavigationList?; + if (otherAs == null) return false; + + if (!(Id == otherAs.Id && Class == otherAs.Class)) { + return false; + } + + if (!collections.listsEqual(NavigationLabels, otherAs.NavigationLabels)) { + return false; + } + if (!collections.listsEqual(NavigationTargets, otherAs.NavigationTargets)) { + return false; + } + return true; + } +} diff --git a/epubx/lib/src/schema/navigation/epub_navigation_map.dart b/epubx/lib/src/schema/navigation/epub_navigation_map.dart new file mode 100644 index 00000000..24208aff --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation_map.dart @@ -0,0 +1,21 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_navigation_point.dart'; + +class EpubNavigationMap { + List? Points; + + @override + int get hashCode { + return hashObjects(Points?.map((point) => point.hashCode) ?? [0]); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubNavigationMap?; + if (otherAs == null) return false; + + return collections.listsEqual(Points, otherAs.Points); + } +} diff --git a/epubx/lib/src/schema/navigation/epub_navigation_page_list.dart b/epubx/lib/src/schema/navigation/epub_navigation_page_list.dart new file mode 100644 index 00000000..f0ae694f --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation_page_list.dart @@ -0,0 +1,21 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_navigation_page_target.dart'; + +class EpubNavigationPageList { + List? Targets; + + @override + int get hashCode { + return hashObjects(Targets?.map((target) => target.hashCode) ?? [0]); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubNavigationPageList?; + if (otherAs == null) return false; + + return collections.listsEqual(Targets, otherAs.Targets); + } +} diff --git a/epubx/lib/src/schema/navigation/epub_navigation_page_target.dart b/epubx/lib/src/schema/navigation/epub_navigation_page_target.dart new file mode 100644 index 00000000..76ebd08f --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation_page_target.dart @@ -0,0 +1,49 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_metadata.dart'; +import 'epub_navigation_label.dart'; +import 'epub_navigation_page_target_type.dart'; + +class EpubNavigationPageTarget { + String? Id; + String? Value; + EpubNavigationPageTargetType? Type; + String? Class; + String? PlayOrder; + List? NavigationLabels; + EpubNavigationContent? Content; + + @override + int get hashCode { + var objects = [ + Id.hashCode, + Value.hashCode, + Type.hashCode, + Class.hashCode, + PlayOrder.hashCode, + Content.hashCode, + ...NavigationLabels?.map((label) => label.hashCode) ?? [0] + ]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubNavigationPageTarget?; + if (otherAs == null) { + return false; + } + + if (!(Id == otherAs.Id && + Value == otherAs.Value && + Type == otherAs.Type && + Class == otherAs.Class && + PlayOrder == otherAs.PlayOrder && + Content == otherAs.Content)) { + return false; + } + + return collections.listsEqual(NavigationLabels, otherAs.NavigationLabels); + } +} diff --git a/epubx/lib/src/schema/navigation/epub_navigation_page_target_type.dart b/epubx/lib/src/schema/navigation/epub_navigation_page_target_type.dart new file mode 100644 index 00000000..49ee43b9 --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation_page_target_type.dart @@ -0,0 +1 @@ +enum EpubNavigationPageTargetType { UNDEFINED, FRONT, NORMAL, SPECIAL } diff --git a/epubx/lib/src/schema/navigation/epub_navigation_point.dart b/epubx/lib/src/schema/navigation/epub_navigation_point.dart new file mode 100644 index 00000000..fc12c652 --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation_point.dart @@ -0,0 +1,52 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_metadata.dart'; +import 'epub_navigation_label.dart'; + +class EpubNavigationPoint { + String? Id; + String? Class; + String? PlayOrder; + List? NavigationLabels; + EpubNavigationContent? Content; + List? ChildNavigationPoints; + + @override + int get hashCode { + var objects = [ + Id.hashCode, + Class.hashCode, + PlayOrder.hashCode, + Content.hashCode, + ...NavigationLabels!.map((label) => label.hashCode), + ...ChildNavigationPoints!.map((point) => point.hashCode) + ]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubNavigationPoint?; + if (otherAs == null) { + return false; + } + + if (!collections.listsEqual(NavigationLabels, otherAs.NavigationLabels)) { + return false; + } + + if (!collections.listsEqual( + ChildNavigationPoints, otherAs.ChildNavigationPoints)) return false; + + return Id == otherAs.Id && + Class == otherAs.Class && + PlayOrder == otherAs.PlayOrder && + Content == otherAs.Content; + } + + @override + String toString() { + return 'Id: $Id, Content.Source: ${Content!.Source}'; + } +} diff --git a/epubx/lib/src/schema/navigation/epub_navigation_target.dart b/epubx/lib/src/schema/navigation/epub_navigation_target.dart new file mode 100644 index 00000000..8ef2b7a1 --- /dev/null +++ b/epubx/lib/src/schema/navigation/epub_navigation_target.dart @@ -0,0 +1,43 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_metadata.dart'; +import 'epub_navigation_label.dart'; + +class EpubNavigationTarget { + String? Id; + String? Class; + String? Value; + String? PlayOrder; + List? NavigationLabels; + EpubNavigationContent? Content; + + @override + int get hashCode { + var objects = [ + Id.hashCode, + Class.hashCode, + Value.hashCode, + PlayOrder.hashCode, + Content.hashCode, + ...NavigationLabels!.map((label) => label.hashCode) + ]; + return hashObjects(objects); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubNavigationTarget?; + if (otherAs == null) return false; + + if (!(Id == otherAs.Id && + Class == otherAs.Class && + Value == otherAs.Value && + PlayOrder == otherAs.PlayOrder && + Content == otherAs.Content)) { + return false; + } + + return collections.listsEqual(NavigationLabels, otherAs.NavigationLabels); + } +} diff --git a/epubx/lib/src/schema/opf/epub_guide.dart b/epubx/lib/src/schema/opf/epub_guide.dart new file mode 100644 index 00000000..f715bc47 --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_guide.dart @@ -0,0 +1,29 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_guide_reference.dart'; + +class EpubGuide { + List? Items; + + EpubGuide() { + Items = []; + } + + @override + int get hashCode { + var objects = []; + objects.addAll(Items!.map((item) => item.hashCode)); + return hashObjects(objects); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubGuide?; + if (otherAs == null) { + return false; + } + + return collections.listsEqual(Items, otherAs.Items); + } +} diff --git a/epubx/lib/src/schema/opf/epub_guide_reference.dart b/epubx/lib/src/schema/opf/epub_guide_reference.dart new file mode 100644 index 00000000..bb56700f --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_guide_reference.dart @@ -0,0 +1,27 @@ +import 'package:quiver/core.dart'; + +class EpubGuideReference { + String? Type; + String? Title; + String? Href; + + @override + int get hashCode => hash3(Type.hashCode, Title.hashCode, Href.hashCode); + + @override + bool operator ==(other) { + var otherAs = other as EpubGuideReference?; + if (otherAs == null) { + return false; + } + + return Type == otherAs.Type && + Title == otherAs.Title && + Href == otherAs.Href; + } + + @override + String toString() { + return 'Type: $Type, Href: $Href'; + } +} diff --git a/epubx/lib/src/schema/opf/epub_manifest.dart b/epubx/lib/src/schema/opf/epub_manifest.dart new file mode 100644 index 00000000..1c45f222 --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_manifest.dart @@ -0,0 +1,26 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_manifest_item.dart'; + +class EpubManifest { + List? Items; + + EpubManifest() { + Items = []; + } + + @override + int get hashCode { + return hashObjects(Items!.map((item) => item.hashCode)); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubManifest?; + if (otherAs == null) { + return false; + } + return collections.listsEqual(Items, otherAs.Items); + } +} diff --git a/epubx/lib/src/schema/opf/epub_manifest_item.dart b/epubx/lib/src/schema/opf/epub_manifest_item.dart new file mode 100644 index 00000000..6af69ee0 --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_manifest_item.dart @@ -0,0 +1,49 @@ +import 'package:quiver/core.dart'; + +class EpubManifestItem { + String? Id; + String? Href; + String? MediaType; + String? MediaOverlay; + String? RequiredNamespace; + String? RequiredModules; + String? Fallback; + String? FallbackStyle; + String? Properties; + + @override + int get hashCode => hashObjects([ + Id.hashCode, + Href.hashCode, + MediaType.hashCode, + MediaOverlay.hashCode, + RequiredNamespace.hashCode, + RequiredModules.hashCode, + Fallback.hashCode, + FallbackStyle.hashCode, + Properties.hashCode + ]); + + @override + bool operator ==(other) { + var otherAs = other as EpubManifestItem?; + if (otherAs == null) { + return false; + } + + return Id == otherAs.Id && + Href == otherAs.Href && + MediaType == otherAs.MediaType && + MediaOverlay == otherAs.MediaOverlay && + RequiredNamespace == otherAs.RequiredNamespace && + RequiredModules == otherAs.RequiredModules && + Fallback == otherAs.Fallback && + FallbackStyle == otherAs.FallbackStyle && + Properties == otherAs.Properties; + } + + @override + String toString() { + return 'Id: $Id, Href = $Href, MediaType = $MediaType, Properties = $Properties, MediaOverlay = $MediaOverlay'; + } +} diff --git a/epubx/lib/src/schema/opf/epub_metadata.dart b/epubx/lib/src/schema/opf/epub_metadata.dart new file mode 100644 index 00000000..88b99f64 --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_metadata.dart @@ -0,0 +1,78 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_metadata_contributor.dart'; +import 'epub_metadata_creator.dart'; +import 'epub_metadata_date.dart'; +import 'epub_metadata_identifier.dart'; +import 'epub_metadata_meta.dart'; + +class EpubMetadata { + List? Titles; + List? Creators; + List? Subjects; + String? Description; + List? Publishers; + List? Contributors; + List? Dates; + List? Types; + List? Formats; + List? Identifiers; + List? Sources; + List? Languages; + List? Relations; + List? Coverages; + List? Rights; + List? MetaItems; + + @override + int get hashCode { + var objects = [ + ...Titles!.map((title) => title.hashCode), + ...Creators!.map((creator) => creator.hashCode), + ...Subjects!.map((subject) => subject.hashCode), + ...Publishers!.map((publisher) => publisher.hashCode), + ...Contributors!.map((contributor) => contributor.hashCode), + ...Dates!.map((date) => date.hashCode), + ...Types!.map((type) => type.hashCode), + ...Formats!.map((format) => format.hashCode), + ...Identifiers!.map((identifier) => identifier.hashCode), + ...Sources!.map((source) => source.hashCode), + ...Languages!.map((language) => language.hashCode), + ...Relations!.map((relation) => relation.hashCode), + ...Coverages!.map((coverage) => coverage.hashCode), + ...Rights!.map((right) => right.hashCode), + ...MetaItems!.map((metaItem) => metaItem.hashCode), + Description.hashCode + ]; + + return hashObjects(objects); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubMetadata?; + if (otherAs == null) return false; + if (Description != otherAs.Description) return false; + + if (!collections.listsEqual(Titles, otherAs.Titles) || + !collections.listsEqual(Creators, otherAs.Creators) || + !collections.listsEqual(Subjects, otherAs.Subjects) || + !collections.listsEqual(Publishers, otherAs.Publishers) || + !collections.listsEqual(Contributors, otherAs.Contributors) || + !collections.listsEqual(Dates, otherAs.Dates) || + !collections.listsEqual(Types, otherAs.Types) || + !collections.listsEqual(Formats, otherAs.Formats) || + !collections.listsEqual(Identifiers, otherAs.Identifiers) || + !collections.listsEqual(Sources, otherAs.Sources) || + !collections.listsEqual(Languages, otherAs.Languages) || + !collections.listsEqual(Relations, otherAs.Relations) || + !collections.listsEqual(Coverages, otherAs.Coverages) || + !collections.listsEqual(Rights, otherAs.Rights) || + !collections.listsEqual(MetaItems, otherAs.MetaItems)) { + return false; + } + + return true; + } +} diff --git a/epubx/lib/src/schema/opf/epub_metadata_contributor.dart b/epubx/lib/src/schema/opf/epub_metadata_contributor.dart new file mode 100644 index 00000000..c10796cc --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_metadata_contributor.dart @@ -0,0 +1,21 @@ +import 'package:quiver/core.dart'; + +class EpubMetadataContributor { + String? Contributor; + String? FileAs; + String? Role; + + @override + int get hashCode => + hash3(Contributor.hashCode, FileAs.hashCode, Role.hashCode); + + @override + bool operator ==(other) { + var otherAs = other as EpubMetadataContributor?; + if (otherAs == null) return false; + + return Contributor == otherAs.Contributor && + FileAs == otherAs.FileAs && + Role == otherAs.Role; + } +} diff --git a/epubx/lib/src/schema/opf/epub_metadata_creator.dart b/epubx/lib/src/schema/opf/epub_metadata_creator.dart new file mode 100644 index 00000000..d81e1ea9 --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_metadata_creator.dart @@ -0,0 +1,19 @@ +import 'package:quiver/core.dart'; + +class EpubMetadataCreator { + String? Creator; + String? FileAs; + String? Role; + + @override + int get hashCode => hash3(Creator.hashCode, FileAs.hashCode, Role.hashCode); + + @override + bool operator ==(other) { + var otherAs = other as EpubMetadataCreator?; + if (otherAs == null) return false; + return Creator == otherAs.Creator && + FileAs == otherAs.FileAs && + Role == otherAs.Role; + } +} diff --git a/epubx/lib/src/schema/opf/epub_metadata_date.dart b/epubx/lib/src/schema/opf/epub_metadata_date.dart new file mode 100644 index 00000000..37983e21 --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_metadata_date.dart @@ -0,0 +1,16 @@ +import 'package:quiver/core.dart'; + +class EpubMetadataDate { + String? Date; + String? Event; + + @override + int get hashCode => hash2(Date.hashCode, Event.hashCode); + + @override + bool operator ==(other) { + var otherAs = other as EpubMetadataDate?; + if (otherAs == null) return false; + return Date == otherAs.Date && Event == otherAs.Event; + } +} diff --git a/epubx/lib/src/schema/opf/epub_metadata_identifier.dart b/epubx/lib/src/schema/opf/epub_metadata_identifier.dart new file mode 100644 index 00000000..52a91e76 --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_metadata_identifier.dart @@ -0,0 +1,19 @@ +import 'package:quiver/core.dart'; + +class EpubMetadataIdentifier { + String? Id; + String? Scheme; + String? Identifier; + + @override + int get hashCode => hash3(Id.hashCode, Scheme.hashCode, Identifier.hashCode); + + @override + bool operator ==(other) { + var otherAs = other as EpubMetadataIdentifier?; + if (otherAs == null) return false; + return Id == otherAs.Id && + Scheme == otherAs.Scheme && + Identifier == otherAs.Identifier; + } +} diff --git a/epubx/lib/src/schema/opf/epub_metadata_meta.dart b/epubx/lib/src/schema/opf/epub_metadata_meta.dart new file mode 100644 index 00000000..7b32b836 --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_metadata_meta.dart @@ -0,0 +1,33 @@ +import 'package:quiver/core.dart'; + +class EpubMetadataMeta { + String? Name; + String? Content; + String? Id; + String? Refines; + String? Property; + String? Scheme; + Map? Attributes; + + @override + int get hashCode => hashObjects([ + Name.hashCode, + Content.hashCode, + Id.hashCode, + Refines.hashCode, + Property.hashCode, + Scheme.hashCode + ]); + + @override + bool operator ==(other) { + var otherAs = other as EpubMetadataMeta?; + if (otherAs == null) return false; + return Name == otherAs.Name && + Content == otherAs.Content && + Id == otherAs.Id && + Refines == otherAs.Refines && + Property == otherAs.Property && + Scheme == otherAs.Scheme; + } +} diff --git a/epubx/lib/src/schema/opf/epub_package.dart b/epubx/lib/src/schema/opf/epub_package.dart new file mode 100644 index 00000000..992839bf --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_package.dart @@ -0,0 +1,38 @@ +import 'package:quiver/core.dart'; + +import 'epub_guide.dart'; +import 'epub_manifest.dart'; +import 'epub_metadata.dart'; +import 'epub_spine.dart'; +import 'epub_version.dart'; + +class EpubPackage { + EpubVersion? Version; + EpubMetadata? Metadata; + EpubManifest? Manifest; + EpubSpine? Spine; + EpubGuide? Guide; + + @override + int get hashCode => hashObjects([ + Version.hashCode, + Metadata.hashCode, + Manifest.hashCode, + Spine.hashCode, + Guide.hashCode + ]); + + @override + bool operator ==(other) { + var otherAs = other as EpubPackage?; + if (otherAs == null) { + return false; + } + + return Version == otherAs.Version && + Metadata == otherAs.Metadata && + Manifest == otherAs.Manifest && + Spine == otherAs.Spine && + Guide == otherAs.Guide; + } +} diff --git a/epubx/lib/src/schema/opf/epub_spine.dart b/epubx/lib/src/schema/opf/epub_spine.dart new file mode 100644 index 00000000..777a4cef --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_spine.dart @@ -0,0 +1,32 @@ +import 'package:quiver/collection.dart' as collections; +import 'package:quiver/core.dart'; + +import 'epub_spine_item_ref.dart'; + +class EpubSpine { + String? TableOfContents; + List? Items; + bool? ltr; + + @override + int get hashCode { + var objs = [ + TableOfContents.hashCode, + ltr.hashCode, + ...Items!.map((item) => item.hashCode) + ]; + return hashObjects(objs); + } + + @override + bool operator ==(other) { + var otherAs = other as EpubSpine?; + if (otherAs == null) return false; + + if (!collections.listsEqual(Items, otherAs.Items)) { + return false; + } + return ((TableOfContents == otherAs.TableOfContents) && + (ltr == otherAs.ltr)); + } +} diff --git a/epubx/lib/src/schema/opf/epub_spine_item_ref.dart b/epubx/lib/src/schema/opf/epub_spine_item_ref.dart new file mode 100644 index 00000000..2e7a9cea --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_spine_item_ref.dart @@ -0,0 +1,24 @@ +import 'package:quiver/core.dart'; + +class EpubSpineItemRef { + String? IdRef; + bool? IsLinear; + + @override + int get hashCode => hash2(IdRef.hashCode, IsLinear.hashCode); + + @override + bool operator ==(other) { + var otherAs = other as EpubSpineItemRef?; + if (otherAs == null) { + return false; + } + + return IdRef == otherAs.IdRef && IsLinear == otherAs.IsLinear; + } + + @override + String toString() { + return 'IdRef: $IdRef'; + } +} diff --git a/epubx/lib/src/schema/opf/epub_version.dart b/epubx/lib/src/schema/opf/epub_version.dart new file mode 100644 index 00000000..bb0eaee3 --- /dev/null +++ b/epubx/lib/src/schema/opf/epub_version.dart @@ -0,0 +1 @@ +enum EpubVersion { Epub2, Epub3 } diff --git a/epubx/lib/src/utils/enum_from_string.dart b/epubx/lib/src/utils/enum_from_string.dart new file mode 100644 index 00000000..02e1f510 --- /dev/null +++ b/epubx/lib/src/utils/enum_from_string.dart @@ -0,0 +1,16 @@ +class EnumFromString { + List enumValues; + + EnumFromString(this.enumValues); + + T? get(String value) { + value = '$T.$value'; + try { + var x = enumValues + .firstWhere((f) => f.toString().toUpperCase() == value.toUpperCase()); + return x; + } catch (e) { + return null; + } + } +} diff --git a/epubx/lib/src/utils/zip_path_utils.dart b/epubx/lib/src/utils/zip_path_utils.dart new file mode 100644 index 00000000..da22d8df --- /dev/null +++ b/epubx/lib/src/utils/zip_path_utils.dart @@ -0,0 +1,20 @@ +class ZipPathUtils { + static String getDirectoryPath(String filePath) { + var lastSlashIndex = filePath.lastIndexOf('/'); + if (lastSlashIndex == -1) { + return ''; + } else { + return filePath.substring(0, lastSlashIndex); + } + } + + static String? combine(String? directory, String? fileName) { + var path; + if (directory == null || directory == '') { + path = fileName; + } else { + path = directory + '/' + fileName!; + } + return Uri.parse(path).normalizePath().path; + } +} diff --git a/epubx/lib/src/writers/epub_guide_writer.dart b/epubx/lib/src/writers/epub_guide_writer.dart new file mode 100644 index 00000000..8dec0fbb --- /dev/null +++ b/epubx/lib/src/writers/epub_guide_writer.dart @@ -0,0 +1,15 @@ +import 'package:epubx/src/schema/opf/epub_guide.dart'; +import 'package:xml/src/xml/builder.dart' show XmlBuilder; + +class EpubGuideWriter { + static void writeGuide(XmlBuilder builder, EpubGuide? guide) { + builder.element('guide', nest: () { + guide!.Items!.forEach((guideItem) => builder.element('reference', + attributes: { + 'type': guideItem.Type!, + 'title': guideItem.Title!, + 'href': guideItem.Href! + })); + }); + } +} diff --git a/epubx/lib/src/writers/epub_manifest_writer.dart b/epubx/lib/src/writers/epub_manifest_writer.dart new file mode 100644 index 00000000..deee2dee --- /dev/null +++ b/epubx/lib/src/writers/epub_manifest_writer.dart @@ -0,0 +1,17 @@ +import 'package:epubx/src/schema/opf/epub_manifest.dart'; +import 'package:xml/src/xml/builder.dart' show XmlBuilder; + +class EpubManifestWriter { + static void writeManifest(XmlBuilder builder, EpubManifest? manifest) { + builder.element('manifest', nest: () { + manifest!.Items!.forEach((item) { + builder.element('item', nest: () { + builder + ..attribute('id', item.Id!) + ..attribute('href', item.Href!) + ..attribute('media-type', item.MediaType!); + }); + }); + }); + } +} diff --git a/epubx/lib/src/writers/epub_metadata_writer.dart b/epubx/lib/src/writers/epub_metadata_writer.dart new file mode 100644 index 00000000..299dc4ab --- /dev/null +++ b/epubx/lib/src/writers/epub_metadata_writer.dart @@ -0,0 +1,105 @@ +import 'package:epubx/src/schema/opf/epub_metadata.dart'; +import 'package:epubx/src/schema/opf/epub_version.dart'; +import 'package:xml/src/xml/builder.dart' show XmlBuilder; + +class EpubMetadataWriter { + static const _dc_namespace = 'http://purl.org/dc/elements/1.1/'; + static const _opf_namespace = 'http://www.idpf.org/2007/opf'; + + static void writeMetadata( + XmlBuilder builder, EpubMetadata? meta, EpubVersion? version) { + builder.element('metadata', + namespaces: {_opf_namespace: 'opf', _dc_namespace: 'dc'}, nest: () { + meta! + ..Titles?.forEach((item) => + builder.element('title', nest: item, namespace: _dc_namespace)) + ..Creators?.forEach((item) => + builder.element('creator', namespace: _dc_namespace, nest: () { + if (item.Role != null) { + builder.attribute('role', item.Role!, + namespace: _opf_namespace); + } + if (item.FileAs != null) { + builder.attribute('file-as', item.FileAs!, + namespace: _opf_namespace); + } + builder.text(item.Creator!); + })) + ..Subjects?.forEach((item) => + builder.element('subject', namespace: _dc_namespace, nest: item)) + ..Publishers?.forEach((item) => + builder.element('publisher', namespace: _dc_namespace, nest: item)) + ..Contributors?.forEach((item) => + builder.element('contributor', namespace: _dc_namespace, nest: () { + if (item.Role != null) { + builder.attribute('role', item.Role!, + namespace: _opf_namespace); + } + if (item.FileAs != null) { + builder.attribute('file-as', item.FileAs!, + namespace: _opf_namespace); + } + builder.text(item.Contributor!); + })) + ..Dates?.forEach((date) => + builder.element('date', namespace: _dc_namespace, nest: () { + if (date.Event != null) { + builder.attribute('event', date.Event!, + namespace: _opf_namespace); + } + builder.text(date.Date!); + })) + ..Types?.forEach((type) => + builder.element('type', namespace: _dc_namespace, nest: type)) + ..Formats?.forEach((format) => + builder.element('format', namespace: _dc_namespace, nest: format)) + ..Identifiers?.forEach((id) => + builder.element('identifier', namespace: _dc_namespace, nest: () { + if (id.Id != null) builder.attribute('id', id.Id!); + if (id.Scheme != null) { + builder.attribute('scheme', id.Scheme!, + namespace: _opf_namespace); + } + builder.text(id.Identifier!); + })) + ..Sources?.forEach((item) => + builder.element('source', namespace: _dc_namespace, nest: item)) + ..Languages?.forEach((item) => + builder.element('language', namespace: _dc_namespace, nest: item)) + ..Relations?.forEach((item) => + builder.element('relation', namespace: _dc_namespace, nest: item)) + ..Coverages?.forEach((item) => + builder.element('coverage', namespace: _dc_namespace, nest: item)) + ..Rights?.forEach((item) => + builder.element('rights', namespace: _dc_namespace, nest: item)) + ..MetaItems?.forEach((metaitem) => builder.element('meta', nest: () { + if (version == EpubVersion.Epub2) { + if (metaitem.Name != null) { + builder.attribute('name', metaitem.Name!); + } + if (metaitem.Content != null) { + builder.attribute('content', metaitem.Content!); + } + } else if (version == EpubVersion.Epub3) { + if (metaitem.Id != null) { + builder.attribute('id', metaitem.Id!); + } + if (metaitem.Refines != null) { + builder.attribute('refines', metaitem.Refines!); + } + if (metaitem.Property != null) { + builder.attribute('property', metaitem.Property!); + } + if (metaitem.Scheme != null) { + builder.attribute('scheme', metaitem.Scheme!); + } + } + })); + + if (meta.Description != null) { + builder.element('description', + namespace: _dc_namespace, nest: meta.Description); + } + }); + } +} diff --git a/epubx/lib/src/writers/epub_navigation_writer.dart b/epubx/lib/src/writers/epub_navigation_writer.dart new file mode 100644 index 00000000..d71e1e41 --- /dev/null +++ b/epubx/lib/src/writers/epub_navigation_writer.dart @@ -0,0 +1,67 @@ +import 'package:epubx/src/schema/navigation/epub_navigation.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_doc_title.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_head.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_map.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_point.dart'; +import 'package:xml/src/xml/builder.dart' show XmlBuilder; + +class EpubNavigationWriter { + static const String _namespace = 'http://www.daisy.org/z3986/2005/ncx/'; + + static String writeNavigation(EpubNavigation navigation) { + var builder = XmlBuilder(); + builder.processing('xml', 'version="1.0"'); + + builder.element('ncx', attributes: { + 'version': '2005-1', + 'lang': 'en', + }, nest: () { + builder.namespace(_namespace); + + writeNavigationHead(builder, navigation.Head!); + writeNavigationDocTitle(builder, navigation.DocTitle!); + writeNavigationMap(builder, navigation.NavMap!); + }); + + return builder.buildDocument().toXmlString(pretty: false); + } + + static void writeNavigationDocTitle( + XmlBuilder builder, EpubNavigationDocTitle title) { + builder.element('docTitle', nest: () { + title.Titles!.forEach((element) { + builder.text(element); + }); + }); + } + + static void writeNavigationHead(XmlBuilder builder, EpubNavigationHead head) { + builder.element('head', nest: () { + head.Metadata!.forEach((item) => builder.element('meta', + attributes: {'content': item.Content!, 'name': item.Name!})); + }); + } + + static void writeNavigationMap(XmlBuilder builder, EpubNavigationMap map) { + builder.element('navMap', nest: () { + map.Points!.forEach((item) => writeNavigationPoint(builder, item)); + }); + } + + static void writeNavigationPoint( + XmlBuilder builder, EpubNavigationPoint point) { + builder.element('navPoint', attributes: { + 'id': point.Id!, + 'playOrder': point.PlayOrder!, + }, nest: () { + point.NavigationLabels!.forEach((element) { + builder.element('navLabel', nest: () { + builder.element('text', nest: () { + builder.text(element.Text!); + }); + }); + }); + builder.element('content', attributes: {'src': point.Content!.Source!}); + }); + } +} diff --git a/epubx/lib/src/writers/epub_package_writer.dart b/epubx/lib/src/writers/epub_package_writer.dart new file mode 100644 index 00000000..97fb4278 --- /dev/null +++ b/epubx/lib/src/writers/epub_package_writer.dart @@ -0,0 +1,31 @@ +import 'package:epubx/src/schema/opf/epub_package.dart'; +import 'package:epubx/src/schema/opf/epub_version.dart'; +import 'package:epubx/src/writers/epub_guide_writer.dart'; +import 'package:epubx/src/writers/epub_manifest_writer.dart'; +import 'package:epubx/src/writers/epub_spine_writer.dart'; +import 'package:xml/src/xml/builder.dart' show XmlBuilder; +import 'epub_metadata_writer.dart'; + +class EpubPackageWriter { + static const String _namespace = 'http://www.idpf.org/2007/opf'; + + static String writeContent(EpubPackage package) { + var builder = XmlBuilder(); + builder.processing('xml', 'version="1.0"'); + + builder.element('package', attributes: { + 'version': package.Version == EpubVersion.Epub2 ? '2.0' : '3.0', + 'unique-identifier': 'etextno', + }, nest: () { + builder.namespace(_namespace); + + EpubMetadataWriter.writeMetadata( + builder, package.Metadata, package.Version); + EpubManifestWriter.writeManifest(builder, package.Manifest); + EpubSpineWriter.writeSpine(builder, package.Spine!); + EpubGuideWriter.writeGuide(builder, package.Guide); + }); + + return builder.buildDocument().toXmlString(pretty: false); + } +} diff --git a/epubx/lib/src/writers/epub_spine_writer.dart b/epubx/lib/src/writers/epub_spine_writer.dart new file mode 100644 index 00000000..3e0ee310 --- /dev/null +++ b/epubx/lib/src/writers/epub_spine_writer.dart @@ -0,0 +1,15 @@ +import 'package:epubx/src/schema/opf/epub_spine.dart'; +import 'package:xml/src/xml/builder.dart' show XmlBuilder; + +class EpubSpineWriter { + static void writeSpine(XmlBuilder builder, EpubSpine spine) { + builder.element('spine', attributes: {'toc': spine.TableOfContents!}, + nest: () { + spine.Items!.forEach((spineitem) => builder.element('itemref', + attributes: { + 'idref': spineitem.IdRef!, + 'linear': spineitem.IsLinear! ? 'yes' : 'no' + })); + }); + } +} diff --git a/epubx/pubspec.yaml b/epubx/pubspec.yaml new file mode 100644 index 00000000..35d789e2 --- /dev/null +++ b/epubx/pubspec.yaml @@ -0,0 +1,20 @@ +name: epubx +description: Epub Parser for Dart. Epub package fork. Suitable for use on the Server, the Web, or in Flutter +homepage: https://github.com/rbcprolabs/epubx.dart +issue_tracker: https://github.com/rbcprolabs/epubx.dart +version: 4.0.3 + +environment: + sdk: ">=3.0.0 <4.0.0" + +dependencies: + archive: ^4.0.5 + quiver: ^3.0.1+1 + path: ^1.9.1 + xml: ^6.0.1 + image: ^4.5.3 + collection: ^1.15.0 + +dev_dependencies: + test: ^1.16.7 + lints: ^5.1.1 diff --git a/epubx/test/entities/epub_book_test.dart b/epubx/test/entities/epub_book_test.dart new file mode 100644 index 00000000..81da0b82 --- /dev/null +++ b/epubx/test/entities/epub_book_test.dart @@ -0,0 +1,148 @@ +library epubreadertest; + +import 'package:epubx/epub.dart'; +import 'package:epubx/src/entities/epub_schema.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubBook(); + reference + ..Author = "orthros" + ..AuthorList = ["orthros"] + ..Chapters = [new EpubChapter()] + ..Content = new EpubContent() + ..CoverImage = Image(100, 100) + ..Schema = new EpubSchema() + ..Title = "A Dissertation on Epubs"; + + EpubBook testBook; + setUp(() async { + testBook = new EpubBook(); + testBook + ..Author = "orthros" + ..AuthorList = ["orthros"] + ..Chapters = [new EpubChapter()] + ..Content = new EpubContent() + ..CoverImage = Image(100, 100) + ..Schema = new EpubSchema() + ..Title = "A Dissertation on Epubs"; + }); + tearDown(() async { + testBook = null; + }); + group("EpubBook", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testBook, equals(reference)); + }); + + test("is false when Content changes", () async { + var file = new EpubTextContentFile(); + file + ..Content = "Hello" + ..ContentMimeType = "application/txt" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthros.txt"; + + EpubContent content = new EpubContent(); + content.AllFiles["hello"] = file; + testBook.Content = content; + + expect(testBook, isNot(reference)); + }); + + test("is false when Author changes", () async { + testBook.Author = "NotOrthros"; + expect(testBook, isNot(reference)); + }); + + test("is false when AuthorList changes", () async { + testBook.AuthorList = ["NotOrthros"]; + expect(testBook, isNot(reference)); + }); + + test("is false when Chapters changes", () async { + var chapter = new EpubChapter(); + chapter + ..Title = "A Brave new Epub" + ..ContentFileName = "orthros.txt"; + testBook.Chapters = [chapter]; + expect(testBook, isNot(reference)); + }); + + test("is false when CoverImage changes", () async { + testBook.CoverImage = new Image(200, 200); + expect(testBook, isNot(reference)); + }); + + test("is false when Schema changes", () async { + var schema = new EpubSchema(); + schema.ContentDirectoryPath = "some/random/path"; + testBook.Schema = schema; + expect(testBook, isNot(reference)); + }); + + test("is false when Title changes", () async { + testBook.Title = "The Philosophy of Epubs"; + expect(testBook, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testBook.hashCode, equals(reference.hashCode)); + }); + + test("is false when Content changes", () async { + var file = new EpubTextContentFile(); + file + ..Content = "Hello" + ..ContentMimeType = "application/txt" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthros.txt"; + + EpubContent content = new EpubContent(); + content.AllFiles["hello"] = file; + testBook.Content = content; + + expect(testBook.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Author changes", () async { + testBook.Author = "NotOrthros"; + expect(testBook.hashCode, isNot(reference.hashCode)); + }); + + test("is false when AuthorList changes", () async { + testBook.AuthorList = ["NotOrthros"]; + expect(testBook.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Chapters changes", () async { + var chapter = new EpubChapter(); + chapter + ..Title = "A Brave new Epub" + ..ContentFileName = "orthros.txt"; + testBook.Chapters = [chapter]; + expect(testBook.hashCode, isNot(reference.hashCode)); + }); + + test("is false when CoverImage changes", () async { + testBook.CoverImage = new Image(200, 200); + expect(testBook.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Schema changes", () async { + var schema = new EpubSchema(); + schema.ContentDirectoryPath = "some/random/path"; + testBook.Schema = schema; + expect(testBook.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Title changes", () async { + testBook.Title = "The Philosophy of Epubs"; + expect(testBook.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/entities/epub_byte_content_file_test.dart b/epubx/test/entities/epub_byte_content_file_test.dart new file mode 100644 index 00000000..a29d0ca6 --- /dev/null +++ b/epubx/test/entities/epub_byte_content_file_test.dart @@ -0,0 +1,78 @@ +library epubreadertest; + +import 'package:epubx/epub.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubByteContentFile(); + reference + ..Content = [0, 1, 2, 3] + ..ContentMimeType = "application/test" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthrosFile"; + + EpubByteContentFile testFile; + + setUp(() async { + testFile = new EpubByteContentFile(); + testFile + ..Content = [0, 1, 2, 3] + ..ContentMimeType = "application/test" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthrosFile"; + }); + + tearDown(() async { + testFile = null; + }); + + group("EpubByteContentFile", () { + test(".equals is true for equivalent objects", () async { + expect(testFile, equals(reference)); + }); + + test(".equals is false when Content changes", () async { + testFile.Content = [3, 2, 1, 0]; + expect(testFile, isNot(reference)); + }); + + test(".equals is false when ContentMimeType changes", () async { + testFile.ContentMimeType = "application/different"; + expect(testFile, isNot(reference)); + }); + + test(".equals is false when ContentType changes", () async { + testFile.ContentType = EpubContentType.CSS; + expect(testFile, isNot(reference)); + }); + + test(".equals is false when FileName changes", () async { + testFile.FileName = "a_different_file_name.txt"; + expect(testFile, isNot(reference)); + }); + + test(".hashCode is the same for equivalent content", () async { + expect(testFile.hashCode, equals(reference.hashCode)); + }); + + test('.hashCode changes when Content changes', () async { + testFile.Content = [3, 2, 1, 0]; + expect(testFile.hashCode, isNot(reference.hashCode)); + }); + + test('.hashCode changes when ContentMimeType changes', () async { + testFile.ContentMimeType = "application/orthros"; + expect(testFile.hashCode, isNot(reference.hashCode)); + }); + + test('.hashCode changes when ContentType changes', () async { + testFile.ContentType = EpubContentType.CSS; + expect(testFile.hashCode, isNot(reference.hashCode)); + }); + + test('.hashCode changes when FileName changes', () async { + testFile.FileName = "a_different_file_name"; + expect(testFile.hashCode, isNot(reference.hashCode)); + }); + }); +} diff --git a/epubx/test/entities/epub_chapter_test.dart b/epubx/test/entities/epub_chapter_test.dart new file mode 100644 index 00000000..d0f5921e --- /dev/null +++ b/epubx/test/entities/epub_chapter_test.dart @@ -0,0 +1,103 @@ +library epubreadertest; + +import 'package:epubx/epub.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubChapter(); + reference + ..Anchor = "anchor" + ..ContentFileName = "orthros" + ..HtmlContent = "" + ..SubChapters = [] + ..Title = "A New Look at Chapters"; + + EpubChapter testChapter; + setUp(() async { + testChapter = new EpubChapter(); + testChapter + ..Anchor = "anchor" + ..ContentFileName = "orthros" + ..HtmlContent = "" + ..SubChapters = [] + ..Title = "A New Look at Chapters"; + }); + tearDown(() async { + testChapter = null; + }); + group("EpubChapter", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testChapter, equals(reference)); + }); + + test("is false when HtmlContent changes", () async { + testChapter.HtmlContent = "I'm sure this isn't valid Html"; + expect(testChapter, isNot(reference)); + }); + + test("is false when Anchor changes", () async { + testChapter.Anchor = "NotAnAnchor"; + expect(testChapter, isNot(reference)); + }); + + test("is false when ContentFileName changes", () async { + testChapter.ContentFileName = "NotOrthros"; + expect(testChapter, isNot(reference)); + }); + + test("is false when SubChapters changes", () async { + var chapter = new EpubChapter(); + chapter + ..Title = "A Brave new Epub" + ..ContentFileName = "orthros.txt"; + testChapter.SubChapters = [chapter]; + expect(testChapter, isNot(reference)); + }); + + test("is false when Title changes", () async { + testChapter.Title = "A Boring Old World"; + expect(testChapter, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testChapter.hashCode, equals(reference.hashCode)); + }); + + test("is true for equivalent objects", () async { + expect(testChapter.hashCode, equals(reference.hashCode)); + }); + + test("is false when HtmlContent changes", () async { + testChapter.HtmlContent = "I'm sure this isn't valid Html"; + expect(testChapter.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Anchor changes", () async { + testChapter.Anchor = "NotAnAnchor"; + expect(testChapter.hashCode, isNot(reference.hashCode)); + }); + + test("is false when ContentFileName changes", () async { + testChapter.ContentFileName = "NotOrthros"; + expect(testChapter.hashCode, isNot(reference.hashCode)); + }); + + test("is false when SubChapters changes", () async { + var chapter = new EpubChapter(); + chapter + ..Title = "A Brave new Epub" + ..ContentFileName = "orthros.txt"; + testChapter.SubChapters = [chapter]; + expect(testChapter.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Title changes", () async { + testChapter.Title = "A Boring Old World"; + expect(testChapter.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/entities/epub_content_test.dart b/epubx/test/entities/epub_content_test.dart new file mode 100644 index 00000000..1da55209 --- /dev/null +++ b/epubx/test/entities/epub_content_test.dart @@ -0,0 +1,98 @@ +library epubreadertest; + +import 'package:epubx/epub.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubContent(); + + EpubContent testContent; + EpubTextContentFile textContentFile; + EpubByteContentFile byteContentFile; + + setUp(() async { + testContent = new EpubContent(); + + textContentFile = new EpubTextContentFile(); + textContentFile + ..Content = "Some string" + ..ContentMimeType = "application/text" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthros.txt"; + + byteContentFile = new EpubByteContentFile() + ..Content = [0, 1, 2, 3] + ..ContentMimeType = "application/orthros" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthros.bin"; + }); + + tearDown(() async { + testContent = null; + textContentFile = null; + byteContentFile = null; + }); + group("EpubContent", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testContent, equals(reference)); + }); + + test("is false when Html changes", () async { + testContent.Html["someKey"] = textContentFile; + expect(testContent, isNot(reference)); + }); + + test("is false when Css changes", () async { + testContent.Css["someKey"] = textContentFile; + expect(testContent, isNot(reference)); + }); + + test("is false when Images changes", () async { + testContent.Images["someKey"] = byteContentFile; + expect(testContent, isNot(reference)); + }); + + test("is false when Fonts changes", () async { + testContent.Fonts["someKey"] = byteContentFile; + expect(testContent, isNot(reference)); + }); + + test("is false when AllFiles changes", () async { + testContent.AllFiles["someKey"] = byteContentFile; + expect(testContent, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testContent.hashCode, equals(reference.hashCode)); + }); + + test("is false when Html changes", () async { + testContent.Html["someKey"] = textContentFile; + expect(testContent.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Css changes", () async { + testContent.Css["someKey"] = textContentFile; + expect(testContent.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Images changes", () async { + testContent.Images["someKey"] = byteContentFile; + expect(testContent.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Fonts changes", () async { + testContent.Fonts["someKey"] = byteContentFile; + expect(testContent.hashCode, isNot(reference.hashCode)); + }); + + test("is false when AllFiles changes", () async { + testContent.AllFiles["someKey"] = byteContentFile; + expect(testContent.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/entities/epub_schema_test.dart b/epubx/test/entities/epub_schema_test.dart new file mode 100644 index 00000000..46c914b9 --- /dev/null +++ b/epubx/test/entities/epub_schema_test.dart @@ -0,0 +1,88 @@ +library epubreadertest; + +import 'package:epubx/epub.dart'; +import 'package:epubx/src/entities/epub_schema.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_doc_author.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_doc_title.dart'; +import 'package:epubx/src/schema/opf/epub_guide.dart'; +import 'package:epubx/src/schema/opf/epub_version.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubSchema(); + reference + ..Package = new EpubPackage() + ..Navigation = new EpubNavigation() + ..ContentDirectoryPath = "some/random/path"; + reference.Package.Version = EpubVersion.Epub2; + + EpubSchema testSchema; + setUp(() async { + testSchema = new EpubSchema(); + testSchema + ..Package = new EpubPackage() + ..Navigation = new EpubNavigation() + ..ContentDirectoryPath = "some/random/path"; + testSchema.Package.Version = EpubVersion.Epub2; + }); + tearDown(() async { + testSchema = null; + }); + group("EpubSchema", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testSchema, equals(reference)); + }); + + test("is false when Package changes", () async { + var package = new EpubPackage() + ..Guide = new EpubGuide() + ..Version = EpubVersion.Epub3; + + testSchema.Package = package; + expect(testSchema, isNot(reference)); + }); + + test("is false when Navigation changes", () async { + testSchema.Navigation = new EpubNavigation() + ..DocTitle = new EpubNavigationDocTitle() + ..DocAuthors = [new EpubNavigationDocAuthor()]; + + expect(testSchema, isNot(reference)); + }); + + test("is false when ContentDirectoryPath changes", () async { + testSchema.ContentDirectoryPath = "some/other/random/path/to/dev/null"; + expect(testSchema, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testSchema.hashCode, equals(reference.hashCode)); + }); + + test("is false when Package changes", () async { + var package = new EpubPackage() + ..Guide = new EpubGuide() + ..Version = EpubVersion.Epub3; + + testSchema.Package = package; + expect(testSchema.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Navigation changes", () async { + testSchema.Navigation = new EpubNavigation() + ..DocTitle = new EpubNavigationDocTitle() + ..DocAuthors = [new EpubNavigationDocAuthor()]; + + expect(testSchema.hashCode, isNot(reference.hashCode)); + }); + + test("is false when ContentDirectoryPath changes", () async { + testSchema.ContentDirectoryPath = "some/other/random/path/to/dev/null"; + expect(testSchema.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/entities/epub_text_content_file_test.dart b/epubx/test/entities/epub_text_content_file_test.dart new file mode 100644 index 00000000..1e4b4bd5 --- /dev/null +++ b/epubx/test/entities/epub_text_content_file_test.dart @@ -0,0 +1,77 @@ +library epubreadertest; + +import 'package:epubx/epub.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubTextContentFile(); + reference + ..Content = "Hello" + ..ContentMimeType = "application/test" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthrosFile"; + EpubTextContentFile testFile; + setUp(() async { + testFile = new EpubTextContentFile(); + testFile + ..Content = "Hello" + ..ContentMimeType = "application/test" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthrosFile"; + }); + tearDown(() async { + testFile = null; + }); + group("EpubTextContentFile", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testFile, equals(reference)); + }); + + test("is false when Content changes", () async { + testFile.Content = "Goodbye"; + expect(testFile, isNot(reference)); + }); + + test("is false when ContentMimeType changes", () async { + testFile.ContentMimeType = "application/different"; + expect(testFile, isNot(reference)); + }); + + test("is false when ContentType changes", () async { + testFile.ContentType = EpubContentType.CSS; + expect(testFile, isNot(reference)); + }); + + test("is false when FileName changes", () async { + testFile.FileName = "a_different_file_name.txt"; + expect(testFile, isNot(reference)); + }); + }); + group(".hashCode", () { + test("is the same for equivalent content", () async { + expect(testFile.hashCode, equals(reference.hashCode)); + }); + + test('changes when Content changes', () async { + testFile.Content = "Goodbye"; + expect(testFile.hashCode, isNot(reference.hashCode)); + }); + + test('changes when ContentMimeType changes', () async { + testFile.ContentMimeType = "application/orthros"; + expect(testFile.hashCode, isNot(reference.hashCode)); + }); + + test('changes when ContentType changes', () async { + testFile.ContentType = EpubContentType.CSS; + expect(testFile.hashCode, isNot(reference.hashCode)); + }); + + test('changes when FileName changes', () async { + testFile.FileName = "a_different_file_name"; + expect(testFile.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/enum_string_test.dart b/epubx/test/enum_string_test.dart new file mode 100644 index 00000000..59a43427 --- /dev/null +++ b/epubx/test/enum_string_test.dart @@ -0,0 +1,26 @@ +library epubtest; + +import 'package:test/test.dart'; + +import 'package:epubx/epub.dart'; + +main() { + test("Enum One", () { + expect(new EnumFromString(Simple.values).get("ONE"), + equals(Simple.ONE)); + }); + test("Enum Two", () { + expect(new EnumFromString(Simple.values).get("TWO"), + equals(Simple.TWO)); + }); + test("Enum One", () { + expect(new EnumFromString(Simple.values).get("THREE"), + equals(Simple.THREE)); + }); + test("Enum One Lower Case", () { + expect(new EnumFromString(Simple.values).get("one"), + equals(Simple.ONE)); + }); +} + +enum Simple { ONE, TWO, THREE } diff --git a/epubx/test/epub_image_tests.dart b/epubx/test/epub_image_tests.dart new file mode 100644 index 00000000..c3f735cd --- /dev/null +++ b/epubx/test/epub_image_tests.dart @@ -0,0 +1,40 @@ +library epubreadertest; + +import 'dart:io' as io; + +import 'package:path/path.dart' as path; +import 'package:test/test.dart'; + +import 'package:epubx/epubx.dart'; + +main() async { + String fileName = "MY VAMPIRE SYSTEM (JKSManga) (Z-Library).epub"; + String fullPath = + path.join(io.Directory.current.path, "test", "res", fileName); + var targetFile = new io.File(fullPath); + if (!(await targetFile.exists())) { + throw new Exception("Specified epub file not found: ${fullPath}"); + } + List bytes = await targetFile.readAsBytes(); + test("Test Epub Image", () async { + EpubBook epubRef = await EpubReader.readBook(bytes); + + expect(epubRef.CoverImage, isNotNull); + + // expect(3, epubRef.CoverImage.format); + // expect(581, epubRef.CoverImage.width); + // expect(1034, epubRef.CoverImage.height); + }); + + test("Test Epub Ref Image", () async { + EpubBookRef epubRef = await EpubReader.openBook(bytes); + + Image? coverImage = await epubRef.readCover(); + + expect(coverImage, isNotNull); + + // expect(3, coverImage.format); + // expect(581, coverImage.width); + // expect(1034, coverImage.height); + }); +} diff --git a/epubx/test/epub_reader_tests.dart b/epubx/test/epub_reader_tests.dart new file mode 100644 index 00000000..acfae5a0 --- /dev/null +++ b/epubx/test/epub_reader_tests.dart @@ -0,0 +1,69 @@ +library epubreadertest; + +import 'dart:io' as io; + +import 'package:path/path.dart' as path; +import 'package:test/test.dart'; +import 'package:epubx/epubx.dart'; + +main() async { + String fileName = "stevenson-a-childs-garden-of-verses-illustrations.epub"; + String fullPath = path.join(io.Directory.current.path, "test", "res", fileName); + var targetFile = new io.File(fullPath); + if (!(await targetFile.exists())) { + throw new Exception("Specified epub file not found: ${fullPath}"); + } + + List bytes = await targetFile.readAsBytes(); + test("Test Epub Ref", () async { + EpubBookRef epubRef = await EpubReader.openBook(bytes); + var t = await epubRef.getChapters(); + print("${t.length}"); + }); + test("Test Epub Read", () async { + EpubBook epubRef = await EpubReader.readBook(bytes); + + expect(epubRef.Author, equals("John S. Hittell")); + expect(epubRef.Title, equals("Hittel on Gold Mines and Mining")); + }); + + test("Test can read", () async { + String baseName = path.join(io.Directory.current.path, "test", "res", "std"); + io.Directory baseDir = new io.Directory(baseName); + if (!(await baseDir.exists())) { + throw new Exception("Base path does not exist: ${baseName}"); + } + + await baseDir.list(recursive: false, followLinks: false).forEach((io.FileSystemEntity fe) async { + try { + io.File tf = new io.File(fe.path); + List bytes = await tf.readAsBytes(); + EpubBook book = await EpubReader.readBook(bytes); + expect(book, isNotNull); + } catch (e) { + print("File: ${fe.path}, Exception: ${e}"); + fail("Caught error..."); + } + }); + }); + + test("Test can open", () async { + var baseName = path.join(io.Directory.current.path, "test", "res", "std"); + var baseDir = new io.Directory(baseName); + if (!(await baseDir.exists())) { + throw new Exception("Base path does not exist: ${baseName}"); + } + + await baseDir.list(recursive: false, followLinks: false).forEach((io.FileSystemEntity fe) async { + try { + var tf = new io.File(fe.path); + var bytes = await tf.readAsBytes(); + var ref = await EpubReader.openBook(bytes); + expect(ref, isNotNull); + } catch (e) { + print("File: ${fe.path}, Exception: ${e}"); + fail("Caught error..."); + } + }); + }); +} diff --git a/epubx/test/epub_writer_tests.dart b/epubx/test/epub_writer_tests.dart new file mode 100644 index 00000000..8d251088 --- /dev/null +++ b/epubx/test/epub_writer_tests.dart @@ -0,0 +1,28 @@ +library epubreadertest; + +import 'dart:io' as io; + +import 'package:epubx/epub.dart'; +import 'package:path/path.dart' as path; +import 'package:test/test.dart'; + +main() async { + String fileName = "alicesAdventuresUnderGround.epub"; + String fullPath = + path.join(io.Directory.current.path, "test", "res", fileName); + var targetFile = new io.File(fullPath); + if (!(await targetFile.exists())) { + throw new Exception("Specified epub file not found: ${fullPath}"); + } + + List bytes = await targetFile.readAsBytes(); + + test("Book Round Trip", () async { + EpubBook book = await EpubReader.readBook(bytes); + + var written = await EpubWriter.writeBook(book); + var bookRoundTrip = await EpubReader.readBook(written); + + expect(bookRoundTrip, equals(book)); + }); +} diff --git a/epubx/test/random_data_generator.dart b/epubx/test/random_data_generator.dart new file mode 100644 index 00000000..d37113fb --- /dev/null +++ b/epubx/test/random_data_generator.dart @@ -0,0 +1,260 @@ +import 'dart:math' show Random; + +import 'package:epubx/epub.dart'; +import 'package:epubx/src/schema/navigation/epub_metadata.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_doc_author.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_doc_title.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_head.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_head_meta.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_label.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_point.dart'; +import 'package:epubx/src/schema/navigation/epub_navigation_target.dart'; +import 'package:epubx/src/schema/opf/epub_guide.dart'; +import 'package:epubx/src/schema/opf/epub_guide_reference.dart'; +import 'package:epubx/src/schema/opf/epub_manifest.dart'; +import 'package:epubx/src/schema/opf/epub_manifest_item.dart'; +import 'package:epubx/src/schema/opf/epub_metadata.dart'; +import 'package:epubx/src/schema/opf/epub_metadata_contributor.dart'; +import 'package:epubx/src/schema/opf/epub_metadata_creator.dart'; +import 'package:epubx/src/schema/opf/epub_metadata_date.dart'; +import 'package:epubx/src/schema/opf/epub_metadata_identifier.dart'; +import 'package:epubx/src/schema/opf/epub_metadata_meta.dart'; +import 'package:epubx/src/schema/opf/epub_spine.dart'; +import 'package:epubx/src/schema/opf/epub_spine_item_ref.dart'; +import 'package:epubx/src/schema/opf/epub_version.dart'; + +class RandomString { + final Random rng; + + RandomString(this.rng) {} + + static const ASCII_START = 33; + static const ASCII_END = 126; + static const NUMERIC_START = 48; + static const NUMERIC_END = 57; + static const LOWER_ALPHA_START = 97; + static const LOWER_ALPHA_END = 122; + static const UPPER_ALPHA_START = 65; + static const UPPER_ALPHA_END = 90; + + /// Generates a random integer where [from] <= [to]. + int randomBetween(int from, int to) { + if (from > to) throw new Exception('$from is not > $to'); + return ((to - from) * rng.nextDouble()).toInt() + from; + } + + /// Generates a random string of [length] with characters + /// between ascii [from] to [to]. + /// Defaults to characters of ascii '!' to '~'. + String randomString(int length, {int from: ASCII_START, int to: ASCII_END}) { + return new String.fromCharCodes( + new List.generate(length, (index) => randomBetween(from, to))); + } + + /// Generates a random string of [length] with only numeric characters. + String randomNumeric(int length) => + randomString(length, from: NUMERIC_START, to: NUMERIC_END); + + /// Generates a random string of [length] with only alpha characters. + String randomAlpha(int length) { + var lowerAlphaLength = randomBetween(0, length); + var upperAlphaLength = length - lowerAlphaLength; + var lowerAlpha = randomString(lowerAlphaLength, + from: LOWER_ALPHA_START, to: LOWER_ALPHA_END); + var upperAlpha = randomString(upperAlphaLength, + from: UPPER_ALPHA_START, to: UPPER_ALPHA_END); + return randomMerge(lowerAlpha, upperAlpha); + } + + /// Generates a random string of [length] with alpha-numeric characters. + String randomAlphaNumeric(int length) { + var alphaLength = randomBetween(0, length); + var numericLength = length - alphaLength; + var alpha = randomAlpha(alphaLength); + var numeric = randomNumeric(numericLength); + return randomMerge(alpha, numeric); + } + + /// Merge [a] with [b] and scramble characters. + String randomMerge(String a, String b) { + List mergedCodeUnits = new List.from("$a$b".codeUnits); + mergedCodeUnits.shuffle(rng); + return new String.fromCharCodes(mergedCodeUnits); + } +} + +class RandomDataGenerator { + final Random rng; + RandomString _randomString; + final int _length; + + RandomDataGenerator(this.rng, this._length) { + _randomString = new RandomString(rng); + } + + String randomString() { + return _randomString.randomAlphaNumeric(_length); + } + + EpubNavigationPoint randomEpubNavigationPoint([int depth = 0]) { + return new EpubNavigationPoint() + ..PlayOrder = randomString() + ..NavigationLabels = [randomEpubNavigationLabel()] + ..Id = randomString() + ..Content = randomEpubNavigationContent() + ..Class = randomString() + ..ChildNavigationPoints = depth > 0 + ? [randomEpubNavigationPoint(depth - 1)] + : new List(); + } + + EpubNavigationContent randomEpubNavigationContent() { + return new EpubNavigationContent() + ..Id = randomString() + ..Source = randomString(); + } + + EpubNavigationTarget randomEpubNavigationTarget() { + return new EpubNavigationTarget() + ..Class = randomString() + ..Content = randomEpubNavigationContent() + ..Id = randomString() + ..NavigationLabels = [randomEpubNavigationLabel()] + ..PlayOrder = randomString() + ..Value = randomString(); + } + + EpubNavigationLabel randomEpubNavigationLabel() { + return new EpubNavigationLabel()..Text = randomString(); + } + + EpubNavigationHead randomEpubNavigationHead() { + return new EpubNavigationHead()..Metadata = [randomNavigationHeadMeta()]; + } + + EpubNavigationHeadMeta randomNavigationHeadMeta() { + return new EpubNavigationHeadMeta() + ..Content = randomString() + ..Name = randomString() + ..Scheme = randomString(); + } + + EpubNavigationDocTitle randomNavigationDocTitle() { + return new EpubNavigationDocTitle()..Titles = [randomString()]; + } + + EpubNavigationDocAuthor randomNavigationDocAuthor() { + return new EpubNavigationDocAuthor()..Authors = [randomString()]; + } + + EpubPackage randomEpubPackage() { + return new EpubPackage() + ..Guide = randomEpubGuide() + ..Manifest = randomEpubManifest() + ..Metadata = randomEpubMetadata() + ..Spine = randomEpubSpine() + ..Version = rng.nextBool() ? EpubVersion.Epub2 : EpubVersion.Epub3; + } + + EpubSpine randomEpubSpine() { + var reference = new EpubSpine() + ..Items = [randomEpubSpineItemRef()] + ..TableOfContents = _randomString.randomAlpha(_length); + return reference; + } + + EpubSpineItemRef randomEpubSpineItemRef() { + return new EpubSpineItemRef() + ..IdRef = _randomString.randomAlpha(_length) + ..IdRef = _randomString.randomAlpha(_length); + } + + EpubManifest randomEpubManifest() { + var reference = new EpubManifest(); + reference.Items = [randomEpubManifestItem()]; + return reference; + } + + EpubManifestItem randomEpubManifestItem() { + return new EpubManifestItem() + ..Fallback = _randomString.randomAlpha(_length) + ..FallbackStyle = _randomString.randomAlpha(_length) + ..Href = _randomString.randomAlpha(_length) + ..Id = _randomString.randomAlpha(_length) + ..MediaType = _randomString.randomAlpha(_length) + ..RequiredModules = _randomString.randomAlpha(_length) + ..RequiredNamespace = _randomString.randomAlpha(_length); + } + + EpubGuide randomEpubGuide() { + var reference = new EpubGuide(); + reference.Items = [randomEpubGuideReference()]; + return reference; + } + + EpubGuideReference randomEpubGuideReference() { + return new EpubGuideReference() + ..Href = _randomString.randomAlpha(_length) + ..Title = _randomString.randomAlpha(_length) + ..Type = _randomString.randomAlpha(_length); + } + + EpubMetadata randomEpubMetadata() { + var reference = new EpubMetadata() + ..Contributors = [randomEpubMetadataContributor()] + ..Coverages = [_randomString.randomAlpha(_length)] + ..Creators = [randomEpubMetadataCreator()] + ..Dates = [randomEpubMetadataDate()] + ..Description = _randomString.randomAlpha(_length) + ..Formats = [_randomString.randomAlpha(_length)] + ..Identifiers = [randomEpubMetadataIdentifier()] + ..Languages = [_randomString.randomAlpha(_length)] + ..MetaItems = [randomEpubMetadataMeta()] + ..Publishers = [_randomString.randomAlpha(_length)] + ..Relations = [_randomString.randomAlpha(_length)] + ..Rights = [_randomString.randomAlpha(_length)] + ..Sources = [_randomString.randomAlpha(_length)] + ..Subjects = [_randomString.randomAlpha(_length)] + ..Titles = [_randomString.randomAlpha(_length)] + ..Types = [_randomString.randomAlpha(_length)]; + + return reference; + } + + EpubMetadataMeta randomEpubMetadataMeta() { + return new EpubMetadataMeta() + ..Content = _randomString.randomAlpha(_length) + ..Id = _randomString.randomAlpha(_length) + ..Name = _randomString.randomAlpha(_length) + ..Property = _randomString.randomAlpha(_length) + ..Refines = _randomString.randomAlpha(_length) + ..Scheme = _randomString.randomAlpha(_length); + } + + EpubMetadataIdentifier randomEpubMetadataIdentifier() { + return new EpubMetadataIdentifier() + ..Id = _randomString.randomAlpha(_length) + ..Identifier = _randomString.randomAlpha(_length) + ..Scheme = _randomString.randomAlpha(_length); + } + + EpubMetadataDate randomEpubMetadataDate() { + return new EpubMetadataDate() + ..Date = _randomString.randomAlpha(_length) + ..Event = _randomString.randomAlpha(_length); + } + + EpubMetadataContributor randomEpubMetadataContributor() { + return new EpubMetadataContributor() + ..Contributor = _randomString.randomAlpha(_length) + ..FileAs = _randomString.randomAlpha(_length) + ..Role = _randomString.randomAlpha(_length); + } + + EpubMetadataCreator randomEpubMetadataCreator() { + return new EpubMetadataCreator() + ..Creator = _randomString.randomAlpha(_length) + ..FileAs = _randomString.randomAlpha(_length) + ..Role = _randomString.randomAlpha(_length); + } +} diff --git a/epubx/test/ref_entities/epub_book_ref_test.dart b/epubx/test/ref_entities/epub_book_ref_test.dart new file mode 100644 index 00000000..720fb931 --- /dev/null +++ b/epubx/test/ref_entities/epub_book_ref_test.dart @@ -0,0 +1,117 @@ +library epubreadertest; + +import 'package:archive/archive.dart'; +import 'package:epubx/epub.dart'; +import 'package:epubx/src/entities/epub_schema.dart'; +import 'package:epubx/src/ref_entities/epub_content_ref.dart'; +import 'package:epubx/src/ref_entities/epub_text_content_file_ref.dart'; +import 'package:test/test.dart'; + +main() async { + Archive arch = new Archive(); + var reference = new EpubBookRef(arch); + reference + ..Author = "orthros" + ..AuthorList = ["orthros"] + ..Schema = new EpubSchema() + ..Title = "A Dissertation on Epubs"; + + EpubBookRef testBookRef; + setUp(() async { + testBookRef = new EpubBookRef(arch); + testBookRef + ..Author = "orthros" + ..AuthorList = ["orthros"] + ..Schema = new EpubSchema() + ..Title = "A Dissertation on Epubs"; + }); + tearDown(() async { + testBookRef = null; + }); + group("EpubBookRef", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testBookRef, equals(reference)); + }); + + test("is false when Content changes", () async { + var file = new EpubTextContentFileRef(testBookRef); + file + ..ContentMimeType = "application/txt" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthros.txt"; + + EpubContentRef content = new EpubContentRef(); + content.AllFiles["hello"] = file; + + testBookRef.Content = content; + + expect(testBookRef, isNot(reference)); + }); + + test("is false when Author changes", () async { + testBookRef.Author = "NotOrthros"; + expect(testBookRef, isNot(reference)); + }); + + test("is false when AuthorList changes", () async { + testBookRef.AuthorList = ["NotOrthros"]; + expect(testBookRef, isNot(reference)); + }); + + test("is false when Schema changes", () async { + var schema = new EpubSchema(); + schema.ContentDirectoryPath = "some/random/path"; + testBookRef.Schema = schema; + expect(testBookRef, isNot(reference)); + }); + + test("is false when Title changes", () async { + testBookRef.Title = "The Philosophy of Epubs"; + expect(testBookRef, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testBookRef.hashCode, equals(reference.hashCode)); + }); + + test("is false when Content changes", () async { + var file = new EpubTextContentFileRef(testBookRef); + file + ..ContentMimeType = "application/txt" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthros.txt"; + + EpubContentRef content = new EpubContentRef(); + content.AllFiles["hello"] = file; + + testBookRef.Content = content; + + expect(testBookRef, isNot(reference)); + }); + + test("is false when Author changes", () async { + testBookRef.Author = "NotOrthros"; + expect(testBookRef.hashCode, isNot(reference.hashCode)); + }); + + test("is false when AuthorList changes", () async { + testBookRef.AuthorList = ["NotOrthros"]; + expect(testBookRef.hashCode, isNot(reference.hashCode)); + }); + test("is false when Schema changes", () async { + var schema = new EpubSchema(); + schema.ContentDirectoryPath = "some/random/path"; + testBookRef.Schema = schema; + expect(testBookRef.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Title changes", () async { + testBookRef.Title = "The Philosophy of Epubs"; + expect(testBookRef.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/ref_entities/epub_byte_content_file_ref_test.dart b/epubx/test/ref_entities/epub_byte_content_file_ref_test.dart new file mode 100644 index 00000000..61f982b8 --- /dev/null +++ b/epubx/test/ref_entities/epub_byte_content_file_ref_test.dart @@ -0,0 +1,78 @@ +library epubreadertest; + +import 'package:archive/archive.dart'; +import 'package:epubx/epub.dart'; +import 'package:epubx/src/ref_entities/epub_byte_content_file_ref.dart'; +import 'package:test/test.dart'; + +main() async { + Archive arch = new Archive(); + EpubBookRef ref = new EpubBookRef(arch); + + var reference = new EpubByteContentFileRef(ref); + reference + ..ContentMimeType = "application/test" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthrosFile"; + + EpubByteContentFileRef testFileRef; + + setUp(() async { + Archive arch2 = new Archive(); + EpubBookRef ref2 = new EpubBookRef(arch2); + + testFileRef = new EpubByteContentFileRef(ref2); + testFileRef + ..ContentMimeType = "application/test" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthrosFile"; + }); + + tearDown(() async { + testFileRef = null; + }); + + group("EpubByteContentFileRef", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testFileRef, equals(reference)); + }); + + test("is false when ContentMimeType changes", () async { + testFileRef.ContentMimeType = "application/different"; + expect(testFileRef, isNot(reference)); + }); + + test("is false when ContentType changes", () async { + testFileRef.ContentType = EpubContentType.CSS; + expect(testFileRef, isNot(reference)); + }); + + test("is false when FileName changes", () async { + testFileRef.FileName = "a_different_file_name.txt"; + expect(testFileRef, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is the same for equivalent content", () async { + expect(testFileRef.hashCode, equals(reference.hashCode)); + }); + + test('changes when ContentMimeType changes', () async { + testFileRef.ContentMimeType = "application/orthros"; + expect(testFileRef.hashCode, isNot(reference.hashCode)); + }); + + test('changes when ContentType changes', () async { + testFileRef.ContentType = EpubContentType.CSS; + expect(testFileRef.hashCode, isNot(reference.hashCode)); + }); + + test('changes when FileName changes', () async { + testFileRef.FileName = "a_different_file_name"; + expect(testFileRef.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/ref_entities/epub_chapter_ref_test.dart b/epubx/test/ref_entities/epub_chapter_ref_test.dart new file mode 100644 index 00000000..e46ac7d6 --- /dev/null +++ b/epubx/test/ref_entities/epub_chapter_ref_test.dart @@ -0,0 +1,107 @@ +library epubreadertest; + +import 'package:archive/archive.dart'; +import 'package:epubx/epub.dart'; +import 'package:epubx/src/ref_entities/epub_chapter_ref.dart'; +import 'package:epubx/src/ref_entities/epub_text_content_file_ref.dart'; +import 'package:test/test.dart'; + +main() async { + var arch = new Archive(); + var bookRef = new EpubBookRef(arch); + var contentFileRef = new EpubTextContentFileRef(bookRef); + var reference = new EpubChapterRef(contentFileRef); + + reference + ..Anchor = "anchor" + ..ContentFileName = "orthros" + ..SubChapters = [] + ..Title = "A New Look at Chapters"; + + EpubBookRef bookRef2; + EpubChapterRef testChapterRef; + setUp(() async { + var arch2 = new Archive(); + bookRef2 = new EpubBookRef(arch2); + var contentFileRef2 = new EpubTextContentFileRef(bookRef2); + + testChapterRef = new EpubChapterRef(contentFileRef2); + testChapterRef + ..Anchor = "anchor" + ..ContentFileName = "orthros" + ..SubChapters = [] + ..Title = "A New Look at Chapters"; + }); + + tearDown(() async { + testChapterRef = null; + bookRef2 = null; + }); + group("EpubChapterRef", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testChapterRef, equals(reference)); + }); + + test("is false when Anchor changes", () async { + testChapterRef.Anchor = "NotAnAnchor"; + expect(testChapterRef, isNot(reference)); + }); + + test("is false when ContentFileName changes", () async { + testChapterRef.ContentFileName = "NotOrthros"; + expect(testChapterRef, isNot(reference)); + }); + + test("is false when SubChapters changes", () async { + var subchapterContentFileRef = new EpubTextContentFileRef(bookRef2); + var chapter = new EpubChapterRef(subchapterContentFileRef); + chapter + ..Title = "A Brave new Epub" + ..ContentFileName = "orthros.txt"; + testChapterRef.SubChapters = [chapter]; + expect(testChapterRef, isNot(reference)); + }); + + test("is false when Title changes", () async { + testChapterRef.Title = "A Boring Old World"; + expect(testChapterRef, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testChapterRef.hashCode, equals(reference.hashCode)); + }); + + test("is true for equivalent objects", () async { + expect(testChapterRef.hashCode, equals(reference.hashCode)); + }); + + test("is false when Anchor changes", () async { + testChapterRef.Anchor = "NotAnAnchor"; + expect(testChapterRef.hashCode, isNot(reference.hashCode)); + }); + + test("is false when ContentFileName changes", () async { + testChapterRef.ContentFileName = "NotOrthros"; + expect(testChapterRef.hashCode, isNot(reference.hashCode)); + }); + + test("is false when SubChapters changes", () async { + var subchapterContentFileRef = new EpubTextContentFileRef(bookRef2); + var chapter = new EpubChapterRef(subchapterContentFileRef); + chapter + ..Title = "A Brave new Epub" + ..ContentFileName = "orthros.txt"; + testChapterRef.SubChapters = [chapter]; + expect(testChapterRef, isNot(reference)); + }); + + test("is false when Title changes", () async { + testChapterRef.Title = "A Boring Old World"; + expect(testChapterRef.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/ref_entities/epub_content_ref_test.dart b/epubx/test/ref_entities/epub_content_ref_test.dart new file mode 100644 index 00000000..01cb1f93 --- /dev/null +++ b/epubx/test/ref_entities/epub_content_ref_test.dart @@ -0,0 +1,102 @@ +library epubreadertest; + +import 'package:archive/archive.dart'; +import 'package:epubx/epub.dart'; +import 'package:epubx/src/ref_entities/epub_byte_content_file_ref.dart'; +import 'package:epubx/src/ref_entities/epub_content_ref.dart'; +import 'package:epubx/src/ref_entities/epub_text_content_file_ref.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubContentRef(); + + EpubContentRef testContent; + EpubTextContentFileRef textContentFile; + EpubByteContentFileRef byteContentFile; + + setUp(() async { + var arch = new Archive(); + var refBook = new EpubBookRef(arch); + + testContent = new EpubContentRef(); + + textContentFile = new EpubTextContentFileRef(refBook) + ..ContentMimeType = "application/text" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthros.txt"; + + byteContentFile = new EpubByteContentFileRef(refBook) + ..ContentMimeType = "application/orthros" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthros.bin"; + }); + + tearDown(() async { + testContent = null; + textContentFile = null; + byteContentFile = null; + }); + group("EpubContentRef", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testContent, equals(reference)); + }); + + test("is false when Html changes", () async { + testContent.Html["someKey"] = textContentFile; + expect(testContent, isNot(reference)); + }); + + test("is false when Css changes", () async { + testContent.Css["someKey"] = textContentFile; + expect(testContent, isNot(reference)); + }); + + test("is false when Images changes", () async { + testContent.Images["someKey"] = byteContentFile; + expect(testContent, isNot(reference)); + }); + + test("is false when Fonts changes", () async { + testContent.Fonts["someKey"] = byteContentFile; + expect(testContent, isNot(reference)); + }); + + test("is false when AllFiles changes", () async { + testContent.AllFiles["someKey"] = byteContentFile; + expect(testContent, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testContent.hashCode, equals(reference.hashCode)); + }); + + test("is false when Html changes", () async { + testContent.Html["someKey"] = textContentFile; + expect(testContent.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Css changes", () async { + testContent.Css["someKey"] = textContentFile; + expect(testContent.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Images changes", () async { + testContent.Images["someKey"] = byteContentFile; + expect(testContent.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Fonts changes", () async { + testContent.Fonts["someKey"] = byteContentFile; + expect(testContent.hashCode, isNot(reference.hashCode)); + }); + + test("is false when AllFiles changes", () async { + testContent.AllFiles["someKey"] = byteContentFile; + expect(testContent.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/ref_entities/epub_text_content_file_ref_test.dart b/epubx/test/ref_entities/epub_text_content_file_ref_test.dart new file mode 100644 index 00000000..00935140 --- /dev/null +++ b/epubx/test/ref_entities/epub_text_content_file_ref_test.dart @@ -0,0 +1,75 @@ +library epubreadertest; + +import 'package:archive/archive.dart'; +import 'package:epubx/epub.dart'; +import 'package:epubx/src/ref_entities/epub_text_content_file_ref.dart'; +import 'package:test/test.dart'; + +main() async { + var arch = new Archive(); + var epubRef = new EpubBookRef(arch); + + var reference = new EpubTextContentFileRef(epubRef); + reference + ..ContentMimeType = "application/test" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthrosFile"; + EpubTextContentFileRef testFile; + + setUp(() async { + var arch2 = new Archive(); + var epubRef2 = new EpubBookRef(arch2); + + testFile = new EpubTextContentFileRef(epubRef2); + testFile + ..ContentMimeType = "application/test" + ..ContentType = EpubContentType.OTHER + ..FileName = "orthrosFile"; + }); + + tearDown(() async { + testFile = null; + }); + group("EpubTextContentFile", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testFile, equals(reference)); + }); + + test("is false when ContentMimeType changes", () async { + testFile.ContentMimeType = "application/different"; + expect(testFile, isNot(reference)); + }); + + test("is false when ContentType changes", () async { + testFile.ContentType = EpubContentType.CSS; + expect(testFile, isNot(reference)); + }); + + test("is false when FileName changes", () async { + testFile.FileName = "a_different_file_name.txt"; + expect(testFile, isNot(reference)); + }); + }); + group(".hashCode", () { + test("is the same for equivalent content", () async { + expect(testFile.hashCode, equals(reference.hashCode)); + }); + + test('changes when ContentMimeType changes', () async { + testFile.ContentMimeType = "application/orthros"; + expect(testFile.hashCode, isNot(reference.hashCode)); + }); + + test('changes when ContentType changes', () async { + testFile.ContentType = EpubContentType.CSS; + expect(testFile.hashCode, isNot(reference.hashCode)); + }); + + test('changes when FileName changes', () async { + testFile.FileName = "a_different_file_name"; + expect(testFile.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/res/alicesAdventuresUnderGround.epub b/epubx/test/res/alicesAdventuresUnderGround.epub new file mode 100644 index 00000000..48af8a2c Binary files /dev/null and b/epubx/test/res/alicesAdventuresUnderGround.epub differ diff --git a/epubx/test/res/hittelOnGoldMines.epub b/epubx/test/res/hittelOnGoldMines.epub new file mode 100644 index 00000000..5f3e555f Binary files /dev/null and b/epubx/test/res/hittelOnGoldMines.epub differ diff --git a/epubx/test/res/std/WCAG.epub b/epubx/test/res/std/WCAG.epub new file mode 100644 index 00000000..95102d2e Binary files /dev/null and b/epubx/test/res/std/WCAG.epub differ diff --git a/epubx/test/res/std/accessible_epub_3.epub b/epubx/test/res/std/accessible_epub_3.epub new file mode 100644 index 00000000..c620e6ee Binary files /dev/null and b/epubx/test/res/std/accessible_epub_3.epub differ diff --git a/epubx/test/res/std/childrens-literature.epub b/epubx/test/res/std/childrens-literature.epub new file mode 100644 index 00000000..9f037a1b Binary files /dev/null and b/epubx/test/res/std/childrens-literature.epub differ diff --git a/epubx/test/res/std/childrens-media-query.epub b/epubx/test/res/std/childrens-media-query.epub new file mode 100644 index 00000000..6aee6ebf Binary files /dev/null and b/epubx/test/res/std/childrens-media-query.epub differ diff --git a/epubx/test/res/std/cole-voyage-of-life-tol.epub b/epubx/test/res/std/cole-voyage-of-life-tol.epub new file mode 100644 index 00000000..17e25d9a Binary files /dev/null and b/epubx/test/res/std/cole-voyage-of-life-tol.epub differ diff --git a/epubx/test/res/std/cole-voyage-of-life.epub b/epubx/test/res/std/cole-voyage-of-life.epub new file mode 100644 index 00000000..08c4c3df Binary files /dev/null and b/epubx/test/res/std/cole-voyage-of-life.epub differ diff --git a/epubx/test/res/std/epub30-spec.epub b/epubx/test/res/std/epub30-spec.epub new file mode 100644 index 00000000..2b80f3ab Binary files /dev/null and b/epubx/test/res/std/epub30-spec.epub differ diff --git a/epubx/test/res/std/figure-gallery-bindings.epub b/epubx/test/res/std/figure-gallery-bindings.epub new file mode 100644 index 00000000..ee8b56f3 Binary files /dev/null and b/epubx/test/res/std/figure-gallery-bindings.epub differ diff --git a/epubx/test/res/std/georgia-cfi.epub b/epubx/test/res/std/georgia-cfi.epub new file mode 100644 index 00000000..0b580b54 Binary files /dev/null and b/epubx/test/res/std/georgia-cfi.epub differ diff --git a/epubx/test/res/std/georgia-pls-ssml.epub b/epubx/test/res/std/georgia-pls-ssml.epub new file mode 100644 index 00000000..d828d98c Binary files /dev/null and b/epubx/test/res/std/georgia-pls-ssml.epub differ diff --git a/epubx/test/res/std/hefty-water.epub b/epubx/test/res/std/hefty-water.epub new file mode 100644 index 00000000..377673e0 Binary files /dev/null and b/epubx/test/res/std/hefty-water.epub differ diff --git a/epubx/test/res/std/igp-year5-school-maths.epub b/epubx/test/res/std/igp-year5-school-maths.epub new file mode 100644 index 00000000..7bc1bbc7 Binary files /dev/null and b/epubx/test/res/std/igp-year5-school-maths.epub differ diff --git a/epubx/test/res/std/indexing-for-eds-and-auths-3f.epub b/epubx/test/res/std/indexing-for-eds-and-auths-3f.epub new file mode 100644 index 00000000..21ffd943 Binary files /dev/null and b/epubx/test/res/std/indexing-for-eds-and-auths-3f.epub differ diff --git a/epubx/test/res/std/indexing-for-eds-and-auths-3md.epub b/epubx/test/res/std/indexing-for-eds-and-auths-3md.epub new file mode 100644 index 00000000..49b4025c Binary files /dev/null and b/epubx/test/res/std/indexing-for-eds-and-auths-3md.epub differ diff --git a/epubx/test/res/std/internallinks.epub b/epubx/test/res/std/internallinks.epub new file mode 100644 index 00000000..59d99040 Binary files /dev/null and b/epubx/test/res/std/internallinks.epub differ diff --git a/epubx/test/res/std/israelsailing.epub b/epubx/test/res/std/israelsailing.epub new file mode 100644 index 00000000..763cceec Binary files /dev/null and b/epubx/test/res/std/israelsailing.epub differ diff --git a/epubx/test/res/std/linear-algebra.epub b/epubx/test/res/std/linear-algebra.epub new file mode 100644 index 00000000..4d72e57c Binary files /dev/null and b/epubx/test/res/std/linear-algebra.epub differ diff --git a/epubx/test/res/std/moby-dick.epub b/epubx/test/res/std/moby-dick.epub new file mode 100644 index 00000000..8501a089 Binary files /dev/null and b/epubx/test/res/std/moby-dick.epub differ diff --git a/epubx/test/res/std/mymedia_lite.epub b/epubx/test/res/std/mymedia_lite.epub new file mode 100644 index 00000000..4114fd91 Binary files /dev/null and b/epubx/test/res/std/mymedia_lite.epub differ diff --git a/epubx/test/res/std/quiz-bindings.epub b/epubx/test/res/std/quiz-bindings.epub new file mode 100644 index 00000000..ea498108 Binary files /dev/null and b/epubx/test/res/std/quiz-bindings.epub differ diff --git a/epubx/test/res/std/svg-in-spine.epub b/epubx/test/res/std/svg-in-spine.epub new file mode 100644 index 00000000..8efd68e8 Binary files /dev/null and b/epubx/test/res/std/svg-in-spine.epub differ diff --git a/epubx/test/res/std/trees.epub b/epubx/test/res/std/trees.epub new file mode 100644 index 00000000..603132a5 Binary files /dev/null and b/epubx/test/res/std/trees.epub differ diff --git a/epubx/test/res/std/wasteland-otf-obf.epub b/epubx/test/res/std/wasteland-otf-obf.epub new file mode 100644 index 00000000..4533bff8 Binary files /dev/null and b/epubx/test/res/std/wasteland-otf-obf.epub differ diff --git a/epubx/test/res/std/wasteland-otf.epub b/epubx/test/res/std/wasteland-otf.epub new file mode 100644 index 00000000..2ad8cb38 Binary files /dev/null and b/epubx/test/res/std/wasteland-otf.epub differ diff --git a/epubx/test/res/std/wasteland-woff-obf.epub b/epubx/test/res/std/wasteland-woff-obf.epub new file mode 100644 index 00000000..e24ebb04 Binary files /dev/null and b/epubx/test/res/std/wasteland-woff-obf.epub differ diff --git a/epubx/test/res/std/wasteland-woff.epub b/epubx/test/res/std/wasteland-woff.epub new file mode 100644 index 00000000..ded12e52 Binary files /dev/null and b/epubx/test/res/std/wasteland-woff.epub differ diff --git a/epubx/test/res/std/wasteland.epub b/epubx/test/res/std/wasteland.epub new file mode 100644 index 00000000..1c4dfc42 Binary files /dev/null and b/epubx/test/res/std/wasteland.epub differ diff --git a/epubx/test/schema/navigation/epub_navigation_doc_author_test.dart b/epubx/test/schema/navigation/epub_navigation_doc_author_test.dart new file mode 100644 index 00000000..2d0c5daa --- /dev/null +++ b/epubx/test/schema/navigation/epub_navigation_doc_author_test.dart @@ -0,0 +1,47 @@ +library epubreadertest; + +import 'dart:math'; + +import 'package:epubx/src/schema/navigation/epub_navigation_doc_author.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + final generator = new RandomDataGenerator(new Random(7898), 10); + final EpubNavigationDocAuthor reference = + generator.randomNavigationDocAuthor(); + + EpubNavigationDocAuthor testNavigationDocAuthor; + setUp(() async { + testNavigationDocAuthor = new EpubNavigationDocAuthor() + ..Authors = List.from(reference.Authors); + }); + tearDown(() async { + testNavigationDocAuthor = null; + }); + + group("EpubNavigationDocAuthor", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testNavigationDocAuthor, equals(reference)); + }); + + test("is false when Authors changes", () async { + testNavigationDocAuthor.Authors.add(generator.randomString()); + expect(testNavigationDocAuthor, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testNavigationDocAuthor.hashCode, equals(reference.hashCode)); + }); + + test("is false when Authors changes", () async { + testNavigationDocAuthor.Authors.add(generator.randomString()); + expect(testNavigationDocAuthor.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/navigation/epub_navigation_doc_title_test.dart b/epubx/test/schema/navigation/epub_navigation_doc_title_test.dart new file mode 100644 index 00000000..94a00386 --- /dev/null +++ b/epubx/test/schema/navigation/epub_navigation_doc_title_test.dart @@ -0,0 +1,46 @@ +library epubreadertest; + +import 'dart:math'; + +import 'package:epubx/src/schema/navigation/epub_navigation_doc_title.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + final generator = new RandomDataGenerator(new Random(7898), 10); + final EpubNavigationDocTitle reference = generator.randomNavigationDocTitle(); + + EpubNavigationDocTitle testNavigationDocTitle; + setUp(() async { + testNavigationDocTitle = new EpubNavigationDocTitle() + ..Titles = List.from(reference.Titles); + }); + tearDown(() async { + testNavigationDocTitle = null; + }); + + group("EpubNavigationDocTitle", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testNavigationDocTitle, equals(reference)); + }); + + test("is false when Titles changes", () async { + testNavigationDocTitle.Titles.add(generator.randomString()); + expect(testNavigationDocTitle, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testNavigationDocTitle.hashCode, equals(reference.hashCode)); + }); + + test("is false when Titles changes", () async { + testNavigationDocTitle.Titles.add(generator.randomString()); + expect(testNavigationDocTitle.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/navigation/epub_navigation_head_meta_test.dart b/epubx/test/schema/navigation/epub_navigation_head_meta_test.dart new file mode 100644 index 00000000..b2286ae1 --- /dev/null +++ b/epubx/test/schema/navigation/epub_navigation_head_meta_test.dart @@ -0,0 +1,64 @@ +library epubreadertest; + +import 'dart:math'; + +import 'package:epubx/src/schema/navigation/epub_navigation_head_meta.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + final generator = new RandomDataGenerator(new Random(7898), 10); + final EpubNavigationHeadMeta reference = generator.randomNavigationHeadMeta(); + + EpubNavigationHeadMeta testNavigationDocTitle; + setUp(() async { + testNavigationDocTitle = new EpubNavigationHeadMeta() + ..Content = reference.Content + ..Name = reference.Name + ..Scheme = reference.Scheme; + }); + tearDown(() async { + testNavigationDocTitle = null; + }); + + group("EpubNavigationHeadMeta", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testNavigationDocTitle, equals(reference)); + }); + + test("is false when Content changes", () async { + testNavigationDocTitle.Content = generator.randomString(); + expect(testNavigationDocTitle, isNot(reference)); + }); + test("is false when Name changes", () async { + testNavigationDocTitle.Name = generator.randomString(); + expect(testNavigationDocTitle, isNot(reference)); + }); + test("is false when Scheme changes", () async { + testNavigationDocTitle.Scheme = generator.randomString(); + expect(testNavigationDocTitle, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testNavigationDocTitle.hashCode, equals(reference.hashCode)); + }); + + test("is false when Content changes", () async { + testNavigationDocTitle.Content = generator.randomString(); + expect(testNavigationDocTitle.hashCode, isNot(reference.hashCode)); + }); + test("is false when Name changes", () async { + testNavigationDocTitle.Name = generator.randomString(); + expect(testNavigationDocTitle.hashCode, isNot(reference.hashCode)); + }); + test("is false when Scheme changes", () async { + testNavigationDocTitle.Scheme = generator.randomString(); + expect(testNavigationDocTitle.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/navigation/epub_navigation_head_test.dart b/epubx/test/schema/navigation/epub_navigation_head_test.dart new file mode 100644 index 00000000..99cad81e --- /dev/null +++ b/epubx/test/schema/navigation/epub_navigation_head_test.dart @@ -0,0 +1,47 @@ +library epubreadertest; + +import 'dart:math'; + +import 'package:epubx/src/schema/navigation/epub_navigation_head.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + final RandomDataGenerator generator = + new RandomDataGenerator(new Random(123778), 10); + + final EpubNavigationHead reference = generator.randomEpubNavigationHead(); + + EpubNavigationHead testGuideReference; + setUp(() async { + testGuideReference = new EpubNavigationHead() + ..Metadata = List.from(reference.Metadata); + }); + tearDown(() async { + testGuideReference = null; + }); + group("EpubNavigationHead", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testGuideReference, equals(reference)); + }); + + test("is false when Metadata changes", () async { + testGuideReference.Metadata.add(generator.randomNavigationHeadMeta()); + expect(testGuideReference, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testGuideReference.hashCode, equals(reference.hashCode)); + }); + + test("is false when Metadata changes", () async { + testGuideReference.Metadata.add(generator.randomNavigationHeadMeta()); + expect(testGuideReference.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/navigation/epub_navigation_label_test.dart b/epubx/test/schema/navigation/epub_navigation_label_test.dart new file mode 100644 index 00000000..32e18cd0 --- /dev/null +++ b/epubx/test/schema/navigation/epub_navigation_label_test.dart @@ -0,0 +1,46 @@ +library epubreadertest; + +import 'dart:math'; + +import 'package:epubx/src/schema/navigation/epub_navigation_label.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + final RandomDataGenerator generator = + new RandomDataGenerator(new Random(123778), 10); + + final EpubNavigationLabel reference = generator.randomEpubNavigationLabel(); + + EpubNavigationLabel testNavigationLabel; + setUp(() async { + testNavigationLabel = new EpubNavigationLabel()..Text = reference.Text; + }); + tearDown(() async { + testNavigationLabel = null; + }); + group("EpubNavigationLabel", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testNavigationLabel, equals(reference)); + }); + + test("is false when Text changes", () async { + testNavigationLabel.Text = generator.randomString(); + expect(testNavigationLabel, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testNavigationLabel.hashCode, equals(reference.hashCode)); + }); + + test("is false when Metadata changes", () async { + testNavigationLabel.Text = generator.randomString(); + expect(testNavigationLabel.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/navigation/epub_navigation_point_test.dart b/epubx/test/schema/navigation/epub_navigation_point_test.dart new file mode 100644 index 00000000..1ae34f81 --- /dev/null +++ b/epubx/test/schema/navigation/epub_navigation_point_test.dart @@ -0,0 +1,95 @@ +library epubreadertest; + +import 'dart:math'; + +import 'package:epubx/src/schema/navigation/epub_navigation_point.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + final generator = new RandomDataGenerator(new Random(7898), 10); + final EpubNavigationPoint reference = generator.randomEpubNavigationPoint(1); + + EpubNavigationPoint testNavigationPoint; + setUp(() async { + testNavigationPoint = new EpubNavigationPoint() + ..ChildNavigationPoints = List.from(reference.ChildNavigationPoints) + ..Class = reference.Class + ..Content = reference.Content + ..Id = reference.Id + ..NavigationLabels = List.from(reference.NavigationLabels) + ..PlayOrder = reference.PlayOrder; + }); + tearDown(() async { + testNavigationPoint = null; + }); + + group("EpubNavigationPoint", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testNavigationPoint, equals(reference)); + }); + + test("is false when ChildNavigationPoints changes", () async { + testNavigationPoint.ChildNavigationPoints.add( + generator.randomEpubNavigationPoint()); + expect(testNavigationPoint, isNot(reference)); + }); + test("is false when Class changes", () async { + testNavigationPoint.Class = generator.randomString(); + expect(testNavigationPoint, isNot(reference)); + }); + test("is false when Content changes", () async { + testNavigationPoint.Content = generator.randomEpubNavigationContent(); + expect(testNavigationPoint, isNot(reference)); + }); + test("is false when Id changes", () async { + testNavigationPoint.Id = generator.randomString(); + expect(testNavigationPoint, isNot(reference)); + }); + test("is false when PlayOrder changes", () async { + testNavigationPoint.PlayOrder = generator.randomString(); + expect(testNavigationPoint, isNot(reference)); + }); + test("is false when NavigationLabels changes", () async { + testNavigationPoint.NavigationLabels.add( + generator.randomEpubNavigationLabel()); + expect(testNavigationPoint, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testNavigationPoint.hashCode, equals(reference.hashCode)); + }); + + test("is false when ChildNavigationPoints changes", () async { + testNavigationPoint.ChildNavigationPoints.add( + generator.randomEpubNavigationPoint()); + expect(testNavigationPoint.hashCode, isNot(reference.hashCode)); + }); + test("is false when Class changes", () async { + testNavigationPoint.Class = generator.randomString(); + expect(testNavigationPoint.hashCode, isNot(reference.hashCode)); + }); + test("is false when Content changes", () async { + testNavigationPoint.Content = generator.randomEpubNavigationContent(); + expect(testNavigationPoint.hashCode, isNot(reference.hashCode)); + }); + test("is false when Id changes", () async { + testNavigationPoint.Id = generator.randomString(); + expect(testNavigationPoint.hashCode, isNot(reference.hashCode)); + }); + test("is false when PlayOrder changes", () async { + testNavigationPoint.PlayOrder = generator.randomString(); + expect(testNavigationPoint.hashCode, isNot(reference.hashCode)); + }); + test("is false when NavigationLabels changes", () async { + testNavigationPoint.NavigationLabels.add( + generator.randomEpubNavigationLabel()); + expect(testNavigationPoint.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/navigation/epub_navigation_target_test.dart b/epubx/test/schema/navigation/epub_navigation_target_test.dart new file mode 100644 index 00000000..0c7ac225 --- /dev/null +++ b/epubx/test/schema/navigation/epub_navigation_target_test.dart @@ -0,0 +1,96 @@ +library epubreadertest; + +import 'dart:math'; + +import 'package:epubx/src/schema/navigation/epub_navigation_target.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + final RandomDataGenerator generator = + new RandomDataGenerator(new Random(123778), 10); + + final EpubNavigationTarget reference = generator.randomEpubNavigationTarget(); + + EpubNavigationTarget testNavigationTarget; + setUp(() async { + testNavigationTarget = new EpubNavigationTarget() + ..Class = reference.Class + ..Content = reference.Content + ..Id = reference.Id + ..NavigationLabels = List.from(reference.NavigationLabels) + ..PlayOrder = reference.PlayOrder + ..Value = reference.Value; + }); + tearDown(() async { + testNavigationTarget = null; + }); + group("EpubNavigationTarget", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testNavigationTarget, equals(reference)); + }); + + test("is false when Class changes", () async { + testNavigationTarget.Class = generator.randomString(); + expect(testNavigationTarget, isNot(reference)); + }); + test("is false when Content changes", () async { + testNavigationTarget.Content = generator.randomEpubNavigationContent(); + expect(testNavigationTarget, isNot(reference)); + }); + test("is false when Id changes", () async { + testNavigationTarget.Id = generator.randomString(); + expect(testNavigationTarget, isNot(reference)); + }); + test("is false when NavigationLabels changes", () async { + testNavigationTarget.NavigationLabels = [ + generator.randomEpubNavigationLabel() + ]; + expect(testNavigationTarget, isNot(reference)); + }); + test("is false when PlayOrder changes", () async { + testNavigationTarget.PlayOrder = generator.randomString(); + expect(testNavigationTarget, isNot(reference)); + }); + test("is false when Value changes", () async { + testNavigationTarget.Value = generator.randomString(); + expect(testNavigationTarget, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testNavigationTarget.hashCode, equals(reference.hashCode)); + }); + + test("is false when Class changes", () async { + testNavigationTarget.Class = generator.randomString(); + expect(testNavigationTarget.hashCode, isNot(reference.hashCode)); + }); + test("is false when Content changes", () async { + testNavigationTarget.Content = generator.randomEpubNavigationContent(); + expect(testNavigationTarget.hashCode, isNot(reference.hashCode)); + }); + test("is false when Id changes", () async { + testNavigationTarget.Id = generator.randomString(); + expect(testNavigationTarget.hashCode, isNot(reference.hashCode)); + }); + test("is false when NavigationLabels changes", () async { + testNavigationTarget.NavigationLabels = [ + generator.randomEpubNavigationLabel() + ]; + expect(testNavigationTarget.hashCode, isNot(reference.hashCode)); + }); + test("is false when PlayOrder changes", () async { + testNavigationTarget.PlayOrder = generator.randomString(); + expect(testNavigationTarget.hashCode, isNot(reference.hashCode)); + }); + test("is false when Value changes", () async { + testNavigationTarget.Value = generator.randomString(); + expect(testNavigationTarget.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_guide_reference_test.dart b/epubx/test/schema/opf/epub_guide_reference_test.dart new file mode 100644 index 00000000..13b37c25 --- /dev/null +++ b/epubx/test/schema/opf/epub_guide_reference_test.dart @@ -0,0 +1,72 @@ +library epubreadertest; + +import 'dart:math'; + +import 'package:epubx/src/schema/opf/epub_guide_reference.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + final RandomDataGenerator generator = + new RandomDataGenerator(new Random(123778), 10); + + var reference = generator.randomEpubGuideReference(); + + EpubGuideReference testGuideReference; + setUp(() async { + testGuideReference = new EpubGuideReference(); + testGuideReference + ..Href = reference.Href + ..Title = reference.Title + ..Type = reference.Type; + }); + tearDown(() async { + testGuideReference = null; + }); + group("EpubGuideReference", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testGuideReference, equals(reference)); + }); + + test("is false when Href changes", () async { + testGuideReference.Href = "A different href"; + + expect(testGuideReference, isNot(reference)); + }); + + test("is false when Title changes", () async { + testGuideReference.Title = "A different Title"; + expect(testGuideReference, isNot(reference)); + }); + + test("is false when Type changes", () async { + testGuideReference.Type = "Some different type"; + expect(testGuideReference, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testGuideReference.hashCode, equals(reference.hashCode)); + }); + + test("is false when Href changes", () async { + testGuideReference.Href = "A different href"; + + expect(testGuideReference.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Title changes", () async { + testGuideReference.Title = "A different Title"; + expect(testGuideReference.hashCode, isNot(reference.hashCode)); + }); + + test("is false when Type changes", () async { + testGuideReference.Type = "Some different type"; + expect(testGuideReference.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_guide_test.dart b/epubx/test/schema/opf/epub_guide_test.dart new file mode 100644 index 00000000..9d68b8e4 --- /dev/null +++ b/epubx/test/schema/opf/epub_guide_test.dart @@ -0,0 +1,44 @@ +library epubreadertest; + +import 'dart:math' show Random; + +import 'package:epubx/src/schema/opf/epub_guide.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + RandomDataGenerator generator = + new RandomDataGenerator(new Random(123445), 10); + + var reference = generator.randomEpubGuide(); + + EpubGuide testGuide; + setUp(() async { + testGuide = new EpubGuide()..Items = List.from(reference.Items); + }); + tearDown(() async { + testGuide = null; + }); + group("EpubGuide", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testGuide, equals(reference)); + }); + test("is false when Items changes", () async { + testGuide.Items.add(generator.randomEpubGuideReference()); + expect(testGuide, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testGuide.hashCode, equals(reference.hashCode)); + }); + test("is false when Items changes", () async { + testGuide.Items.add(generator.randomEpubGuideReference()); + expect(testGuide.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_manifest_item_test.dart b/epubx/test/schema/opf/epub_manifest_item_test.dart new file mode 100644 index 00000000..6846e938 --- /dev/null +++ b/epubx/test/schema/opf/epub_manifest_item_test.dart @@ -0,0 +1,102 @@ +library epubreadertest; + +import 'package:epubx/src/schema/opf/epub_manifest_item.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubManifestItem() + ..Fallback = "Some Fallback" + ..FallbackStyle = "A Very Stylish Fallback" + ..Href = "Some HREF" + ..Id = "Some ID" + ..MediaType = "MKV" + ..RequiredModules = "nodejs require()" + ..RequiredNamespace = ".NET Namespace"; + + EpubManifestItem testManifestItem; + setUp(() async { + testManifestItem = new EpubManifestItem() + ..Fallback = reference.Fallback + ..FallbackStyle = reference.FallbackStyle + ..Href = reference.Href + ..Id = reference.Id + ..MediaType = reference.MediaType + ..RequiredModules = reference.RequiredModules + ..RequiredNamespace = reference.RequiredNamespace; + }); + tearDown(() async { + testManifestItem = null; + }); + + group("EpubManifestItem", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testManifestItem, equals(reference)); + }); + + test("is false when Fallback changes", () async { + testManifestItem.Fallback = "Some Different Fallback"; + expect(testManifestItem, isNot(reference)); + }); + test("is false when FallbackStyle changes", () async { + testManifestItem.FallbackStyle = "A less than Stylish Fallback"; + expect(testManifestItem, isNot(reference)); + }); + test("is false when Href changes", () async { + testManifestItem.Href = "A different Href"; + expect(testManifestItem, isNot(reference)); + }); + test("is false when Id changes", () async { + testManifestItem.Id = "A guarenteed unique Id"; + expect(testManifestItem, isNot(reference)); + }); + test("is false when MediaType changes", () async { + testManifestItem.MediaType = "RealPlayer"; + expect(testManifestItem, isNot(reference)); + }); + test("is false when RequiredModules changes", () async { + testManifestItem.RequiredModules = "A non node-js module"; + expect(testManifestItem, isNot(reference)); + }); + test("is false when RequiredNamespaces changes", () async { + testManifestItem.RequiredNamespace = "Some non-dot net namespace"; + expect(testManifestItem, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testManifestItem.hashCode, equals(reference.hashCode)); + }); + + test("is false when Fallback changes", () async { + testManifestItem.Fallback = "Some Different Fallback"; + expect(testManifestItem.hashCode, isNot(reference.hashCode)); + }); + test("is false when FallbackStyle changes", () async { + testManifestItem.FallbackStyle = "A less than Stylish Fallback"; + expect(testManifestItem.hashCode, isNot(reference.hashCode)); + }); + test("is false when Href changes", () async { + testManifestItem.Href = "A different Href"; + expect(testManifestItem.hashCode, isNot(reference.hashCode)); + }); + test("is false when Id changes", () async { + testManifestItem.Id = "A guarenteed unique Id"; + expect(testManifestItem.hashCode, isNot(reference.hashCode)); + }); + test("is false when MediaType changes", () async { + testManifestItem.MediaType = "RealPlayer"; + expect(testManifestItem.hashCode, isNot(reference.hashCode)); + }); + test("is false when RequiredModules changes", () async { + testManifestItem.RequiredModules = "A non node-js module"; + expect(testManifestItem.hashCode, isNot(reference.hashCode)); + }); + test("is false when RequiredNamespaces changes", () async { + testManifestItem.RequiredNamespace = "Some non-dot net namespace"; + expect(testManifestItem.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_manifest_test.dart b/epubx/test/schema/opf/epub_manifest_test.dart new file mode 100644 index 00000000..a898db07 --- /dev/null +++ b/epubx/test/schema/opf/epub_manifest_test.dart @@ -0,0 +1,65 @@ +library epubreadertest; + +import 'package:epubx/src/schema/opf/epub_manifest.dart'; +import 'package:epubx/src/schema/opf/epub_manifest_item.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubManifest(); + reference.Items = [ + new EpubManifestItem() + ..Fallback = "Some Fallback" + ..FallbackStyle = "A Very Stylish Fallback" + ..Href = "Some HREF" + ..Id = "Some ID" + ..MediaType = "MKV" + ..RequiredModules = "nodejs require()" + ..RequiredNamespace = ".NET Namespace" + ]; + + EpubManifest testManifest; + setUp(() async { + testManifest = new EpubManifest()..Items = List.from(reference.Items); + }); + tearDown(() async { + testManifest = null; + }); + group("EpubManifest", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testManifest, equals(reference)); + }); + + test("is false when Items changes", () async { + testManifest.Items.add(new EpubManifestItem() + ..Fallback = "Some Different Fallback" + ..FallbackStyle = "A less than Stylish Fallback" + ..Href = "Some Different HREF" + ..Id = "Some Different ID" + ..MediaType = "RealPlayer" + ..RequiredModules = "require()" + ..RequiredNamespace = "Namespace"); + + expect(testManifest, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testManifest.hashCode, equals(reference.hashCode)); + }); + + test("is false when Items changes", () async { + testManifest.Items.add(new EpubManifestItem() + ..Fallback = "Some Different Fallback" + ..FallbackStyle = "A less than Stylish Fallback" + ..Href = "Some Different HREF" + ..Id = "Some Different ID" + ..MediaType = "RealPlayer" + ..RequiredModules = "require()" + ..RequiredNamespace = "Namespace"); + expect(testManifest.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_metadata_contributor_test.dart b/epubx/test/schema/opf/epub_metadata_contributor_test.dart new file mode 100644 index 00000000..8597a280 --- /dev/null +++ b/epubx/test/schema/opf/epub_metadata_contributor_test.dart @@ -0,0 +1,62 @@ +library epubreadertest; + +import 'package:epubx/src/schema/opf/epub_metadata_contributor.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubMetadataContributor() + ..Contributor = "orthros" + ..FileAs = "Large" + ..Role = "Creator"; + + EpubMetadataContributor testMetadataContributor; + setUp(() async { + testMetadataContributor = new EpubMetadataContributor() + ..Contributor = reference.Contributor + ..FileAs = reference.FileAs + ..Role = reference.Role; + }); + tearDown(() async { + testMetadataContributor = null; + }); + + group("EpubMetadataContributor", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testMetadataContributor, equals(reference)); + }); + + test("is false when Contributor changes", () async { + testMetadataContributor.Contributor = "NotOrthros"; + expect(testMetadataContributor, isNot(reference)); + }); + test("is false when FileAs changes", () async { + testMetadataContributor.FileAs = "Small"; + expect(testMetadataContributor, isNot(reference)); + }); + test("is false when Role changes", () async { + testMetadataContributor.Role = "Copier"; + expect(testMetadataContributor, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testMetadataContributor.hashCode, equals(reference.hashCode)); + }); + + test("is false when Contributor changes", () async { + testMetadataContributor.Contributor = "NotOrthros"; + expect(testMetadataContributor.hashCode, isNot(reference.hashCode)); + }); + test("is false when FileAs changes", () async { + testMetadataContributor.FileAs = "Small"; + expect(testMetadataContributor.hashCode, isNot(reference.hashCode)); + }); + test("is false when Role changes", () async { + testMetadataContributor.Role = "Copier"; + expect(testMetadataContributor.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_metadata_creator_test.dart b/epubx/test/schema/opf/epub_metadata_creator_test.dart new file mode 100644 index 00000000..213d8898 --- /dev/null +++ b/epubx/test/schema/opf/epub_metadata_creator_test.dart @@ -0,0 +1,62 @@ +library epubreadertest; + +import 'package:epubx/src/schema/opf/epub_metadata_creator.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubMetadataCreator() + ..Creator = "orthros" + ..FileAs = "Large" + ..Role = "Creator"; + + EpubMetadataCreator testMetadataCreator; + setUp(() async { + testMetadataCreator = new EpubMetadataCreator() + ..Creator = reference.Creator + ..FileAs = reference.FileAs + ..Role = reference.Role; + }); + tearDown(() async { + testMetadataCreator = null; + }); + + group("EpubMetadataCreator", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testMetadataCreator, equals(reference)); + }); + + test("is false when Creator changes", () async { + testMetadataCreator.Creator = "NotOrthros"; + expect(testMetadataCreator, isNot(reference)); + }); + test("is false when FileAs changes", () async { + testMetadataCreator.FileAs = "Small"; + expect(testMetadataCreator, isNot(reference)); + }); + test("is false when Role changes", () async { + testMetadataCreator.Role = "Copier"; + expect(testMetadataCreator, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testMetadataCreator.hashCode, equals(reference.hashCode)); + }); + + test("is false when Creator changes", () async { + testMetadataCreator.Creator = "NotOrthros"; + expect(testMetadataCreator.hashCode, isNot(reference.hashCode)); + }); + test("is false when FileAs changes", () async { + testMetadataCreator.FileAs = "Small"; + expect(testMetadataCreator.hashCode, isNot(reference.hashCode)); + }); + test("is false when Role changes", () async { + testMetadataCreator.Role = "Copier"; + expect(testMetadataCreator.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_metadata_date_test.dart b/epubx/test/schema/opf/epub_metadata_date_test.dart new file mode 100644 index 00000000..057e633b --- /dev/null +++ b/epubx/test/schema/opf/epub_metadata_date_test.dart @@ -0,0 +1,52 @@ +library epubreadertest; + +import 'package:epubx/src/schema/opf/epub_metadata_date.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubMetadataDate() + ..Date = "a date" + ..Event = "Some important event"; + + EpubMetadataDate testMetadataDate; + setUp(() async { + testMetadataDate = new EpubMetadataDate() + ..Date = reference.Date + ..Event = reference.Event; + }); + tearDown(() async { + testMetadataDate = null; + }); + + group("EpubMetadataIdentifier", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testMetadataDate, equals(reference)); + }); + + test("is false when Date changes", () async { + testMetadataDate.Date = "A different Date"; + expect(testMetadataDate, isNot(reference)); + }); + test("is false when Event changes", () async { + testMetadataDate.Event = "A non important event"; + expect(testMetadataDate, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testMetadataDate.hashCode, equals(reference.hashCode)); + }); + + test("is false when Date changes", () async { + testMetadataDate.Date = "A different date"; + expect(testMetadataDate.hashCode, isNot(reference.hashCode)); + }); + test("is false when Event changes", () async { + testMetadataDate.Event = "A non important event"; + expect(testMetadataDate.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_metadata_identifier_test.dart b/epubx/test/schema/opf/epub_metadata_identifier_test.dart new file mode 100644 index 00000000..4fa03399 --- /dev/null +++ b/epubx/test/schema/opf/epub_metadata_identifier_test.dart @@ -0,0 +1,62 @@ +library epubreadertest; + +import 'package:epubx/src/schema/opf/epub_metadata_identifier.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubMetadataIdentifier() + ..Id = "Unique" + ..Identifier = "Identifier" + ..Scheme = "A plot"; + + EpubMetadataIdentifier testMetadataIdentifier; + setUp(() async { + testMetadataIdentifier = new EpubMetadataIdentifier() + ..Id = reference.Id + ..Identifier = reference.Identifier + ..Scheme = reference.Scheme; + }); + tearDown(() async { + testMetadataIdentifier = null; + }); + + group("EpubMetadataIdentifier", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testMetadataIdentifier, equals(reference)); + }); + + test("is false when Id changes", () async { + testMetadataIdentifier.Id = "A different ID"; + expect(testMetadataIdentifier, isNot(reference)); + }); + test("is false when Identifier changes", () async { + testMetadataIdentifier.Identifier = "A different identifier"; + expect(testMetadataIdentifier, isNot(reference)); + }); + test("is false when Scheme changes", () async { + testMetadataIdentifier.Scheme = "A strange scheme"; + expect(testMetadataIdentifier, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testMetadataIdentifier.hashCode, equals(reference.hashCode)); + }); + + test("is false when Id changes", () async { + testMetadataIdentifier.Id = "A different Id"; + expect(testMetadataIdentifier.hashCode, isNot(reference.hashCode)); + }); + test("is false when Identifier changes", () async { + testMetadataIdentifier.Identifier = "A different identifier"; + expect(testMetadataIdentifier.hashCode, isNot(reference.hashCode)); + }); + test("is false when Scheme changes", () async { + testMetadataIdentifier.Scheme = "A strange scheme"; + expect(testMetadataIdentifier.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_metadata_meta_test.dart b/epubx/test/schema/opf/epub_metadata_meta_test.dart new file mode 100644 index 00000000..f191178a --- /dev/null +++ b/epubx/test/schema/opf/epub_metadata_meta_test.dart @@ -0,0 +1,91 @@ +library epubreadertest; + +import 'package:epubx/src/schema/opf/epub_metadata_meta.dart'; +import 'package:test/test.dart'; + +main() async { + var reference = new EpubMetadataMeta() + ..Content = "some content" + ..Name = "Orthros" + ..Property = "Prop" + ..Refines = "Oil" + ..Id = "Unique" + ..Scheme = "A plot"; + + EpubMetadataMeta testMetadataMeta; + setUp(() async { + testMetadataMeta = new EpubMetadataMeta() + ..Content = reference.Content + ..Name = reference.Name + ..Property = reference.Property + ..Refines = reference.Refines + ..Id = reference.Id + ..Scheme = reference.Scheme; + }); + tearDown(() async { + testMetadataMeta = null; + }); + + group("EpubMetadataMeta", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testMetadataMeta, equals(reference)); + }); + + test("is false when Refines changes", () async { + testMetadataMeta.Refines = "Natural gas"; + expect(testMetadataMeta, isNot(reference)); + }); + test("is false when Property changes", () async { + testMetadataMeta.Property = "A different Property"; + expect(testMetadataMeta, isNot(reference)); + }); + test("is false when Name changes", () async { + testMetadataMeta.Id = "notOrthros"; + expect(testMetadataMeta, isNot(reference)); + }); + test("is false when Content changes", () async { + testMetadataMeta.Content = "A different Content"; + expect(testMetadataMeta, isNot(reference)); + }); + test("is false when Id changes", () async { + testMetadataMeta.Id = "A different ID"; + expect(testMetadataMeta, isNot(reference)); + }); + test("is false when Scheme changes", () async { + testMetadataMeta.Scheme = "A strange scheme"; + expect(testMetadataMeta, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testMetadataMeta.hashCode, equals(reference.hashCode)); + }); + test("is false when Refines changes", () async { + testMetadataMeta.Refines = "Natural Gas"; + expect(testMetadataMeta.hashCode, isNot(reference.hashCode)); + }); + test("is false when Property changes", () async { + testMetadataMeta.Property = "A different property"; + expect(testMetadataMeta.hashCode, isNot(reference.hashCode)); + }); + test("is false when Name changes", () async { + testMetadataMeta.Name = "NotOrthros"; + expect(testMetadataMeta.hashCode, isNot(reference.hashCode)); + }); + test("is false when Content changes", () async { + testMetadataMeta.Content = "Different Content"; + expect(testMetadataMeta.hashCode, isNot(reference.hashCode)); + }); + test("is false when Id changes", () async { + testMetadataMeta.Id = "A different Id"; + expect(testMetadataMeta.hashCode, isNot(reference.hashCode)); + }); + test("is false when Scheme changes", () async { + testMetadataMeta.Scheme = "A strange scheme"; + expect(testMetadataMeta.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_metadata_test.dart b/epubx/test/schema/opf/epub_metadata_test.dart new file mode 100644 index 00000000..45a2a058 --- /dev/null +++ b/epubx/test/schema/opf/epub_metadata_test.dart @@ -0,0 +1,187 @@ +library epubreadertest; + +import 'dart:math'; + +import 'package:epubx/src/schema/opf/epub_metadata.dart'; +import 'package:epubx/src/schema/opf/epub_metadata_contributor.dart'; +import 'package:epubx/src/schema/opf/epub_metadata_creator.dart'; +import 'package:epubx/src/schema/opf/epub_metadata_date.dart'; +import 'package:epubx/src/schema/opf/epub_metadata_identifier.dart'; +import 'package:epubx/src/schema/opf/epub_metadata_meta.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + final int length = 10; + final RandomString randomString = new RandomString(new Random(123788)); + final RandomDataGenerator generator = + new RandomDataGenerator(new Random(123778), length); + + var reference = generator.randomEpubMetadata(); + EpubMetadata testMetadata; + setUp(() async { + testMetadata = new EpubMetadata() + ..Contributors = List.from(reference.Contributors) + ..Coverages = List.from(reference.Coverages) + ..Creators = List.from(reference.Creators) + ..Dates = List.from(reference.Dates) + ..Description = reference.Description + ..Formats = List.from(reference.Formats) + ..Identifiers = List.from(reference.Identifiers) + ..Languages = List.from(reference.Languages) + ..MetaItems = List.from(reference.MetaItems) + ..Publishers = List.from(reference.Publishers) + ..Relations = List.from(reference.Relations) + ..Rights = List.from(reference.Rights) + ..Sources = List.from(reference.Sources) + ..Subjects = List.from(reference.Subjects) + ..Titles = List.from(reference.Titles) + ..Types = List.from(reference.Types); + }); + tearDown(() async { + testMetadata = null; + }); + + group("EpubMetadata", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testMetadata, equals(reference)); + }); + test("is false when Contributors changes", () async { + testMetadata.Contributors = [new EpubMetadataContributor()]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Coverages changes", () async { + testMetadata.Coverages = [randomString.randomAlpha(length)]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Creators changes", () async { + testMetadata.Creators = [new EpubMetadataCreator()]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Dates changes", () async { + testMetadata.Dates = [new EpubMetadataDate()]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Description changes", () async { + testMetadata.Description = randomString.randomAlpha(length); + expect(testMetadata, isNot(reference)); + }); + test("is false when Formats changes", () async { + testMetadata.Formats = [randomString.randomAlpha(length)]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Identifiers changes", () async { + testMetadata.Identifiers = [new EpubMetadataIdentifier()]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Languages changes", () async { + testMetadata.Languages = [randomString.randomAlpha(length)]; + expect(testMetadata, isNot(reference)); + }); + test("is false when MetaItems changes", () async { + testMetadata.MetaItems = [new EpubMetadataMeta()]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Publishers changes", () async { + testMetadata.Publishers = [randomString.randomAlpha(length)]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Relations changes", () async { + testMetadata.Relations = [randomString.randomAlpha(length)]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Rights changes", () async { + testMetadata.Rights = [randomString.randomAlpha(length)]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Sources changes", () async { + testMetadata.Sources = [randomString.randomAlpha(length)]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Subjects changes", () async { + testMetadata.Subjects = [randomString.randomAlpha(length)]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Titles changes", () async { + testMetadata.Titles = [randomString.randomAlpha(length)]; + expect(testMetadata, isNot(reference)); + }); + test("is false when Types changes", () async { + testMetadata.Types = [randomString.randomAlpha(length)]; + expect(testMetadata, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testMetadata.hashCode, equals(reference.hashCode)); + }); + test("is false when Contributors changes", () async { + testMetadata.Contributors = [new EpubMetadataContributor()]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Coverages changes", () async { + testMetadata.Coverages = [randomString.randomAlpha(length)]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Creators changes", () async { + testMetadata.Creators = [new EpubMetadataCreator()]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Dates changes", () async { + testMetadata.Dates = [new EpubMetadataDate()]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Description changes", () async { + testMetadata.Description = randomString.randomAlpha(length); + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Formats changes", () async { + testMetadata.Formats = [randomString.randomAlpha(length)]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Identifiers changes", () async { + testMetadata.Identifiers = [new EpubMetadataIdentifier()]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Languages changes", () async { + testMetadata.Languages = [randomString.randomAlpha(length)]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when MetaItems changes", () async { + testMetadata.MetaItems = [new EpubMetadataMeta()]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Publishers changes", () async { + testMetadata.Publishers = [randomString.randomAlpha(length)]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Relations changes", () async { + testMetadata.Relations = [randomString.randomAlpha(length)]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Rights changes", () async { + testMetadata.Rights = [randomString.randomAlpha(length)]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Sources changes", () async { + testMetadata.Sources = [randomString.randomAlpha(length)]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Subjects changes", () async { + testMetadata.Subjects = [randomString.randomAlpha(length)]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Titles changes", () async { + testMetadata.Titles = [randomString.randomAlpha(length)]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + test("is false when Types changes", () async { + testMetadata.Types = [randomString.randomAlpha(length)]; + expect(testMetadata.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_package_test.dart b/epubx/test/schema/opf/epub_package_test.dart new file mode 100644 index 00000000..e202fc1e --- /dev/null +++ b/epubx/test/schema/opf/epub_package_test.dart @@ -0,0 +1,89 @@ +library epubreadertest; + +import 'dart:math'; + +import 'package:epubx/epub.dart'; +import 'package:epubx/src/schema/opf/epub_version.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + final int length = 10; + + final RandomDataGenerator generator = + new RandomDataGenerator(new Random(123778), length); + + var reference = generator.randomEpubPackage()..Version = EpubVersion.Epub3; + + EpubPackage testPackage; + setUp(() async { + testPackage = new EpubPackage() + ..Guide = reference.Guide + ..Manifest = reference.Manifest + ..Metadata = reference.Metadata + ..Spine = reference.Spine + ..Version = reference.Version; + }); + tearDown(() async { + testPackage = null; + }); + + group("EpubSpine", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testPackage, equals(reference)); + }); + test("is false when Guide changes", () async { + testPackage.Guide = generator.randomEpubGuide(); + expect(testPackage, isNot(reference)); + }); + test("is false when Manifest changes", () async { + testPackage.Manifest = generator.randomEpubManifest(); + expect(testPackage, isNot(reference)); + }); + test("is false when Metadata changes", () async { + testPackage.Metadata = generator.randomEpubMetadata(); + expect(testPackage, isNot(reference)); + }); + test("is false when Spine changes", () async { + testPackage.Spine = generator.randomEpubSpine(); + expect(testPackage, isNot(reference)); + }); + test("is false when Version changes", () async { + testPackage.Version = testPackage.Version == EpubVersion.Epub2 + ? EpubVersion.Epub3 + : EpubVersion.Epub2; + expect(testPackage, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testPackage.hashCode, equals(reference.hashCode)); + }); + test("is false when Guide changes", () async { + testPackage.Guide = generator.randomEpubGuide(); + expect(testPackage.hashCode, isNot(reference.hashCode)); + }); + test("is false when Manifest changes", () async { + testPackage.Manifest = generator.randomEpubManifest(); + expect(testPackage.hashCode, isNot(reference.hashCode)); + }); + test("is false when Metadata changes", () async { + testPackage.Metadata = generator.randomEpubMetadata(); + expect(testPackage.hashCode, isNot(reference.hashCode)); + }); + test("is false when Spine changes", () async { + testPackage.Spine = generator.randomEpubSpine(); + expect(testPackage.hashCode, isNot(reference.hashCode)); + }); + test("is false when Version changes", () async { + testPackage.Version = testPackage.Version == EpubVersion.Epub2 + ? EpubVersion.Epub3 + : EpubVersion.Epub2; + expect(testPackage.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_spine_item_ref_test.dart b/epubx/test/schema/opf/epub_spine_item_ref_test.dart new file mode 100644 index 00000000..75be5098 --- /dev/null +++ b/epubx/test/schema/opf/epub_spine_item_ref_test.dart @@ -0,0 +1,57 @@ +library epubreadertest; + +import 'dart:math'; + +import 'package:epubx/src/schema/opf/epub_spine_item_ref.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + final int length = 10; + final RandomString randomString = new RandomString(new Random(123788)); + + var reference = new EpubSpineItemRef() + ..IsLinear = true + ..IdRef = randomString.randomAlpha(length); + + EpubSpineItemRef testSpineItemRef; + setUp(() async { + testSpineItemRef = new EpubSpineItemRef() + ..IsLinear = reference.IsLinear + ..IdRef = reference.IdRef; + }); + tearDown(() async { + testSpineItemRef = null; + }); + + group("EpubSpineItemRef", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testSpineItemRef, equals(reference)); + }); + test("is false when IsLinear changes", () async { + testSpineItemRef.IsLinear = !testSpineItemRef.IsLinear; + expect(testSpineItemRef, isNot(reference)); + }); + test("is false when IdRef changes", () async { + testSpineItemRef.IdRef = randomString.randomAlpha(length); + expect(testSpineItemRef, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testSpineItemRef.hashCode, equals(reference.hashCode)); + }); + test("is false when IsLinear changes", () async { + testSpineItemRef.IsLinear = !testSpineItemRef.IsLinear; + expect(testSpineItemRef.hashCode, isNot(reference.hashCode)); + }); + test("is false when IdRef changes", () async { + testSpineItemRef.IdRef = randomString.randomAlpha(length); + expect(testSpineItemRef.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/test/schema/opf/epub_spine_test.dart b/epubx/test/schema/opf/epub_spine_test.dart new file mode 100644 index 00000000..8757692a --- /dev/null +++ b/epubx/test/schema/opf/epub_spine_test.dart @@ -0,0 +1,70 @@ +library epubreadertest; + +import 'dart:math'; + +import 'package:epubx/src/schema/opf/epub_spine.dart'; +import 'package:epubx/src/schema/opf/epub_spine_item_ref.dart'; +import 'package:test/test.dart'; + +import '../../random_data_generator.dart'; + +main() async { + final int length = 10; + final RandomString randomString = new RandomString(new Random(123788)); + + var reference = new EpubSpine() + ..Items = [ + new EpubSpineItemRef() + ..IdRef = randomString.randomAlpha(length) + ..IdRef = randomString.randomAlpha(length) + ] + ..TableOfContents = randomString.randomAlpha(length); + + EpubSpine testSpine; + setUp(() async { + testSpine = new EpubSpine() + ..Items = List.from(reference.Items) + ..TableOfContents = reference.TableOfContents; + }); + tearDown(() async { + testSpine = null; + }); + + group("EpubSpine", () { + group(".equals", () { + test("is true for equivalent objects", () async { + expect(testSpine, equals(reference)); + }); + test("is false when Items changes", () async { + testSpine.Items = [ + new EpubSpineItemRef() + ..IdRef = randomString.randomAlpha(length) + ..IsLinear = false + ]; + expect(testSpine, isNot(reference)); + }); + test("is false when TableOfContents changes", () async { + testSpine.TableOfContents = randomString.randomAlpha(length); + expect(testSpine, isNot(reference)); + }); + }); + + group(".hashCode", () { + test("is true for equivalent objects", () async { + expect(testSpine.hashCode, equals(reference.hashCode)); + }); + test("is false when IsLinear changes", () async { + testSpine.Items = [ + new EpubSpineItemRef() + ..IdRef = randomString.randomAlpha(length) + ..IsLinear = false + ]; + expect(testSpine.hashCode, isNot(reference.hashCode)); + }); + test("is false when TableOfContents changes", () async { + testSpine.TableOfContents = randomString.randomAlpha(length); + expect(testSpine.hashCode, isNot(reference.hashCode)); + }); + }); + }); +} diff --git a/epubx/tool/publish.sh b/epubx/tool/publish.sh new file mode 100644 index 00000000..fa3709c5 --- /dev/null +++ b/epubx/tool/publish.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +mkdir -p .pub-cache + +cat < ~/.pub-cache/credentials.json +{ + "accessToken":"$accessToken", + "refreshToken":"$refreshToken", + "tokenEndpoint":"$tokenEndpoint", + "scopes":["$scopes"], + "expiration":$expiration +} +EOF + +pub publish -f \ No newline at end of file diff --git a/epubx/tool/travis.sh b/epubx/tool/travis.sh new file mode 100644 index 00000000..0995671f --- /dev/null +++ b/epubx/tool/travis.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Fast fail the script on failures. +set -e + +# Analyze the code. +dartanalyzer --strong --fatal-warnings . + +# Test the entire test directory +pub run test test/ \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index aa02ece1..632e4978 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,9 +1,10 @@ PODS: + - app_links (0.0.2): + - Flutter - audio_session (0.0.1): - Flutter - connectivity_plus (0.0.1): - Flutter - - FlutterMacOS - DKImagePickerController/Core (4.3.4): - DKImagePickerController/ImageDataManager - DKImagePickerController/Resource @@ -95,8 +96,9 @@ PODS: - FlutterMacOS DEPENDENCIES: + - app_links (from `.symlinks/plugins/app_links/ios`) - audio_session (from `.symlinks/plugins/audio_session/ios`) - - connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`) + - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) - Flutter (from `Flutter`) - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) @@ -129,10 +131,12 @@ SPEC REPOS: - SwiftyGif EXTERNAL SOURCES: + app_links: + :path: ".symlinks/plugins/app_links/ios" audio_session: :path: ".symlinks/plugins/audio_session/ios" connectivity_plus: - :path: ".symlinks/plugins/connectivity_plus/darwin" + :path: ".symlinks/plugins/connectivity_plus/ios" file_picker: :path: ".symlinks/plugins/file_picker/ios" Flutter: @@ -179,8 +183,9 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/webview_flutter_wkwebview/darwin" SPEC CHECKSUMS: + app_links: 76b66b60cc809390ca1ad69bfd66b998d2387ac7 audio_session: f08db0697111ac84ba46191b55488c0563bb29c6 - connectivity_plus: 2256d3e20624a7749ed21653aafe291a46446fee + connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517 @@ -205,7 +210,7 @@ SPEC CHECKSUMS: SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f url_launcher_ios: 694010445543906933d732453a59da0a173ae33d video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b - volume_controller: ca1cde542ee70fad77d388f82e9616488110942b + volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12 wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49 webview_flutter_wkwebview: 44d4dee7d7056d5ad185d25b38404436d56c547c diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 8e3ca5df..15cada48 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -59,6 +59,7 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" + enableGPUValidationMode = "1" allowLocationSimulation = "YES"> diff --git a/lib/eval/dart/bridge/m_provider.dart b/lib/eval/dart/bridge/m_provider.dart index db9d0c01..0b6218ad 100644 --- a/lib/eval/dart/bridge/m_provider.dart +++ b/lib/eval/dart/bridge/m_provider.dart @@ -164,6 +164,11 @@ class $MProvider extends MProvider with $Bridge { BridgeTypeRef(CoreTypes.future, [BridgeTypeRef(CoreTypes.string)]), ), params: [ + BridgeParameter( + 'name', + BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), + false, + ), BridgeParameter( 'url', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), @@ -1673,8 +1678,8 @@ class $MProvider extends MProvider with $Bridge { } @override - Future getHtmlContent(String url) async => - await $_invoke('getHtmlContent', [$String(url)]); + Future getHtmlContent(String name, String url) async => + await $_invoke('getHtmlContent', [$String(name), $String(url)]); @override Future cleanHtmlContent(String html) async => diff --git a/lib/eval/dart/bridge/m_source.dart b/lib/eval/dart/bridge/m_source.dart index 3f7648e3..3c5b7bb2 100644 --- a/lib/eval/dart/bridge/m_source.dart +++ b/lib/eval/dart/bridge/m_source.dart @@ -45,6 +45,9 @@ class $MSource implements MSource, $Instance { 'additionalParams': BridgeFieldDef( BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), ), + 'notes': BridgeFieldDef( + BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), + ), }, wrap: true, ); @@ -84,6 +87,8 @@ class $MSource implements MSource, $Instance { return $String($value.apiUrl!); case 'additionalParams': return $String($value.additionalParams!); + case 'notes': + return $String($value.notes!); default: return _superclass.$getProperty(runtime, identifier); @@ -116,6 +121,8 @@ class $MSource implements MSource, $Instance { $value.apiUrl = value.$reified; case 'additionalParams': $value.additionalParams = value.$reified; + case 'notes': + $value.notes = value.$reified; default: _superclass.$setProperty(runtime, identifier, value); } @@ -151,6 +158,9 @@ class $MSource implements MSource, $Instance { @override String? get additionalParams => $value.additionalParams; + @override + String? get notes => $value.notes; + @override set apiUrl(String? apiUrl) {} @@ -181,6 +191,9 @@ class $MSource implements MSource, $Instance { @override set additionalParams(String? additionalParams) {} + @override + set notes(String? notes) {} + @override Map toJson() => { 'apiUrl': apiUrl, @@ -193,5 +206,6 @@ class $MSource implements MSource, $Instance { 'lang': lang, 'name': name, 'additionalParams': additionalParams, + 'notes': notes, }; } diff --git a/lib/eval/dart/service.dart b/lib/eval/dart/service.dart index a1d34e91..527825ff 100644 --- a/lib/eval/dart/service.dart +++ b/lib/eval/dart/service.dart @@ -118,8 +118,8 @@ class DartExtensionService implements ExtensionService { } @override - Future getHtmlContent(String url) async { - return await _executeLib().getHtmlContent(url); + Future getHtmlContent(String name, String url) async { + return await _executeLib().getHtmlContent(name, url); } @override diff --git a/lib/eval/interface.dart b/lib/eval/interface.dart index 0f147705..56a150b8 100644 --- a/lib/eval/interface.dart +++ b/lib/eval/interface.dart @@ -29,7 +29,7 @@ abstract interface class ExtensionService { Future> getVideoList(String url); - Future getHtmlContent(String url); + Future getHtmlContent(String name, String url); Future cleanHtmlContent(String html); diff --git a/lib/eval/javascript/http.dart b/lib/eval/javascript/http.dart index 7a077421..3e3f4f9d 100644 --- a/lib/eval/javascript/http.dart +++ b/lib/eval/javascript/http.dart @@ -16,6 +16,9 @@ class JsHttpClient { ); } + runtime.onMessage('http_head', (dynamic args) async { + return await _toHttpResponse(client(args[1]), "HEAD", args); + }); runtime.onMessage('http_get', (dynamic args) async { return await _toHttpResponse(client(args[1]), "GET", args); }); @@ -36,6 +39,14 @@ class Client { constructor(reqcopyWith) { this.reqcopyWith = reqcopyWith; } + async head(url, headers) { + headers = headers; + const result = await sendMessage( + "http_head", + JSON.stringify([null, this.reqcopyWith, url, headers]) + ); + return JSON.parse(result); + } async get(url, headers) { headers = headers; const result = await sendMessage( @@ -115,6 +126,7 @@ Future _toHttpResponse(Client client, String method, List args) async { return jsonEncode(resMap); } final future = switch (method) { + "HEAD" => client.head(Uri.parse(url), headers: headers), "GET" => client.get(Uri.parse(url), headers: headers), "POST" => client.post(Uri.parse(url), headers: headers, body: body), "PUT" => client.put(Uri.parse(url), headers: headers, body: body), diff --git a/lib/eval/javascript/service.dart b/lib/eval/javascript/service.dart index 78f6363a..72a1f247 100644 --- a/lib/eval/javascript/service.dart +++ b/lib/eval/javascript/service.dart @@ -59,7 +59,7 @@ class MProvider { async getVideoList(url) { throw new Error("getVideoList not implemented"); } - async getHtmlContent(url) { + async getHtmlContent(name, url) { throw new Error("getHtmlContent not implemented"); } async cleanHtmlContent(html) { @@ -150,12 +150,12 @@ var extention = new DefaultExtension(); } @override - Future getHtmlContent(String url) async { + Future getHtmlContent(String name, String url) async { _init(); final res = (await runtime.handlePromise( await runtime.evaluateAsync( - 'jsonStringify(() => extention.getHtmlContent(`$url`))', + 'jsonStringify(() => extention.getHtmlContent(`$name`, `$url`))', ), )).stringResult; return res; diff --git a/lib/eval/javascript/utils.dart b/lib/eval/javascript/utils.dart index 654cdba6..b5e6147e 100644 --- a/lib/eval/javascript/utils.dart +++ b/lib/eval/javascript/utils.dart @@ -1,7 +1,17 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:epubx/epubx.dart'; import 'package:flutter_qjs/flutter_qjs.dart'; +import 'package:http/http.dart' as http; +import 'package:path/path.dart' as p; +import 'package:http_interceptor/http/intercepted_client.dart'; import 'package:js_packer/js_packer.dart'; import 'package:mangayomi/eval/javascript/http.dart'; import 'package:mangayomi/eval/model/m_bridge.dart'; +import 'package:mangayomi/providers/storage_provider.dart'; +import 'package:mangayomi/services/http/m_client.dart'; import 'package:mangayomi/utils/cryptoaes/js_unpacker.dart'; import 'package:mangayomi/utils/log/log.dart'; @@ -10,6 +20,10 @@ class JsUtils { JsUtils(this.runtime); void init() { + InterceptedClient client() { + return MClient.init(); + } + runtime.onMessage('log', (dynamic args) { Logger.add(LoggerLevel.warning, "${args[0]}"); return null; @@ -39,6 +53,29 @@ class JsUtils { (args[2]! as List).map((e) => e.toString()).toList(), ); }); + runtime.onMessage('parseEpub', (dynamic args) async { + final bytes = await _toBytesResponse(client(), "GET", args); + final book = await EpubReader.readBook(bytes); + final List chapters = []; + for (var chapter in book.Chapters ?? []) { + final chapterTitle = chapter.Title; + chapters.add(chapterTitle); + } + return jsonEncode({ + "title": book.Title, + "author": book.Author, + "chapters": chapters, + }); + }); + runtime.onMessage('parseEpubChapter', (dynamic args) async { + final bytes = await _toBytesResponse(client(), "GET", args); + final book = await EpubReader.readBook(bytes); + final chapter = + book.Chapters?.where( + (element) => element.Title == args[3], + ).firstOrNull; + return chapter?.HtmlContent; + }); runtime.evaluate(''' console.log = function (message) { @@ -143,6 +180,62 @@ async function evaluateJavascriptViaWebview(url, headers, scripts) { JSON.stringify([url, headers, scripts]) ); } +async function parseEpub(bookName, url, headers) { + return JSON.parse(await sendMessage( + "parseEpub", + JSON.stringify([bookName, url, headers]) + )); +} +async function parseEpubChapter(bookName, url, headers, chapterTitle) { + return await sendMessage( + "parseEpubChapter", + JSON.stringify([bookName, url, headers, chapterTitle]) + ); +} '''); } + + Future _toBytesResponse( + http.Client client, + String method, + List args, + ) async { + final bookName = args[0] as String; + final url = args[1] as String; + final headers = (args[2] as Map?)?.toMapStringString; + final body = + args.length >= 4 + ? args[3] is List + ? args[3] as List + : args[3] is String + ? args[3] as String + : (args[3] as Map?)?.toMapStringDynamic + : null; + + final tmpDirectory = (await StorageProvider().getTmpDirectory())!; + if (Platform.isAndroid) { + if (!(await File(p.join(tmpDirectory.path, ".nomedia")).exists())) { + await File(p.join(tmpDirectory.path, ".nomedia")).create(); + } + } + final file = File( + p.join(tmpDirectory.path, "$bookName.epub"), + ); + if (await file.exists()) { + return await file.readAsBytes(); + } + + var request = http.Request(method, Uri.parse(url)); + request.headers.addAll(headers ?? {}); + final future = switch (method) { + "GET" => client.get(Uri.parse(url), headers: headers), + "POST" => client.post(Uri.parse(url), headers: headers, body: body), + "PUT" => client.put(Uri.parse(url), headers: headers, body: body), + "DELETE" => client.delete(Uri.parse(url), headers: headers, body: body), + _ => client.patch(Uri.parse(url), headers: headers, body: body), + }; + final bytes = (await future).bodyBytes; + await file.writeAsBytes(bytes); + return bytes; + } } diff --git a/lib/eval/model/m_bridge.dart b/lib/eval/model/m_bridge.dart index 9b06239d..771e0413 100644 --- a/lib/eval/model/m_bridge.dart +++ b/lib/eval/model/m_bridge.dart @@ -773,7 +773,7 @@ final List _dateFormats = [ "MMM dd,yyyy", ]; -void botToast( +void Function() botToast( String title, { int second = 10, double? fontSize, @@ -781,20 +781,33 @@ void botToast( double alignY = 0.99, bool hasCloudFlare = false, String? url, + int animationDuration = 200, + List dismissDirections = const [ + DismissDirection.horizontal, + DismissDirection.down, + ], + bool onlyOne = true, + bool? themeDark, }) { final context = navigatorKey.currentState?.context; final assets = [ 'assets/app_icons/icon-black.png', 'assets/app_icons/icon-red.png', ]; - BotToast.showNotification( - onlyOne: true, - dismissDirections: [DismissDirection.horizontal, DismissDirection.down], + return BotToast.showNotification( + onlyOne: onlyOne, + dismissDirections: dismissDirections, align: Alignment(alignX, alignY), duration: Duration(seconds: second), - animationDuration: const Duration(milliseconds: 200), - animationReverseDuration: const Duration(milliseconds: 200), - leading: (_) => Image.asset((assets..shuffle()).first, height: 25), + animationDuration: Duration(milliseconds: animationDuration), + animationReverseDuration: Duration(milliseconds: animationDuration), + leading: + (_) => Image.asset( + (themeDark == null + ? (assets..shuffle()).first + : assets[themeDark ? 0 : 1]), + height: 25, + ), title: (_) => Text(title, style: TextStyle(fontSize: fontSize)), trailing: hasCloudFlare diff --git a/lib/eval/model/m_provider.dart b/lib/eval/model/m_provider.dart index 61e29c4e..4f03ae18 100644 --- a/lib/eval/model/m_provider.dart +++ b/lib/eval/model/m_provider.dart @@ -24,7 +24,7 @@ abstract class MProvider { Future> getVideoList(String url); - Future getHtmlContent(String url); + Future getHtmlContent(String name, String url); Future cleanHtmlContent(String html); diff --git a/lib/eval/model/m_source.dart b/lib/eval/model/m_source.dart index e9704b83..4db5e8fc 100644 --- a/lib/eval/model/m_source.dart +++ b/lib/eval/model/m_source.dart @@ -19,6 +19,8 @@ class MSource { String? additionalParams; + String? notes; + MSource({ this.id, this.name, @@ -30,6 +32,7 @@ class MSource { this.dateFormatLocale, this.apiUrl, this.additionalParams, + this.notes, }); Map toJson() => { @@ -43,5 +46,6 @@ class MSource { 'lang': lang, 'name': name, 'additionalParams': additionalParams, + 'notes': notes, }; } diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index c374f0a4..fcaff6e2 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -285,7 +285,7 @@ "aniskip_button_timeout": "مهلة زر", "fullscreen": "شاشة كاملة", "update_library": "تحديث المكتبة", - "updating_library": "جاري تحديث المكتبة", + "updating_library": "جاري تحديث المكتبة ({max} / {cur}) - فشل: {failed}", "next_chapter": "الفصل التالي", "next_5_chapters": "الفصول الخمسة التالية", "next_10_chapters": "الفصول العشرة التالية", diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 75d47dfa..bc67f021 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -362,7 +362,7 @@ "skip_ending": "Ending überspringen", "fullscreen": "Vollbild", "update_library": "Bibliothek aktualisieren", - "updating_library": "Bibliothek wird aktualisiert", + "updating_library": "Bibliothek wird aktualisiert ({cur} / {max}) - Fehlgeschlagen: {failed}", "next_chapter": "Nächstes Kapitel", "next_5_chapters": "Nächsten 5 Kapitel", "next_10_chapters": "Nächsten 10 Kapitel", @@ -464,5 +464,6 @@ "clear_all_sources": "Alle Quellen löschen", "clear_all_sources_msg": "Dies wird alle Quellen der Anwendung vollständig löschen. Möchten Sie wirklich fortfahren?", "sources_cleared": "Quellen gelöscht!", - "add_repo": "Repository hinzufügen?" + "add_repo": "Repository hinzufügen?", + "extension_notes": "Hinweis: {notes}" } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index ebb4d9de..9bffa268 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -121,6 +121,7 @@ "custom_location": "Custom location", "only_on_wifi": "Only on wifi", "save_as_cbz_archive": "Save as CBZ archive", + "concurrent_downloads": "Concurrent downloads", "browse_subtitle": "Sources, global search", "only_include_pinned_sources": "Only include pinned sources", "nsfw_sources": "NSFW (+18) sources", @@ -366,15 +367,17 @@ "skip_ending": "Skip ending", "fullscreen": "Fullscreen", "update_library": "Update library", - "updating_library": "Updating library", + "updating_library": "Updating library ({cur} / {max}) - Failed: {failed}", "next_chapter": "Next chapter", "next_5_chapters": "Next 5 chapters", "next_10_chapters": "Next 10 chapters", "next_25_chapters": "Next 25 chapters", + "all_chapters": "All chapters", "next_episode": "Next episode", "next_5_episodes": "Next 5 episodes", "next_10_episodes": "Next 10 episodes", "next_25_episodes": "Next 25 episodes", + "all_episodes": "All episodes", "cover_saved": "Cover saved", "set_as_cover": "Set as cover", "use_this_as_cover_art": "Use this as cover art?", @@ -461,5 +464,6 @@ "genre_search_library": "Search genre in library", "genre_search_source": "Browse in source", "source_not_added": "Source is not installed!", - "load_own_subtitles": "Load your own subtitles..." + "load_own_subtitles": "Load your own subtitles...", + "extension_notes": "Notes: {notes}" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index b0a926ae..1447c775 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -285,7 +285,7 @@ "aniskip_button_timeout": "Tiempo de espera del botón", "fullscreen": "Pantalla completa", "update_library": "Actualizar biblioteca", - "updating_library": "Actualizando biblioteca", + "updating_library": "Actualizando biblioteca ({cur} / {max}) - Fallido: {failed}", "next_chapter": "Próximo capítulo", "next_5_chapters": "Próximos 5 capítulos", "next_10_chapters": "Próximos 10 capítulos", diff --git a/lib/l10n/app_es_419.arb b/lib/l10n/app_es_419.arb index fee5cbdc..c9437003 100644 --- a/lib/l10n/app_es_419.arb +++ b/lib/l10n/app_es_419.arb @@ -285,7 +285,7 @@ "aniskip_button_timeout": "Tiempo de espera del botón", "fullscreen": "Pantalla completa", "update_library": "Actualizar biblioteca", - "updating_library": "Actualizando biblioteca", + "updating_library": "Actualizando biblioteca ({cur} / {max}) - Fallido: {failed}", "next_chapter": "Siguiente capítulo", "next_5_chapters": "Siguientes 5 capítulos", "next_10_chapters": "Siguientes 10 capítulos", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index a8fbbff9..f6daba57 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -286,7 +286,7 @@ "skip_opening": "Passer l'opening", "skip_ending": "Passer l'ending", "update_library": "Mettre à jour la bibliothèque", - "updating_library": "Mise à jour de la bibliothèque", + "updating_library": "Mise à jour de la bibliothèque ({cur} / {max}) - Échec: {failed}", "next_chapter": "Chapitre suivant", "next_5_chapters": "5 chapitres suivants", "next_10_chapters": "10 chapitres suivants", diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index ee08b4ae..49b9c5ae 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -285,7 +285,7 @@ "aniskip_button_timeout": "Timeout tombol", "fullscreen": "Layar Penuh", "update_library": "Perbarui perpustakaan", - "updating_library": "Memperbarui perpustakaan", + "updating_library": "Memperbarui perpustakaan ({cur} / {max}) - Gagal: {failed}", "next_chapter": "Berikutnya bab", "next_5_chapters": "5 bab berikutnya", "next_10_chapters": "10 bab berikutnya", diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 9bac94f5..ff4c9fee 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -285,7 +285,7 @@ "aniskip_button_timeout": "Timeout del pulsante", "fullscreen": "Schermo intero", "update_library": "Aggiorna libreria", - "updating_library": "Aggiornamento della libreria", + "updating_library": "Aggiornamento della libreria ({cur} / {max}) - Fallito: {failed}", "next_chapter": "Capitolo successivo", "next_5_chapters": "Prossimi 5 capitoli", "next_10_chapters": "Prossimi 10 capitoli", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index d33a827e..d01f4696 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -285,7 +285,7 @@ "aniskip_button_timeout": "Tempo limite do botão", "fullscreen": "Tela cheia", "update_library": "Atualizar biblioteca", - "updating_library": "Atualizando biblioteca", + "updating_library": "Atualizando biblioteca ({cur} / {max}) - Falha: {failed}", "next_chapter": "Próximo capítulo", "next_5_chapters": "Próximos 5 capítulos", "next_10_chapters": "Próximos 10 capítulos", diff --git a/lib/l10n/app_pt_BR.arb b/lib/l10n/app_pt_BR.arb index 26acb106..a4081da8 100644 --- a/lib/l10n/app_pt_BR.arb +++ b/lib/l10n/app_pt_BR.arb @@ -285,7 +285,7 @@ "aniskip_button_timeout": "Timeout do botão", "fullscreen": "Tela cheia", "update_library": "Atualizar biblioteca", - "updating_library": "Atualizando biblioteca", + "updating_library": "Atualizando biblioteca ({cur} / {max}) - Falha: {failed}", "next_chapter": "Próximo capítulo", "next_5_chapters": "Próximos 5 capítulos", "next_10_chapters": "Próximos 10 capítulos", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 5a17bbbc..053dc349 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -285,7 +285,7 @@ "aniskip_button_timeout": "Тайм-аут кнопки", "fullscreen": "Полноэкранный режим", "update_library": "Обновить библиотеку", - "updating_library": "Обновление библиотеки", + "updating_library": "Обновление библиотеки ({cur} / {max}) - Не удалось: {failed}", "next_chapter": "Следующая глава", "next_5_chapters": "Следующие 5 глав", "next_10_chapters": "Следующие 10 глав", diff --git a/lib/l10n/app_th.arb b/lib/l10n/app_th.arb index 76b6028c..a21d1625 100644 --- a/lib/l10n/app_th.arb +++ b/lib/l10n/app_th.arb @@ -290,7 +290,7 @@ "skip_ending": "ข้ามตอนจบ", "fullscreen": "เต็มจอ", "update_library": "อัพเดทชั้นหนังสือ", - "updating_library": "กำลังอัพเดทชั้นหนังสือ", + "updating_library": "กำลังอัพเดทชั้นหนังสือ ({cur} / {max}) - ล้มเหลว: {failed}", "next_chapter": "ตอนถัดไป", "next_5_chapters": "5 ตอนถัดไป", "next_10_chapters": "10 ตอนถัดไป", diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index e4126779..0e2d8753 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -285,7 +285,7 @@ "aniskip_button_timeout": "Düğme Zaman Aşımı", "fullscreen": "Tam ekran", "update_library": "Kütüphaneyi güncelle", - "updating_library": "Kütüphaneyi güncelleme", + "updating_library": "Kütüphaneyi güncelleme ({cur} / {max}) - Başarısız: {failed}", "next_chapter": "Sonraki bölüm", "next_5_chapters": "Sonraki 5 bölüm", "next_10_chapters": "Sonraki 10 bölüm", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index e26b3a42..0ec5e5fc 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -290,7 +290,7 @@ "skip_ending": "跳过结尾", "fullscreen": "全屏", "update_library": "更新库", - "updating_library": "正在更新库", + "updating_library": "正在更新库 ({cur} / {max}) - 失败: {failed}", "next_chapter": "下一章", "next_5_chapters": "下5章", "next_10_chapters": "下10章", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 7fc73f5b..f675e14d 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -843,6 +843,12 @@ abstract class AppLocalizations { /// **'Save as CBZ archive'** String get save_as_cbz_archive; + /// No description provided for @concurrent_downloads. + /// + /// In en, this message translates to: + /// **'Concurrent downloads'** + String get concurrent_downloads; + /// No description provided for @browse_subtitle. /// /// In en, this message translates to: @@ -2316,8 +2322,8 @@ abstract class AppLocalizations { /// No description provided for @updating_library. /// /// In en, this message translates to: - /// **'Updating library'** - String get updating_library; + /// **'Updating library ({cur} / {max}) - Failed: {failed}'** + String updating_library(Object cur, Object failed, Object max); /// No description provided for @next_chapter. /// @@ -2343,6 +2349,12 @@ abstract class AppLocalizations { /// **'Next 25 chapters'** String get next_25_chapters; + /// No description provided for @all_chapters. + /// + /// In en, this message translates to: + /// **'All chapters'** + String get all_chapters; + /// No description provided for @next_episode. /// /// In en, this message translates to: @@ -2367,6 +2379,12 @@ abstract class AppLocalizations { /// **'Next 25 episodes'** String get next_25_episodes; + /// No description provided for @all_episodes. + /// + /// In en, this message translates to: + /// **'All episodes'** + String get all_episodes; + /// No description provided for @cover_saved. /// /// In en, this message translates to: @@ -2888,6 +2906,12 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Load your own subtitles...'** String get load_own_subtitles; + + /// No description provided for @extension_notes. + /// + /// In en, this message translates to: + /// **'Notes: {notes}'** + String extension_notes(Object notes); } class _AppLocalizationsDelegate extends LocalizationsDelegate { diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart index a0a15008..ca27ec04 100644 --- a/lib/l10n/generated/app_localizations_ar.dart +++ b/lib/l10n/generated/app_localizations_ar.dart @@ -375,6 +375,9 @@ class AppLocalizationsAr extends AppLocalizations { @override String get save_as_cbz_archive => 'حفظ كأرشيف CBZ'; + @override + String get concurrent_downloads => 'Concurrent downloads'; + @override String get browse_subtitle => 'المصادر، البحث العام'; @@ -1139,7 +1142,9 @@ class AppLocalizationsAr extends AppLocalizations { String get update_library => 'تحديث المكتبة'; @override - String get updating_library => 'جاري تحديث المكتبة'; + String updating_library(Object cur, Object failed, Object max) { + return 'جاري تحديث المكتبة ($max / $cur) - فشل: $failed'; + } @override String get next_chapter => 'الفصل التالي'; @@ -1153,6 +1158,9 @@ class AppLocalizationsAr extends AppLocalizations { @override String get next_25_chapters => 'الفصول الخمسة والعشرون التالية'; + @override + String get all_chapters => 'All chapters'; + @override String get next_episode => 'الحلقة التالية'; @@ -1165,6 +1173,9 @@ class AppLocalizationsAr extends AppLocalizations { @override String get next_25_episodes => 'الخمسة وعشرون حلقة التالية'; + @override + String get all_episodes => 'All episodes'; + @override String get cover_saved => 'الغلاف المحفوظ'; @@ -1439,4 +1450,9 @@ class AppLocalizationsAr extends AppLocalizations { @override String get load_own_subtitles => 'تحميل الترجمة الخاصة بك...'; + + @override + String extension_notes(Object notes) { + return 'Notes: $notes'; + } } diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 3e1d37ac..fa22b28f 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -375,6 +375,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get save_as_cbz_archive => 'Als CBZ-Archiv speichern'; + @override + String get concurrent_downloads => 'Concurrent downloads'; + @override String get browse_subtitle => 'Quellen, globale Suche'; @@ -1139,7 +1142,9 @@ class AppLocalizationsDe extends AppLocalizations { String get update_library => 'Bibliothek aktualisieren'; @override - String get updating_library => 'Bibliothek wird aktualisiert'; + String updating_library(Object cur, Object failed, Object max) { + return 'Bibliothek wird aktualisiert ($cur / $max) - Fehlgeschlagen: $failed'; + } @override String get next_chapter => 'Nächstes Kapitel'; @@ -1153,6 +1158,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get next_25_chapters => 'Nächsten 25 Kapitel'; + @override + String get all_chapters => 'All chapters'; + @override String get next_episode => 'Nächste Episode'; @@ -1165,6 +1173,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get next_25_episodes => 'Nächsten 25 Episoden'; + @override + String get all_episodes => 'All episodes'; + @override String get cover_saved => 'Titelbild gespeichert'; @@ -1439,4 +1450,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get load_own_subtitles => 'Deine eigene Untertiteln laden...'; + + @override + String extension_notes(Object notes) { + return 'Hinweis: $notes'; + } } diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 5dce637c..b311d647 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -375,6 +375,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get save_as_cbz_archive => 'Save as CBZ archive'; + @override + String get concurrent_downloads => 'Concurrent downloads'; + @override String get browse_subtitle => 'Sources, global search'; @@ -1139,7 +1142,9 @@ class AppLocalizationsEn extends AppLocalizations { String get update_library => 'Update library'; @override - String get updating_library => 'Updating library'; + String updating_library(Object cur, Object failed, Object max) { + return 'Updating library ($cur / $max) - Failed: $failed'; + } @override String get next_chapter => 'Next chapter'; @@ -1153,6 +1158,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get next_25_chapters => 'Next 25 chapters'; + @override + String get all_chapters => 'All chapters'; + @override String get next_episode => 'Next episode'; @@ -1165,6 +1173,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get next_25_episodes => 'Next 25 episodes'; + @override + String get all_episodes => 'All episodes'; + @override String get cover_saved => 'Cover saved'; @@ -1439,4 +1450,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get load_own_subtitles => 'Load your own subtitles...'; + + @override + String extension_notes(Object notes) { + return 'Notes: $notes'; + } } diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index dd113bcb..6637b18f 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -375,6 +375,9 @@ class AppLocalizationsEs extends AppLocalizations { @override String get save_as_cbz_archive => 'Guardar como archivo CBZ'; + @override + String get concurrent_downloads => 'Concurrent downloads'; + @override String get browse_subtitle => 'Fuentes, búsqueda global'; @@ -1139,7 +1142,9 @@ class AppLocalizationsEs extends AppLocalizations { String get update_library => 'Actualizar biblioteca'; @override - String get updating_library => 'Actualizando biblioteca'; + String updating_library(Object cur, Object failed, Object max) { + return 'Actualizando biblioteca ($cur / $max) - Fallido: $failed'; + } @override String get next_chapter => 'Próximo capítulo'; @@ -1153,6 +1158,9 @@ class AppLocalizationsEs extends AppLocalizations { @override String get next_25_chapters => 'Próximos 25 capítulos'; + @override + String get all_chapters => 'All chapters'; + @override String get next_episode => 'Siguiente episodio'; @@ -1165,6 +1173,9 @@ class AppLocalizationsEs extends AppLocalizations { @override String get next_25_episodes => 'Siguientes 25 episodios'; + @override + String get all_episodes => 'All episodes'; + @override String get cover_saved => 'Portada guardada'; @@ -1439,6 +1450,11 @@ class AppLocalizationsEs extends AppLocalizations { @override String get load_own_subtitles => 'Cargar tus propios subtítulos...'; + + @override + String extension_notes(Object notes) { + return 'Notes: $notes'; + } } /// The translations for Spanish Castilian, as used in Latin America and the Caribbean (`es_419`). @@ -2576,7 +2592,9 @@ class AppLocalizationsEs419 extends AppLocalizationsEs { String get update_library => 'Actualizar biblioteca'; @override - String get updating_library => 'Actualizando biblioteca'; + String updating_library(Object cur, Object failed, Object max) { + return 'Actualizando biblioteca ($cur / $max) - Fallido: $failed'; + } @override String get next_chapter => 'Siguiente capítulo'; diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart index ea61c66c..9c24fdf0 100644 --- a/lib/l10n/generated/app_localizations_fr.dart +++ b/lib/l10n/generated/app_localizations_fr.dart @@ -375,6 +375,9 @@ class AppLocalizationsFr extends AppLocalizations { @override String get save_as_cbz_archive => 'Enregistrer comme archive CBZ'; + @override + String get concurrent_downloads => 'Concurrent downloads'; + @override String get browse_subtitle => 'Sources, extensions, recherche globale'; @@ -1139,7 +1142,9 @@ class AppLocalizationsFr extends AppLocalizations { String get update_library => 'Mettre à jour la bibliothèque'; @override - String get updating_library => 'Mise à jour de la bibliothèque'; + String updating_library(Object cur, Object failed, Object max) { + return 'Mise à jour de la bibliothèque ($cur / $max) - Échec: $failed'; + } @override String get next_chapter => 'Chapitre suivant'; @@ -1153,6 +1158,9 @@ class AppLocalizationsFr extends AppLocalizations { @override String get next_25_chapters => '25 chapitres suivants'; + @override + String get all_chapters => 'All chapters'; + @override String get next_episode => 'Épisode suivant'; @@ -1165,6 +1173,9 @@ class AppLocalizationsFr extends AppLocalizations { @override String get next_25_episodes => '25 épisodes suivants'; + @override + String get all_episodes => 'All episodes'; + @override String get cover_saved => 'Couverture enregistrée'; @@ -1439,4 +1450,9 @@ class AppLocalizationsFr extends AppLocalizations { @override String get load_own_subtitles => 'Charger vos propres sous-titres...'; + + @override + String extension_notes(Object notes) { + return 'Notes: $notes'; + } } diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart index d9e03e66..260cf335 100644 --- a/lib/l10n/generated/app_localizations_id.dart +++ b/lib/l10n/generated/app_localizations_id.dart @@ -375,6 +375,9 @@ class AppLocalizationsId extends AppLocalizations { @override String get save_as_cbz_archive => 'Simpan sebagai Arsip CBZ'; + @override + String get concurrent_downloads => 'Concurrent downloads'; + @override String get browse_subtitle => 'Sumber, Pencarian Umum'; @@ -1139,7 +1142,9 @@ class AppLocalizationsId extends AppLocalizations { String get update_library => 'Perbarui perpustakaan'; @override - String get updating_library => 'Memperbarui perpustakaan'; + String updating_library(Object cur, Object failed, Object max) { + return 'Memperbarui perpustakaan ($cur / $max) - Gagal: $failed'; + } @override String get next_chapter => 'Berikutnya bab'; @@ -1153,6 +1158,9 @@ class AppLocalizationsId extends AppLocalizations { @override String get next_25_chapters => '25 bab berikutnya'; + @override + String get all_chapters => 'All chapters'; + @override String get next_episode => 'Episode berikutnya'; @@ -1165,6 +1173,9 @@ class AppLocalizationsId extends AppLocalizations { @override String get next_25_episodes => '25 episode berikutnya'; + @override + String get all_episodes => 'All episodes'; + @override String get cover_saved => 'Sampul disimpan'; @@ -1439,4 +1450,9 @@ class AppLocalizationsId extends AppLocalizations { @override String get load_own_subtitles => 'Muat subtitle Anda sendiri...'; + + @override + String extension_notes(Object notes) { + return 'Notes: $notes'; + } } diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart index e828e9cf..4e72330e 100644 --- a/lib/l10n/generated/app_localizations_it.dart +++ b/lib/l10n/generated/app_localizations_it.dart @@ -375,6 +375,9 @@ class AppLocalizationsIt extends AppLocalizations { @override String get save_as_cbz_archive => 'Salva come archivio CBZ'; + @override + String get concurrent_downloads => 'Concurrent downloads'; + @override String get browse_subtitle => 'Fonti, ricerca globale'; @@ -1139,7 +1142,9 @@ class AppLocalizationsIt extends AppLocalizations { String get update_library => 'Aggiorna libreria'; @override - String get updating_library => 'Aggiornamento della libreria'; + String updating_library(Object cur, Object failed, Object max) { + return 'Aggiornamento della libreria ($cur / $max) - Fallito: $failed'; + } @override String get next_chapter => 'Capitolo successivo'; @@ -1153,6 +1158,9 @@ class AppLocalizationsIt extends AppLocalizations { @override String get next_25_chapters => 'Prossimi 25 capitoli'; + @override + String get all_chapters => 'All chapters'; + @override String get next_episode => 'Prossimo episodio'; @@ -1165,6 +1173,9 @@ class AppLocalizationsIt extends AppLocalizations { @override String get next_25_episodes => 'Prossimi 25 episodi'; + @override + String get all_episodes => 'All episodes'; + @override String get cover_saved => 'Copertina salvata'; @@ -1439,4 +1450,9 @@ class AppLocalizationsIt extends AppLocalizations { @override String get load_own_subtitles => 'Carica i tuoi sottotitoli...'; + + @override + String extension_notes(Object notes) { + return 'Notes: $notes'; + } } diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index 686e2f54..c397ee63 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -375,6 +375,9 @@ class AppLocalizationsPt extends AppLocalizations { @override String get save_as_cbz_archive => 'Salvar como arquivo CBZ'; + @override + String get concurrent_downloads => 'Concurrent downloads'; + @override String get browse_subtitle => 'Fontes, pesquisa global'; @@ -1139,7 +1142,9 @@ class AppLocalizationsPt extends AppLocalizations { String get update_library => 'Atualizar biblioteca'; @override - String get updating_library => 'Atualizando biblioteca'; + String updating_library(Object cur, Object failed, Object max) { + return 'Atualizando biblioteca ($cur / $max) - Falha: $failed'; + } @override String get next_chapter => 'Próximo capítulo'; @@ -1153,6 +1158,9 @@ class AppLocalizationsPt extends AppLocalizations { @override String get next_25_chapters => 'Próximos 25 capítulos'; + @override + String get all_chapters => 'All chapters'; + @override String get next_episode => 'Próximo episódio'; @@ -1165,6 +1173,9 @@ class AppLocalizationsPt extends AppLocalizations { @override String get next_25_episodes => 'Próximos 25 episódios'; + @override + String get all_episodes => 'All episodes'; + @override String get cover_saved => 'Capa salva'; @@ -1439,6 +1450,11 @@ class AppLocalizationsPt extends AppLocalizations { @override String get load_own_subtitles => 'Carregar suas próprias legendas...'; + + @override + String extension_notes(Object notes) { + return 'Notes: $notes'; + } } /// The translations for Portuguese, as used in Brazil (`pt_BR`). @@ -2576,7 +2592,9 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { String get update_library => 'Atualizar biblioteca'; @override - String get updating_library => 'Atualizando biblioteca'; + String updating_library(Object cur, Object failed, Object max) { + return 'Atualizando biblioteca ($cur / $max) - Falha: $failed'; + } @override String get next_chapter => 'Próximo capítulo'; diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index eff605d0..cb130701 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -375,6 +375,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get save_as_cbz_archive => 'Сохранить как архив CBZ'; + @override + String get concurrent_downloads => 'Concurrent downloads'; + @override String get browse_subtitle => 'Источники, глобальный поиск'; @@ -1139,7 +1142,9 @@ class AppLocalizationsRu extends AppLocalizations { String get update_library => 'Обновить библиотеку'; @override - String get updating_library => 'Обновление библиотеки'; + String updating_library(Object cur, Object failed, Object max) { + return 'Обновление библиотеки ($cur / $max) - Не удалось: $failed'; + } @override String get next_chapter => 'Следующая глава'; @@ -1153,6 +1158,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get next_25_chapters => 'Следующие 25 глав'; + @override + String get all_chapters => 'All chapters'; + @override String get next_episode => 'Следующий эпизод'; @@ -1165,6 +1173,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get next_25_episodes => 'Следующие 25 эпизодов'; + @override + String get all_episodes => 'All episodes'; + @override String get cover_saved => 'Обложка сохранена'; @@ -1439,4 +1450,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get load_own_subtitles => 'Загрузить свои собственные субтитры...'; + + @override + String extension_notes(Object notes) { + return 'Notes: $notes'; + } } diff --git a/lib/l10n/generated/app_localizations_th.dart b/lib/l10n/generated/app_localizations_th.dart index 8149fae9..c0dafde7 100644 --- a/lib/l10n/generated/app_localizations_th.dart +++ b/lib/l10n/generated/app_localizations_th.dart @@ -375,6 +375,9 @@ class AppLocalizationsTh extends AppLocalizations { @override String get save_as_cbz_archive => 'จัดเก็บเป็น CBZ'; + @override + String get concurrent_downloads => 'Concurrent downloads'; + @override String get browse_subtitle => 'Sources, global search'; @@ -1139,7 +1142,9 @@ class AppLocalizationsTh extends AppLocalizations { String get update_library => 'อัพเดทชั้นหนังสือ'; @override - String get updating_library => 'กำลังอัพเดทชั้นหนังสือ'; + String updating_library(Object cur, Object failed, Object max) { + return 'กำลังอัพเดทชั้นหนังสือ ($cur / $max) - ล้มเหลว: $failed'; + } @override String get next_chapter => 'ตอนถัดไป'; @@ -1153,6 +1158,9 @@ class AppLocalizationsTh extends AppLocalizations { @override String get next_25_chapters => '25 ตอนถัดไป'; + @override + String get all_chapters => 'All chapters'; + @override String get next_episode => 'ตอนถัดไป'; @@ -1165,6 +1173,9 @@ class AppLocalizationsTh extends AppLocalizations { @override String get next_25_episodes => '25 ตอนถัดไป'; + @override + String get all_episodes => 'All episodes'; + @override String get cover_saved => 'จัดเก็บภาพปกแล้ว'; @@ -1439,4 +1450,9 @@ class AppLocalizationsTh extends AppLocalizations { @override String get load_own_subtitles => 'โหลดคำบรรยายของคุณเอง...'; + + @override + String extension_notes(Object notes) { + return 'Notes: $notes'; + } } diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart index d7f9bf9d..6a745c08 100644 --- a/lib/l10n/generated/app_localizations_tr.dart +++ b/lib/l10n/generated/app_localizations_tr.dart @@ -375,6 +375,9 @@ class AppLocalizationsTr extends AppLocalizations { @override String get save_as_cbz_archive => 'CBZ Arşivi Olarak Kaydet'; + @override + String get concurrent_downloads => 'Concurrent downloads'; + @override String get browse_subtitle => 'Kaynaklar, genel arama'; @@ -1139,7 +1142,9 @@ class AppLocalizationsTr extends AppLocalizations { String get update_library => 'Kütüphaneyi güncelle'; @override - String get updating_library => 'Kütüphaneyi güncelleme'; + String updating_library(Object cur, Object failed, Object max) { + return 'Kütüphaneyi güncelleme ($cur / $max) - Başarısız: $failed'; + } @override String get next_chapter => 'Sonraki bölüm'; @@ -1153,6 +1158,9 @@ class AppLocalizationsTr extends AppLocalizations { @override String get next_25_chapters => 'Sonraki 25 bölüm'; + @override + String get all_chapters => 'All chapters'; + @override String get next_episode => 'Sonraki Bölüm'; @@ -1165,6 +1173,9 @@ class AppLocalizationsTr extends AppLocalizations { @override String get next_25_episodes => 'Sonraki 25 Bölüm'; + @override + String get all_episodes => 'All episodes'; + @override String get cover_saved => 'Kapak kaydedildi'; @@ -1439,4 +1450,9 @@ class AppLocalizationsTr extends AppLocalizations { @override String get load_own_subtitles => 'Kendi altyazılarınızı yükleyin...'; + + @override + String extension_notes(Object notes) { + return 'Notes: $notes'; + } } diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart index 990cf5ca..5c0251ca 100644 --- a/lib/l10n/generated/app_localizations_zh.dart +++ b/lib/l10n/generated/app_localizations_zh.dart @@ -375,6 +375,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get save_as_cbz_archive => '保存为CBZ档案'; + @override + String get concurrent_downloads => 'Concurrent downloads'; + @override String get browse_subtitle => '来源,全球搜索'; @@ -1139,7 +1142,9 @@ class AppLocalizationsZh extends AppLocalizations { String get update_library => '更新库'; @override - String get updating_library => '正在更新库'; + String updating_library(Object cur, Object failed, Object max) { + return '正在更新库 ($cur / $max) - 失败: $failed'; + } @override String get next_chapter => '下一章'; @@ -1153,6 +1158,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get next_25_chapters => '下25章'; + @override + String get all_chapters => 'All chapters'; + @override String get next_episode => '下一集'; @@ -1165,6 +1173,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get next_25_episodes => '接下来的 25 集'; + @override + String get all_episodes => 'All episodes'; + @override String get cover_saved => '封面已保存'; @@ -1439,4 +1450,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get load_own_subtitles => '加载自定义字幕'; + + @override + String extension_notes(Object notes) { + return 'Notes: $notes'; + } } diff --git a/lib/models/settings.dart b/lib/models/settings.dart index 154d04c7..303d61a4 100644 --- a/lib/models/settings.dart +++ b/lib/models/settings.dart @@ -82,6 +82,8 @@ class Settings { bool? saveAsCBZArchive; + int? concurrentDownloads; + String? downloadLocation; List? filterScanlatorList; @@ -271,6 +273,7 @@ class Settings { this.pureBlackDarkMode = false, this.downloadOnlyOnWifi = false, this.saveAsCBZArchive = false, + this.concurrentDownloads = 2, this.downloadLocation = "", this.cropBorders = false, this.libraryLocalSource, @@ -404,6 +407,7 @@ class Settings { doubleTapAnimationSpeed = json['doubleTapAnimationSpeed']; downloadLocation = json['downloadLocation']; downloadOnlyOnWifi = json['downloadOnlyOnWifi']; + concurrentDownloads = json['concurrentDownloads']; filterScanlatorList = (json['filterScanlatorList'] as List?) ?.map((e) => FilterScanlator.fromJson(e)) @@ -604,6 +608,7 @@ class Settings { 'doubleTapAnimationSpeed': doubleTapAnimationSpeed, 'downloadLocation': downloadLocation, 'downloadOnlyOnWifi': downloadOnlyOnWifi, + 'concurrentDownloads': concurrentDownloads, 'filterScanlatorList': filterScanlatorList, 'flexColorSchemeBlendLevel': flexColorSchemeBlendLevel, 'flexSchemeColorIndex': flexSchemeColorIndex, diff --git a/lib/models/settings.g.dart b/lib/models/settings.g.dart index dac2ecbf..d8bb0fd9 100644 --- a/lib/models/settings.g.dart +++ b/lib/models/settings.g.dart @@ -167,424 +167,429 @@ const SettingsSchema = CollectionSchema( type: IsarType.byte, enumMap: _SettingscolorFilterBlendModeEnumValueMap, ), - r'cookiesList': PropertySchema( + r'concurrentDownloads': PropertySchema( id: 28, + name: r'concurrentDownloads', + type: IsarType.long, + ), + r'cookiesList': PropertySchema( + id: 29, name: r'cookiesList', type: IsarType.objectList, target: r'MCookie', ), r'cropBorders': PropertySchema( - id: 29, + id: 30, name: r'cropBorders', type: IsarType.bool, ), r'customColorFilter': PropertySchema( - id: 30, + id: 31, name: r'customColorFilter', type: IsarType.object, target: r'CustomColorFilter', ), r'dateFormat': PropertySchema( - id: 31, + id: 32, name: r'dateFormat', type: IsarType.string, ), r'defaultDoubleTapToSkipLength': PropertySchema( - id: 32, + id: 33, name: r'defaultDoubleTapToSkipLength', type: IsarType.long, ), r'defaultPlayBackSpeed': PropertySchema( - id: 33, + id: 34, name: r'defaultPlayBackSpeed', type: IsarType.double, ), r'defaultReaderMode': PropertySchema( - id: 34, + id: 35, name: r'defaultReaderMode', type: IsarType.byte, enumMap: _SettingsdefaultReaderModeEnumValueMap, ), r'defaultSkipIntroLength': PropertySchema( - id: 35, + id: 36, name: r'defaultSkipIntroLength', type: IsarType.long, ), r'defaultSubtitleLang': PropertySchema( - id: 36, + id: 37, name: r'defaultSubtitleLang', type: IsarType.object, target: r'L10nLocale', ), r'disableSectionType': PropertySchema( - id: 37, + id: 38, name: r'disableSectionType', type: IsarType.byte, enumMap: _SettingsdisableSectionTypeEnumValueMap, ), r'displayType': PropertySchema( - id: 38, + id: 39, name: r'displayType', type: IsarType.byte, enumMap: _SettingsdisplayTypeEnumValueMap, ), r'doubleTapAnimationSpeed': PropertySchema( - id: 39, + id: 40, name: r'doubleTapAnimationSpeed', type: IsarType.long, ), r'downloadLocation': PropertySchema( - id: 40, + id: 41, name: r'downloadLocation', type: IsarType.string, ), r'downloadOnlyOnWifi': PropertySchema( - id: 41, + id: 42, name: r'downloadOnlyOnWifi', type: IsarType.bool, ), r'enableAniSkip': PropertySchema( - id: 42, + id: 43, name: r'enableAniSkip', type: IsarType.bool, ), r'enableAutoSkip': PropertySchema( - id: 43, + id: 44, name: r'enableAutoSkip', type: IsarType.bool, ), r'enableCustomColorFilter': PropertySchema( - id: 44, + id: 45, name: r'enableCustomColorFilter', type: IsarType.bool, ), r'filterScanlatorList': PropertySchema( - id: 45, + id: 46, name: r'filterScanlatorList', type: IsarType.objectList, target: r'FilterScanlator', ), r'flexColorSchemeBlendLevel': PropertySchema( - id: 46, + id: 47, name: r'flexColorSchemeBlendLevel', type: IsarType.double, ), r'flexSchemeColorIndex': PropertySchema( - id: 47, + id: 48, name: r'flexSchemeColorIndex', type: IsarType.long, ), r'followSystemTheme': PropertySchema( - id: 48, + id: 49, name: r'followSystemTheme', type: IsarType.bool, ), r'fullScreenPlayer': PropertySchema( - id: 49, + id: 50, name: r'fullScreenPlayer', type: IsarType.bool, ), r'fullScreenReader': PropertySchema( - id: 50, + id: 51, name: r'fullScreenReader', type: IsarType.bool, ), r'hideItems': PropertySchema( - id: 51, + id: 52, name: r'hideItems', type: IsarType.stringList, ), r'incognitoMode': PropertySchema( - id: 52, + id: 53, name: r'incognitoMode', type: IsarType.bool, ), r'libraryDownloadedChapters': PropertySchema( - id: 53, + id: 54, name: r'libraryDownloadedChapters', type: IsarType.bool, ), r'libraryFilterAnimeBookMarkedType': PropertySchema( - id: 54, + id: 55, name: r'libraryFilterAnimeBookMarkedType', type: IsarType.long, ), r'libraryFilterAnimeDownloadType': PropertySchema( - id: 55, + id: 56, name: r'libraryFilterAnimeDownloadType', type: IsarType.long, ), r'libraryFilterAnimeStartedType': PropertySchema( - id: 56, + id: 57, name: r'libraryFilterAnimeStartedType', type: IsarType.long, ), r'libraryFilterAnimeUnreadType': PropertySchema( - id: 57, + id: 58, name: r'libraryFilterAnimeUnreadType', type: IsarType.long, ), r'libraryFilterMangasBookMarkedType': PropertySchema( - id: 58, + id: 59, name: r'libraryFilterMangasBookMarkedType', type: IsarType.long, ), r'libraryFilterMangasDownloadType': PropertySchema( - id: 59, + id: 60, name: r'libraryFilterMangasDownloadType', type: IsarType.long, ), r'libraryFilterMangasStartedType': PropertySchema( - id: 60, + id: 61, name: r'libraryFilterMangasStartedType', type: IsarType.long, ), r'libraryFilterMangasUnreadType': PropertySchema( - id: 61, + id: 62, name: r'libraryFilterMangasUnreadType', type: IsarType.long, ), r'libraryFilterNovelBookMarkedType': PropertySchema( - id: 62, + id: 63, name: r'libraryFilterNovelBookMarkedType', type: IsarType.long, ), r'libraryFilterNovelDownloadType': PropertySchema( - id: 63, + id: 64, name: r'libraryFilterNovelDownloadType', type: IsarType.long, ), r'libraryFilterNovelStartedType': PropertySchema( - id: 64, + id: 65, name: r'libraryFilterNovelStartedType', type: IsarType.long, ), r'libraryFilterNovelUnreadType': PropertySchema( - id: 65, + id: 66, name: r'libraryFilterNovelUnreadType', type: IsarType.long, ), r'libraryLocalSource': PropertySchema( - id: 66, + id: 67, name: r'libraryLocalSource', type: IsarType.bool, ), r'libraryShowCategoryTabs': PropertySchema( - id: 67, + id: 68, name: r'libraryShowCategoryTabs', type: IsarType.bool, ), r'libraryShowContinueReadingButton': PropertySchema( - id: 68, + id: 69, name: r'libraryShowContinueReadingButton', type: IsarType.bool, ), r'libraryShowLanguage': PropertySchema( - id: 69, + id: 70, name: r'libraryShowLanguage', type: IsarType.bool, ), r'libraryShowNumbersOfItems': PropertySchema( - id: 70, + id: 71, name: r'libraryShowNumbersOfItems', type: IsarType.bool, ), r'locale': PropertySchema( - id: 71, + id: 72, name: r'locale', type: IsarType.object, target: r'L10nLocale', ), r'mangaExtensionsRepo': PropertySchema( - id: 72, + id: 73, name: r'mangaExtensionsRepo', type: IsarType.objectList, target: r'Repo', ), r'mangaGridSize': PropertySchema( - id: 73, + id: 74, name: r'mangaGridSize', type: IsarType.long, ), r'mangaHomeDisplayType': PropertySchema( - id: 74, + id: 75, name: r'mangaHomeDisplayType', type: IsarType.byte, enumMap: _SettingsmangaHomeDisplayTypeEnumValueMap, ), r'markEpisodeAsSeenType': PropertySchema( - id: 75, + id: 76, name: r'markEpisodeAsSeenType', type: IsarType.long, ), r'navigationOrder': PropertySchema( - id: 76, + id: 77, name: r'navigationOrder', type: IsarType.stringList, ), r'novelDisplayType': PropertySchema( - id: 77, + id: 78, name: r'novelDisplayType', type: IsarType.byte, enumMap: _SettingsnovelDisplayTypeEnumValueMap, ), r'novelExtensionsRepo': PropertySchema( - id: 78, + id: 79, name: r'novelExtensionsRepo', type: IsarType.objectList, target: r'Repo', ), r'novelFontSize': PropertySchema( - id: 79, + id: 80, name: r'novelFontSize', type: IsarType.long, ), r'novelGridSize': PropertySchema( - id: 80, + id: 81, name: r'novelGridSize', type: IsarType.long, ), r'novelLibraryDownloadedChapters': PropertySchema( - id: 81, + id: 82, name: r'novelLibraryDownloadedChapters', type: IsarType.bool, ), r'novelLibraryLocalSource': PropertySchema( - id: 82, + id: 83, name: r'novelLibraryLocalSource', type: IsarType.bool, ), r'novelLibraryShowCategoryTabs': PropertySchema( - id: 83, + id: 84, name: r'novelLibraryShowCategoryTabs', type: IsarType.bool, ), r'novelLibraryShowContinueReadingButton': PropertySchema( - id: 84, + id: 85, name: r'novelLibraryShowContinueReadingButton', type: IsarType.bool, ), r'novelLibraryShowLanguage': PropertySchema( - id: 85, + id: 86, name: r'novelLibraryShowLanguage', type: IsarType.bool, ), r'novelLibraryShowNumbersOfItems': PropertySchema( - id: 86, + id: 87, name: r'novelLibraryShowNumbersOfItems', type: IsarType.bool, ), r'novelTextAlign': PropertySchema( - id: 87, + id: 88, name: r'novelTextAlign', type: IsarType.byte, enumMap: _SettingsnovelTextAlignEnumValueMap, ), r'onlyIncludePinnedSources': PropertySchema( - id: 88, + id: 89, name: r'onlyIncludePinnedSources', type: IsarType.bool, ), r'pagePreloadAmount': PropertySchema( - id: 89, + id: 90, name: r'pagePreloadAmount', type: IsarType.long, ), r'personalPageModeList': PropertySchema( - id: 90, + id: 91, name: r'personalPageModeList', type: IsarType.objectList, target: r'PersonalPageMode', ), r'personalReaderModeList': PropertySchema( - id: 91, + id: 92, name: r'personalReaderModeList', type: IsarType.objectList, target: r'PersonalReaderMode', ), r'playerSubtitleSettings': PropertySchema( - id: 92, + id: 93, name: r'playerSubtitleSettings', type: IsarType.object, target: r'PlayerSubtitleSettings', ), r'pureBlackDarkMode': PropertySchema( - id: 93, + id: 94, name: r'pureBlackDarkMode', type: IsarType.bool, ), r'relativeTimesTamps': PropertySchema( - id: 94, + id: 95, name: r'relativeTimesTamps', type: IsarType.long, ), r'saveAsCBZArchive': PropertySchema( - id: 95, + id: 96, name: r'saveAsCBZArchive', type: IsarType.bool, ), r'scaleType': PropertySchema( - id: 96, + id: 97, name: r'scaleType', type: IsarType.byte, enumMap: _SettingsscaleTypeEnumValueMap, ), r'showPagesNumber': PropertySchema( - id: 97, + id: 98, name: r'showPagesNumber', type: IsarType.bool, ), r'sortChapterList': PropertySchema( - id: 98, + id: 99, name: r'sortChapterList', type: IsarType.objectList, target: r'SortChapter', ), r'sortLibraryAnime': PropertySchema( - id: 99, + id: 100, name: r'sortLibraryAnime', type: IsarType.object, target: r'SortLibraryManga', ), r'sortLibraryManga': PropertySchema( - id: 100, + id: 101, name: r'sortLibraryManga', type: IsarType.object, target: r'SortLibraryManga', ), r'sortLibraryNovel': PropertySchema( - id: 101, + id: 102, name: r'sortLibraryNovel', type: IsarType.object, target: r'SortLibraryManga', ), r'startDatebackup': PropertySchema( - id: 102, + id: 103, name: r'startDatebackup', type: IsarType.long, ), r'themeIsDark': PropertySchema( - id: 103, + id: 104, name: r'themeIsDark', type: IsarType.bool, ), r'updateProgressAfterReading': PropertySchema( - id: 104, + id: 105, name: r'updateProgressAfterReading', type: IsarType.bool, ), r'useLibass': PropertySchema( - id: 105, + id: 106, name: r'useLibass', type: IsarType.bool, ), r'usePageTapZones': PropertySchema( - id: 106, + id: 107, name: r'usePageTapZones', type: IsarType.bool, ), r'userAgent': PropertySchema( - id: 107, + id: 108, name: r'userAgent', type: IsarType.string, ) @@ -1019,156 +1024,157 @@ void _settingsSerialize( writer.writeBool(offsets[25], object.checkForExtensionUpdates); writer.writeBool(offsets[26], object.clearChapterCacheOnAppLaunch); writer.writeByte(offsets[27], object.colorFilterBlendMode.index); + writer.writeLong(offsets[28], object.concurrentDownloads); writer.writeObjectList( - offsets[28], + offsets[29], allOffsets, MCookieSchema.serialize, object.cookiesList, ); - writer.writeBool(offsets[29], object.cropBorders); + writer.writeBool(offsets[30], object.cropBorders); writer.writeObject( - offsets[30], + offsets[31], allOffsets, CustomColorFilterSchema.serialize, object.customColorFilter, ); - writer.writeString(offsets[31], object.dateFormat); - writer.writeLong(offsets[32], object.defaultDoubleTapToSkipLength); - writer.writeDouble(offsets[33], object.defaultPlayBackSpeed); - writer.writeByte(offsets[34], object.defaultReaderMode.index); - writer.writeLong(offsets[35], object.defaultSkipIntroLength); + writer.writeString(offsets[32], object.dateFormat); + writer.writeLong(offsets[33], object.defaultDoubleTapToSkipLength); + writer.writeDouble(offsets[34], object.defaultPlayBackSpeed); + writer.writeByte(offsets[35], object.defaultReaderMode.index); + writer.writeLong(offsets[36], object.defaultSkipIntroLength); writer.writeObject( - offsets[36], + offsets[37], allOffsets, L10nLocaleSchema.serialize, object.defaultSubtitleLang, ); - writer.writeByte(offsets[37], object.disableSectionType.index); - writer.writeByte(offsets[38], object.displayType.index); - writer.writeLong(offsets[39], object.doubleTapAnimationSpeed); - writer.writeString(offsets[40], object.downloadLocation); - writer.writeBool(offsets[41], object.downloadOnlyOnWifi); - writer.writeBool(offsets[42], object.enableAniSkip); - writer.writeBool(offsets[43], object.enableAutoSkip); - writer.writeBool(offsets[44], object.enableCustomColorFilter); + writer.writeByte(offsets[38], object.disableSectionType.index); + writer.writeByte(offsets[39], object.displayType.index); + writer.writeLong(offsets[40], object.doubleTapAnimationSpeed); + writer.writeString(offsets[41], object.downloadLocation); + writer.writeBool(offsets[42], object.downloadOnlyOnWifi); + writer.writeBool(offsets[43], object.enableAniSkip); + writer.writeBool(offsets[44], object.enableAutoSkip); + writer.writeBool(offsets[45], object.enableCustomColorFilter); writer.writeObjectList( - offsets[45], + offsets[46], allOffsets, FilterScanlatorSchema.serialize, object.filterScanlatorList, ); - writer.writeDouble(offsets[46], object.flexColorSchemeBlendLevel); - writer.writeLong(offsets[47], object.flexSchemeColorIndex); - writer.writeBool(offsets[48], object.followSystemTheme); - writer.writeBool(offsets[49], object.fullScreenPlayer); - writer.writeBool(offsets[50], object.fullScreenReader); - writer.writeStringList(offsets[51], object.hideItems); - writer.writeBool(offsets[52], object.incognitoMode); - writer.writeBool(offsets[53], object.libraryDownloadedChapters); - writer.writeLong(offsets[54], object.libraryFilterAnimeBookMarkedType); - writer.writeLong(offsets[55], object.libraryFilterAnimeDownloadType); - writer.writeLong(offsets[56], object.libraryFilterAnimeStartedType); - writer.writeLong(offsets[57], object.libraryFilterAnimeUnreadType); - writer.writeLong(offsets[58], object.libraryFilterMangasBookMarkedType); - writer.writeLong(offsets[59], object.libraryFilterMangasDownloadType); - writer.writeLong(offsets[60], object.libraryFilterMangasStartedType); - writer.writeLong(offsets[61], object.libraryFilterMangasUnreadType); - writer.writeLong(offsets[62], object.libraryFilterNovelBookMarkedType); - writer.writeLong(offsets[63], object.libraryFilterNovelDownloadType); - writer.writeLong(offsets[64], object.libraryFilterNovelStartedType); - writer.writeLong(offsets[65], object.libraryFilterNovelUnreadType); - writer.writeBool(offsets[66], object.libraryLocalSource); - writer.writeBool(offsets[67], object.libraryShowCategoryTabs); - writer.writeBool(offsets[68], object.libraryShowContinueReadingButton); - writer.writeBool(offsets[69], object.libraryShowLanguage); - writer.writeBool(offsets[70], object.libraryShowNumbersOfItems); + writer.writeDouble(offsets[47], object.flexColorSchemeBlendLevel); + writer.writeLong(offsets[48], object.flexSchemeColorIndex); + writer.writeBool(offsets[49], object.followSystemTheme); + writer.writeBool(offsets[50], object.fullScreenPlayer); + writer.writeBool(offsets[51], object.fullScreenReader); + writer.writeStringList(offsets[52], object.hideItems); + writer.writeBool(offsets[53], object.incognitoMode); + writer.writeBool(offsets[54], object.libraryDownloadedChapters); + writer.writeLong(offsets[55], object.libraryFilterAnimeBookMarkedType); + writer.writeLong(offsets[56], object.libraryFilterAnimeDownloadType); + writer.writeLong(offsets[57], object.libraryFilterAnimeStartedType); + writer.writeLong(offsets[58], object.libraryFilterAnimeUnreadType); + writer.writeLong(offsets[59], object.libraryFilterMangasBookMarkedType); + writer.writeLong(offsets[60], object.libraryFilterMangasDownloadType); + writer.writeLong(offsets[61], object.libraryFilterMangasStartedType); + writer.writeLong(offsets[62], object.libraryFilterMangasUnreadType); + writer.writeLong(offsets[63], object.libraryFilterNovelBookMarkedType); + writer.writeLong(offsets[64], object.libraryFilterNovelDownloadType); + writer.writeLong(offsets[65], object.libraryFilterNovelStartedType); + writer.writeLong(offsets[66], object.libraryFilterNovelUnreadType); + writer.writeBool(offsets[67], object.libraryLocalSource); + writer.writeBool(offsets[68], object.libraryShowCategoryTabs); + writer.writeBool(offsets[69], object.libraryShowContinueReadingButton); + writer.writeBool(offsets[70], object.libraryShowLanguage); + writer.writeBool(offsets[71], object.libraryShowNumbersOfItems); writer.writeObject( - offsets[71], + offsets[72], allOffsets, L10nLocaleSchema.serialize, object.locale, ); writer.writeObjectList( - offsets[72], + offsets[73], allOffsets, RepoSchema.serialize, object.mangaExtensionsRepo, ); - writer.writeLong(offsets[73], object.mangaGridSize); - writer.writeByte(offsets[74], object.mangaHomeDisplayType.index); - writer.writeLong(offsets[75], object.markEpisodeAsSeenType); - writer.writeStringList(offsets[76], object.navigationOrder); - writer.writeByte(offsets[77], object.novelDisplayType.index); + writer.writeLong(offsets[74], object.mangaGridSize); + writer.writeByte(offsets[75], object.mangaHomeDisplayType.index); + writer.writeLong(offsets[76], object.markEpisodeAsSeenType); + writer.writeStringList(offsets[77], object.navigationOrder); + writer.writeByte(offsets[78], object.novelDisplayType.index); writer.writeObjectList( - offsets[78], + offsets[79], allOffsets, RepoSchema.serialize, object.novelExtensionsRepo, ); - writer.writeLong(offsets[79], object.novelFontSize); - writer.writeLong(offsets[80], object.novelGridSize); - writer.writeBool(offsets[81], object.novelLibraryDownloadedChapters); - writer.writeBool(offsets[82], object.novelLibraryLocalSource); - writer.writeBool(offsets[83], object.novelLibraryShowCategoryTabs); - writer.writeBool(offsets[84], object.novelLibraryShowContinueReadingButton); - writer.writeBool(offsets[85], object.novelLibraryShowLanguage); - writer.writeBool(offsets[86], object.novelLibraryShowNumbersOfItems); - writer.writeByte(offsets[87], object.novelTextAlign.index); - writer.writeBool(offsets[88], object.onlyIncludePinnedSources); - writer.writeLong(offsets[89], object.pagePreloadAmount); + writer.writeLong(offsets[80], object.novelFontSize); + writer.writeLong(offsets[81], object.novelGridSize); + writer.writeBool(offsets[82], object.novelLibraryDownloadedChapters); + writer.writeBool(offsets[83], object.novelLibraryLocalSource); + writer.writeBool(offsets[84], object.novelLibraryShowCategoryTabs); + writer.writeBool(offsets[85], object.novelLibraryShowContinueReadingButton); + writer.writeBool(offsets[86], object.novelLibraryShowLanguage); + writer.writeBool(offsets[87], object.novelLibraryShowNumbersOfItems); + writer.writeByte(offsets[88], object.novelTextAlign.index); + writer.writeBool(offsets[89], object.onlyIncludePinnedSources); + writer.writeLong(offsets[90], object.pagePreloadAmount); writer.writeObjectList( - offsets[90], + offsets[91], allOffsets, PersonalPageModeSchema.serialize, object.personalPageModeList, ); writer.writeObjectList( - offsets[91], + offsets[92], allOffsets, PersonalReaderModeSchema.serialize, object.personalReaderModeList, ); writer.writeObject( - offsets[92], + offsets[93], allOffsets, PlayerSubtitleSettingsSchema.serialize, object.playerSubtitleSettings, ); - writer.writeBool(offsets[93], object.pureBlackDarkMode); - writer.writeLong(offsets[94], object.relativeTimesTamps); - writer.writeBool(offsets[95], object.saveAsCBZArchive); - writer.writeByte(offsets[96], object.scaleType.index); - writer.writeBool(offsets[97], object.showPagesNumber); + writer.writeBool(offsets[94], object.pureBlackDarkMode); + writer.writeLong(offsets[95], object.relativeTimesTamps); + writer.writeBool(offsets[96], object.saveAsCBZArchive); + writer.writeByte(offsets[97], object.scaleType.index); + writer.writeBool(offsets[98], object.showPagesNumber); writer.writeObjectList( - offsets[98], + offsets[99], allOffsets, SortChapterSchema.serialize, object.sortChapterList, ); writer.writeObject( - offsets[99], + offsets[100], allOffsets, SortLibraryMangaSchema.serialize, object.sortLibraryAnime, ); writer.writeObject( - offsets[100], + offsets[101], allOffsets, SortLibraryMangaSchema.serialize, object.sortLibraryManga, ); writer.writeObject( - offsets[101], + offsets[102], allOffsets, SortLibraryMangaSchema.serialize, object.sortLibraryNovel, ); - writer.writeLong(offsets[102], object.startDatebackup); - writer.writeBool(offsets[103], object.themeIsDark); - writer.writeBool(offsets[104], object.updateProgressAfterReading); - writer.writeBool(offsets[105], object.useLibass); - writer.writeBool(offsets[106], object.usePageTapZones); - writer.writeString(offsets[107], object.userAgent); + writer.writeLong(offsets[103], object.startDatebackup); + writer.writeBool(offsets[104], object.themeIsDark); + writer.writeBool(offsets[105], object.updateProgressAfterReading); + writer.writeBool(offsets[106], object.useLibass); + writer.writeBool(offsets[107], object.usePageTapZones); + writer.writeString(offsets[108], object.userAgent); } Settings _settingsDeserialize( @@ -1235,147 +1241,148 @@ Settings _settingsDeserialize( colorFilterBlendMode: _SettingscolorFilterBlendModeValueEnumMap[ reader.readByteOrNull(offsets[27])] ?? ColorFilterBlendMode.none, + concurrentDownloads: reader.readLongOrNull(offsets[28]), cookiesList: reader.readObjectList( - offsets[28], + offsets[29], MCookieSchema.deserialize, allOffsets, MCookie(), ), - cropBorders: reader.readBoolOrNull(offsets[29]), + cropBorders: reader.readBoolOrNull(offsets[30]), customColorFilter: reader.readObjectOrNull( - offsets[30], + offsets[31], CustomColorFilterSchema.deserialize, allOffsets, ), - dateFormat: reader.readStringOrNull(offsets[31]), - defaultDoubleTapToSkipLength: reader.readLongOrNull(offsets[32]), - defaultPlayBackSpeed: reader.readDoubleOrNull(offsets[33]), + dateFormat: reader.readStringOrNull(offsets[32]), + defaultDoubleTapToSkipLength: reader.readLongOrNull(offsets[33]), + defaultPlayBackSpeed: reader.readDoubleOrNull(offsets[34]), defaultReaderMode: _SettingsdefaultReaderModeValueEnumMap[ - reader.readByteOrNull(offsets[34])] ?? + reader.readByteOrNull(offsets[35])] ?? ReaderMode.vertical, - defaultSkipIntroLength: reader.readLongOrNull(offsets[35]), + defaultSkipIntroLength: reader.readLongOrNull(offsets[36]), disableSectionType: _SettingsdisableSectionTypeValueEnumMap[ - reader.readByteOrNull(offsets[37])] ?? + reader.readByteOrNull(offsets[38])] ?? SectionType.all, displayType: - _SettingsdisplayTypeValueEnumMap[reader.readByteOrNull(offsets[38])] ?? + _SettingsdisplayTypeValueEnumMap[reader.readByteOrNull(offsets[39])] ?? DisplayType.compactGrid, - doubleTapAnimationSpeed: reader.readLongOrNull(offsets[39]), - downloadLocation: reader.readStringOrNull(offsets[40]), - downloadOnlyOnWifi: reader.readBoolOrNull(offsets[41]), - enableAniSkip: reader.readBoolOrNull(offsets[42]), - enableAutoSkip: reader.readBoolOrNull(offsets[43]), - enableCustomColorFilter: reader.readBoolOrNull(offsets[44]), - flexColorSchemeBlendLevel: reader.readDoubleOrNull(offsets[46]), - flexSchemeColorIndex: reader.readLongOrNull(offsets[47]), - followSystemTheme: reader.readBoolOrNull(offsets[48]), - fullScreenPlayer: reader.readBoolOrNull(offsets[49]), - fullScreenReader: reader.readBoolOrNull(offsets[50]), - hideItems: reader.readStringList(offsets[51]), + doubleTapAnimationSpeed: reader.readLongOrNull(offsets[40]), + downloadLocation: reader.readStringOrNull(offsets[41]), + downloadOnlyOnWifi: reader.readBoolOrNull(offsets[42]), + enableAniSkip: reader.readBoolOrNull(offsets[43]), + enableAutoSkip: reader.readBoolOrNull(offsets[44]), + enableCustomColorFilter: reader.readBoolOrNull(offsets[45]), + flexColorSchemeBlendLevel: reader.readDoubleOrNull(offsets[47]), + flexSchemeColorIndex: reader.readLongOrNull(offsets[48]), + followSystemTheme: reader.readBoolOrNull(offsets[49]), + fullScreenPlayer: reader.readBoolOrNull(offsets[50]), + fullScreenReader: reader.readBoolOrNull(offsets[51]), + hideItems: reader.readStringList(offsets[52]), id: id, - incognitoMode: reader.readBoolOrNull(offsets[52]), - libraryDownloadedChapters: reader.readBoolOrNull(offsets[53]), - libraryFilterAnimeBookMarkedType: reader.readLongOrNull(offsets[54]), - libraryFilterAnimeDownloadType: reader.readLongOrNull(offsets[55]), - libraryFilterAnimeStartedType: reader.readLongOrNull(offsets[56]), - libraryFilterAnimeUnreadType: reader.readLongOrNull(offsets[57]), - libraryFilterMangasBookMarkedType: reader.readLongOrNull(offsets[58]), - libraryFilterMangasDownloadType: reader.readLongOrNull(offsets[59]), - libraryFilterMangasStartedType: reader.readLongOrNull(offsets[60]), - libraryFilterMangasUnreadType: reader.readLongOrNull(offsets[61]), - libraryFilterNovelBookMarkedType: reader.readLongOrNull(offsets[62]), - libraryFilterNovelDownloadType: reader.readLongOrNull(offsets[63]), - libraryFilterNovelStartedType: reader.readLongOrNull(offsets[64]), - libraryFilterNovelUnreadType: reader.readLongOrNull(offsets[65]), - libraryLocalSource: reader.readBoolOrNull(offsets[66]), - libraryShowCategoryTabs: reader.readBoolOrNull(offsets[67]), - libraryShowContinueReadingButton: reader.readBoolOrNull(offsets[68]), - libraryShowLanguage: reader.readBoolOrNull(offsets[69]), - libraryShowNumbersOfItems: reader.readBoolOrNull(offsets[70]), + incognitoMode: reader.readBoolOrNull(offsets[53]), + libraryDownloadedChapters: reader.readBoolOrNull(offsets[54]), + libraryFilterAnimeBookMarkedType: reader.readLongOrNull(offsets[55]), + libraryFilterAnimeDownloadType: reader.readLongOrNull(offsets[56]), + libraryFilterAnimeStartedType: reader.readLongOrNull(offsets[57]), + libraryFilterAnimeUnreadType: reader.readLongOrNull(offsets[58]), + libraryFilterMangasBookMarkedType: reader.readLongOrNull(offsets[59]), + libraryFilterMangasDownloadType: reader.readLongOrNull(offsets[60]), + libraryFilterMangasStartedType: reader.readLongOrNull(offsets[61]), + libraryFilterMangasUnreadType: reader.readLongOrNull(offsets[62]), + libraryFilterNovelBookMarkedType: reader.readLongOrNull(offsets[63]), + libraryFilterNovelDownloadType: reader.readLongOrNull(offsets[64]), + libraryFilterNovelStartedType: reader.readLongOrNull(offsets[65]), + libraryFilterNovelUnreadType: reader.readLongOrNull(offsets[66]), + libraryLocalSource: reader.readBoolOrNull(offsets[67]), + libraryShowCategoryTabs: reader.readBoolOrNull(offsets[68]), + libraryShowContinueReadingButton: reader.readBoolOrNull(offsets[69]), + libraryShowLanguage: reader.readBoolOrNull(offsets[70]), + libraryShowNumbersOfItems: reader.readBoolOrNull(offsets[71]), mangaExtensionsRepo: reader.readObjectList( - offsets[72], + offsets[73], RepoSchema.deserialize, allOffsets, Repo(), ), - mangaGridSize: reader.readLongOrNull(offsets[73]), + mangaGridSize: reader.readLongOrNull(offsets[74]), mangaHomeDisplayType: _SettingsmangaHomeDisplayTypeValueEnumMap[ - reader.readByteOrNull(offsets[74])] ?? + reader.readByteOrNull(offsets[75])] ?? DisplayType.comfortableGrid, - markEpisodeAsSeenType: reader.readLongOrNull(offsets[75]), - navigationOrder: reader.readStringList(offsets[76]), + markEpisodeAsSeenType: reader.readLongOrNull(offsets[76]), + navigationOrder: reader.readStringList(offsets[77]), novelDisplayType: _SettingsnovelDisplayTypeValueEnumMap[ - reader.readByteOrNull(offsets[77])] ?? + reader.readByteOrNull(offsets[78])] ?? DisplayType.comfortableGrid, novelExtensionsRepo: reader.readObjectList( - offsets[78], + offsets[79], RepoSchema.deserialize, allOffsets, Repo(), ), - novelFontSize: reader.readLongOrNull(offsets[79]), - novelLibraryDownloadedChapters: reader.readBoolOrNull(offsets[81]), - novelLibraryLocalSource: reader.readBoolOrNull(offsets[82]), - novelLibraryShowCategoryTabs: reader.readBoolOrNull(offsets[83]), - novelLibraryShowContinueReadingButton: reader.readBoolOrNull(offsets[84]), - novelLibraryShowLanguage: reader.readBoolOrNull(offsets[85]), - novelLibraryShowNumbersOfItems: reader.readBoolOrNull(offsets[86]), + novelFontSize: reader.readLongOrNull(offsets[80]), + novelLibraryDownloadedChapters: reader.readBoolOrNull(offsets[82]), + novelLibraryLocalSource: reader.readBoolOrNull(offsets[83]), + novelLibraryShowCategoryTabs: reader.readBoolOrNull(offsets[84]), + novelLibraryShowContinueReadingButton: reader.readBoolOrNull(offsets[85]), + novelLibraryShowLanguage: reader.readBoolOrNull(offsets[86]), + novelLibraryShowNumbersOfItems: reader.readBoolOrNull(offsets[87]), novelTextAlign: _SettingsnovelTextAlignValueEnumMap[ - reader.readByteOrNull(offsets[87])] ?? + reader.readByteOrNull(offsets[88])] ?? NovelTextAlign.left, - onlyIncludePinnedSources: reader.readBoolOrNull(offsets[88]), - pagePreloadAmount: reader.readLongOrNull(offsets[89]), + onlyIncludePinnedSources: reader.readBoolOrNull(offsets[89]), + pagePreloadAmount: reader.readLongOrNull(offsets[90]), personalPageModeList: reader.readObjectList( - offsets[90], + offsets[91], PersonalPageModeSchema.deserialize, allOffsets, PersonalPageMode(), ), personalReaderModeList: reader.readObjectList( - offsets[91], + offsets[92], PersonalReaderModeSchema.deserialize, allOffsets, PersonalReaderMode(), ), playerSubtitleSettings: reader.readObjectOrNull( - offsets[92], + offsets[93], PlayerSubtitleSettingsSchema.deserialize, allOffsets, ), - pureBlackDarkMode: reader.readBoolOrNull(offsets[93]), - relativeTimesTamps: reader.readLongOrNull(offsets[94]), - saveAsCBZArchive: reader.readBoolOrNull(offsets[95]), + pureBlackDarkMode: reader.readBoolOrNull(offsets[94]), + relativeTimesTamps: reader.readLongOrNull(offsets[95]), + saveAsCBZArchive: reader.readBoolOrNull(offsets[96]), scaleType: - _SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offsets[96])] ?? + _SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offsets[97])] ?? ScaleType.fitScreen, - showPagesNumber: reader.readBoolOrNull(offsets[97]), + showPagesNumber: reader.readBoolOrNull(offsets[98]), sortChapterList: reader.readObjectList( - offsets[98], + offsets[99], SortChapterSchema.deserialize, allOffsets, SortChapter(), ), sortLibraryAnime: reader.readObjectOrNull( - offsets[99], - SortLibraryMangaSchema.deserialize, - allOffsets, - ), - sortLibraryManga: reader.readObjectOrNull( offsets[100], SortLibraryMangaSchema.deserialize, allOffsets, ), - sortLibraryNovel: reader.readObjectOrNull( + sortLibraryManga: reader.readObjectOrNull( offsets[101], SortLibraryMangaSchema.deserialize, allOffsets, ), - startDatebackup: reader.readLongOrNull(offsets[102]), - themeIsDark: reader.readBoolOrNull(offsets[103]), - updateProgressAfterReading: reader.readBoolOrNull(offsets[104]), - useLibass: reader.readBoolOrNull(offsets[105]), - usePageTapZones: reader.readBoolOrNull(offsets[106]), - userAgent: reader.readStringOrNull(offsets[107]), + sortLibraryNovel: reader.readObjectOrNull( + offsets[102], + SortLibraryMangaSchema.deserialize, + allOffsets, + ), + startDatebackup: reader.readLongOrNull(offsets[103]), + themeIsDark: reader.readBoolOrNull(offsets[104]), + updateProgressAfterReading: reader.readBoolOrNull(offsets[105]), + useLibass: reader.readBoolOrNull(offsets[106]), + usePageTapZones: reader.readBoolOrNull(offsets[107]), + userAgent: reader.readStringOrNull(offsets[108]), ); object.chapterFilterBookmarkedList = reader.readObjectList( @@ -1391,22 +1398,22 @@ Settings _settingsDeserialize( ChapterFilterUnread(), ); object.defaultSubtitleLang = reader.readObjectOrNull( - offsets[36], + offsets[37], L10nLocaleSchema.deserialize, allOffsets, ); object.filterScanlatorList = reader.readObjectList( - offsets[45], + offsets[46], FilterScanlatorSchema.deserialize, allOffsets, FilterScanlator(), ); object.locale = reader.readObjectOrNull( - offsets[71], + offsets[72], L10nLocaleSchema.deserialize, allOffsets, ); - object.novelGridSize = reader.readLongOrNull(offsets[80]); + object.novelGridSize = reader.readLongOrNull(offsets[81]); return object; } @@ -1515,51 +1522,51 @@ P _settingsDeserializeProp

( reader.readByteOrNull(offset)] ?? ColorFilterBlendMode.none) as P; case 28: + return (reader.readLongOrNull(offset)) as P; + case 29: return (reader.readObjectList( offset, MCookieSchema.deserialize, allOffsets, MCookie(), )) as P; - case 29: - return (reader.readBoolOrNull(offset)) as P; case 30: + return (reader.readBoolOrNull(offset)) as P; + case 31: return (reader.readObjectOrNull( offset, CustomColorFilterSchema.deserialize, allOffsets, )) as P; - case 31: - return (reader.readStringOrNull(offset)) as P; case 32: - return (reader.readLongOrNull(offset)) as P; + return (reader.readStringOrNull(offset)) as P; case 33: - return (reader.readDoubleOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 34: + return (reader.readDoubleOrNull(offset)) as P; + case 35: return (_SettingsdefaultReaderModeValueEnumMap[ reader.readByteOrNull(offset)] ?? ReaderMode.vertical) as P; - case 35: - return (reader.readLongOrNull(offset)) as P; case 36: + return (reader.readLongOrNull(offset)) as P; + case 37: return (reader.readObjectOrNull( offset, L10nLocaleSchema.deserialize, allOffsets, )) as P; - case 37: + case 38: return (_SettingsdisableSectionTypeValueEnumMap[ reader.readByteOrNull(offset)] ?? SectionType.all) as P; - case 38: + case 39: return (_SettingsdisplayTypeValueEnumMap[reader.readByteOrNull(offset)] ?? DisplayType.compactGrid) as P; - case 39: - return (reader.readLongOrNull(offset)) as P; case 40: - return (reader.readStringOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 41: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readStringOrNull(offset)) as P; case 42: return (reader.readBoolOrNull(offset)) as P; case 43: @@ -1567,30 +1574,30 @@ P _settingsDeserializeProp

( case 44: return (reader.readBoolOrNull(offset)) as P; case 45: + return (reader.readBoolOrNull(offset)) as P; + case 46: return (reader.readObjectList( offset, FilterScanlatorSchema.deserialize, allOffsets, FilterScanlator(), )) as P; - case 46: - return (reader.readDoubleOrNull(offset)) as P; case 47: - return (reader.readLongOrNull(offset)) as P; + return (reader.readDoubleOrNull(offset)) as P; case 48: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 49: return (reader.readBoolOrNull(offset)) as P; case 50: return (reader.readBoolOrNull(offset)) as P; case 51: - return (reader.readStringList(offset)) as P; - case 52: return (reader.readBoolOrNull(offset)) as P; + case 52: + return (reader.readStringList(offset)) as P; case 53: return (reader.readBoolOrNull(offset)) as P; case 54: - return (reader.readLongOrNull(offset)) as P; + return (reader.readBoolOrNull(offset)) as P; case 55: return (reader.readLongOrNull(offset)) as P; case 56: @@ -1614,7 +1621,7 @@ P _settingsDeserializeProp

( case 65: return (reader.readLongOrNull(offset)) as P; case 66: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 67: return (reader.readBoolOrNull(offset)) as P; case 68: @@ -1624,45 +1631,45 @@ P _settingsDeserializeProp

( case 70: return (reader.readBoolOrNull(offset)) as P; case 71: + return (reader.readBoolOrNull(offset)) as P; + case 72: return (reader.readObjectOrNull( offset, L10nLocaleSchema.deserialize, allOffsets, )) as P; - case 72: + case 73: return (reader.readObjectList( offset, RepoSchema.deserialize, allOffsets, Repo(), )) as P; - case 73: - return (reader.readLongOrNull(offset)) as P; case 74: + return (reader.readLongOrNull(offset)) as P; + case 75: return (_SettingsmangaHomeDisplayTypeValueEnumMap[ reader.readByteOrNull(offset)] ?? DisplayType.comfortableGrid) as P; - case 75: - return (reader.readLongOrNull(offset)) as P; case 76: - return (reader.readStringList(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 77: + return (reader.readStringList(offset)) as P; + case 78: return (_SettingsnovelDisplayTypeValueEnumMap[ reader.readByteOrNull(offset)] ?? DisplayType.comfortableGrid) as P; - case 78: + case 79: return (reader.readObjectList( offset, RepoSchema.deserialize, allOffsets, Repo(), )) as P; - case 79: - return (reader.readLongOrNull(offset)) as P; case 80: return (reader.readLongOrNull(offset)) as P; case 81: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 82: return (reader.readBoolOrNull(offset)) as P; case 83: @@ -1674,57 +1681,53 @@ P _settingsDeserializeProp

( case 86: return (reader.readBoolOrNull(offset)) as P; case 87: + return (reader.readBoolOrNull(offset)) as P; + case 88: return (_SettingsnovelTextAlignValueEnumMap[ reader.readByteOrNull(offset)] ?? NovelTextAlign.left) as P; - case 88: - return (reader.readBoolOrNull(offset)) as P; case 89: - return (reader.readLongOrNull(offset)) as P; + return (reader.readBoolOrNull(offset)) as P; case 90: + return (reader.readLongOrNull(offset)) as P; + case 91: return (reader.readObjectList( offset, PersonalPageModeSchema.deserialize, allOffsets, PersonalPageMode(), )) as P; - case 91: + case 92: return (reader.readObjectList( offset, PersonalReaderModeSchema.deserialize, allOffsets, PersonalReaderMode(), )) as P; - case 92: + case 93: return (reader.readObjectOrNull( offset, PlayerSubtitleSettingsSchema.deserialize, allOffsets, )) as P; - case 93: - return (reader.readBoolOrNull(offset)) as P; case 94: - return (reader.readLongOrNull(offset)) as P; - case 95: return (reader.readBoolOrNull(offset)) as P; + case 95: + return (reader.readLongOrNull(offset)) as P; case 96: + return (reader.readBoolOrNull(offset)) as P; + case 97: return (_SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offset)] ?? ScaleType.fitScreen) as P; - case 97: - return (reader.readBoolOrNull(offset)) as P; case 98: + return (reader.readBoolOrNull(offset)) as P; + case 99: return (reader.readObjectList( offset, SortChapterSchema.deserialize, allOffsets, SortChapter(), )) as P; - case 99: - return (reader.readObjectOrNull( - offset, - SortLibraryMangaSchema.deserialize, - allOffsets, - )) as P; case 100: return (reader.readObjectOrNull( offset, @@ -1738,9 +1741,13 @@ P _settingsDeserializeProp

( allOffsets, )) as P; case 102: - return (reader.readLongOrNull(offset)) as P; + return (reader.readObjectOrNull( + offset, + SortLibraryMangaSchema.deserialize, + allOffsets, + )) as P; case 103: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 104: return (reader.readBoolOrNull(offset)) as P; case 105: @@ -1748,6 +1755,8 @@ P _settingsDeserializeProp

( case 106: return (reader.readBoolOrNull(offset)) as P; case 107: + return (reader.readBoolOrNull(offset)) as P; + case 108: return (reader.readStringOrNull(offset)) as P; default: throw IsarError('Unknown property with id $propertyId'); @@ -4100,6 +4109,80 @@ extension SettingsQueryFilter }); } + QueryBuilder + concurrentDownloadsIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'concurrentDownloads', + )); + }); + } + + QueryBuilder + concurrentDownloadsIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'concurrentDownloads', + )); + }); + } + + QueryBuilder + concurrentDownloadsEqualTo(int? value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'concurrentDownloads', + value: value, + )); + }); + } + + QueryBuilder + concurrentDownloadsGreaterThan( + int? value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'concurrentDownloads', + value: value, + )); + }); + } + + QueryBuilder + concurrentDownloadsLessThan( + int? value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'concurrentDownloads', + value: value, + )); + }); + } + + QueryBuilder + concurrentDownloadsBetween( + int? lower, + int? upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'concurrentDownloads', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + QueryBuilder cookiesListIsNull() { return QueryBuilder.apply(this, (query) { return query.addFilterCondition(const FilterCondition.isNull( @@ -9509,6 +9592,19 @@ extension SettingsQuerySortBy on QueryBuilder { }); } + QueryBuilder sortByConcurrentDownloads() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'concurrentDownloads', Sort.asc); + }); + } + + QueryBuilder + sortByConcurrentDownloadsDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'concurrentDownloads', Sort.desc); + }); + } + QueryBuilder sortByCropBorders() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'cropBorders', Sort.asc); @@ -10613,6 +10709,19 @@ extension SettingsQuerySortThenBy }); } + QueryBuilder thenByConcurrentDownloads() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'concurrentDownloads', Sort.asc); + }); + } + + QueryBuilder + thenByConcurrentDownloadsDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'concurrentDownloads', Sort.desc); + }); + } + QueryBuilder thenByCropBorders() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'cropBorders', Sort.asc); @@ -11607,6 +11716,12 @@ extension SettingsQueryWhereDistinct }); } + QueryBuilder distinctByConcurrentDownloads() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'concurrentDownloads'); + }); + } + QueryBuilder distinctByCropBorders() { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'cropBorders'); @@ -12237,6 +12352,12 @@ extension SettingsQueryProperty }); } + QueryBuilder concurrentDownloadsProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'concurrentDownloads'); + }); + } + QueryBuilder?, QQueryOperations> cookiesListProperty() { return QueryBuilder.apply(this, (query) { diff --git a/lib/models/source.dart b/lib/models/source.dart index b965a21b..a873261b 100644 --- a/lib/models/source.dart +++ b/lib/models/source.dart @@ -65,6 +65,8 @@ class Source { @enumerated SourceCodeLanguage sourceCodeLanguage = SourceCodeLanguage.dart; + String? notes; + Repo? repo; Source({ @@ -95,6 +97,7 @@ class Source { this.additionalParams = "", this.isLocal = false, this.isObsolete = false, + this.notes = '', this.repo, }); @@ -128,6 +131,7 @@ class Source { isLocal = json['isLocal']; sourceCodeLanguage = SourceCodeLanguage.values[json['sourceCodeLanguage'] ?? 0]; + notes = json['notes'] ?? ""; repo = json['repo'] != null ? Repo.fromJson(json['repo']) : null; } @@ -160,6 +164,7 @@ class Source { 'sourceCodeLanguage': sourceCodeLanguage.index, 'isObsolete': isObsolete, 'isLocal': isLocal, + 'notes': notes, 'repo': repo?.toJson(), }; diff --git a/lib/models/source.g.dart b/lib/models/source.g.dart index 403049f0..c6635c3c 100644 --- a/lib/models/source.g.dart +++ b/lib/models/source.g.dart @@ -128,40 +128,45 @@ const SourceSchema = CollectionSchema( name: r'name', type: IsarType.string, ), - r'repo': PropertySchema( + r'notes': PropertySchema( id: 22, + name: r'notes', + type: IsarType.string, + ), + r'repo': PropertySchema( + id: 23, name: r'repo', type: IsarType.object, target: r'Repo', ), r'sourceCode': PropertySchema( - id: 23, + id: 24, name: r'sourceCode', type: IsarType.string, ), r'sourceCodeLanguage': PropertySchema( - id: 24, + id: 25, name: r'sourceCodeLanguage', type: IsarType.byte, enumMap: _SourcesourceCodeLanguageEnumValueMap, ), r'sourceCodeUrl': PropertySchema( - id: 25, + id: 26, name: r'sourceCodeUrl', type: IsarType.string, ), r'typeSource': PropertySchema( - id: 26, + id: 27, name: r'typeSource', type: IsarType.string, ), r'version': PropertySchema( - id: 27, + id: 28, name: r'version', type: IsarType.string, ), r'versionLast': PropertySchema( - id: 28, + id: 29, name: r'versionLast', type: IsarType.string, ) @@ -246,6 +251,12 @@ int _sourceEstimateSize( bytesCount += 3 + value.length * 3; } } + { + final value = object.notes; + if (value != null) { + bytesCount += 3 + value.length * 3; + } + } { final value = object.repo; if (value != null) { @@ -314,18 +325,19 @@ void _sourceSerialize( writer.writeString(offsets[19], object.lang); writer.writeBool(offsets[20], object.lastUsed); writer.writeString(offsets[21], object.name); + writer.writeString(offsets[22], object.notes); writer.writeObject( - offsets[22], + offsets[23], allOffsets, RepoSchema.serialize, object.repo, ); - writer.writeString(offsets[23], object.sourceCode); - writer.writeByte(offsets[24], object.sourceCodeLanguage.index); - writer.writeString(offsets[25], object.sourceCodeUrl); - writer.writeString(offsets[26], object.typeSource); - writer.writeString(offsets[27], object.version); - writer.writeString(offsets[28], object.versionLast); + writer.writeString(offsets[24], object.sourceCode); + writer.writeByte(offsets[25], object.sourceCodeLanguage.index); + writer.writeString(offsets[26], object.sourceCodeUrl); + writer.writeString(offsets[27], object.typeSource); + writer.writeString(offsets[28], object.version); + writer.writeString(offsets[29], object.versionLast); } Source _sourceDeserialize( @@ -358,19 +370,20 @@ Source _sourceDeserialize( lang: reader.readStringOrNull(offsets[19]), lastUsed: reader.readBoolOrNull(offsets[20]), name: reader.readStringOrNull(offsets[21]), + notes: reader.readStringOrNull(offsets[22]), repo: reader.readObjectOrNull( - offsets[22], + offsets[23], RepoSchema.deserialize, allOffsets, ), - sourceCode: reader.readStringOrNull(offsets[23]), - sourceCodeUrl: reader.readStringOrNull(offsets[25]), - typeSource: reader.readStringOrNull(offsets[26]), - version: reader.readStringOrNull(offsets[27]), - versionLast: reader.readStringOrNull(offsets[28]), + sourceCode: reader.readStringOrNull(offsets[24]), + sourceCodeUrl: reader.readStringOrNull(offsets[26]), + typeSource: reader.readStringOrNull(offsets[27]), + version: reader.readStringOrNull(offsets[28]), + versionLast: reader.readStringOrNull(offsets[29]), ); object.sourceCodeLanguage = _SourcesourceCodeLanguageValueEnumMap[ - reader.readByteOrNull(offsets[24])] ?? + reader.readByteOrNull(offsets[25])] ?? SourceCodeLanguage.dart; return object; } @@ -428,25 +441,27 @@ P _sourceDeserializeProp

( case 21: return (reader.readStringOrNull(offset)) as P; case 22: + return (reader.readStringOrNull(offset)) as P; + case 23: return (reader.readObjectOrNull( offset, RepoSchema.deserialize, allOffsets, )) as P; - case 23: - return (reader.readStringOrNull(offset)) as P; case 24: + return (reader.readStringOrNull(offset)) as P; + case 25: return (_SourcesourceCodeLanguageValueEnumMap[ reader.readByteOrNull(offset)] ?? SourceCodeLanguage.dart) as P; - case 25: - return (reader.readStringOrNull(offset)) as P; case 26: return (reader.readStringOrNull(offset)) as P; case 27: return (reader.readStringOrNull(offset)) as P; case 28: return (reader.readStringOrNull(offset)) as P; + case 29: + return (reader.readStringOrNull(offset)) as P; default: throw IsarError('Unknown property with id $propertyId'); } @@ -2418,6 +2433,152 @@ extension SourceQueryFilter on QueryBuilder { }); } + QueryBuilder notesIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'notes', + )); + }); + } + + QueryBuilder notesIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'notes', + )); + }); + } + + QueryBuilder notesEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'notes', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder notesGreaterThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'notes', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder notesLessThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'notes', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder notesBetween( + String? lower, + String? upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'notes', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder notesStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'notes', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder notesEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'notes', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder notesContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'notes', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder notesMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'notes', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder notesIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'notes', + value: '', + )); + }); + } + + QueryBuilder notesIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'notes', + value: '', + )); + }); + } + QueryBuilder repoIsNull() { return QueryBuilder.apply(this, (query) { return query.addFilterCondition(const FilterCondition.isNull( @@ -3497,6 +3658,18 @@ extension SourceQuerySortBy on QueryBuilder { }); } + QueryBuilder sortByNotes() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'notes', Sort.asc); + }); + } + + QueryBuilder sortByNotesDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'notes', Sort.desc); + }); + } + QueryBuilder sortBySourceCode() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'sourceCode', Sort.asc); @@ -3847,6 +4020,18 @@ extension SourceQuerySortThenBy on QueryBuilder { }); } + QueryBuilder thenByNotes() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'notes', Sort.asc); + }); + } + + QueryBuilder thenByNotesDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'notes', Sort.desc); + }); + } + QueryBuilder thenBySourceCode() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'sourceCode', Sort.asc); @@ -4065,6 +4250,13 @@ extension SourceQueryWhereDistinct on QueryBuilder { }); } + QueryBuilder distinctByNotes( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'notes', caseSensitive: caseSensitive); + }); + } + QueryBuilder distinctBySourceCode( {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { @@ -4247,6 +4439,12 @@ extension SourceQueryProperty on QueryBuilder { }); } + QueryBuilder notesProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'notes'); + }); + } + QueryBuilder repoProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'repo'); diff --git a/lib/modules/browse/extension/edit_code.dart b/lib/modules/browse/extension/edit_code.dart index 4b6ef767..9d919f78 100644 --- a/lib/modules/browse/extension/edit_code.dart +++ b/lib/modules/browse/extension/edit_code.dart @@ -380,6 +380,7 @@ class _CodeEditorPageState extends ConsumerState { )).map((e) => e.toJson()).toList(); } else if (_serviceIndex == 6) { result = (await service.getHtmlContent( + "test", _url, )); } else { diff --git a/lib/modules/browse/extension/widgets/create_extension.dart b/lib/modules/browse/extension/widgets/create_extension.dart index 0526c495..c8b805c2 100644 --- a/lib/modules/browse/extension/widgets/create_extension.dart +++ b/lib/modules/browse/extension/widgets/create_extension.dart @@ -22,6 +22,7 @@ class _CreateExtensionState extends State { String _baseUrl = ""; String _apiUrl = ""; String _iconUrl = ""; + String _notes = ""; int _sourceTypeIndex = 0; int _itemTypeIndex = 0; int _languageIndex = 0; @@ -111,6 +112,11 @@ class _CreateExtensionState extends State { _iconUrl = v; }); }), + _textEditing("notes", context, "ex: this extension requires login", (v) { + setState(() { + _notes = v; + }); + }), Padding( padding: const EdgeInsets.symmetric(horizontal: 17), child: Row( @@ -217,6 +223,7 @@ class _CreateExtensionState extends State { isActive: true, version: "0.0.1", isNsfw: false, + notes: _notes, )..sourceCodeLanguage = _sourceCodeLanguage; source = source @@ -331,7 +338,7 @@ class TestSource extends MProvider { // For novel html content @override - Future getHtmlContent(String url) async { + Future getHtmlContent(String name, String url) async { // TODO: implement } @@ -378,7 +385,8 @@ const mangayomiSources = [{ "typeSource": "${source.typeSource}", "itemType": ${source.itemType.index}, "version": "${source.version}", - "pkgPath": "" + "pkgPath": "", + "notes": "" }]; class DefaultExtension extends MProvider { @@ -401,7 +409,7 @@ class DefaultExtension extends MProvider { throw new Error("getDetail not implemented"); } // For novel html content - async getHtmlContent(url) { + async getHtmlContent(name, url) { throw new Error("getHtmlContent not implemented"); } // Clean html up for reader diff --git a/lib/modules/history/history_screen.dart b/lib/modules/history/history_screen.dart index 2bd57fa0..596af6be 100644 --- a/lib/modules/history/history_screen.dart +++ b/lib/modules/history/history_screen.dart @@ -2,6 +2,7 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; +import 'package:mangayomi/l10n/generated/app_localizations.dart'; import 'package:mangayomi/modules/widgets/custom_sliver_grouped_list_view.dart'; import 'package:isar/isar.dart'; @@ -137,45 +138,7 @@ class _HistoryScreenState extends ConsumerState ), const SizedBox(width: 15), TextButton( - onPressed: () { - List histories = - isar.historys - .filter() - .idIsNotNull() - .chapter( - (q) => q.manga( - (q) => q.itemTypeEqualTo( - _tabBarController.index == 0 && - !hideItems.contains( - "/MangaLibrary", - ) - ? ItemType.manga - : _tabBarController.index == - 1 - - (hideItems.contains( - "/MangaLibrary", - ) - ? 1 - : 0) && - !hideItems.contains( - "/AnimeLibrary", - ) - ? ItemType.anime - : ItemType.novel, - ), - ), - ) - .findAllSync() - .toList(); - isar.writeTxnSync(() { - for (var history in histories) { - isar.historys.deleteSync(history.id!); - } - }); - if (mounted) { - Navigator.pop(context); - } - }, + onPressed: () => clearHistory(hideItems), child: Text(l10n.ok), ), ], @@ -227,6 +190,38 @@ class _HistoryScreenState extends ConsumerState ), ); } + + void clearHistory(List hideItems) { + List histories = + isar.historys + .filter() + .idIsNotNull() + .chapter( + (q) => q.manga( + (q) => q.itemTypeEqualTo(getCurrentItemType(hideItems)), + ), + ) + .findAllSync() + .toList(); + isar.writeTxnSync(() { + for (var history in histories) { + isar.historys.deleteSync(history.id!); + } + }); + if (mounted) { + Navigator.pop(context); + } + } + + ItemType getCurrentItemType(List hideItems) { + return _tabBarController.index == 0 && !hideItems.contains("/MangaLibrary") + ? ItemType.manga + : _tabBarController.index == + 1 - (hideItems.contains("/MangaLibrary") ? 1 : 0) && + !hideItems.contains("/AnimeLibrary") + ? ItemType.anime + : ItemType.novel; + } } class HistoryTab extends ConsumerStatefulWidget { @@ -243,23 +238,14 @@ class _HistoryTabState extends ConsumerState { Widget build(BuildContext context) { final l10n = l10nLocalizations(context)!; final history = ref.watch( - getAllHistoryStreamProvider(itemType: widget.itemType), + getAllHistoryStreamProvider( + itemType: widget.itemType, + search: widget.query, + ), ); 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(); - + data: (entries) { if (entries.isNotEmpty) { return CustomScrollView( slivers: [ @@ -302,8 +288,8 @@ class _HistoryTabState extends ConsumerState { elevation: 0, shadowColor: Colors.transparent, ), - onPressed: () { - chapter.pushToReaderView(context); + onPressed: () async { + await chapter.pushToReaderView(context); }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12), @@ -330,28 +316,7 @@ class _HistoryTabState extends ConsumerState { }, 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: toImgUrl( - manga.customCoverFromTracker ?? - manga.imageUrl ?? - "", - ), - width: 60, - height: 90, - fit: BoxFit.cover, - ), + child: getCoverImage(manga), ), ), ), @@ -418,81 +383,12 @@ class _HistoryTabState extends ConsumerState { ), ), 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 manga.chapters - .load(); - final chapters = - manga.chapters; - await isar.writeTxn( - () async { - await isar.historys - .delete( - element.id!, - ); - for (var chapter - in chapters) { - await isar - .chapters - .delete( - chapter.id!, - ); - } - await isar.mangas - .delete( - manga.id!, - ); - }, - ); - await ref - .read( - synchingProvider( - syncId: 1, - ).notifier, - ) - .addChangedPartAsync( - ActionType - .removeItem, - manga.id, - "{}", - true, - ); - if (context.mounted) { - Navigator.pop( - context, - ); - } - }, - child: Text(l10n.remove), - ), - ], - ), - ], - ); - }, - ); - }, + onPressed: + () => openDeleteDialog( + l10n, + manga, + element.id, + ), icon: Icon( Icons.delete_outline, size: 25, @@ -529,4 +425,72 @@ class _HistoryTabState extends ConsumerState { ), ); } + + Widget getCoverImage(Manga manga) { + return manga.customCoverImage != null + ? Image.memory(manga.customCoverImage as Uint8List) + : cachedCompressedNetworkImage( + headers: ref.watch( + headersProvider(source: manga.source!, lang: manga.lang!), + ), + imageUrl: toImgUrl( + manga.customCoverFromTracker ?? manga.imageUrl ?? "", + ), + width: 60, + height: 90, + fit: BoxFit.cover, + ); + } + + void openDeleteDialog(AppLocalizations l10n, Manga manga, int? deleteId) { + 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 => deleteManga(context, manga, deleteId), + child: Text(l10n.remove), + ), + ], + ), + ], + ); + }, + ); + } + + Future deleteManga( + BuildContext context, + Manga manga, + int? deleteId, + ) async { + await manga.chapters.load(); + final chapters = manga.chapters; + await isar.writeTxn(() async { + await isar.historys.delete(deleteId!); + for (var chapter in chapters) { + await isar.chapters.delete(chapter.id!); + } + await isar.mangas.delete(manga.id!); + }); + await ref + .read(synchingProvider(syncId: 1).notifier) + .addChangedPartAsync(ActionType.removeItem, manga.id, "{}", true); + if (context.mounted) { + Navigator.pop(context); + } + } } diff --git a/lib/modules/history/providers/isar_providers.dart b/lib/modules/history/providers/isar_providers.dart index 7b93a8f7..93433365 100644 --- a/lib/modules/history/providers/isar_providers.dart +++ b/lib/modules/history/providers/isar_providers.dart @@ -12,12 +12,17 @@ part 'isar_providers.g.dart'; Stream> getAllHistoryStream( Ref ref, { required ItemType itemType, + String search = "", }) async* { yield* isar.historys .filter() .idIsNotNull() .and() .chapter((q) => q.manga((q) => q.itemTypeEqualTo(itemType))) + .and() + .chapter( + (q) => q.manga((q) => q.nameContains(search, caseSensitive: false)), + ) .watch(fireImmediately: true); } @@ -25,11 +30,16 @@ Stream> getAllHistoryStream( Stream> getAllUpdateStream( Ref ref, { required ItemType itemType, + String search = "", }) async* { yield* isar.updates .filter() .idIsNotNull() .and() .chapter((q) => q.manga((q) => q.itemTypeEqualTo(itemType))) + .and() + .chapter( + (q) => q.manga((q) => q.nameContains(search, caseSensitive: false)), + ) .watch(fireImmediately: true); } diff --git a/lib/modules/history/providers/isar_providers.g.dart b/lib/modules/history/providers/isar_providers.g.dart index f7f4e360..41a4934f 100644 --- a/lib/modules/history/providers/isar_providers.g.dart +++ b/lib/modules/history/providers/isar_providers.g.dart @@ -7,7 +7,7 @@ part of 'isar_providers.dart'; // ************************************************************************** String _$getAllHistoryStreamHash() => - r'42048cb03035be55b52fc501fb2309cdb2acfcb8'; + r'1ce5bd0046fbbec46e91b7a486523945699d95f3'; /// Copied from Dart SDK class _SystemHash { @@ -42,9 +42,11 @@ class GetAllHistoryStreamFamily extends Family>> { /// See also [getAllHistoryStream]. GetAllHistoryStreamProvider call({ required ItemType itemType, + String search = "", }) { return GetAllHistoryStreamProvider( itemType: itemType, + search: search, ); } @@ -54,6 +56,7 @@ class GetAllHistoryStreamFamily extends Family>> { ) { return call( itemType: provider.itemType, + search: provider.search, ); } @@ -78,10 +81,12 @@ class GetAllHistoryStreamProvider /// See also [getAllHistoryStream]. GetAllHistoryStreamProvider({ required ItemType itemType, + String search = "", }) : this._internal( (ref) => getAllHistoryStream( ref as GetAllHistoryStreamRef, itemType: itemType, + search: search, ), from: getAllHistoryStreamProvider, name: r'getAllHistoryStreamProvider', @@ -93,6 +98,7 @@ class GetAllHistoryStreamProvider allTransitiveDependencies: GetAllHistoryStreamFamily._allTransitiveDependencies, itemType: itemType, + search: search, ); GetAllHistoryStreamProvider._internal( @@ -103,9 +109,11 @@ class GetAllHistoryStreamProvider required super.debugGetCreateSourceHash, required super.from, required this.itemType, + required this.search, }) : super.internal(); final ItemType itemType; + final String search; @override Override overrideWith( @@ -121,6 +129,7 @@ class GetAllHistoryStreamProvider allTransitiveDependencies: null, debugGetCreateSourceHash: null, itemType: itemType, + search: search, ), ); } @@ -132,13 +141,16 @@ class GetAllHistoryStreamProvider @override bool operator ==(Object other) { - return other is GetAllHistoryStreamProvider && other.itemType == itemType; + return other is GetAllHistoryStreamProvider && + other.itemType == itemType && + other.search == search; } @override int get hashCode { var hash = _SystemHash.combine(0, runtimeType.hashCode); hash = _SystemHash.combine(hash, itemType.hashCode); + hash = _SystemHash.combine(hash, search.hashCode); return _SystemHash.finish(hash); } @@ -149,6 +161,9 @@ class GetAllHistoryStreamProvider mixin GetAllHistoryStreamRef on AutoDisposeStreamProviderRef> { /// The parameter `itemType` of this provider. ItemType get itemType; + + /// The parameter `search` of this provider. + String get search; } class _GetAllHistoryStreamProviderElement @@ -158,10 +173,12 @@ class _GetAllHistoryStreamProviderElement @override ItemType get itemType => (origin as GetAllHistoryStreamProvider).itemType; + @override + String get search => (origin as GetAllHistoryStreamProvider).search; } String _$getAllUpdateStreamHash() => - r'6a20f8feba3010c2ab7a80560f7a7f6cf10c7366'; + r'43369b20d702d12aeae627fcd04ceb61caf0dc74'; /// See also [getAllUpdateStream]. @ProviderFor(getAllUpdateStream) @@ -175,9 +192,11 @@ class GetAllUpdateStreamFamily extends Family>> { /// See also [getAllUpdateStream]. GetAllUpdateStreamProvider call({ required ItemType itemType, + String search = "", }) { return GetAllUpdateStreamProvider( itemType: itemType, + search: search, ); } @@ -187,6 +206,7 @@ class GetAllUpdateStreamFamily extends Family>> { ) { return call( itemType: provider.itemType, + search: provider.search, ); } @@ -211,10 +231,12 @@ class GetAllUpdateStreamProvider /// See also [getAllUpdateStream]. GetAllUpdateStreamProvider({ required ItemType itemType, + String search = "", }) : this._internal( (ref) => getAllUpdateStream( ref as GetAllUpdateStreamRef, itemType: itemType, + search: search, ), from: getAllUpdateStreamProvider, name: r'getAllUpdateStreamProvider', @@ -226,6 +248,7 @@ class GetAllUpdateStreamProvider allTransitiveDependencies: GetAllUpdateStreamFamily._allTransitiveDependencies, itemType: itemType, + search: search, ); GetAllUpdateStreamProvider._internal( @@ -236,9 +259,11 @@ class GetAllUpdateStreamProvider required super.debugGetCreateSourceHash, required super.from, required this.itemType, + required this.search, }) : super.internal(); final ItemType itemType; + final String search; @override Override overrideWith( @@ -254,6 +279,7 @@ class GetAllUpdateStreamProvider allTransitiveDependencies: null, debugGetCreateSourceHash: null, itemType: itemType, + search: search, ), ); } @@ -265,13 +291,16 @@ class GetAllUpdateStreamProvider @override bool operator ==(Object other) { - return other is GetAllUpdateStreamProvider && other.itemType == itemType; + return other is GetAllUpdateStreamProvider && + other.itemType == itemType && + other.search == search; } @override int get hashCode { var hash = _SystemHash.combine(0, runtimeType.hashCode); hash = _SystemHash.combine(hash, itemType.hashCode); + hash = _SystemHash.combine(hash, search.hashCode); return _SystemHash.finish(hash); } @@ -282,6 +311,9 @@ class GetAllUpdateStreamProvider mixin GetAllUpdateStreamRef on AutoDisposeStreamProviderRef> { /// The parameter `itemType` of this provider. ItemType get itemType; + + /// The parameter `search` of this provider. + String get search; } class _GetAllUpdateStreamProviderElement @@ -291,6 +323,8 @@ class _GetAllUpdateStreamProviderElement @override ItemType get itemType => (origin as GetAllUpdateStreamProvider).itemType; + @override + String get search => (origin as GetAllUpdateStreamProvider).search; } // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/modules/library/library_screen.dart b/lib/modules/library/library_screen.dart index b25b43b7..e4d5046a 100644 --- a/lib/modules/library/library_screen.dart +++ b/lib/modules/library/library_screen.dart @@ -22,6 +22,7 @@ import 'package:mangayomi/modules/library/providers/add_torrent.dart'; import 'package:mangayomi/modules/library/providers/local_archive.dart'; import 'package:mangayomi/modules/manga/detail/providers/update_manga_detail_providers.dart'; import 'package:mangayomi/modules/more/categories/providers/isar_providers.dart'; +import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_state_provider.dart'; import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart'; import 'package:mangayomi/modules/widgets/custom_draggable_tabbar.dart'; import 'package:mangayomi/modules/widgets/manga_image_card_widget.dart'; @@ -72,20 +73,37 @@ class _LibraryScreenState extends ConsumerState } Future _updateLibrary(List mangaList) async { + bool isDark = ref.read(themeModeStateProvider); botToast( - context.l10n.updating_library, + context.l10n.updating_library("0", "0", "0"), fontSize: 13, - second: 1600, + second: 30, alignY: !context.isTablet ? 0.85 : 1, + themeDark: isDark, ); int numbers = 0; + int failed = 0; for (var manga in mangaList) { try { await ref.read( updateMangaDetailProvider(mangaId: manga.id, isInit: false).future, ); - } catch (_) {} + } catch (_) { + failed++; + } numbers++; + if (context.mounted) { + botToast( + context.l10n.updating_library(numbers, failed, mangaList.length), + fontSize: 13, + second: 10, + alignY: !context.isTablet ? 0.85 : 1, + animationDuration: 0, + dismissDirections: [DismissDirection.none], + onlyOne: false, + themeDark: isDark, + ); + } } await Future.doWhile(() async { await Future.delayed(const Duration(seconds: 1)); diff --git a/lib/modules/manga/detail/manga_detail_view.dart b/lib/modules/manga/detail/manga_detail_view.dart index 26c7053c..473e426c 100644 --- a/lib/modules/manga/detail/manga_detail_view.dart +++ b/lib/modules/manga/detail/manga_detail_view.dart @@ -160,6 +160,38 @@ class _MangaDetailViewState extends ConsumerState ); } + List _getFilteredAndSortedChapters() { + final filterScanlator = ref.read( + scanlatorsFilterStateProvider(widget.manga!), + ); + final filterUnread = ref.read( + chapterFilterUnreadStateProvider(mangaId: widget.manga!.id!), + ); + final filterBookmarked = ref.read( + chapterFilterBookmarkedStateProvider(mangaId: widget.manga!.id!), + ); + final filterDownloaded = ref.read( + chapterFilterDownloadedStateProvider(mangaId: widget.manga!.id!), + ); + final sortChapter = + ref.read(sortChapterStateProvider(mangaId: widget.manga!.id!)).index + as int; + final chapters = + isar.chapters + .filter() + .idIsNotNull() + .mangaIdEqualTo(widget.manga!.id!) + .findAllSync(); + return _filterAndSortChapter( + data: chapters, + filterUnread: filterUnread, + filterBookmarked: filterBookmarked, + filterDownloaded: filterDownloaded, + sortChapter: sortChapter, + filterScanlator: filterScanlator.$2, + ); + } + List _filterAndSortChapter({ required List data, required int filterUnread, @@ -443,15 +475,18 @@ class _MangaDetailViewState extends ConsumerState : context.l10n.unwatched, ), ), + PopupMenuItem( + value: 5, + child: Text( + widget.itemType != ItemType.anime + ? context.l10n.all_chapters + : context.l10n.all_episodes, + ), + ), ]; }, onSelected: (value) { - final chapters = - isar.chapters - .filter() - .idIsNotNull() - .mangaIdEqualTo(widget.manga!.id!) - .findAllSync(); + final chapters = _getFilteredAndSortedChapters(); if (value == 0 || value == 1 || value == 2 || @@ -470,8 +505,11 @@ class _MangaDetailViewState extends ConsumerState .findFirstSync(); if (entry == null || !entry.isDownload!) { ref.watch( - downloadChapterProvider(chapter: chapter), + addDownloadToQueueProvider( + chapter: chapter, + ), ); + ref.watch(processDownloadsProvider()); } } else { final length = switch (value) { @@ -495,22 +533,29 @@ class _MangaDetailViewState extends ConsumerState .findFirstSync(); if (entry == null || !entry.isDownload!) { ref.watch( - downloadChapterProvider( + addDownloadToQueueProvider( chapter: chapter, ), ); } } } + ref.watch(processDownloadsProvider()); } } else if (value == 4) { - final unreadChapters = - isar.chapters - .filter() - .idIsNotNull() - .mangaIdEqualTo(widget.manga!.id!) - .isReadEqualTo(false) - .findAllSync(); + final List unreadChapters = + _getFilteredAndSortedChapters() + .where( + (element) => + !(element.isRead ?? false), + ) + .toList(); + isar.chapters + .filter() + .idIsNotNull() + .mangaIdEqualTo(widget.manga!.id!) + .isReadEqualTo(false) + .findAllSync(); for (var chapter in unreadChapters) { final entry = isar.downloads @@ -519,10 +564,31 @@ class _MangaDetailViewState extends ConsumerState .findFirstSync(); if (entry == null || !entry.isDownload!) { ref.watch( - downloadChapterProvider(chapter: chapter), + addDownloadToQueueProvider( + chapter: chapter, + ), ); } } + ref.watch(processDownloadsProvider()); + } else if (value == 5) { + final List allChapters = + _getFilteredAndSortedChapters(); + for (var chapter in allChapters) { + final entry = + isar.downloads + .filter() + .idEqualTo(chapter.id) + .findFirstSync(); + if (entry == null || !entry.isDownload!) { + ref.watch( + addDownloadToQueueProvider( + chapter: chapter, + ), + ); + } + } + ref.watch(processDownloadsProvider()); } }, ), @@ -971,7 +1037,9 @@ class _MangaDetailViewState extends ConsumerState if (entries.isEmpty || !entries.first.isDownload!) { ref.watch( - downloadChapterProvider(chapter: chapter), + addDownloadToQueueProvider( + chapter: chapter, + ), ); } } @@ -1513,16 +1581,26 @@ class _MangaDetailViewState extends ConsumerState return; } if (value == 0) { - final genre = widget.manga!.genre![i]; + final genre = + widget.manga!.genre![i]; switch (widget.manga!.itemType) { case ItemType.manga: - context.pushReplacement('/MangaLibrary', extra: genre); + context.pushReplacement( + '/MangaLibrary', + extra: genre, + ); break; case ItemType.anime: - context.pushReplacement('/AnimeLibrary', extra: genre); + context.pushReplacement( + '/AnimeLibrary', + extra: genre, + ); break; case ItemType.novel: - context.pushReplacement('/NovelLibrary', extra: genre); + context.pushReplacement( + '/NovelLibrary', + extra: genre, + ); break; } } else { diff --git a/lib/modules/manga/detail/providers/state_providers.dart b/lib/modules/manga/detail/providers/state_providers.dart index 46bdd54a..64c05e28 100644 --- a/lib/modules/manga/detail/providers/state_providers.dart +++ b/lib/modules/manga/detail/providers/state_providers.dart @@ -364,7 +364,7 @@ class ChapterSetDownloadState extends _$ChapterSetDownloadState { final entries = isar.downloads.filter().idEqualTo(chapter.id).findAllSync(); if (entries.isEmpty || !entries.first.isDownload!) { - ref.watch(downloadChapterProvider(chapter: chapter)); + ref.watch(addDownloadToQueueProvider(chapter: chapter)); } } }); diff --git a/lib/modules/manga/detail/providers/state_providers.g.dart b/lib/modules/manga/detail/providers/state_providers.g.dart index b831d018..6dd8d95a 100644 --- a/lib/modules/manga/detail/providers/state_providers.g.dart +++ b/lib/modules/manga/detail/providers/state_providers.g.dart @@ -1110,7 +1110,7 @@ class _ChapterSetIsReadStateProviderElement } String _$chapterSetDownloadStateHash() => - r'321f00669a4644016076dcf5e007355d696d26e3'; + r'2f35d274b76e28376b0089b2f6ee6d9d7ebcbeec'; abstract class _$ChapterSetDownloadState extends BuildlessAutoDisposeNotifier { diff --git a/lib/modules/manga/detail/providers/track_state_providers.g.dart b/lib/modules/manga/detail/providers/track_state_providers.g.dart index b8dfabf0..4021f109 100644 --- a/lib/modules/manga/detail/providers/track_state_providers.g.dart +++ b/lib/modules/manga/detail/providers/track_state_providers.g.dart @@ -6,7 +6,7 @@ part of 'track_state_providers.dart'; // RiverpodGenerator // ************************************************************************** -String _$trackStateHash() => r'f8d5a962cfbff41400945c0e7140071c76fa80fd'; +String _$trackStateHash() => r'1aecb0459141daa3e44fe3bbf6b49c0992b5f8bc'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/modules/manga/detail/providers/update_manga_detail_providers.dart b/lib/modules/manga/detail/providers/update_manga_detail_providers.dart index 22188e5f..3b02dae0 100644 --- a/lib/modules/manga/detail/providers/update_manga_detail_providers.dart +++ b/lib/modules/manga/detail/providers/update_manga_detail_providers.dart @@ -17,6 +17,7 @@ Future updateMangaDetail( Ref ref, { required int? mangaId, required bool isInit, + bool showToast = true, }) async { final manga = isar.mangas.getSync(mangaId!); if (manga!.chapters.isNotEmpty && isInit) { @@ -29,7 +30,7 @@ Future updateMangaDetail( getDetailProvider(url: manga.link!, source: source!).future, ); } catch (e) { - botToast(e.toString()); + if (showToast) botToast(e.toString()); return; } final genre = diff --git a/lib/modules/manga/detail/providers/update_manga_detail_providers.g.dart b/lib/modules/manga/detail/providers/update_manga_detail_providers.g.dart index 9ff3cbeb..8dfb2fb4 100644 --- a/lib/modules/manga/detail/providers/update_manga_detail_providers.g.dart +++ b/lib/modules/manga/detail/providers/update_manga_detail_providers.g.dart @@ -6,7 +6,7 @@ part of 'update_manga_detail_providers.dart'; // RiverpodGenerator // ************************************************************************** -String _$updateMangaDetailHash() => r'cfeaefe8375a38abbf07a774830d97ca57c6f2c9'; +String _$updateMangaDetailHash() => r'47fb1d79d48c4832fa7027ea76020044eb1fa2b4'; /// Copied from Dart SDK class _SystemHash { @@ -42,10 +42,12 @@ class UpdateMangaDetailFamily extends Family> { UpdateMangaDetailProvider call({ required int? mangaId, required bool isInit, + bool showToast = true, }) { return UpdateMangaDetailProvider( mangaId: mangaId, isInit: isInit, + showToast: showToast, ); } @@ -56,6 +58,7 @@ class UpdateMangaDetailFamily extends Family> { return call( mangaId: provider.mangaId, isInit: provider.isInit, + showToast: provider.showToast, ); } @@ -80,11 +83,13 @@ class UpdateMangaDetailProvider extends AutoDisposeFutureProvider { UpdateMangaDetailProvider({ required int? mangaId, required bool isInit, + bool showToast = true, }) : this._internal( (ref) => updateMangaDetail( ref as UpdateMangaDetailRef, mangaId: mangaId, isInit: isInit, + showToast: showToast, ), from: updateMangaDetailProvider, name: r'updateMangaDetailProvider', @@ -97,6 +102,7 @@ class UpdateMangaDetailProvider extends AutoDisposeFutureProvider { UpdateMangaDetailFamily._allTransitiveDependencies, mangaId: mangaId, isInit: isInit, + showToast: showToast, ); UpdateMangaDetailProvider._internal( @@ -108,10 +114,12 @@ class UpdateMangaDetailProvider extends AutoDisposeFutureProvider { required super.from, required this.mangaId, required this.isInit, + required this.showToast, }) : super.internal(); final int? mangaId; final bool isInit; + final bool showToast; @override Override overrideWith( @@ -128,6 +136,7 @@ class UpdateMangaDetailProvider extends AutoDisposeFutureProvider { debugGetCreateSourceHash: null, mangaId: mangaId, isInit: isInit, + showToast: showToast, ), ); } @@ -141,7 +150,8 @@ class UpdateMangaDetailProvider extends AutoDisposeFutureProvider { bool operator ==(Object other) { return other is UpdateMangaDetailProvider && other.mangaId == mangaId && - other.isInit == isInit; + other.isInit == isInit && + other.showToast == showToast; } @override @@ -149,6 +159,7 @@ class UpdateMangaDetailProvider extends AutoDisposeFutureProvider { var hash = _SystemHash.combine(0, runtimeType.hashCode); hash = _SystemHash.combine(hash, mangaId.hashCode); hash = _SystemHash.combine(hash, isInit.hashCode); + hash = _SystemHash.combine(hash, showToast.hashCode); return _SystemHash.finish(hash); } @@ -162,6 +173,9 @@ mixin UpdateMangaDetailRef on AutoDisposeFutureProviderRef { /// The parameter `isInit` of this provider. bool get isInit; + + /// The parameter `showToast` of this provider. + bool get showToast; } class _UpdateMangaDetailProviderElement @@ -173,6 +187,8 @@ class _UpdateMangaDetailProviderElement int? get mangaId => (origin as UpdateMangaDetailProvider).mangaId; @override bool get isInit => (origin as UpdateMangaDetailProvider).isInit; + @override + bool get showToast => (origin as UpdateMangaDetailProvider).showToast; } // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/modules/manga/download/providers/download_provider.dart b/lib/modules/manga/download/providers/download_provider.dart index 99446021..90eadc1c 100644 --- a/lib/modules/manga/download/providers/download_provider.dart +++ b/lib/modules/manga/download/providers/download_provider.dart @@ -1,6 +1,8 @@ import 'dart:convert'; import 'dart:io'; +import 'dart:ui'; import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:isar/isar.dart'; import 'package:mangayomi/eval/model/m_bridge.dart'; import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/models/page.dart'; @@ -19,6 +21,7 @@ import 'package:mangayomi/services/get_chapter_pages.dart'; import 'package:mangayomi/services/http/m_client.dart'; import 'package:mangayomi/services/download_manager/m3u8/m3u8_downloader.dart'; import 'package:mangayomi/services/download_manager/m3u8/models/download.dart'; +import 'package:mangayomi/utils/extensions/chapter.dart'; import 'package:mangayomi/utils/extensions/string_extensions.dart'; import 'package:mangayomi/utils/headers.dart'; import 'package:mangayomi/utils/reg_exp_matcher.dart'; @@ -27,15 +30,36 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; part 'download_provider.g.dart'; +@riverpod +Future addDownloadToQueue(Ref ref, {required Chapter chapter}) async { + final download = isar.downloads.getSync(chapter.id!); + if (download == null) { + final download = Download( + id: chapter.id, + succeeded: 0, + failed: 0, + total: 100, + isDownload: false, + isStartDownload: true, + ); + isar.writeTxnSync(() { + isar.downloads.putSync(download..chapter.value = chapter); + }); + } +} + @riverpod Future downloadChapter( Ref ref, { required Chapter chapter, bool? useWifi, + VoidCallback? callback, }) async { bool onlyOnWifi = useWifi ?? ref.watch(onlyOnWifiStateProvider); final connectivity = await Connectivity().checkConnectivity(); - final isOnWifi = connectivity.contains(ConnectivityResult.wifi) || connectivity.contains(ConnectivityResult.ethernet); + final isOnWifi = + connectivity.contains(ConnectivityResult.wifi) || + connectivity.contains(ConnectivityResult.ethernet); if (onlyOnWifi && !isOnWifi) { botToast(navigatorKey.currentContext!.l10n.downloads_are_limited_to_wifi); return; @@ -338,4 +362,45 @@ Future downloadChapter( setProgress(progress); }); } + if (callback != null) { + callback(); + } +} + +@riverpod +Future processDownloads(Ref ref, {bool? useWifi}) async { + final ongoingDownloads = + await isar.downloads + .filter() + .idIsNotNull() + .isDownloadEqualTo(false) + .isStartDownloadEqualTo(true) + .findAll(); + final maxConcurrentDownloads = ref.read(concurrentDownloadsStateProvider); + int index = 0; + int downloaded = 0; + int current = 0; + await Future.doWhile(() async { + await Future.delayed(const Duration(seconds: 1)); + if (ongoingDownloads.length == downloaded) { + return false; + } + if (current < maxConcurrentDownloads) { + current++; + final downloadItem = ongoingDownloads[index++]; + final chapter = downloadItem.chapter.value!; + chapter.cancelDownloads(downloadItem.id); + ref.read( + downloadChapterProvider( + chapter: chapter, + useWifi: useWifi, + callback: () { + downloaded++; + current--; + }, + ), + ); + } + return true; + }); } diff --git a/lib/modules/manga/download/providers/download_provider.g.dart b/lib/modules/manga/download/providers/download_provider.g.dart index e0fe6be9..3df105f2 100644 --- a/lib/modules/manga/download/providers/download_provider.g.dart +++ b/lib/modules/manga/download/providers/download_provider.g.dart @@ -6,7 +6,8 @@ part of 'download_provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$downloadChapterHash() => r'bf43fddf83fce382ff794c688288153477f9a3aa'; +String _$addDownloadToQueueHash() => + r'35e8e724755be265a9bf167e4641336630a465d2'; /// Copied from Dart SDK class _SystemHash { @@ -29,6 +30,136 @@ class _SystemHash { } } +/// See also [addDownloadToQueue]. +@ProviderFor(addDownloadToQueue) +const addDownloadToQueueProvider = AddDownloadToQueueFamily(); + +/// See also [addDownloadToQueue]. +class AddDownloadToQueueFamily extends Family> { + /// See also [addDownloadToQueue]. + const AddDownloadToQueueFamily(); + + /// See also [addDownloadToQueue]. + AddDownloadToQueueProvider call({ + required Chapter chapter, + }) { + return AddDownloadToQueueProvider( + chapter: chapter, + ); + } + + @override + AddDownloadToQueueProvider getProviderOverride( + covariant AddDownloadToQueueProvider provider, + ) { + return call( + chapter: provider.chapter, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'addDownloadToQueueProvider'; +} + +/// See also [addDownloadToQueue]. +class AddDownloadToQueueProvider extends AutoDisposeFutureProvider { + /// See also [addDownloadToQueue]. + AddDownloadToQueueProvider({ + required Chapter chapter, + }) : this._internal( + (ref) => addDownloadToQueue( + ref as AddDownloadToQueueRef, + chapter: chapter, + ), + from: addDownloadToQueueProvider, + name: r'addDownloadToQueueProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$addDownloadToQueueHash, + dependencies: AddDownloadToQueueFamily._dependencies, + allTransitiveDependencies: + AddDownloadToQueueFamily._allTransitiveDependencies, + chapter: chapter, + ); + + AddDownloadToQueueProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.chapter, + }) : super.internal(); + + final Chapter chapter; + + @override + Override overrideWith( + FutureOr Function(AddDownloadToQueueRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: AddDownloadToQueueProvider._internal( + (ref) => create(ref as AddDownloadToQueueRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + chapter: chapter, + ), + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _AddDownloadToQueueProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is AddDownloadToQueueProvider && other.chapter == chapter; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, chapter.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin AddDownloadToQueueRef on AutoDisposeFutureProviderRef { + /// The parameter `chapter` of this provider. + Chapter get chapter; +} + +class _AddDownloadToQueueProviderElement + extends AutoDisposeFutureProviderElement with AddDownloadToQueueRef { + _AddDownloadToQueueProviderElement(super.provider); + + @override + Chapter get chapter => (origin as AddDownloadToQueueProvider).chapter; +} + +String _$downloadChapterHash() => r'd20136bb2b86f930c3c48bc0dd07b16eaf1de133'; + /// See also [downloadChapter]. @ProviderFor(downloadChapter) const downloadChapterProvider = DownloadChapterFamily(); @@ -42,10 +173,12 @@ class DownloadChapterFamily extends Family> { DownloadChapterProvider call({ required Chapter chapter, bool? useWifi, + void Function()? callback, }) { return DownloadChapterProvider( chapter: chapter, useWifi: useWifi, + callback: callback, ); } @@ -56,6 +189,7 @@ class DownloadChapterFamily extends Family> { return call( chapter: provider.chapter, useWifi: provider.useWifi, + callback: provider.callback, ); } @@ -80,11 +214,13 @@ class DownloadChapterProvider extends AutoDisposeFutureProvider { DownloadChapterProvider({ required Chapter chapter, bool? useWifi, + void Function()? callback, }) : this._internal( (ref) => downloadChapter( ref as DownloadChapterRef, chapter: chapter, useWifi: useWifi, + callback: callback, ), from: downloadChapterProvider, name: r'downloadChapterProvider', @@ -97,6 +233,7 @@ class DownloadChapterProvider extends AutoDisposeFutureProvider { DownloadChapterFamily._allTransitiveDependencies, chapter: chapter, useWifi: useWifi, + callback: callback, ); DownloadChapterProvider._internal( @@ -108,10 +245,12 @@ class DownloadChapterProvider extends AutoDisposeFutureProvider { required super.from, required this.chapter, required this.useWifi, + required this.callback, }) : super.internal(); final Chapter chapter; final bool? useWifi; + final void Function()? callback; @override Override overrideWith( @@ -128,6 +267,7 @@ class DownloadChapterProvider extends AutoDisposeFutureProvider { debugGetCreateSourceHash: null, chapter: chapter, useWifi: useWifi, + callback: callback, ), ); } @@ -141,7 +281,8 @@ class DownloadChapterProvider extends AutoDisposeFutureProvider { bool operator ==(Object other) { return other is DownloadChapterProvider && other.chapter == chapter && - other.useWifi == useWifi; + other.useWifi == useWifi && + other.callback == callback; } @override @@ -149,6 +290,7 @@ class DownloadChapterProvider extends AutoDisposeFutureProvider { var hash = _SystemHash.combine(0, runtimeType.hashCode); hash = _SystemHash.combine(hash, chapter.hashCode); hash = _SystemHash.combine(hash, useWifi.hashCode); + hash = _SystemHash.combine(hash, callback.hashCode); return _SystemHash.finish(hash); } @@ -162,6 +304,9 @@ mixin DownloadChapterRef on AutoDisposeFutureProviderRef { /// The parameter `useWifi` of this provider. bool? get useWifi; + + /// The parameter `callback` of this provider. + void Function()? get callback; } class _DownloadChapterProviderElement @@ -172,6 +317,138 @@ class _DownloadChapterProviderElement Chapter get chapter => (origin as DownloadChapterProvider).chapter; @override bool? get useWifi => (origin as DownloadChapterProvider).useWifi; + @override + void Function()? get callback => (origin as DownloadChapterProvider).callback; +} + +String _$processDownloadsHash() => r'ef5107f9674f2175a7aa18b8e4fc4555f3b6b584'; + +/// See also [processDownloads]. +@ProviderFor(processDownloads) +const processDownloadsProvider = ProcessDownloadsFamily(); + +/// See also [processDownloads]. +class ProcessDownloadsFamily extends Family> { + /// See also [processDownloads]. + const ProcessDownloadsFamily(); + + /// See also [processDownloads]. + ProcessDownloadsProvider call({ + bool? useWifi, + }) { + return ProcessDownloadsProvider( + useWifi: useWifi, + ); + } + + @override + ProcessDownloadsProvider getProviderOverride( + covariant ProcessDownloadsProvider provider, + ) { + return call( + useWifi: provider.useWifi, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'processDownloadsProvider'; +} + +/// See also [processDownloads]. +class ProcessDownloadsProvider extends AutoDisposeFutureProvider { + /// See also [processDownloads]. + ProcessDownloadsProvider({ + bool? useWifi, + }) : this._internal( + (ref) => processDownloads( + ref as ProcessDownloadsRef, + useWifi: useWifi, + ), + from: processDownloadsProvider, + name: r'processDownloadsProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$processDownloadsHash, + dependencies: ProcessDownloadsFamily._dependencies, + allTransitiveDependencies: + ProcessDownloadsFamily._allTransitiveDependencies, + useWifi: useWifi, + ); + + ProcessDownloadsProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.useWifi, + }) : super.internal(); + + final bool? useWifi; + + @override + Override overrideWith( + FutureOr Function(ProcessDownloadsRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: ProcessDownloadsProvider._internal( + (ref) => create(ref as ProcessDownloadsRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + useWifi: useWifi, + ), + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _ProcessDownloadsProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is ProcessDownloadsProvider && other.useWifi == useWifi; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, useWifi.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin ProcessDownloadsRef on AutoDisposeFutureProviderRef { + /// The parameter `useWifi` of this provider. + bool? get useWifi; +} + +class _ProcessDownloadsProviderElement + extends AutoDisposeFutureProviderElement with ProcessDownloadsRef { + _ProcessDownloadsProviderElement(super.provider); + + @override + bool? get useWifi => (origin as ProcessDownloadsProvider).useWifi; } // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/modules/manga/home/manga_home_screen.dart b/lib/modules/manga/home/manga_home_screen.dart index 0ffc6083..972fdc51 100644 --- a/lib/modules/manga/home/manga_home_screen.dart +++ b/lib/modules/manga/home/manga_home_screen.dart @@ -25,6 +25,7 @@ import 'package:mangayomi/modules/manga/home/widget/mangas_card_selector.dart'; import 'package:mangayomi/modules/widgets/gridview_widget.dart'; import 'package:mangayomi/modules/widgets/manga_image_card_widget.dart'; import 'package:mangayomi/utils/global_style.dart'; +import 'package:marquee/marquee.dart'; import 'package:super_sliver_list/super_sliver_list.dart'; class MangaHomeScreen extends ConsumerStatefulWidget { @@ -149,7 +150,29 @@ class _MangaHomeScreenState extends ConsumerState { }; return Scaffold( appBar: AppBar( - title: _isSearch ? null : Text('${source.name}'), + title: + _isSearch + ? null + : Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("${source.name}"), + source.notes != null && source.notes!.isNotEmpty + ? SizedBox( + height: 20, + child: Marquee( + text: l10n.extension_notes(source.notes!), + style: const TextStyle(fontSize: 12), + blankSpace: 40.0, + velocity: 30.0, + pauseAfterRound: const Duration(seconds: 1), + startPadding: 10.0, + ), + ) + : Container(), + ], + ), leading: !_isSearch ? null : Container(), actions: [ _isSearch diff --git a/lib/modules/more/data_and_storage/providers/storage_usage.dart b/lib/modules/more/data_and_storage/providers/storage_usage.dart index e804a21d..e02e3e65 100644 --- a/lib/modules/more/data_and_storage/providers/storage_usage.dart +++ b/lib/modules/more/data_and_storage/providers/storage_usage.dart @@ -3,6 +3,7 @@ import 'package:mangayomi/eval/model/m_bridge.dart'; import 'package:mangayomi/main.dart'; import 'package:mangayomi/models/settings.dart'; import 'package:mangayomi/providers/l10n_providers.dart'; +import 'package:mangayomi/providers/storage_provider.dart'; import 'package:mangayomi/router/router.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; @@ -37,6 +38,9 @@ class TotalChapterCacheSizeState extends _$TotalChapterCacheSizeState { } msg = "0.00 B"; } catch (_) {} + try { + await StorageProvider().deleteTmpDirectory(); + } catch (_) {} if (msg != null && showToast) { state = msg; botToast( diff --git a/lib/modules/more/download_queue/download_queue_screen.dart b/lib/modules/more/download_queue/download_queue_screen.dart index bcd0eca7..e634c2d3 100644 --- a/lib/modules/more/download_queue/download_queue_screen.dart +++ b/lib/modules/more/download_queue/download_queue_screen.dart @@ -5,6 +5,8 @@ import 'package:isar/isar.dart'; import 'package:mangayomi/main.dart'; import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/download.dart'; +import 'package:mangayomi/modules/manga/detail/widgets/custom_floating_action_btn.dart'; +import 'package:mangayomi/modules/manga/download/providers/download_provider.dart'; import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/utils/extensions/chapter.dart'; import 'package:mangayomi/utils/global_style.dart'; @@ -16,16 +18,16 @@ class DownloadQueueScreen extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final l10n = l10nLocalizations(context); return StreamBuilder( - stream: isar.downloads.filter().idIsNotNull().watch( - fireImmediately: true, - ), + stream: isar.downloads + .filter() + .idIsNotNull() + .isDownloadEqualTo(false) + .isStartDownloadEqualTo(true) + .sortBySucceededDesc() + .watch(fireImmediately: true), builder: (context, snapshot) { if (snapshot.hasData && snapshot.data!.isNotEmpty) { - final entries = - snapshot.data! - .where((element) => element.isDownload == false) - .where((element) => element.isStartDownload == true) - .toList(); + final entries = snapshot.data!; final allQueueLength = entries.toList().length; return Scaffold( appBar: AppBar( @@ -172,6 +174,23 @@ class DownloadQueueScreen extends ConsumerWidget { ), order: GroupedListOrder.DESC, ), + floatingActionButton: CustomFloatingActionBtn( + isExtended: false, + label: l10n.download_queue, + onPressed: () { + ref.read(processDownloadsProvider()); + }, + textWidth: + measureText( + l10n.download_queue, + Theme.of(context).textTheme.labelLarge!, + ).width, + width: calculateDynamicButtonWidth( + l10n.download_queue, + Theme.of(context).textTheme.labelLarge!, + 50, + ), // 50 Padding, else RenderFlex overflow Exception + ), ); } return Scaffold( @@ -181,4 +200,21 @@ class DownloadQueueScreen extends ConsumerWidget { }, ); } + + Size measureText(String text, TextStyle style) { + final TextPainter textPainter = TextPainter( + text: TextSpan(text: text, style: style), + textDirection: TextDirection.ltr, + )..layout(); + return textPainter.size; + } + + double calculateDynamicButtonWidth( + String text, + TextStyle textStyle, + double padding, + ) { + final textSize = measureText(text, textStyle); + return textSize.width + padding; + } } diff --git a/lib/modules/more/settings/appearance/providers/theme_mode_state_provider.dart b/lib/modules/more/settings/appearance/providers/theme_mode_state_provider.dart index a832475a..850be721 100644 --- a/lib/modules/more/settings/appearance/providers/theme_mode_state_provider.dart +++ b/lib/modules/more/settings/appearance/providers/theme_mode_state_provider.dart @@ -14,6 +14,14 @@ class ThemeModeState extends _$ThemeModeState { return isar.settings.getSync(227)!.themeIsDark!; } + void setTheme(Brightness brightness) { + if (brightness == Brightness.light) { + ref.read(themeModeStateProvider.notifier).setLightTheme(); + } else { + ref.read(themeModeStateProvider.notifier).setDarkTheme(); + } + } + void setLightTheme() { final settings = isar.settings.getSync(227); state = false; diff --git a/lib/modules/more/settings/appearance/providers/theme_mode_state_provider.g.dart b/lib/modules/more/settings/appearance/providers/theme_mode_state_provider.g.dart index bd7d791a..e577d76d 100644 --- a/lib/modules/more/settings/appearance/providers/theme_mode_state_provider.g.dart +++ b/lib/modules/more/settings/appearance/providers/theme_mode_state_provider.g.dart @@ -6,7 +6,7 @@ part of 'theme_mode_state_provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$themeModeStateHash() => r'49a0f05f3d5eb1fcd49ec3c8c0d0b57a732b54fc'; +String _$themeModeStateHash() => r'264bf4a814cec831e34d916f273b4db6513e583c'; /// See also [ThemeModeState]. @ProviderFor(ThemeModeState) diff --git a/lib/modules/more/settings/downloads/downloads_screen.dart b/lib/modules/more/settings/downloads/downloads_screen.dart index ea6188af..b3c46de3 100644 --- a/lib/modules/more/settings/downloads/downloads_screen.dart +++ b/lib/modules/more/settings/downloads/downloads_screen.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mangayomi/modules/more/settings/downloads/providers/downloads_state_provider.dart'; import 'package:mangayomi/providers/l10n_providers.dart'; +import 'package:mangayomi/utils/extensions/build_context_extensions.dart'; +import 'package:numberpicker/numberpicker.dart'; class DownloadsScreen extends ConsumerStatefulWidget { const DownloadsScreen({super.key}); @@ -15,6 +17,7 @@ class _DownloadsScreenState extends ConsumerState { Widget build(BuildContext context) { final saveAsCBZArchiveState = ref.watch(saveAsCBZArchiveStateProvider); final onlyOnWifiState = ref.watch(onlyOnWifiStateProvider); + final concurrentDownloads = ref.watch(concurrentDownloadsStateProvider); final l10n = l10nLocalizations(context); return Scaffold( appBar: AppBar(title: Text(l10n!.downloads)), @@ -35,6 +38,77 @@ class _DownloadsScreenState extends ConsumerState { ref.read(saveAsCBZArchiveStateProvider.notifier).set(value); }, ), + ListTile( + onTap: () { + int currentIntValue = concurrentDownloads; + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text(context.l10n.concurrent_downloads), + content: StatefulBuilder( + builder: + (context, setState) => SizedBox( + height: 200, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + NumberPicker( + value: currentIntValue, + minValue: 1, + maxValue: 255, + step: 1, + haptics: true, + textMapper: (numberText) => numberText, + onChanged: + (value) => setState( + () => currentIntValue = value, + ), + ), + ], + ), + ), + ), + actions: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () async { + Navigator.pop(context); + }, + child: Text( + context.l10n.cancel, + style: TextStyle(color: context.primaryColor), + ), + ), + TextButton( + onPressed: () async { + ref + .read( + concurrentDownloadsStateProvider.notifier, + ) + .set(currentIntValue); + Navigator.pop(context); + }, + child: Text( + context.l10n.ok, + style: TextStyle(color: context.primaryColor), + ), + ), + ], + ), + ], + ); + }, + ); + }, + title: Text(context.l10n.concurrent_downloads), + subtitle: Text( + "$concurrentDownloads", + style: TextStyle(fontSize: 11, color: context.secondaryColor), + ), + ), ], ), ), diff --git a/lib/modules/more/settings/downloads/providers/downloads_state_provider.dart b/lib/modules/more/settings/downloads/providers/downloads_state_provider.dart index 1c157f26..f0c82a86 100644 --- a/lib/modules/more/settings/downloads/providers/downloads_state_provider.dart +++ b/lib/modules/more/settings/downloads/providers/downloads_state_provider.dart @@ -65,3 +65,19 @@ class DownloadLocationState extends _$DownloadLocationState { ); } } + +@riverpod +class ConcurrentDownloadsState extends _$ConcurrentDownloadsState { + @override + int build() { + return isar.settings.getSync(227)!.concurrentDownloads ?? 2; + } + + void set(int value) { + final settings = isar.settings.getSync(227); + state = value; + isar.writeTxnSync( + () => isar.settings.putSync(settings!..concurrentDownloads = value), + ); + } +} diff --git a/lib/modules/more/settings/downloads/providers/downloads_state_provider.g.dart b/lib/modules/more/settings/downloads/providers/downloads_state_provider.g.dart index 7c83d041..b4df323a 100644 --- a/lib/modules/more/settings/downloads/providers/downloads_state_provider.g.dart +++ b/lib/modules/more/settings/downloads/providers/downloads_state_provider.g.dart @@ -56,5 +56,22 @@ final downloadLocationStateProvider = AutoDisposeNotifierProvider< ); typedef _$DownloadLocationState = AutoDisposeNotifier<(String, String)>; +String _$concurrentDownloadsStateHash() => + r'665ec25af7d72e3345ce1ca96319419f11f121e6'; + +/// See also [ConcurrentDownloadsState]. +@ProviderFor(ConcurrentDownloadsState) +final concurrentDownloadsStateProvider = + AutoDisposeNotifierProvider.internal( + ConcurrentDownloadsState.new, + name: r'concurrentDownloadsStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$concurrentDownloadsStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$ConcurrentDownloadsState = AutoDisposeNotifier; // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/modules/updates/updates_screen.dart b/lib/modules/updates/updates_screen.dart index 660e908a..fb651033 100644 --- a/lib/modules/updates/updates_screen.dart +++ b/lib/modules/updates/updates_screen.dart @@ -1,6 +1,7 @@ import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_state_provider.dart'; import 'package:mangayomi/modules/widgets/custom_sliver_grouped_list_view.dart'; import 'package:isar/isar.dart'; @@ -37,11 +38,13 @@ class _UpdatesScreenState extends ConsumerState setState(() { _isLoading = true; }); + bool isDark = ref.read(themeModeStateProvider); botToast( - context.l10n.updating_library, + context.l10n.updating_library("0", "0", "0"), fontSize: 13, - second: 1600, + second: 30, alignY: !context.isTablet ? 0.85 : 1, + themeDark: isDark, ); final mangaList = isar.mangas @@ -60,14 +63,33 @@ class _UpdatesScreenState extends ConsumerState .isLocalArchiveEqualTo(false) .findAllSync(); int numbers = 0; + int failed = 0; for (var manga in mangaList) { try { await ref.read( - updateMangaDetailProvider(mangaId: manga.id, isInit: false).future, + updateMangaDetailProvider( + mangaId: manga.id, + isInit: false, + showToast: false, + ).future, ); - } catch (_) {} + } catch (_) { + failed++; + } numbers++; + if (context.mounted) { + botToast( + context.l10n.updating_library(numbers, failed, mangaList.length), + fontSize: 13, + second: 10, + alignY: !context.isTablet ? 0.85 : 1, + animationDuration: 0, + dismissDirections: [DismissDirection.none], + onlyOne: false, + themeDark: isDark, + ); + } } await Future.doWhile(() async { await Future.delayed(const Duration(seconds: 1)); @@ -196,45 +218,7 @@ class _UpdatesScreenState extends ConsumerState ), const SizedBox(width: 15), TextButton( - onPressed: () { - List updates = - isar.updates - .filter() - .idIsNotNull() - .chapter( - (q) => q.manga( - (q) => q.itemTypeEqualTo( - _tabBarController.index == 0 && - !hideItems.contains( - "/MangaLibrary", - ) - ? ItemType.manga - : _tabBarController.index == - 1 - - (hideItems.contains( - "/MangaLibrary", - ) - ? 1 - : 0) && - !hideItems.contains( - "/AnimeLibrary", - ) - ? ItemType.anime - : ItemType.novel, - ), - ), - ) - .findAllSync() - .toList(); - isar.writeTxnSync(() { - for (var update in updates) { - isar.updates.deleteSync(update.id!); - } - }); - if (mounted) { - Navigator.pop(context); - } - }, + onPressed: () => clearUpdates(hideItems), child: Text(l10n.ok), ), ], @@ -313,6 +297,38 @@ class _UpdatesScreenState extends ConsumerState ), ); } + + void clearUpdates(List hideItems) { + List updates = + isar.updates + .filter() + .idIsNotNull() + .chapter( + (q) => q.manga( + (q) => q.itemTypeEqualTo(getCurrentItemType(hideItems)), + ), + ) + .findAllSync() + .toList(); + isar.writeTxnSync(() { + for (var update in updates) { + isar.updates.deleteSync(update.id!); + } + }); + if (mounted) { + Navigator.pop(context); + } + } + + ItemType getCurrentItemType(List hideItems) { + return _tabBarController.index == 0 && !hideItems.contains("/MangaLibrary") + ? ItemType.manga + : _tabBarController.index == + 1 - (hideItems.contains("/MangaLibrary") ? 1 : 0) && + !hideItems.contains("/AnimeLibrary") + ? ItemType.anime + : ItemType.novel; + } } class UpdateTab extends ConsumerStatefulWidget { @@ -335,29 +351,21 @@ class _UpdateTabState extends ConsumerState { Widget build(BuildContext context) { final l10n = l10nLocalizations(context)!; final update = ref.watch( - getAllUpdateStreamProvider(itemType: widget.itemType), + getAllUpdateStreamProvider( + itemType: widget.itemType, + search: widget.query, + ), ); return Scaffold( body: Stack( children: [ update.when( - data: (data) { - final entries = - data - .where( - (element) => - widget.query.isNotEmpty - ? element.chapter.value!.manga.value!.name! - .toLowerCase() - .contains(widget.query.toLowerCase()) - : true, - ) - .toList(); + data: (entries) { final lastUpdatedList = - data + entries .map((e) => e.chapter.value!.manga.value!.lastUpdate!) .toList(); - lastUpdatedList.sort((a, b) => a.compareTo(b)); + lastUpdatedList.sort((a, b) => b.compareTo(a)); final lastUpdated = lastUpdatedList.firstOrNull; if (entries.isNotEmpty) { return CustomScrollView( diff --git a/lib/modules/widgets/custom_extended_image_provider.dart b/lib/modules/widgets/custom_extended_image_provider.dart index 5a4cb4e9..ddc14719 100644 --- a/lib/modules/widgets/custom_extended_image_provider.dart +++ b/lib/modules/widgets/custom_extended_image_provider.dart @@ -365,4 +365,7 @@ class CustomExtendedNetworkImageProvider return await _loadNetwork(this, chunkEvents); } + + @override + WebHtmlElementStrategy get webHtmlElementStrategy => WebHtmlElementStrategy.fallback; } diff --git a/lib/providers/storage_provider.dart b/lib/providers/storage_provider.dart index bcea5c74..3e5c52d9 100644 --- a/lib/providers/storage_provider.dart +++ b/lib/providers/storage_provider.dart @@ -42,6 +42,11 @@ class StorageProvider { await Directory(d!.path).delete(recursive: true); } + Future deleteTmpDirectory() async { + final d = await getTmpDirectory(); + await Directory(d!.path).delete(recursive: true); + } + Future getDefaultDirectory() async { Directory? directory; if (Platform.isAndroid) { @@ -60,6 +65,13 @@ class StorageProvider { return Directory(dbDir); } + Future getTmpDirectory() async { + final gefaultDirectory = await getDirectory(); + String dbDir = path.join(gefaultDirectory!.path, 'tmp'); + await Directory(dbDir).create(recursive: true); + return Directory(dbDir); + } + Future getIosBackupDirectory() async { final gefaultDirectory = await getDefaultDirectory(); String dbDir = path.join(gefaultDirectory!.path, 'backup'); diff --git a/lib/services/aniskip.g.dart b/lib/services/aniskip.g.dart index b2e1defb..c05db920 100644 --- a/lib/services/aniskip.g.dart +++ b/lib/services/aniskip.g.dart @@ -6,7 +6,7 @@ part of 'aniskip.dart'; // RiverpodGenerator // ************************************************************************** -String _$aniSkipHash() => r'887869b54e2e151633efd46da83bde845e14f421'; +String _$aniSkipHash() => r'2e5d19b025a2207ff64da7bf7908450ea9e5ff8c'; /// See also [AniSkip]. @ProviderFor(AniSkip) diff --git a/lib/services/download_manager/m3u8/m3u8_downloader.dart b/lib/services/download_manager/m3u8/m3u8_downloader.dart index f8770b41..aab970da 100644 --- a/lib/services/download_manager/m3u8/m3u8_downloader.dart +++ b/lib/services/download_manager/m3u8/m3u8_downloader.dart @@ -39,7 +39,7 @@ class M3u8Downloader { required this.fileName, this.headers, required this.chapter, - this.concurrentDownloads = 15, + this.concurrentDownloads = 2, }); void _log(String message) { diff --git a/lib/services/download_manager/m_downloader.dart b/lib/services/download_manager/m_downloader.dart index 56c85a38..e8a38195 100644 --- a/lib/services/download_manager/m_downloader.dart +++ b/lib/services/download_manager/m_downloader.dart @@ -29,7 +29,7 @@ class MDownloader { MDownloader({ required this.chapter, required this.pageUrls, - this.concurrentDownloads = 15, + this.concurrentDownloads = 2, }); void _log(String message) { diff --git a/lib/services/fetch_sources_list.dart b/lib/services/fetch_sources_list.dart index 530c26e0..1f6af705 100644 --- a/lib/services/fetch_sources_list.dart +++ b/lib/services/fetch_sources_list.dart @@ -106,6 +106,7 @@ Future _updateSource( ..sourceCodeLanguage = source.sourceCodeLanguage ..additionalParams = source.additionalParams ?? "" ..isObsolete = false + ..notes = source.notes ..repo = repo; isar.writeTxnSync(() { @@ -144,6 +145,7 @@ void _addNewSource(Source source, Ref ref, Repo? repo, ItemType itemType) { ..isFullData = source.isFullData ?? false ..appMinVerReq = source.appMinVerReq ..isObsolete = false + ..notes = source.notes ..repo = repo; isar.sources.putSync(newSource); ref diff --git a/lib/services/get_html_content.dart b/lib/services/get_html_content.dart index fe1268d9..1451d85b 100644 --- a/lib/services/get_html_content.dart +++ b/lib/services/get_html_content.dart @@ -33,7 +33,7 @@ Future getHtmlContent(Ref ref, {required Chapter chapter}) async { if (htmlContent != null) { html = await getExtensionService(source!).cleanHtmlContent(htmlContent); } else { - html = await getExtensionService(source!).getHtmlContent(chapter.url!); + html = await getExtensionService(source!).getHtmlContent(chapter.manga.value!.name!, chapter.url!); } return '''

${html.substring(1, html.length - 1)}
''' .replaceAll("\\n", "") diff --git a/lib/services/trackers/anilist.g.dart b/lib/services/trackers/anilist.g.dart index 558da2c4..834afd64 100644 --- a/lib/services/trackers/anilist.g.dart +++ b/lib/services/trackers/anilist.g.dart @@ -6,7 +6,7 @@ part of 'anilist.dart'; // RiverpodGenerator // ************************************************************************** -String _$anilistHash() => r'70e8cd537270a9054a1ef72de117fc7ad5545218'; +String _$anilistHash() => r'ddd07acc8d28d2aa95c942566109e9393ca9e5ed'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/services/trackers/kitsu.g.dart b/lib/services/trackers/kitsu.g.dart index 98dec282..19daa16b 100644 --- a/lib/services/trackers/kitsu.g.dart +++ b/lib/services/trackers/kitsu.g.dart @@ -6,7 +6,7 @@ part of 'kitsu.dart'; // RiverpodGenerator // ************************************************************************** -String _$kitsuHash() => r'9a123ca11d2b9e01d7d78b75d408a9f7a7b9b4e6'; +String _$kitsuHash() => r'09e9b9599bd536b94ca24bc087c8e9310d2b9ef9'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/src/rust/api/rhttp/client.freezed.dart b/lib/src/rust/api/rhttp/client.freezed.dart index dd2cc967..930a6b78 100644 --- a/lib/src/rust/api/rhttp/client.freezed.dart +++ b/lib/src/rust/api/rhttp/client.freezed.dart @@ -12,8 +12,7 @@ part of 'client.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', -); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); /// @nodoc mixin _$ProxySettings { @@ -21,43 +20,48 @@ mixin _$ProxySettings { TResult when({ required TResult Function() noProxy, required TResult Function(List field0) customProxyList, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ TResult? Function()? noProxy, TResult? Function(List field0)? customProxyList, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function()? noProxy, TResult Function(List field0)? customProxyList, required TResult orElse(), - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult map({ required TResult Function(ProxySettings_NoProxy value) noProxy, required TResult Function(ProxySettings_CustomProxyList value) - customProxyList, - }) => throw _privateConstructorUsedError; + customProxyList, + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult? mapOrNull({ TResult? Function(ProxySettings_NoProxy value)? noProxy, TResult? Function(ProxySettings_CustomProxyList value)? customProxyList, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeMap({ TResult Function(ProxySettings_NoProxy value)? noProxy, TResult Function(ProxySettings_CustomProxyList value)? customProxyList, required TResult orElse(), - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; } /// @nodoc abstract class $ProxySettingsCopyWith<$Res> { factory $ProxySettingsCopyWith( - ProxySettings value, - $Res Function(ProxySettings) then, - ) = _$ProxySettingsCopyWithImpl<$Res, ProxySettings>; + ProxySettings value, $Res Function(ProxySettings) then) = + _$ProxySettingsCopyWithImpl<$Res, ProxySettings>; } /// @nodoc @@ -77,19 +81,18 @@ class _$ProxySettingsCopyWithImpl<$Res, $Val extends ProxySettings> /// @nodoc abstract class _$$ProxySettings_NoProxyImplCopyWith<$Res> { factory _$$ProxySettings_NoProxyImplCopyWith( - _$ProxySettings_NoProxyImpl value, - $Res Function(_$ProxySettings_NoProxyImpl) then, - ) = __$$ProxySettings_NoProxyImplCopyWithImpl<$Res>; + _$ProxySettings_NoProxyImpl value, + $Res Function(_$ProxySettings_NoProxyImpl) then) = + __$$ProxySettings_NoProxyImplCopyWithImpl<$Res>; } /// @nodoc class __$$ProxySettings_NoProxyImplCopyWithImpl<$Res> extends _$ProxySettingsCopyWithImpl<$Res, _$ProxySettings_NoProxyImpl> implements _$$ProxySettings_NoProxyImplCopyWith<$Res> { - __$$ProxySettings_NoProxyImplCopyWithImpl( - _$ProxySettings_NoProxyImpl _value, - $Res Function(_$ProxySettings_NoProxyImpl) _then, - ) : super(_value, _then); + __$$ProxySettings_NoProxyImplCopyWithImpl(_$ProxySettings_NoProxyImpl _value, + $Res Function(_$ProxySettings_NoProxyImpl) _then) + : super(_value, _then); /// Create a copy of ProxySettings /// with the given fields replaced by the non-null parameter values. @@ -151,7 +154,7 @@ class _$ProxySettings_NoProxyImpl extends ProxySettings_NoProxy { TResult map({ required TResult Function(ProxySettings_NoProxy value) noProxy, required TResult Function(ProxySettings_CustomProxyList value) - customProxyList, + customProxyList, }) { return noProxy(this); } @@ -187,36 +190,36 @@ abstract class ProxySettings_NoProxy extends ProxySettings { /// @nodoc abstract class _$$ProxySettings_CustomProxyListImplCopyWith<$Res> { factory _$$ProxySettings_CustomProxyListImplCopyWith( - _$ProxySettings_CustomProxyListImpl value, - $Res Function(_$ProxySettings_CustomProxyListImpl) then, - ) = __$$ProxySettings_CustomProxyListImplCopyWithImpl<$Res>; + _$ProxySettings_CustomProxyListImpl value, + $Res Function(_$ProxySettings_CustomProxyListImpl) then) = + __$$ProxySettings_CustomProxyListImplCopyWithImpl<$Res>; @useResult $Res call({List field0}); } /// @nodoc class __$$ProxySettings_CustomProxyListImplCopyWithImpl<$Res> - extends - _$ProxySettingsCopyWithImpl<$Res, _$ProxySettings_CustomProxyListImpl> + extends _$ProxySettingsCopyWithImpl<$Res, + _$ProxySettings_CustomProxyListImpl> implements _$$ProxySettings_CustomProxyListImplCopyWith<$Res> { __$$ProxySettings_CustomProxyListImplCopyWithImpl( - _$ProxySettings_CustomProxyListImpl _value, - $Res Function(_$ProxySettings_CustomProxyListImpl) _then, - ) : super(_value, _then); + _$ProxySettings_CustomProxyListImpl _value, + $Res Function(_$ProxySettings_CustomProxyListImpl) _then) + : super(_value, _then); /// Create a copy of ProxySettings /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({Object? field0 = null}) { - return _then( - _$ProxySettings_CustomProxyListImpl( - null == field0 - ? _value._field0 - : field0 // ignore: cast_nullable_to_non_nullable - as List, - ), - ); + $Res call({ + Object? field0 = null, + }) { + return _then(_$ProxySettings_CustomProxyListImpl( + null == field0 + ? _value._field0 + : field0 // ignore: cast_nullable_to_non_nullable + as List, + )); } } @@ -225,8 +228,8 @@ class __$$ProxySettings_CustomProxyListImplCopyWithImpl<$Res> class _$ProxySettings_CustomProxyListImpl extends ProxySettings_CustomProxyList { const _$ProxySettings_CustomProxyListImpl(final List field0) - : _field0 = field0, - super._(); + : _field0 = field0, + super._(); final List _field0; @override @@ -259,11 +262,9 @@ class _$ProxySettings_CustomProxyListImpl @override @pragma('vm:prefer-inline') _$$ProxySettings_CustomProxyListImplCopyWith< - _$ProxySettings_CustomProxyListImpl - > - get copyWith => __$$ProxySettings_CustomProxyListImplCopyWithImpl< - _$ProxySettings_CustomProxyListImpl - >(this, _$identity); + _$ProxySettings_CustomProxyListImpl> + get copyWith => __$$ProxySettings_CustomProxyListImplCopyWithImpl< + _$ProxySettings_CustomProxyListImpl>(this, _$identity); @override @optionalTypeArgs @@ -301,7 +302,7 @@ class _$ProxySettings_CustomProxyListImpl TResult map({ required TResult Function(ProxySettings_NoProxy value) noProxy, required TResult Function(ProxySettings_CustomProxyList value) - customProxyList, + customProxyList, }) { return customProxyList(this); } @@ -340,9 +341,8 @@ abstract class ProxySettings_CustomProxyList extends ProxySettings { /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) _$$ProxySettings_CustomProxyListImplCopyWith< - _$ProxySettings_CustomProxyListImpl - > - get copyWith => throw _privateConstructorUsedError; + _$ProxySettings_CustomProxyListImpl> + get copyWith => throw _privateConstructorUsedError; } /// @nodoc @@ -351,44 +351,49 @@ mixin _$RedirectSettings { TResult when({ required TResult Function() noRedirect, required TResult Function(int field0) limitedRedirects, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ TResult? Function()? noRedirect, TResult? Function(int field0)? limitedRedirects, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function()? noRedirect, TResult Function(int field0)? limitedRedirects, required TResult orElse(), - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult map({ required TResult Function(RedirectSettings_NoRedirect value) noRedirect, required TResult Function(RedirectSettings_LimitedRedirects value) - limitedRedirects, - }) => throw _privateConstructorUsedError; + limitedRedirects, + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult? mapOrNull({ TResult? Function(RedirectSettings_NoRedirect value)? noRedirect, TResult? Function(RedirectSettings_LimitedRedirects value)? - limitedRedirects, - }) => throw _privateConstructorUsedError; + limitedRedirects, + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeMap({ TResult Function(RedirectSettings_NoRedirect value)? noRedirect, TResult Function(RedirectSettings_LimitedRedirects value)? limitedRedirects, required TResult orElse(), - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; } /// @nodoc abstract class $RedirectSettingsCopyWith<$Res> { factory $RedirectSettingsCopyWith( - RedirectSettings value, - $Res Function(RedirectSettings) then, - ) = _$RedirectSettingsCopyWithImpl<$Res, RedirectSettings>; + RedirectSettings value, $Res Function(RedirectSettings) then) = + _$RedirectSettingsCopyWithImpl<$Res, RedirectSettings>; } /// @nodoc @@ -408,20 +413,20 @@ class _$RedirectSettingsCopyWithImpl<$Res, $Val extends RedirectSettings> /// @nodoc abstract class _$$RedirectSettings_NoRedirectImplCopyWith<$Res> { factory _$$RedirectSettings_NoRedirectImplCopyWith( - _$RedirectSettings_NoRedirectImpl value, - $Res Function(_$RedirectSettings_NoRedirectImpl) then, - ) = __$$RedirectSettings_NoRedirectImplCopyWithImpl<$Res>; + _$RedirectSettings_NoRedirectImpl value, + $Res Function(_$RedirectSettings_NoRedirectImpl) then) = + __$$RedirectSettings_NoRedirectImplCopyWithImpl<$Res>; } /// @nodoc class __$$RedirectSettings_NoRedirectImplCopyWithImpl<$Res> - extends - _$RedirectSettingsCopyWithImpl<$Res, _$RedirectSettings_NoRedirectImpl> + extends _$RedirectSettingsCopyWithImpl<$Res, + _$RedirectSettings_NoRedirectImpl> implements _$$RedirectSettings_NoRedirectImplCopyWith<$Res> { __$$RedirectSettings_NoRedirectImplCopyWithImpl( - _$RedirectSettings_NoRedirectImpl _value, - $Res Function(_$RedirectSettings_NoRedirectImpl) _then, - ) : super(_value, _then); + _$RedirectSettings_NoRedirectImpl _value, + $Res Function(_$RedirectSettings_NoRedirectImpl) _then) + : super(_value, _then); /// Create a copy of RedirectSettings /// with the given fields replaced by the non-null parameter values. @@ -483,7 +488,7 @@ class _$RedirectSettings_NoRedirectImpl extends RedirectSettings_NoRedirect { TResult map({ required TResult Function(RedirectSettings_NoRedirect value) noRedirect, required TResult Function(RedirectSettings_LimitedRedirects value) - limitedRedirects, + limitedRedirects, }) { return noRedirect(this); } @@ -493,7 +498,7 @@ class _$RedirectSettings_NoRedirectImpl extends RedirectSettings_NoRedirect { TResult? mapOrNull({ TResult? Function(RedirectSettings_NoRedirect value)? noRedirect, TResult? Function(RedirectSettings_LimitedRedirects value)? - limitedRedirects, + limitedRedirects, }) { return noRedirect?.call(this); } @@ -521,39 +526,36 @@ abstract class RedirectSettings_NoRedirect extends RedirectSettings { /// @nodoc abstract class _$$RedirectSettings_LimitedRedirectsImplCopyWith<$Res> { factory _$$RedirectSettings_LimitedRedirectsImplCopyWith( - _$RedirectSettings_LimitedRedirectsImpl value, - $Res Function(_$RedirectSettings_LimitedRedirectsImpl) then, - ) = __$$RedirectSettings_LimitedRedirectsImplCopyWithImpl<$Res>; + _$RedirectSettings_LimitedRedirectsImpl value, + $Res Function(_$RedirectSettings_LimitedRedirectsImpl) then) = + __$$RedirectSettings_LimitedRedirectsImplCopyWithImpl<$Res>; @useResult $Res call({int field0}); } /// @nodoc class __$$RedirectSettings_LimitedRedirectsImplCopyWithImpl<$Res> - extends - _$RedirectSettingsCopyWithImpl< - $Res, - _$RedirectSettings_LimitedRedirectsImpl - > + extends _$RedirectSettingsCopyWithImpl<$Res, + _$RedirectSettings_LimitedRedirectsImpl> implements _$$RedirectSettings_LimitedRedirectsImplCopyWith<$Res> { __$$RedirectSettings_LimitedRedirectsImplCopyWithImpl( - _$RedirectSettings_LimitedRedirectsImpl _value, - $Res Function(_$RedirectSettings_LimitedRedirectsImpl) _then, - ) : super(_value, _then); + _$RedirectSettings_LimitedRedirectsImpl _value, + $Res Function(_$RedirectSettings_LimitedRedirectsImpl) _then) + : super(_value, _then); /// Create a copy of RedirectSettings /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({Object? field0 = null}) { - return _then( - _$RedirectSettings_LimitedRedirectsImpl( - null == field0 - ? _value.field0 - : field0 // ignore: cast_nullable_to_non_nullable - as int, - ), - ); + $Res call({ + Object? field0 = null, + }) { + return _then(_$RedirectSettings_LimitedRedirectsImpl( + null == field0 + ? _value.field0 + : field0 // ignore: cast_nullable_to_non_nullable + as int, + )); } } @@ -588,11 +590,9 @@ class _$RedirectSettings_LimitedRedirectsImpl @override @pragma('vm:prefer-inline') _$$RedirectSettings_LimitedRedirectsImplCopyWith< - _$RedirectSettings_LimitedRedirectsImpl - > - get copyWith => __$$RedirectSettings_LimitedRedirectsImplCopyWithImpl< - _$RedirectSettings_LimitedRedirectsImpl - >(this, _$identity); + _$RedirectSettings_LimitedRedirectsImpl> + get copyWith => __$$RedirectSettings_LimitedRedirectsImplCopyWithImpl< + _$RedirectSettings_LimitedRedirectsImpl>(this, _$identity); @override @optionalTypeArgs @@ -630,7 +630,7 @@ class _$RedirectSettings_LimitedRedirectsImpl TResult map({ required TResult Function(RedirectSettings_NoRedirect value) noRedirect, required TResult Function(RedirectSettings_LimitedRedirects value) - limitedRedirects, + limitedRedirects, }) { return limitedRedirects(this); } @@ -640,7 +640,7 @@ class _$RedirectSettings_LimitedRedirectsImpl TResult? mapOrNull({ TResult? Function(RedirectSettings_NoRedirect value)? noRedirect, TResult? Function(RedirectSettings_LimitedRedirects value)? - limitedRedirects, + limitedRedirects, }) { return limitedRedirects?.call(this); } @@ -670,7 +670,6 @@ abstract class RedirectSettings_LimitedRedirects extends RedirectSettings { /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) _$$RedirectSettings_LimitedRedirectsImplCopyWith< - _$RedirectSettings_LimitedRedirectsImpl - > - get copyWith => throw _privateConstructorUsedError; + _$RedirectSettings_LimitedRedirectsImpl> + get copyWith => throw _privateConstructorUsedError; } diff --git a/lib/src/rust/api/rhttp/error.freezed.dart b/lib/src/rust/api/rhttp/error.freezed.dart index 00957f75..07e5f871 100644 --- a/lib/src/rust/api/rhttp/error.freezed.dart +++ b/lib/src/rust/api/rhttp/error.freezed.dart @@ -12,8 +12,7 @@ part of 'error.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', -); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); /// @nodoc mixin _$RhttpError { @@ -23,98 +22,94 @@ mixin _$RhttpError { required TResult Function() rhttpTimeoutError, required TResult Function() rhttpRedirectError, required TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - ) - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2) + rhttpStatusCodeError, required TResult Function(String field0) rhttpInvalidCertificateError, required TResult Function(String field0) rhttpConnectionError, required TResult Function(String field0) rhttpUnknownError, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ TResult? Function()? rhttpCancelError, TResult? Function()? rhttpTimeoutError, TResult? Function()? rhttpRedirectError, TResult? Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult? Function(String field0)? rhttpInvalidCertificateError, TResult? Function(String field0)? rhttpConnectionError, TResult? Function(String field0)? rhttpUnknownError, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function()? rhttpCancelError, TResult Function()? rhttpTimeoutError, TResult Function()? rhttpRedirectError, TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult Function(String field0)? rhttpInvalidCertificateError, TResult Function(String field0)? rhttpConnectionError, TResult Function(String field0)? rhttpUnknownError, required TResult orElse(), - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult map({ required TResult Function(RhttpError_RhttpCancelError value) - rhttpCancelError, + rhttpCancelError, required TResult Function(RhttpError_RhttpTimeoutError value) - rhttpTimeoutError, + rhttpTimeoutError, required TResult Function(RhttpError_RhttpRedirectError value) - rhttpRedirectError, + rhttpRedirectError, required TResult Function(RhttpError_RhttpStatusCodeError value) - rhttpStatusCodeError, + rhttpStatusCodeError, required TResult Function(RhttpError_RhttpInvalidCertificateError value) - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, required TResult Function(RhttpError_RhttpConnectionError value) - rhttpConnectionError, + rhttpConnectionError, required TResult Function(RhttpError_RhttpUnknownError value) - rhttpUnknownError, - }) => throw _privateConstructorUsedError; + rhttpUnknownError, + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult? mapOrNull({ TResult? Function(RhttpError_RhttpCancelError value)? rhttpCancelError, TResult? Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult? Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult? Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult? Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult? Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult? Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeMap({ TResult Function(RhttpError_RhttpCancelError value)? rhttpCancelError, TResult Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, required TResult orElse(), - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; } /// @nodoc abstract class $RhttpErrorCopyWith<$Res> { factory $RhttpErrorCopyWith( - RhttpError value, - $Res Function(RhttpError) then, - ) = _$RhttpErrorCopyWithImpl<$Res, RhttpError>; + RhttpError value, $Res Function(RhttpError) then) = + _$RhttpErrorCopyWithImpl<$Res, RhttpError>; } /// @nodoc @@ -134,9 +129,9 @@ class _$RhttpErrorCopyWithImpl<$Res, $Val extends RhttpError> /// @nodoc abstract class _$$RhttpError_RhttpCancelErrorImplCopyWith<$Res> { factory _$$RhttpError_RhttpCancelErrorImplCopyWith( - _$RhttpError_RhttpCancelErrorImpl value, - $Res Function(_$RhttpError_RhttpCancelErrorImpl) then, - ) = __$$RhttpError_RhttpCancelErrorImplCopyWithImpl<$Res>; + _$RhttpError_RhttpCancelErrorImpl value, + $Res Function(_$RhttpError_RhttpCancelErrorImpl) then) = + __$$RhttpError_RhttpCancelErrorImplCopyWithImpl<$Res>; } /// @nodoc @@ -144,9 +139,9 @@ class __$$RhttpError_RhttpCancelErrorImplCopyWithImpl<$Res> extends _$RhttpErrorCopyWithImpl<$Res, _$RhttpError_RhttpCancelErrorImpl> implements _$$RhttpError_RhttpCancelErrorImplCopyWith<$Res> { __$$RhttpError_RhttpCancelErrorImplCopyWithImpl( - _$RhttpError_RhttpCancelErrorImpl _value, - $Res Function(_$RhttpError_RhttpCancelErrorImpl) _then, - ) : super(_value, _then); + _$RhttpError_RhttpCancelErrorImpl _value, + $Res Function(_$RhttpError_RhttpCancelErrorImpl) _then) + : super(_value, _then); /// Create a copy of RhttpError /// with the given fields replaced by the non-null parameter values. @@ -179,11 +174,8 @@ class _$RhttpError_RhttpCancelErrorImpl extends RhttpError_RhttpCancelError { required TResult Function() rhttpTimeoutError, required TResult Function() rhttpRedirectError, required TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - ) - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2) + rhttpStatusCodeError, required TResult Function(String field0) rhttpInvalidCertificateError, required TResult Function(String field0) rhttpConnectionError, required TResult Function(String field0) rhttpUnknownError, @@ -198,11 +190,8 @@ class _$RhttpError_RhttpCancelErrorImpl extends RhttpError_RhttpCancelError { TResult? Function()? rhttpTimeoutError, TResult? Function()? rhttpRedirectError, TResult? Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult? Function(String field0)? rhttpInvalidCertificateError, TResult? Function(String field0)? rhttpConnectionError, TResult? Function(String field0)? rhttpUnknownError, @@ -217,11 +206,8 @@ class _$RhttpError_RhttpCancelErrorImpl extends RhttpError_RhttpCancelError { TResult Function()? rhttpTimeoutError, TResult Function()? rhttpRedirectError, TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult Function(String field0)? rhttpInvalidCertificateError, TResult Function(String field0)? rhttpConnectionError, TResult Function(String field0)? rhttpUnknownError, @@ -237,19 +223,19 @@ class _$RhttpError_RhttpCancelErrorImpl extends RhttpError_RhttpCancelError { @optionalTypeArgs TResult map({ required TResult Function(RhttpError_RhttpCancelError value) - rhttpCancelError, + rhttpCancelError, required TResult Function(RhttpError_RhttpTimeoutError value) - rhttpTimeoutError, + rhttpTimeoutError, required TResult Function(RhttpError_RhttpRedirectError value) - rhttpRedirectError, + rhttpRedirectError, required TResult Function(RhttpError_RhttpStatusCodeError value) - rhttpStatusCodeError, + rhttpStatusCodeError, required TResult Function(RhttpError_RhttpInvalidCertificateError value) - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, required TResult Function(RhttpError_RhttpConnectionError value) - rhttpConnectionError, + rhttpConnectionError, required TResult Function(RhttpError_RhttpUnknownError value) - rhttpUnknownError, + rhttpUnknownError, }) { return rhttpCancelError(this); } @@ -261,11 +247,11 @@ class _$RhttpError_RhttpCancelErrorImpl extends RhttpError_RhttpCancelError { TResult? Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult? Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult? Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult? Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult? Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult? Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, }) { return rhttpCancelError?.call(this); @@ -278,11 +264,11 @@ class _$RhttpError_RhttpCancelErrorImpl extends RhttpError_RhttpCancelError { TResult Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, required TResult orElse(), }) { @@ -302,9 +288,9 @@ abstract class RhttpError_RhttpCancelError extends RhttpError { /// @nodoc abstract class _$$RhttpError_RhttpTimeoutErrorImplCopyWith<$Res> { factory _$$RhttpError_RhttpTimeoutErrorImplCopyWith( - _$RhttpError_RhttpTimeoutErrorImpl value, - $Res Function(_$RhttpError_RhttpTimeoutErrorImpl) then, - ) = __$$RhttpError_RhttpTimeoutErrorImplCopyWithImpl<$Res>; + _$RhttpError_RhttpTimeoutErrorImpl value, + $Res Function(_$RhttpError_RhttpTimeoutErrorImpl) then) = + __$$RhttpError_RhttpTimeoutErrorImplCopyWithImpl<$Res>; } /// @nodoc @@ -312,9 +298,9 @@ class __$$RhttpError_RhttpTimeoutErrorImplCopyWithImpl<$Res> extends _$RhttpErrorCopyWithImpl<$Res, _$RhttpError_RhttpTimeoutErrorImpl> implements _$$RhttpError_RhttpTimeoutErrorImplCopyWith<$Res> { __$$RhttpError_RhttpTimeoutErrorImplCopyWithImpl( - _$RhttpError_RhttpTimeoutErrorImpl _value, - $Res Function(_$RhttpError_RhttpTimeoutErrorImpl) _then, - ) : super(_value, _then); + _$RhttpError_RhttpTimeoutErrorImpl _value, + $Res Function(_$RhttpError_RhttpTimeoutErrorImpl) _then) + : super(_value, _then); /// Create a copy of RhttpError /// with the given fields replaced by the non-null parameter values. @@ -347,11 +333,8 @@ class _$RhttpError_RhttpTimeoutErrorImpl extends RhttpError_RhttpTimeoutError { required TResult Function() rhttpTimeoutError, required TResult Function() rhttpRedirectError, required TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - ) - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2) + rhttpStatusCodeError, required TResult Function(String field0) rhttpInvalidCertificateError, required TResult Function(String field0) rhttpConnectionError, required TResult Function(String field0) rhttpUnknownError, @@ -366,11 +349,8 @@ class _$RhttpError_RhttpTimeoutErrorImpl extends RhttpError_RhttpTimeoutError { TResult? Function()? rhttpTimeoutError, TResult? Function()? rhttpRedirectError, TResult? Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult? Function(String field0)? rhttpInvalidCertificateError, TResult? Function(String field0)? rhttpConnectionError, TResult? Function(String field0)? rhttpUnknownError, @@ -385,11 +365,8 @@ class _$RhttpError_RhttpTimeoutErrorImpl extends RhttpError_RhttpTimeoutError { TResult Function()? rhttpTimeoutError, TResult Function()? rhttpRedirectError, TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult Function(String field0)? rhttpInvalidCertificateError, TResult Function(String field0)? rhttpConnectionError, TResult Function(String field0)? rhttpUnknownError, @@ -405,19 +382,19 @@ class _$RhttpError_RhttpTimeoutErrorImpl extends RhttpError_RhttpTimeoutError { @optionalTypeArgs TResult map({ required TResult Function(RhttpError_RhttpCancelError value) - rhttpCancelError, + rhttpCancelError, required TResult Function(RhttpError_RhttpTimeoutError value) - rhttpTimeoutError, + rhttpTimeoutError, required TResult Function(RhttpError_RhttpRedirectError value) - rhttpRedirectError, + rhttpRedirectError, required TResult Function(RhttpError_RhttpStatusCodeError value) - rhttpStatusCodeError, + rhttpStatusCodeError, required TResult Function(RhttpError_RhttpInvalidCertificateError value) - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, required TResult Function(RhttpError_RhttpConnectionError value) - rhttpConnectionError, + rhttpConnectionError, required TResult Function(RhttpError_RhttpUnknownError value) - rhttpUnknownError, + rhttpUnknownError, }) { return rhttpTimeoutError(this); } @@ -429,11 +406,11 @@ class _$RhttpError_RhttpTimeoutErrorImpl extends RhttpError_RhttpTimeoutError { TResult? Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult? Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult? Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult? Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult? Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult? Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, }) { return rhttpTimeoutError?.call(this); @@ -446,11 +423,11 @@ class _$RhttpError_RhttpTimeoutErrorImpl extends RhttpError_RhttpTimeoutError { TResult Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, required TResult orElse(), }) { @@ -470,9 +447,9 @@ abstract class RhttpError_RhttpTimeoutError extends RhttpError { /// @nodoc abstract class _$$RhttpError_RhttpRedirectErrorImplCopyWith<$Res> { factory _$$RhttpError_RhttpRedirectErrorImplCopyWith( - _$RhttpError_RhttpRedirectErrorImpl value, - $Res Function(_$RhttpError_RhttpRedirectErrorImpl) then, - ) = __$$RhttpError_RhttpRedirectErrorImplCopyWithImpl<$Res>; + _$RhttpError_RhttpRedirectErrorImpl value, + $Res Function(_$RhttpError_RhttpRedirectErrorImpl) then) = + __$$RhttpError_RhttpRedirectErrorImplCopyWithImpl<$Res>; } /// @nodoc @@ -480,9 +457,9 @@ class __$$RhttpError_RhttpRedirectErrorImplCopyWithImpl<$Res> extends _$RhttpErrorCopyWithImpl<$Res, _$RhttpError_RhttpRedirectErrorImpl> implements _$$RhttpError_RhttpRedirectErrorImplCopyWith<$Res> { __$$RhttpError_RhttpRedirectErrorImplCopyWithImpl( - _$RhttpError_RhttpRedirectErrorImpl _value, - $Res Function(_$RhttpError_RhttpRedirectErrorImpl) _then, - ) : super(_value, _then); + _$RhttpError_RhttpRedirectErrorImpl _value, + $Res Function(_$RhttpError_RhttpRedirectErrorImpl) _then) + : super(_value, _then); /// Create a copy of RhttpError /// with the given fields replaced by the non-null parameter values. @@ -516,11 +493,8 @@ class _$RhttpError_RhttpRedirectErrorImpl required TResult Function() rhttpTimeoutError, required TResult Function() rhttpRedirectError, required TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - ) - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2) + rhttpStatusCodeError, required TResult Function(String field0) rhttpInvalidCertificateError, required TResult Function(String field0) rhttpConnectionError, required TResult Function(String field0) rhttpUnknownError, @@ -535,11 +509,8 @@ class _$RhttpError_RhttpRedirectErrorImpl TResult? Function()? rhttpTimeoutError, TResult? Function()? rhttpRedirectError, TResult? Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult? Function(String field0)? rhttpInvalidCertificateError, TResult? Function(String field0)? rhttpConnectionError, TResult? Function(String field0)? rhttpUnknownError, @@ -554,11 +525,8 @@ class _$RhttpError_RhttpRedirectErrorImpl TResult Function()? rhttpTimeoutError, TResult Function()? rhttpRedirectError, TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult Function(String field0)? rhttpInvalidCertificateError, TResult Function(String field0)? rhttpConnectionError, TResult Function(String field0)? rhttpUnknownError, @@ -574,19 +542,19 @@ class _$RhttpError_RhttpRedirectErrorImpl @optionalTypeArgs TResult map({ required TResult Function(RhttpError_RhttpCancelError value) - rhttpCancelError, + rhttpCancelError, required TResult Function(RhttpError_RhttpTimeoutError value) - rhttpTimeoutError, + rhttpTimeoutError, required TResult Function(RhttpError_RhttpRedirectError value) - rhttpRedirectError, + rhttpRedirectError, required TResult Function(RhttpError_RhttpStatusCodeError value) - rhttpStatusCodeError, + rhttpStatusCodeError, required TResult Function(RhttpError_RhttpInvalidCertificateError value) - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, required TResult Function(RhttpError_RhttpConnectionError value) - rhttpConnectionError, + rhttpConnectionError, required TResult Function(RhttpError_RhttpUnknownError value) - rhttpUnknownError, + rhttpUnknownError, }) { return rhttpRedirectError(this); } @@ -598,11 +566,11 @@ class _$RhttpError_RhttpRedirectErrorImpl TResult? Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult? Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult? Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult? Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult? Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult? Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, }) { return rhttpRedirectError?.call(this); @@ -615,11 +583,11 @@ class _$RhttpError_RhttpRedirectErrorImpl TResult Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, required TResult orElse(), }) { @@ -639,28 +607,25 @@ abstract class RhttpError_RhttpRedirectError extends RhttpError { /// @nodoc abstract class _$$RhttpError_RhttpStatusCodeErrorImplCopyWith<$Res> { factory _$$RhttpError_RhttpStatusCodeErrorImplCopyWith( - _$RhttpError_RhttpStatusCodeErrorImpl value, - $Res Function(_$RhttpError_RhttpStatusCodeErrorImpl) then, - ) = __$$RhttpError_RhttpStatusCodeErrorImplCopyWithImpl<$Res>; + _$RhttpError_RhttpStatusCodeErrorImpl value, + $Res Function(_$RhttpError_RhttpStatusCodeErrorImpl) then) = + __$$RhttpError_RhttpStatusCodeErrorImplCopyWithImpl<$Res>; @useResult - $Res call({ - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - }); + $Res call( + {int field0, List<(String, String)> field1, HttpResponseBody field2}); $HttpResponseBodyCopyWith<$Res> get field2; } /// @nodoc class __$$RhttpError_RhttpStatusCodeErrorImplCopyWithImpl<$Res> - extends - _$RhttpErrorCopyWithImpl<$Res, _$RhttpError_RhttpStatusCodeErrorImpl> + extends _$RhttpErrorCopyWithImpl<$Res, + _$RhttpError_RhttpStatusCodeErrorImpl> implements _$$RhttpError_RhttpStatusCodeErrorImplCopyWith<$Res> { __$$RhttpError_RhttpStatusCodeErrorImplCopyWithImpl( - _$RhttpError_RhttpStatusCodeErrorImpl _value, - $Res Function(_$RhttpError_RhttpStatusCodeErrorImpl) _then, - ) : super(_value, _then); + _$RhttpError_RhttpStatusCodeErrorImpl _value, + $Res Function(_$RhttpError_RhttpStatusCodeErrorImpl) _then) + : super(_value, _then); /// Create a copy of RhttpError /// with the given fields replaced by the non-null parameter values. @@ -671,22 +636,20 @@ class __$$RhttpError_RhttpStatusCodeErrorImplCopyWithImpl<$Res> Object? field1 = null, Object? field2 = null, }) { - return _then( - _$RhttpError_RhttpStatusCodeErrorImpl( - null == field0 - ? _value.field0 - : field0 // ignore: cast_nullable_to_non_nullable - as int, - null == field1 - ? _value._field1 - : field1 // ignore: cast_nullable_to_non_nullable - as List<(String, String)>, - null == field2 - ? _value.field2 - : field2 // ignore: cast_nullable_to_non_nullable - as HttpResponseBody, - ), - ); + return _then(_$RhttpError_RhttpStatusCodeErrorImpl( + null == field0 + ? _value.field0 + : field0 // ignore: cast_nullable_to_non_nullable + as int, + null == field1 + ? _value._field1 + : field1 // ignore: cast_nullable_to_non_nullable + as List<(String, String)>, + null == field2 + ? _value.field2 + : field2 // ignore: cast_nullable_to_non_nullable + as HttpResponseBody, + )); } /// Create a copy of RhttpError @@ -705,11 +668,9 @@ class __$$RhttpError_RhttpStatusCodeErrorImplCopyWithImpl<$Res> class _$RhttpError_RhttpStatusCodeErrorImpl extends RhttpError_RhttpStatusCodeError { const _$RhttpError_RhttpStatusCodeErrorImpl( - this.field0, - final List<(String, String)> field1, - this.field2, - ) : _field1 = field1, - super._(); + this.field0, final List<(String, String)> field1, this.field2) + : _field1 = field1, + super._(); @override final int field0; @@ -740,12 +701,8 @@ class _$RhttpError_RhttpStatusCodeErrorImpl } @override - int get hashCode => Object.hash( - runtimeType, - field0, - const DeepCollectionEquality().hash(_field1), - field2, - ); + int get hashCode => Object.hash(runtimeType, field0, + const DeepCollectionEquality().hash(_field1), field2); /// Create a copy of RhttpError /// with the given fields replaced by the non-null parameter values. @@ -753,11 +710,9 @@ class _$RhttpError_RhttpStatusCodeErrorImpl @override @pragma('vm:prefer-inline') _$$RhttpError_RhttpStatusCodeErrorImplCopyWith< - _$RhttpError_RhttpStatusCodeErrorImpl - > - get copyWith => __$$RhttpError_RhttpStatusCodeErrorImplCopyWithImpl< - _$RhttpError_RhttpStatusCodeErrorImpl - >(this, _$identity); + _$RhttpError_RhttpStatusCodeErrorImpl> + get copyWith => __$$RhttpError_RhttpStatusCodeErrorImplCopyWithImpl< + _$RhttpError_RhttpStatusCodeErrorImpl>(this, _$identity); @override @optionalTypeArgs @@ -766,11 +721,8 @@ class _$RhttpError_RhttpStatusCodeErrorImpl required TResult Function() rhttpTimeoutError, required TResult Function() rhttpRedirectError, required TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - ) - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2) + rhttpStatusCodeError, required TResult Function(String field0) rhttpInvalidCertificateError, required TResult Function(String field0) rhttpConnectionError, required TResult Function(String field0) rhttpUnknownError, @@ -785,11 +737,8 @@ class _$RhttpError_RhttpStatusCodeErrorImpl TResult? Function()? rhttpTimeoutError, TResult? Function()? rhttpRedirectError, TResult? Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult? Function(String field0)? rhttpInvalidCertificateError, TResult? Function(String field0)? rhttpConnectionError, TResult? Function(String field0)? rhttpUnknownError, @@ -804,11 +753,8 @@ class _$RhttpError_RhttpStatusCodeErrorImpl TResult Function()? rhttpTimeoutError, TResult Function()? rhttpRedirectError, TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult Function(String field0)? rhttpInvalidCertificateError, TResult Function(String field0)? rhttpConnectionError, TResult Function(String field0)? rhttpUnknownError, @@ -824,19 +770,19 @@ class _$RhttpError_RhttpStatusCodeErrorImpl @optionalTypeArgs TResult map({ required TResult Function(RhttpError_RhttpCancelError value) - rhttpCancelError, + rhttpCancelError, required TResult Function(RhttpError_RhttpTimeoutError value) - rhttpTimeoutError, + rhttpTimeoutError, required TResult Function(RhttpError_RhttpRedirectError value) - rhttpRedirectError, + rhttpRedirectError, required TResult Function(RhttpError_RhttpStatusCodeError value) - rhttpStatusCodeError, + rhttpStatusCodeError, required TResult Function(RhttpError_RhttpInvalidCertificateError value) - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, required TResult Function(RhttpError_RhttpConnectionError value) - rhttpConnectionError, + rhttpConnectionError, required TResult Function(RhttpError_RhttpUnknownError value) - rhttpUnknownError, + rhttpUnknownError, }) { return rhttpStatusCodeError(this); } @@ -848,11 +794,11 @@ class _$RhttpError_RhttpStatusCodeErrorImpl TResult? Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult? Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult? Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult? Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult? Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult? Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, }) { return rhttpStatusCodeError?.call(this); @@ -865,11 +811,11 @@ class _$RhttpError_RhttpStatusCodeErrorImpl TResult Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, required TResult orElse(), }) { @@ -882,10 +828,9 @@ class _$RhttpError_RhttpStatusCodeErrorImpl abstract class RhttpError_RhttpStatusCodeError extends RhttpError { const factory RhttpError_RhttpStatusCodeError( - final int field0, - final List<(String, String)> field1, - final HttpResponseBody field2, - ) = _$RhttpError_RhttpStatusCodeErrorImpl; + final int field0, + final List<(String, String)> field1, + final HttpResponseBody field2) = _$RhttpError_RhttpStatusCodeErrorImpl; const RhttpError_RhttpStatusCodeError._() : super._(); int get field0; @@ -896,47 +841,43 @@ abstract class RhttpError_RhttpStatusCodeError extends RhttpError { /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) _$$RhttpError_RhttpStatusCodeErrorImplCopyWith< - _$RhttpError_RhttpStatusCodeErrorImpl - > - get copyWith => throw _privateConstructorUsedError; + _$RhttpError_RhttpStatusCodeErrorImpl> + get copyWith => throw _privateConstructorUsedError; } /// @nodoc abstract class _$$RhttpError_RhttpInvalidCertificateErrorImplCopyWith<$Res> { factory _$$RhttpError_RhttpInvalidCertificateErrorImplCopyWith( - _$RhttpError_RhttpInvalidCertificateErrorImpl value, - $Res Function(_$RhttpError_RhttpInvalidCertificateErrorImpl) then, - ) = __$$RhttpError_RhttpInvalidCertificateErrorImplCopyWithImpl<$Res>; + _$RhttpError_RhttpInvalidCertificateErrorImpl value, + $Res Function(_$RhttpError_RhttpInvalidCertificateErrorImpl) then) = + __$$RhttpError_RhttpInvalidCertificateErrorImplCopyWithImpl<$Res>; @useResult $Res call({String field0}); } /// @nodoc class __$$RhttpError_RhttpInvalidCertificateErrorImplCopyWithImpl<$Res> - extends - _$RhttpErrorCopyWithImpl< - $Res, - _$RhttpError_RhttpInvalidCertificateErrorImpl - > + extends _$RhttpErrorCopyWithImpl<$Res, + _$RhttpError_RhttpInvalidCertificateErrorImpl> implements _$$RhttpError_RhttpInvalidCertificateErrorImplCopyWith<$Res> { __$$RhttpError_RhttpInvalidCertificateErrorImplCopyWithImpl( - _$RhttpError_RhttpInvalidCertificateErrorImpl _value, - $Res Function(_$RhttpError_RhttpInvalidCertificateErrorImpl) _then, - ) : super(_value, _then); + _$RhttpError_RhttpInvalidCertificateErrorImpl _value, + $Res Function(_$RhttpError_RhttpInvalidCertificateErrorImpl) _then) + : super(_value, _then); /// Create a copy of RhttpError /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({Object? field0 = null}) { - return _then( - _$RhttpError_RhttpInvalidCertificateErrorImpl( - null == field0 - ? _value.field0 - : field0 // ignore: cast_nullable_to_non_nullable - as String, - ), - ); + $Res call({ + Object? field0 = null, + }) { + return _then(_$RhttpError_RhttpInvalidCertificateErrorImpl( + null == field0 + ? _value.field0 + : field0 // ignore: cast_nullable_to_non_nullable + as String, + )); } } @@ -971,11 +912,10 @@ class _$RhttpError_RhttpInvalidCertificateErrorImpl @override @pragma('vm:prefer-inline') _$$RhttpError_RhttpInvalidCertificateErrorImplCopyWith< - _$RhttpError_RhttpInvalidCertificateErrorImpl - > - get copyWith => __$$RhttpError_RhttpInvalidCertificateErrorImplCopyWithImpl< - _$RhttpError_RhttpInvalidCertificateErrorImpl - >(this, _$identity); + _$RhttpError_RhttpInvalidCertificateErrorImpl> + get copyWith => + __$$RhttpError_RhttpInvalidCertificateErrorImplCopyWithImpl< + _$RhttpError_RhttpInvalidCertificateErrorImpl>(this, _$identity); @override @optionalTypeArgs @@ -984,11 +924,8 @@ class _$RhttpError_RhttpInvalidCertificateErrorImpl required TResult Function() rhttpTimeoutError, required TResult Function() rhttpRedirectError, required TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - ) - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2) + rhttpStatusCodeError, required TResult Function(String field0) rhttpInvalidCertificateError, required TResult Function(String field0) rhttpConnectionError, required TResult Function(String field0) rhttpUnknownError, @@ -1003,11 +940,8 @@ class _$RhttpError_RhttpInvalidCertificateErrorImpl TResult? Function()? rhttpTimeoutError, TResult? Function()? rhttpRedirectError, TResult? Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult? Function(String field0)? rhttpInvalidCertificateError, TResult? Function(String field0)? rhttpConnectionError, TResult? Function(String field0)? rhttpUnknownError, @@ -1022,11 +956,8 @@ class _$RhttpError_RhttpInvalidCertificateErrorImpl TResult Function()? rhttpTimeoutError, TResult Function()? rhttpRedirectError, TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult Function(String field0)? rhttpInvalidCertificateError, TResult Function(String field0)? rhttpConnectionError, TResult Function(String field0)? rhttpUnknownError, @@ -1042,19 +973,19 @@ class _$RhttpError_RhttpInvalidCertificateErrorImpl @optionalTypeArgs TResult map({ required TResult Function(RhttpError_RhttpCancelError value) - rhttpCancelError, + rhttpCancelError, required TResult Function(RhttpError_RhttpTimeoutError value) - rhttpTimeoutError, + rhttpTimeoutError, required TResult Function(RhttpError_RhttpRedirectError value) - rhttpRedirectError, + rhttpRedirectError, required TResult Function(RhttpError_RhttpStatusCodeError value) - rhttpStatusCodeError, + rhttpStatusCodeError, required TResult Function(RhttpError_RhttpInvalidCertificateError value) - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, required TResult Function(RhttpError_RhttpConnectionError value) - rhttpConnectionError, + rhttpConnectionError, required TResult Function(RhttpError_RhttpUnknownError value) - rhttpUnknownError, + rhttpUnknownError, }) { return rhttpInvalidCertificateError(this); } @@ -1066,11 +997,11 @@ class _$RhttpError_RhttpInvalidCertificateErrorImpl TResult? Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult? Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult? Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult? Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult? Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult? Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, }) { return rhttpInvalidCertificateError?.call(this); @@ -1083,11 +1014,11 @@ class _$RhttpError_RhttpInvalidCertificateErrorImpl TResult Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, required TResult orElse(), }) { @@ -1109,44 +1040,43 @@ abstract class RhttpError_RhttpInvalidCertificateError extends RhttpError { /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) _$$RhttpError_RhttpInvalidCertificateErrorImplCopyWith< - _$RhttpError_RhttpInvalidCertificateErrorImpl - > - get copyWith => throw _privateConstructorUsedError; + _$RhttpError_RhttpInvalidCertificateErrorImpl> + get copyWith => throw _privateConstructorUsedError; } /// @nodoc abstract class _$$RhttpError_RhttpConnectionErrorImplCopyWith<$Res> { factory _$$RhttpError_RhttpConnectionErrorImplCopyWith( - _$RhttpError_RhttpConnectionErrorImpl value, - $Res Function(_$RhttpError_RhttpConnectionErrorImpl) then, - ) = __$$RhttpError_RhttpConnectionErrorImplCopyWithImpl<$Res>; + _$RhttpError_RhttpConnectionErrorImpl value, + $Res Function(_$RhttpError_RhttpConnectionErrorImpl) then) = + __$$RhttpError_RhttpConnectionErrorImplCopyWithImpl<$Res>; @useResult $Res call({String field0}); } /// @nodoc class __$$RhttpError_RhttpConnectionErrorImplCopyWithImpl<$Res> - extends - _$RhttpErrorCopyWithImpl<$Res, _$RhttpError_RhttpConnectionErrorImpl> + extends _$RhttpErrorCopyWithImpl<$Res, + _$RhttpError_RhttpConnectionErrorImpl> implements _$$RhttpError_RhttpConnectionErrorImplCopyWith<$Res> { __$$RhttpError_RhttpConnectionErrorImplCopyWithImpl( - _$RhttpError_RhttpConnectionErrorImpl _value, - $Res Function(_$RhttpError_RhttpConnectionErrorImpl) _then, - ) : super(_value, _then); + _$RhttpError_RhttpConnectionErrorImpl _value, + $Res Function(_$RhttpError_RhttpConnectionErrorImpl) _then) + : super(_value, _then); /// Create a copy of RhttpError /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({Object? field0 = null}) { - return _then( - _$RhttpError_RhttpConnectionErrorImpl( - null == field0 - ? _value.field0 - : field0 // ignore: cast_nullable_to_non_nullable - as String, - ), - ); + $Res call({ + Object? field0 = null, + }) { + return _then(_$RhttpError_RhttpConnectionErrorImpl( + null == field0 + ? _value.field0 + : field0 // ignore: cast_nullable_to_non_nullable + as String, + )); } } @@ -1181,11 +1111,9 @@ class _$RhttpError_RhttpConnectionErrorImpl @override @pragma('vm:prefer-inline') _$$RhttpError_RhttpConnectionErrorImplCopyWith< - _$RhttpError_RhttpConnectionErrorImpl - > - get copyWith => __$$RhttpError_RhttpConnectionErrorImplCopyWithImpl< - _$RhttpError_RhttpConnectionErrorImpl - >(this, _$identity); + _$RhttpError_RhttpConnectionErrorImpl> + get copyWith => __$$RhttpError_RhttpConnectionErrorImplCopyWithImpl< + _$RhttpError_RhttpConnectionErrorImpl>(this, _$identity); @override @optionalTypeArgs @@ -1194,11 +1122,8 @@ class _$RhttpError_RhttpConnectionErrorImpl required TResult Function() rhttpTimeoutError, required TResult Function() rhttpRedirectError, required TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - ) - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2) + rhttpStatusCodeError, required TResult Function(String field0) rhttpInvalidCertificateError, required TResult Function(String field0) rhttpConnectionError, required TResult Function(String field0) rhttpUnknownError, @@ -1213,11 +1138,8 @@ class _$RhttpError_RhttpConnectionErrorImpl TResult? Function()? rhttpTimeoutError, TResult? Function()? rhttpRedirectError, TResult? Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult? Function(String field0)? rhttpInvalidCertificateError, TResult? Function(String field0)? rhttpConnectionError, TResult? Function(String field0)? rhttpUnknownError, @@ -1232,11 +1154,8 @@ class _$RhttpError_RhttpConnectionErrorImpl TResult Function()? rhttpTimeoutError, TResult Function()? rhttpRedirectError, TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult Function(String field0)? rhttpInvalidCertificateError, TResult Function(String field0)? rhttpConnectionError, TResult Function(String field0)? rhttpUnknownError, @@ -1252,19 +1171,19 @@ class _$RhttpError_RhttpConnectionErrorImpl @optionalTypeArgs TResult map({ required TResult Function(RhttpError_RhttpCancelError value) - rhttpCancelError, + rhttpCancelError, required TResult Function(RhttpError_RhttpTimeoutError value) - rhttpTimeoutError, + rhttpTimeoutError, required TResult Function(RhttpError_RhttpRedirectError value) - rhttpRedirectError, + rhttpRedirectError, required TResult Function(RhttpError_RhttpStatusCodeError value) - rhttpStatusCodeError, + rhttpStatusCodeError, required TResult Function(RhttpError_RhttpInvalidCertificateError value) - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, required TResult Function(RhttpError_RhttpConnectionError value) - rhttpConnectionError, + rhttpConnectionError, required TResult Function(RhttpError_RhttpUnknownError value) - rhttpUnknownError, + rhttpUnknownError, }) { return rhttpConnectionError(this); } @@ -1276,11 +1195,11 @@ class _$RhttpError_RhttpConnectionErrorImpl TResult? Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult? Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult? Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult? Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult? Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult? Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, }) { return rhttpConnectionError?.call(this); @@ -1293,11 +1212,11 @@ class _$RhttpError_RhttpConnectionErrorImpl TResult Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, required TResult orElse(), }) { @@ -1319,17 +1238,16 @@ abstract class RhttpError_RhttpConnectionError extends RhttpError { /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) _$$RhttpError_RhttpConnectionErrorImplCopyWith< - _$RhttpError_RhttpConnectionErrorImpl - > - get copyWith => throw _privateConstructorUsedError; + _$RhttpError_RhttpConnectionErrorImpl> + get copyWith => throw _privateConstructorUsedError; } /// @nodoc abstract class _$$RhttpError_RhttpUnknownErrorImplCopyWith<$Res> { factory _$$RhttpError_RhttpUnknownErrorImplCopyWith( - _$RhttpError_RhttpUnknownErrorImpl value, - $Res Function(_$RhttpError_RhttpUnknownErrorImpl) then, - ) = __$$RhttpError_RhttpUnknownErrorImplCopyWithImpl<$Res>; + _$RhttpError_RhttpUnknownErrorImpl value, + $Res Function(_$RhttpError_RhttpUnknownErrorImpl) then) = + __$$RhttpError_RhttpUnknownErrorImplCopyWithImpl<$Res>; @useResult $Res call({String field0}); } @@ -1339,23 +1257,23 @@ class __$$RhttpError_RhttpUnknownErrorImplCopyWithImpl<$Res> extends _$RhttpErrorCopyWithImpl<$Res, _$RhttpError_RhttpUnknownErrorImpl> implements _$$RhttpError_RhttpUnknownErrorImplCopyWith<$Res> { __$$RhttpError_RhttpUnknownErrorImplCopyWithImpl( - _$RhttpError_RhttpUnknownErrorImpl _value, - $Res Function(_$RhttpError_RhttpUnknownErrorImpl) _then, - ) : super(_value, _then); + _$RhttpError_RhttpUnknownErrorImpl _value, + $Res Function(_$RhttpError_RhttpUnknownErrorImpl) _then) + : super(_value, _then); /// Create a copy of RhttpError /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({Object? field0 = null}) { - return _then( - _$RhttpError_RhttpUnknownErrorImpl( - null == field0 - ? _value.field0 - : field0 // ignore: cast_nullable_to_non_nullable - as String, - ), - ); + $Res call({ + Object? field0 = null, + }) { + return _then(_$RhttpError_RhttpUnknownErrorImpl( + null == field0 + ? _value.field0 + : field0 // ignore: cast_nullable_to_non_nullable + as String, + )); } } @@ -1389,11 +1307,9 @@ class _$RhttpError_RhttpUnknownErrorImpl extends RhttpError_RhttpUnknownError { @override @pragma('vm:prefer-inline') _$$RhttpError_RhttpUnknownErrorImplCopyWith< - _$RhttpError_RhttpUnknownErrorImpl - > - get copyWith => __$$RhttpError_RhttpUnknownErrorImplCopyWithImpl< - _$RhttpError_RhttpUnknownErrorImpl - >(this, _$identity); + _$RhttpError_RhttpUnknownErrorImpl> + get copyWith => __$$RhttpError_RhttpUnknownErrorImplCopyWithImpl< + _$RhttpError_RhttpUnknownErrorImpl>(this, _$identity); @override @optionalTypeArgs @@ -1402,11 +1318,8 @@ class _$RhttpError_RhttpUnknownErrorImpl extends RhttpError_RhttpUnknownError { required TResult Function() rhttpTimeoutError, required TResult Function() rhttpRedirectError, required TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - ) - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2) + rhttpStatusCodeError, required TResult Function(String field0) rhttpInvalidCertificateError, required TResult Function(String field0) rhttpConnectionError, required TResult Function(String field0) rhttpUnknownError, @@ -1421,11 +1334,8 @@ class _$RhttpError_RhttpUnknownErrorImpl extends RhttpError_RhttpUnknownError { TResult? Function()? rhttpTimeoutError, TResult? Function()? rhttpRedirectError, TResult? Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult? Function(String field0)? rhttpInvalidCertificateError, TResult? Function(String field0)? rhttpConnectionError, TResult? Function(String field0)? rhttpUnknownError, @@ -1440,11 +1350,8 @@ class _$RhttpError_RhttpUnknownErrorImpl extends RhttpError_RhttpUnknownError { TResult Function()? rhttpTimeoutError, TResult Function()? rhttpRedirectError, TResult Function( - int field0, - List<(String, String)> field1, - HttpResponseBody field2, - )? - rhttpStatusCodeError, + int field0, List<(String, String)> field1, HttpResponseBody field2)? + rhttpStatusCodeError, TResult Function(String field0)? rhttpInvalidCertificateError, TResult Function(String field0)? rhttpConnectionError, TResult Function(String field0)? rhttpUnknownError, @@ -1460,19 +1367,19 @@ class _$RhttpError_RhttpUnknownErrorImpl extends RhttpError_RhttpUnknownError { @optionalTypeArgs TResult map({ required TResult Function(RhttpError_RhttpCancelError value) - rhttpCancelError, + rhttpCancelError, required TResult Function(RhttpError_RhttpTimeoutError value) - rhttpTimeoutError, + rhttpTimeoutError, required TResult Function(RhttpError_RhttpRedirectError value) - rhttpRedirectError, + rhttpRedirectError, required TResult Function(RhttpError_RhttpStatusCodeError value) - rhttpStatusCodeError, + rhttpStatusCodeError, required TResult Function(RhttpError_RhttpInvalidCertificateError value) - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, required TResult Function(RhttpError_RhttpConnectionError value) - rhttpConnectionError, + rhttpConnectionError, required TResult Function(RhttpError_RhttpUnknownError value) - rhttpUnknownError, + rhttpUnknownError, }) { return rhttpUnknownError(this); } @@ -1484,11 +1391,11 @@ class _$RhttpError_RhttpUnknownErrorImpl extends RhttpError_RhttpUnknownError { TResult? Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult? Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult? Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult? Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult? Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult? Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, }) { return rhttpUnknownError?.call(this); @@ -1501,11 +1408,11 @@ class _$RhttpError_RhttpUnknownErrorImpl extends RhttpError_RhttpUnknownError { TResult Function(RhttpError_RhttpTimeoutError value)? rhttpTimeoutError, TResult Function(RhttpError_RhttpRedirectError value)? rhttpRedirectError, TResult Function(RhttpError_RhttpStatusCodeError value)? - rhttpStatusCodeError, + rhttpStatusCodeError, TResult Function(RhttpError_RhttpInvalidCertificateError value)? - rhttpInvalidCertificateError, + rhttpInvalidCertificateError, TResult Function(RhttpError_RhttpConnectionError value)? - rhttpConnectionError, + rhttpConnectionError, TResult Function(RhttpError_RhttpUnknownError value)? rhttpUnknownError, required TResult orElse(), }) { @@ -1527,7 +1434,6 @@ abstract class RhttpError_RhttpUnknownError extends RhttpError { /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) _$$RhttpError_RhttpUnknownErrorImplCopyWith< - _$RhttpError_RhttpUnknownErrorImpl - > - get copyWith => throw _privateConstructorUsedError; + _$RhttpError_RhttpUnknownErrorImpl> + get copyWith => throw _privateConstructorUsedError; } diff --git a/lib/src/rust/api/rhttp/http.freezed.dart b/lib/src/rust/api/rhttp/http.freezed.dart index 805408bb..d6941458 100644 --- a/lib/src/rust/api/rhttp/http.freezed.dart +++ b/lib/src/rust/api/rhttp/http.freezed.dart @@ -12,8 +12,7 @@ part of 'http.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', -); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); /// @nodoc mixin _$HttpHeaders { @@ -22,42 +21,47 @@ mixin _$HttpHeaders { TResult when({ required TResult Function(Map field0) map, required TResult Function(List<(String, String)> field0) list, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ TResult? Function(Map field0)? map, TResult? Function(List<(String, String)> field0)? list, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function(Map field0)? map, TResult Function(List<(String, String)> field0)? list, required TResult orElse(), - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult map({ required TResult Function(HttpHeaders_Map value) map, required TResult Function(HttpHeaders_List value) list, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult? mapOrNull({ TResult? Function(HttpHeaders_Map value)? map, TResult? Function(HttpHeaders_List value)? list, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeMap({ TResult Function(HttpHeaders_Map value)? map, TResult Function(HttpHeaders_List value)? list, required TResult orElse(), - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; } /// @nodoc abstract class $HttpHeadersCopyWith<$Res> { factory $HttpHeadersCopyWith( - HttpHeaders value, - $Res Function(HttpHeaders) then, - ) = _$HttpHeadersCopyWithImpl<$Res, HttpHeaders>; + HttpHeaders value, $Res Function(HttpHeaders) then) = + _$HttpHeadersCopyWithImpl<$Res, HttpHeaders>; } /// @nodoc @@ -76,10 +80,9 @@ class _$HttpHeadersCopyWithImpl<$Res, $Val extends HttpHeaders> /// @nodoc abstract class _$$HttpHeaders_MapImplCopyWith<$Res> { - factory _$$HttpHeaders_MapImplCopyWith( - _$HttpHeaders_MapImpl value, - $Res Function(_$HttpHeaders_MapImpl) then, - ) = __$$HttpHeaders_MapImplCopyWithImpl<$Res>; + factory _$$HttpHeaders_MapImplCopyWith(_$HttpHeaders_MapImpl value, + $Res Function(_$HttpHeaders_MapImpl) then) = + __$$HttpHeaders_MapImplCopyWithImpl<$Res>; @useResult $Res call({Map field0}); } @@ -89,23 +92,22 @@ class __$$HttpHeaders_MapImplCopyWithImpl<$Res> extends _$HttpHeadersCopyWithImpl<$Res, _$HttpHeaders_MapImpl> implements _$$HttpHeaders_MapImplCopyWith<$Res> { __$$HttpHeaders_MapImplCopyWithImpl( - _$HttpHeaders_MapImpl _value, - $Res Function(_$HttpHeaders_MapImpl) _then, - ) : super(_value, _then); + _$HttpHeaders_MapImpl _value, $Res Function(_$HttpHeaders_MapImpl) _then) + : super(_value, _then); /// Create a copy of HttpHeaders /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({Object? field0 = null}) { - return _then( - _$HttpHeaders_MapImpl( - null == field0 - ? _value._field0 - : field0 // ignore: cast_nullable_to_non_nullable - as Map, - ), - ); + $Res call({ + Object? field0 = null, + }) { + return _then(_$HttpHeaders_MapImpl( + null == field0 + ? _value._field0 + : field0 // ignore: cast_nullable_to_non_nullable + as Map, + )); } } @@ -113,8 +115,8 @@ class __$$HttpHeaders_MapImplCopyWithImpl<$Res> class _$HttpHeaders_MapImpl extends HttpHeaders_Map { const _$HttpHeaders_MapImpl(final Map field0) - : _field0 = field0, - super._(); + : _field0 = field0, + super._(); final Map _field0; @override @@ -148,9 +150,7 @@ class _$HttpHeaders_MapImpl extends HttpHeaders_Map { @pragma('vm:prefer-inline') _$$HttpHeaders_MapImplCopyWith<_$HttpHeaders_MapImpl> get copyWith => __$$HttpHeaders_MapImplCopyWithImpl<_$HttpHeaders_MapImpl>( - this, - _$identity, - ); + this, _$identity); @override @optionalTypeArgs @@ -232,10 +232,9 @@ abstract class HttpHeaders_Map extends HttpHeaders { /// @nodoc abstract class _$$HttpHeaders_ListImplCopyWith<$Res> { - factory _$$HttpHeaders_ListImplCopyWith( - _$HttpHeaders_ListImpl value, - $Res Function(_$HttpHeaders_ListImpl) then, - ) = __$$HttpHeaders_ListImplCopyWithImpl<$Res>; + factory _$$HttpHeaders_ListImplCopyWith(_$HttpHeaders_ListImpl value, + $Res Function(_$HttpHeaders_ListImpl) then) = + __$$HttpHeaders_ListImplCopyWithImpl<$Res>; @useResult $Res call({List<(String, String)> field0}); } @@ -244,24 +243,23 @@ abstract class _$$HttpHeaders_ListImplCopyWith<$Res> { class __$$HttpHeaders_ListImplCopyWithImpl<$Res> extends _$HttpHeadersCopyWithImpl<$Res, _$HttpHeaders_ListImpl> implements _$$HttpHeaders_ListImplCopyWith<$Res> { - __$$HttpHeaders_ListImplCopyWithImpl( - _$HttpHeaders_ListImpl _value, - $Res Function(_$HttpHeaders_ListImpl) _then, - ) : super(_value, _then); + __$$HttpHeaders_ListImplCopyWithImpl(_$HttpHeaders_ListImpl _value, + $Res Function(_$HttpHeaders_ListImpl) _then) + : super(_value, _then); /// Create a copy of HttpHeaders /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({Object? field0 = null}) { - return _then( - _$HttpHeaders_ListImpl( - null == field0 - ? _value._field0 - : field0 // ignore: cast_nullable_to_non_nullable - as List<(String, String)>, - ), - ); + $Res call({ + Object? field0 = null, + }) { + return _then(_$HttpHeaders_ListImpl( + null == field0 + ? _value._field0 + : field0 // ignore: cast_nullable_to_non_nullable + as List<(String, String)>, + )); } } @@ -269,8 +267,8 @@ class __$$HttpHeaders_ListImplCopyWithImpl<$Res> class _$HttpHeaders_ListImpl extends HttpHeaders_List { const _$HttpHeaders_ListImpl(final List<(String, String)> field0) - : _field0 = field0, - super._(); + : _field0 = field0, + super._(); final List<(String, String)> _field0; @override @@ -304,9 +302,7 @@ class _$HttpHeaders_ListImpl extends HttpHeaders_List { @pragma('vm:prefer-inline') _$$HttpHeaders_ListImplCopyWith<_$HttpHeaders_ListImpl> get copyWith => __$$HttpHeaders_ListImplCopyWithImpl<_$HttpHeaders_ListImpl>( - this, - _$identity, - ); + this, _$identity); @override @optionalTypeArgs @@ -393,47 +389,52 @@ mixin _$HttpResponseBody { required TResult Function(String field0) text, required TResult Function(Uint8List field0) bytes, required TResult Function() stream, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ TResult? Function(String field0)? text, TResult? Function(Uint8List field0)? bytes, TResult? Function()? stream, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function(String field0)? text, TResult Function(Uint8List field0)? bytes, TResult Function()? stream, required TResult orElse(), - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult map({ required TResult Function(HttpResponseBody_Text value) text, required TResult Function(HttpResponseBody_Bytes value) bytes, required TResult Function(HttpResponseBody_Stream value) stream, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult? mapOrNull({ TResult? Function(HttpResponseBody_Text value)? text, TResult? Function(HttpResponseBody_Bytes value)? bytes, TResult? Function(HttpResponseBody_Stream value)? stream, - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeMap({ TResult Function(HttpResponseBody_Text value)? text, TResult Function(HttpResponseBody_Bytes value)? bytes, TResult Function(HttpResponseBody_Stream value)? stream, required TResult orElse(), - }) => throw _privateConstructorUsedError; + }) => + throw _privateConstructorUsedError; } /// @nodoc abstract class $HttpResponseBodyCopyWith<$Res> { factory $HttpResponseBodyCopyWith( - HttpResponseBody value, - $Res Function(HttpResponseBody) then, - ) = _$HttpResponseBodyCopyWithImpl<$Res, HttpResponseBody>; + HttpResponseBody value, $Res Function(HttpResponseBody) then) = + _$HttpResponseBodyCopyWithImpl<$Res, HttpResponseBody>; } /// @nodoc @@ -453,9 +454,9 @@ class _$HttpResponseBodyCopyWithImpl<$Res, $Val extends HttpResponseBody> /// @nodoc abstract class _$$HttpResponseBody_TextImplCopyWith<$Res> { factory _$$HttpResponseBody_TextImplCopyWith( - _$HttpResponseBody_TextImpl value, - $Res Function(_$HttpResponseBody_TextImpl) then, - ) = __$$HttpResponseBody_TextImplCopyWithImpl<$Res>; + _$HttpResponseBody_TextImpl value, + $Res Function(_$HttpResponseBody_TextImpl) then) = + __$$HttpResponseBody_TextImplCopyWithImpl<$Res>; @useResult $Res call({String field0}); } @@ -464,24 +465,23 @@ abstract class _$$HttpResponseBody_TextImplCopyWith<$Res> { class __$$HttpResponseBody_TextImplCopyWithImpl<$Res> extends _$HttpResponseBodyCopyWithImpl<$Res, _$HttpResponseBody_TextImpl> implements _$$HttpResponseBody_TextImplCopyWith<$Res> { - __$$HttpResponseBody_TextImplCopyWithImpl( - _$HttpResponseBody_TextImpl _value, - $Res Function(_$HttpResponseBody_TextImpl) _then, - ) : super(_value, _then); + __$$HttpResponseBody_TextImplCopyWithImpl(_$HttpResponseBody_TextImpl _value, + $Res Function(_$HttpResponseBody_TextImpl) _then) + : super(_value, _then); /// Create a copy of HttpResponseBody /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({Object? field0 = null}) { - return _then( - _$HttpResponseBody_TextImpl( - null == field0 - ? _value.field0 - : field0 // ignore: cast_nullable_to_non_nullable - as String, - ), - ); + $Res call({ + Object? field0 = null, + }) { + return _then(_$HttpResponseBody_TextImpl( + null == field0 + ? _value.field0 + : field0 // ignore: cast_nullable_to_non_nullable + as String, + )); } } @@ -515,11 +515,8 @@ class _$HttpResponseBody_TextImpl extends HttpResponseBody_Text { @override @pragma('vm:prefer-inline') _$$HttpResponseBody_TextImplCopyWith<_$HttpResponseBody_TextImpl> - get copyWith => - __$$HttpResponseBody_TextImplCopyWithImpl<_$HttpResponseBody_TextImpl>( - this, - _$identity, - ); + get copyWith => __$$HttpResponseBody_TextImplCopyWithImpl< + _$HttpResponseBody_TextImpl>(this, _$identity); @override @optionalTypeArgs @@ -601,15 +598,15 @@ abstract class HttpResponseBody_Text extends HttpResponseBody { /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) _$$HttpResponseBody_TextImplCopyWith<_$HttpResponseBody_TextImpl> - get copyWith => throw _privateConstructorUsedError; + get copyWith => throw _privateConstructorUsedError; } /// @nodoc abstract class _$$HttpResponseBody_BytesImplCopyWith<$Res> { factory _$$HttpResponseBody_BytesImplCopyWith( - _$HttpResponseBody_BytesImpl value, - $Res Function(_$HttpResponseBody_BytesImpl) then, - ) = __$$HttpResponseBody_BytesImplCopyWithImpl<$Res>; + _$HttpResponseBody_BytesImpl value, + $Res Function(_$HttpResponseBody_BytesImpl) then) = + __$$HttpResponseBody_BytesImplCopyWithImpl<$Res>; @useResult $Res call({Uint8List field0}); } @@ -619,23 +616,23 @@ class __$$HttpResponseBody_BytesImplCopyWithImpl<$Res> extends _$HttpResponseBodyCopyWithImpl<$Res, _$HttpResponseBody_BytesImpl> implements _$$HttpResponseBody_BytesImplCopyWith<$Res> { __$$HttpResponseBody_BytesImplCopyWithImpl( - _$HttpResponseBody_BytesImpl _value, - $Res Function(_$HttpResponseBody_BytesImpl) _then, - ) : super(_value, _then); + _$HttpResponseBody_BytesImpl _value, + $Res Function(_$HttpResponseBody_BytesImpl) _then) + : super(_value, _then); /// Create a copy of HttpResponseBody /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({Object? field0 = null}) { - return _then( - _$HttpResponseBody_BytesImpl( - null == field0 - ? _value.field0 - : field0 // ignore: cast_nullable_to_non_nullable - as Uint8List, - ), - ); + $Res call({ + Object? field0 = null, + }) { + return _then(_$HttpResponseBody_BytesImpl( + null == field0 + ? _value.field0 + : field0 // ignore: cast_nullable_to_non_nullable + as Uint8List, + )); } } @@ -670,11 +667,8 @@ class _$HttpResponseBody_BytesImpl extends HttpResponseBody_Bytes { @override @pragma('vm:prefer-inline') _$$HttpResponseBody_BytesImplCopyWith<_$HttpResponseBody_BytesImpl> - get copyWith => - __$$HttpResponseBody_BytesImplCopyWithImpl<_$HttpResponseBody_BytesImpl>( - this, - _$identity, - ); + get copyWith => __$$HttpResponseBody_BytesImplCopyWithImpl< + _$HttpResponseBody_BytesImpl>(this, _$identity); @override @optionalTypeArgs @@ -756,15 +750,15 @@ abstract class HttpResponseBody_Bytes extends HttpResponseBody { /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) _$$HttpResponseBody_BytesImplCopyWith<_$HttpResponseBody_BytesImpl> - get copyWith => throw _privateConstructorUsedError; + get copyWith => throw _privateConstructorUsedError; } /// @nodoc abstract class _$$HttpResponseBody_StreamImplCopyWith<$Res> { factory _$$HttpResponseBody_StreamImplCopyWith( - _$HttpResponseBody_StreamImpl value, - $Res Function(_$HttpResponseBody_StreamImpl) then, - ) = __$$HttpResponseBody_StreamImplCopyWithImpl<$Res>; + _$HttpResponseBody_StreamImpl value, + $Res Function(_$HttpResponseBody_StreamImpl) then) = + __$$HttpResponseBody_StreamImplCopyWithImpl<$Res>; } /// @nodoc @@ -772,9 +766,9 @@ class __$$HttpResponseBody_StreamImplCopyWithImpl<$Res> extends _$HttpResponseBodyCopyWithImpl<$Res, _$HttpResponseBody_StreamImpl> implements _$$HttpResponseBody_StreamImplCopyWith<$Res> { __$$HttpResponseBody_StreamImplCopyWithImpl( - _$HttpResponseBody_StreamImpl _value, - $Res Function(_$HttpResponseBody_StreamImpl) _then, - ) : super(_value, _then); + _$HttpResponseBody_StreamImpl _value, + $Res Function(_$HttpResponseBody_StreamImpl) _then) + : super(_value, _then); /// Create a copy of HttpResponseBody /// with the given fields replaced by the non-null parameter values. diff --git a/lib/utils/cached_network.dart b/lib/utils/cached_network.dart index 0b5e5ab4..80de1443 100644 --- a/lib/utils/cached_network.dart +++ b/lib/utils/cached_network.dart @@ -31,3 +31,37 @@ Widget cachedNetworkImage({ }, ); } + +Widget cachedCompressedNetworkImage({ + Map? headers, + required String imageUrl, + required double? width, + required double? height, + required BoxFit? fit, + AlignmentGeometry? alignment, + bool useCustomNetworkImage = true, + Widget errorWidget = const Icon(Icons.error, size: 50), + int maxBytes = 5 << 10, +}) { + return ExtendedImage( + image: ExtendedResizeImage( + useCustomNetworkImage + ? CustomExtendedNetworkImageProvider(imageUrl, headers: headers) + : ExtendedNetworkImageProvider(imageUrl, headers: headers), + maxBytes: maxBytes, + ), + width: width, + height: height, + fit: fit, + filterQuality: FilterQuality.medium, + mode: ExtendedImageMode.gesture, + handleLoadingProgress: true, + clearMemoryCacheWhenDispose: true, + loadStateChanged: (state) { + if (state.extendedImageLoadState == LoadState.failed) { + return errorWidget; + } + return null; + }, + ); +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 43b375ce..2190c4d4 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,6 +9,7 @@ import app_links import audio_session import connectivity_plus import device_info_plus +import file_picker import flutter_inappwebview_macos import flutter_qjs import flutter_web_auth_2 @@ -35,6 +36,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) FlutterQjsPlugin.register(with: registry.registrar(forPlugin: "FlutterQjsPlugin")) FlutterWebAuth2Plugin.register(with: registry.registrar(forPlugin: "FlutterWebAuth2Plugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 654e52a2..8f7e352f 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -7,6 +7,8 @@ PODS: - FlutterMacOS - device_info_plus (0.0.1): - FlutterMacOS + - file_picker (0.0.1): + - FlutterMacOS - flutter_inappwebview_macos (0.0.1): - FlutterMacOS - OrderedSet (~> 6.0.3) @@ -63,6 +65,7 @@ DEPENDENCIES: - audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`) - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) + - file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`) - flutter_inappwebview_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos`) - flutter_qjs (from `Flutter/ephemeral/.symlinks/plugins/flutter_qjs/macos`) - flutter_web_auth_2 (from `Flutter/ephemeral/.symlinks/plugins/flutter_web_auth_2/macos`) @@ -99,6 +102,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos device_info_plus: :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos + file_picker: + :path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos flutter_inappwebview_macos: :path: Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos flutter_qjs: @@ -149,6 +154,7 @@ SPEC CHECKSUMS: audio_session: eaca2512cf2b39212d724f35d11f46180ad3a33e connectivity_plus: 4adf20a405e25b42b9c9f87feff8f4b6fde18a4e device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 + file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a flutter_inappwebview_macos: c2d68649f9f8f1831bfcd98d73fd6256366d9d1d flutter_qjs: cb2d0cba9deade1d03b89f6c432eac126f39482a flutter_web_auth_2: 62b08da29f15a20fa63f144234622a1488d45b65 diff --git a/pubspec.lock b/pubspec.lock index 53822118..2d3e1072 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -439,6 +439,13 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.3" + epubx: + dependency: "direct main" + description: + path: epubx + relative: true + source: path + version: "4.0.3" exception_templates: dependency: transitive description: @@ -467,18 +474,18 @@ packages: dependency: "direct main" description: name: extended_image - sha256: "85199f9233e03abc2ce2e68cbb2991648666af4a527ae4e6250935be8edfddae" + sha256: f6cbb1d798f51262ed1a3d93b4f1f2aa0d76128df39af18ecb77fa740f88b2e0 url: "https://pub.dev" source: hosted - version: "9.1.0" + version: "10.0.1" extended_image_library: dependency: transitive description: name: extended_image_library - sha256: e61dafd94400fff6ef7ed1523d445ff3af137f198f3228e4a3107bc5b4bec5d1 + sha256: ae468c31c375064964de11cbb31310a58c4462df6e3bae1a0bc0066f586795d5 url: "https://pub.dev" source: hosted - version: "4.0.6" + version: "5.0.0" fading_edge_scrollview: dependency: transitive description: @@ -523,10 +530,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "16dc141db5a2ccc6520ebb6a2eb5945b1b09e95085c021d9f914f8ded7f1465c" + sha256: "8986dec4581b4bcd4b6df5d75a2ea0bede3db802f500635d05fa8be298f9467f" url: "https://pub.dev" source: hosted - version: "8.1.4" + version: "10.1.2" fixnum: dependency: transitive description: @@ -640,10 +647,10 @@ packages: dependency: "direct dev" description: name: flutter_launcher_icons - sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" + sha256: bfa04787c85d80ecb3f8777bde5fc10c3de809240c48fa061a2c2bf15ea5211c url: "https://pub.dev" source: hosted - version: "0.13.1" + version: "0.14.3" flutter_lints: dependency: "direct dev" description: @@ -937,10 +944,10 @@ packages: dependency: "direct dev" description: name: inno_bundle - sha256: e9d0ab41a82157da42ebd4206bda22ed04bf096a6e7d416c79d79201c388d563 + sha256: "544ca69ce64c5b06b346f328170ae407ca99605beab23ccc779b39acf6ba1c9a" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.9.0" intl: dependency: "direct main" description: @@ -1466,18 +1473,18 @@ packages: dependency: "direct main" description: name: protobuf - sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d" + sha256: fbb0c37d435641d0b84813c1dad41e6fa61ddc880a320bce16b3063ecec35aa6 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.0.0" protoc_plugin: dependency: "direct dev" description: name: protoc_plugin - sha256: fb0554851c9eca30bd18405fbbfe81e39166d4a2f0e5b770606fd69da3da0b2f + sha256: cdec62ff876e61f4421aa7c87373c91db9b1430c748b38fb6d23613356064375 url: "https://pub.dev" source: hosted - version: "21.1.2" + version: "22.0.1" provider: dependency: transitive description: @@ -1530,10 +1537,10 @@ packages: dependency: "direct main" description: name: re_editor - sha256: "2169c114c7877bcaae72d6e8b69cdaa2a9cded69a51e3cf26209dad4a3ed2b9c" + sha256: "17e430f0591dd361992ec2dd6f69191c1853fa46e05432e095310a8f82ee820e" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.7.0" re_highlight: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index ca31d7e8..349293a7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: font_awesome_flutter: ^10.8.0 expandable_text: ^2.3.0 flex_color_scheme: ^8.1.0 - extended_image: ^9.1.0 + extended_image: ^10.0.0 photo_view: ^0.15.0 grouped_list: ^6.0.0 intl: ^0.19.0 @@ -33,7 +33,7 @@ dependencies: share_plus: ^10.0.2 xpath_selector_html_parser: ^3.0.1 archive: ^4.0.1 - file_picker: 8.1.4 + file_picker: ^10.0.0 path_provider: ^2.1.5 scrollable_positioned_list: ^0.3.8 dart_eval: ^0.7.10 @@ -61,7 +61,7 @@ dependencies: url: https://github.com/kodjodevf/flutter_qjs.git ref: main http: ^1.3.0 - re_editor: ^0.6.0 + re_editor: ^0.7.0 re_highlight: ^0.0.3 json_view: ^0.4.2 super_sliver_list: ^0.4.1 @@ -82,10 +82,12 @@ dependencies: connectivity_plus: ^6.1.3 app_links: ^6.4.0 win32: ^5.10.1 - protobuf: ^3.1.0 + protobuf: ^4.0.0 device_info_plus: ^11.3.3 flutter_app_installer: ^1.0.0 marquee: ^2.2.3 + epubx: + path: ./epubx dependency_overrides: ffi: ^2.1.3 @@ -103,12 +105,12 @@ dev_dependencies: sdk: flutter build_runner: ^2.4.6 riverpod_generator: ^2.6.3 - flutter_launcher_icons: ^0.13.1 + flutter_launcher_icons: ^0.14.3 isar_generator: ^3.1.0+1 flutter_lints: ^5.0.0 freezed: ^2.0.0 - inno_bundle: ^0.8.0 - protoc_plugin: ^21.1.2 + inno_bundle: ^0.9.0 + protoc_plugin: ^22.0.1 flutter: uses-material-design: true