Repository: wgh136/pixes
Branch: master
Commit: abf249b941dd
Files: 173
Total size: 679.3 KB
Directory structure:
gitextract_i0cj6x04/
├── .github/
│ └── workflows/
│ └── main.yml
├── .gitignore
├── .metadata
├── .vscode/
│ └── settings.json
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android/
│ ├── .gitignore
│ ├── app/
│ │ ├── build.gradle
│ │ └── src/
│ │ ├── debug/
│ │ │ └── AndroidManifest.xml
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin/
│ │ │ │ └── com/
│ │ │ │ └── github/
│ │ │ │ └── wgh136/
│ │ │ │ └── pixes/
│ │ │ │ └── MainActivity.kt
│ │ │ └── res/
│ │ │ ├── drawable/
│ │ │ │ └── launch_background.xml
│ │ │ ├── drawable-v21/
│ │ │ │ └── launch_background.xml
│ │ │ ├── mipmap-anydpi-v26/
│ │ │ │ └── ic_launcher.xml
│ │ │ ├── values/
│ │ │ │ └── styles.xml
│ │ │ └── values-night/
│ │ │ └── styles.xml
│ │ └── profile/
│ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ └── settings.gradle
├── assets/
│ └── tr.json
├── debian/
│ ├── build.py
│ ├── debian.yaml
│ └── gui/
│ └── pixes.desktop
├── ios/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Podfile
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── LaunchImage.imageset/
│ │ │ ├── Contents.json
│ │ │ └── README.md
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
│ └── RunnerTests/
│ └── RunnerTests.swift
├── lib/
│ ├── appdata.dart
│ ├── components/
│ │ ├── animated_image.dart
│ │ ├── batch_download.dart
│ │ ├── button.dart
│ │ ├── grid.dart
│ │ ├── illust_widget.dart
│ │ ├── keyboard.dart
│ │ ├── loading.dart
│ │ ├── md.dart
│ │ ├── message.dart
│ │ ├── novel.dart
│ │ ├── page_route.dart
│ │ ├── search_field.dart
│ │ ├── segmented_button.dart
│ │ ├── title_bar.dart
│ │ ├── ugoira.dart
│ │ └── user_preview.dart
│ ├── foundation/
│ │ ├── app.dart
│ │ ├── cache_manager.dart
│ │ ├── history.dart
│ │ ├── image_provider.dart
│ │ ├── log.dart
│ │ ├── navigation.dart
│ │ ├── pair.dart
│ │ ├── state_controller.dart
│ │ └── widget_utils.dart
│ ├── main.dart
│ ├── network/
│ │ ├── app_dio.dart
│ │ ├── download.dart
│ │ ├── models.dart
│ │ ├── network.dart
│ │ ├── novel.dart
│ │ ├── res.dart
│ │ └── translator.dart
│ ├── pages/
│ │ ├── bookmarks.dart
│ │ ├── comments_page.dart
│ │ ├── downloaded_page.dart
│ │ ├── downloading_page.dart
│ │ ├── following_artworks.dart
│ │ ├── following_novels_page.dart
│ │ ├── following_users_page.dart
│ │ ├── history.dart
│ │ ├── illust_page.dart
│ │ ├── image_page.dart
│ │ ├── login_page.dart
│ │ ├── logs.dart
│ │ ├── main_page.dart
│ │ ├── novel_bookmarks_page.dart
│ │ ├── novel_page.dart
│ │ ├── novel_ranking_page.dart
│ │ ├── novel_reading_page.dart
│ │ ├── novel_recommendation_page.dart
│ │ ├── ranking.dart
│ │ ├── recommendation_page.dart
│ │ ├── related_page.dart
│ │ ├── search_page.dart
│ │ ├── settings_page.dart
│ │ ├── user_info_page.dart
│ │ └── webview_page.dart
│ └── utils/
│ ├── app_links.dart
│ ├── block.dart
│ ├── debounce.dart
│ ├── debug.dart
│ ├── ext.dart
│ ├── io.dart
│ ├── loop.dart
│ ├── mouse_listener.dart
│ ├── translation.dart
│ ├── update.dart
│ └── window.dart
├── linux/
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── flutter/
│ │ ├── CMakeLists.txt
│ │ ├── generated_plugin_registrant.cc
│ │ ├── generated_plugin_registrant.h
│ │ └── generated_plugins.cmake
│ ├── main.cc
│ ├── my_application.cc
│ └── my_application.h
├── macos/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── Flutter-Debug.xcconfig
│ │ ├── Flutter-Release.xcconfig
│ │ └── GeneratedPluginRegistrant.swift
│ ├── Podfile
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ └── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── MainMenu.xib
│ │ ├── Configs/
│ │ │ ├── AppInfo.xcconfig
│ │ │ ├── Debug.xcconfig
│ │ │ ├── Release.xcconfig
│ │ │ └── Warnings.xcconfig
│ │ ├── DebugProfile.entitlements
│ │ ├── Info.plist
│ │ ├── MainFlutterWindow.swift
│ │ └── Release.entitlements
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ └── RunnerTests/
│ └── RunnerTests.swift
├── pubspec.yaml
├── test/
│ └── widget_test.dart
└── windows/
├── .gitignore
├── CMakeLists.txt
├── build.iss
├── build.py
├── flutter/
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
└── runner/
├── CMakeLists.txt
├── RCa14464
├── RCa18972
├── Runner.aps
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/main.yml
================================================
name: Build ALL
run-name: Build ALL
on:
workflow_dispatch:
inputs:
# macOS build disabled: the macOS job frequently exceeds GitHub Actions' job time limit during Flutter builds.
# build_macos:
# description: Build macOS
# type: boolean
# default: true
build_ios:
description: Build iOS
type: boolean
default: true
build_android:
description: Build Android
type: boolean
default: true
build_windows:
description: Build Windows
type: boolean
default: true
build_linux:
description: Build Linux (x64)
type: boolean
default: true
build_linux_arm64:
description: Build Linux (ARM64)
type: boolean
default: true
release:
types: [published]
jobs:
# macOS build disabled: macOS builds on GitHub-hosted runners often hit the job timeout.
# Build_MacOS:
# if: github.event_name == 'release' || github.event.inputs.build_macos == 'true'
# runs-on: macos-15
# steps:
# - uses: actions/checkout@v3
# - uses: subosito/flutter-action@v2
# with:
# channel: "stable"
# flutter-version-file: pubspec.yaml
# - run: sudo xcode-select --switch /Applications/Xcode_16.4.0.app
# - run: flutter pub get
# # Step 1: Decode and install the certificate
# - name: Decode and install certificate
# env:
# CERTIFICATE: ${{ secrets.CERTIFICATE }}
# CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
# run: |
# echo "$CERTIFICATE" | base64 --decode > signing_certificate.p12
# security import signing_certificate.p12 -k ~/Library/Keychains/login.keychain -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign
#
# # Step 2: Build the Flutter macOS app
# - name: Build Flutter macOS App
# run: flutter build macos --release
#
# # Step 3: Create the DMG file
# - name: Create DMG
# run: |
# mkdir -p dist
# mkdir -p dist/dmg_contents
# cp -R build/macos/Build/Products/Release/pixes.app dist/dmg_contents/
# ln -s /Applications dist/dmg_contents/Applications
# hdiutil create -volname "pixes" -srcfolder dist/dmg_contents -ov -format UDZO "dist/pixes.dmg"
#
# - name: Add version to filename
# run: |
# APP_VERSION=$(grep "version:" pubspec.yaml | cut -d':' -f2 | tr -d ' ')
# mkdir -p result
# mv dist/pixes.dmg result/pixes-$APP_VERSION.dmg
#
# # Step 4: Attach and upload artifacts (optional)
# - name: Upload DMG
# uses: actions/upload-artifact@v4
# with:
# name: macos_build
# path: result/
Build_IOS:
if: github.event_name == 'release' || github.event.inputs.build_ios == 'true'
runs-on: macos-26
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version-file: pubspec.yaml
- run: sudo xcode-select --switch /Applications/Xcode_26.4.0.app
- run: flutter pub get
- run: flutter build ios --release --no-codesign
- run: |
mkdir -p /Users/runner/work/pixes/pixes/build/ios/iphoneos/Payload
mv /Users/runner/work/pixes/pixes/build/ios/iphoneos/Runner.app /Users/runner/work/pixes/pixes/build/ios/iphoneos/Payload
cd /Users/runner/work/pixes/pixes/build/ios/iphoneos/
zip -r pixes-ios.ipa Payload
- uses: actions/upload-artifact@v4
with:
name: app-ios.ipa
path: /Users/runner/work/pixes/pixes/build/ios/iphoneos/pixes-ios.ipa
Build_Android:
if: github.event_name == 'release' || github.event.inputs.build_android == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version-file: pubspec.yaml
architecture: x64
- name: Decode and install certificate
env:
STORE_FILE: ${{ secrets.ANDROID_KEYSTORE }}
PROPERTY_FILE: ${{ secrets.ANDROID_KEY_PROPERTIES }}
run: |
echo "$STORE_FILE" | base64 --decode > android/keystore.jks
echo "$PROPERTY_FILE" > android/key.properties
- uses: actions/setup-java@v4
with:
distribution: 'oracle'
java-version: '17'
- run: flutter pub get
- run: flutter build apk --release
- uses: actions/upload-artifact@v4
with:
name: apks
path: build/app/outputs/apk/release
Build_Windows:
if: github.event_name == 'release' || github.event.inputs.build_windows == 'true'
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: install dependencies
run: |
choco install yq -y
- uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version-file: pubspec.yaml
architecture: x64
- name: Decode and install certificate
shell: bash
env:
STORE_FILE: ${{ secrets.WINDOWS_KEYSTORE }}
run: |
echo "$STORE_FILE" | base64 --decode > windows/app.pfx
- name: build
env:
CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_KEYSTORE_PASSWORD }}
run: |
flutter pub get
dart run msix:create -p ${{ env.CERTIFICATE_PASSWORD }} --install-certificate false
- uses: actions/upload-artifact@v4
with:
name: windows_build
path: build/windows/x64/runner/Release/pixes.msix
Build_Linux:
if: github.event_name == 'release' || github.event.inputs.build_linux == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
flutter-version-file: pubspec.yaml
architecture: x64
- run: |
sudo apt-get update -y
sudo apt-get install -y ninja-build libgtk-3-dev webkit2gtk-4.1
dart pub global activate flutter_to_debian
- run: python3 debian/build.py x64
- run: dart run flutter_to_arch
- run: |
sudo rm -rf build/linux/arch/app.tar.gz
sudo rm -rf build/linux/arch/pkg
sudo rm -rf build/linux/arch/src
sudo rm -rf build/linux/arch/PKGBUILD
- uses: actions/upload-artifact@v4
with:
name: deb_build
path: build/linux/x64/release/debian
- uses: actions/upload-artifact@v4
with:
name: arch_build
path: build/linux/arch/
Build_Linux_ARM64:
if: github.event_name == 'release' || github.event.inputs.build_linux_arm64 == 'true'
runs-on: ubuntu-22.04-arm
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: 'master'
flutter-version-file: pubspec.yaml
- run: |
flutter pub get
sudo apt-get update -y
sudo apt-get install -y ninja-build libgtk-3-dev webkit2gtk-4.1
dart pub global activate flutter_to_debian
- run: python3 debian/build.py arm64
- uses: actions/upload-artifact@v4
with:
name: deb_arm64_build
path: build/linux/x64/release/debian # This is a bug related to flutter_to_debian, but it's not a big deal.
Release:
runs-on: ubuntu-latest
needs: [Build_IOS, Build_Android, Build_Windows, Build_Linux, Build_Linux_ARM64]
if: github.event_name == 'release'
steps:
# macOS artifact: disabled together with Build_MacOS (was macos.zip / DMG from that job).
# - uses: actions/download-artifact@v4
# with:
# name: macos.zip
# path: outputs
- uses: actions/download-artifact@v4
with:
name: app-ios.ipa
path: outputs
- uses: actions/download-artifact@v4
with:
name: apks
path: outputs
- uses: actions/download-artifact@v4
with:
name: windows_build
path: outputs
- uses: actions/download-artifact@v4
with:
name: deb_build
path: outputs
- uses: actions/download-artifact@v4
with:
name: arch_build
path: outputs
- uses: actions/download-artifact@v4
with:
name: deb_arm64_build
path: outputs
- name: Download public key
run: wget https://nyne.dev/files/windows_app.cer
- uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
files: |
outputs/*.ipa
outputs/*.dmg
outputs/*.apk
outputs/*.zip
outputs/*.exe
outputs/*.deb
outputs/*.zst
outputs/*.msix
windows_app.cer
token: ${{ secrets.ACTION_GITHUB_TOKEN }}
================================================
FILE: .gitignore
================================================
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# 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/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
*.pfx
================================================
FILE: .metadata
================================================
# 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: "54e66469a933b60ddf175f858f82eaeb97e48c8d"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
- platform: android
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
- platform: ios
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
- platform: linux
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
- platform: macos
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
- platform: windows
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
================================================
FILE: .vscode/settings.json
================================================
{
"cSpell.words": [
"appdata",
"Bungo",
"gjzr",
"microtask",
"mypixiv",
"pawoo",
"Rorigod",
"sleepinglife",
"Ugoira",
"vocaloidhm",
"vsync"
]
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2024 nyne
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.
================================================
FILE: README.md
================================================
# pixes
[](https://flutter.dev/)
[](https://github.com/wgh136/pixes/blob/master/LICENSE)
[](https://github.com/wgh136/pixes)
[](https://github.com/wgh136/pixes/stargazers)
Unofficial Pixiv app, support Windows, Android, iOS, macOS, linux
All main features are implemented.
## Download
Download from [Release](https://github.com/wgh136/pixes/releases)
## Build from source
### Install Flutter
View [Flutter Document](https://flutter.dev/docs/get-started/install)
### Build Android
Put your keystore file (`key.jks`, `key.properties`) in `android/`
Run `flutter build apk`
### Build iOS/Windows/macOS
Run `flutter build ios/windows/macos`
### Build Linux
Use`python3 debian/build.py {ARCH}` to build deb package. Replace {ARCH} with `x64` or `arm64`.
For other linux distributions, you can use `flutter build linux` to build.
You must register the `pixiv` scheme in the `.desktop` file, otherwise the login will not work.
## Screenshots
================================================
FILE: analysis_options.yaml
================================================
# 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.dev/lints.
#
# 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
================================================
FILE: android/.gitignore
================================================
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
================================================
FILE: android/app/build.gradle
================================================
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
ext.abiCodes = ["armeabi-v7a": 1, "arm64-v8a": 2, "x86_64": 3]
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
namespace "com.github.wgh136.pixes"
compileSdk flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
packaging {
jniLibs {
useLegacyPackaging true
}
}
splits{
abi {
reset()
include 'armeabi-v7a', 'arm64-v8a', 'x86_64'
enable true
universalApk true
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions{
jvmTarget = JavaVersion.VERSION_17
}
defaultConfig {
applicationId "com.github.wgh136.pixes"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
debug {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
ndk {
abiFilters "armeabi-v7a", "arm64-v8a", "x86_64"
}
signingConfig signingConfigs.release
applicationVariants.all { variant ->
variant.outputs.all { output ->
def abi = output.getFilter(com.android.build.OutputFile.ABI)
if (abi != null) {
outputFileName = "pixes-${variant.versionName}-${abi}.apk"
def abiVersionCode = project.ext.abiCodes.get(abi)
if (abiVersionCode != null) {
versionCodeOverride = variant.versionCode * 10 + abiVersionCode
}
} else {
outputFileName = "pixes-${variant.versionName}.apk"
versionCodeOverride = variant.versionCode * 10
}
}
}
}
}
}
flutter {
source '../..'
}
dependencies {}
================================================
FILE: android/app/src/debug/AndroidManifest.xml
================================================
================================================
FILE: android/app/src/main/AndroidManifest.xml
================================================
================================================
FILE: android/app/src/main/kotlin/com/github/wgh136/pixes/MainActivity.kt
================================================
package com.github.wgh136.pixes
import io.flutter.embedding.android.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.plugin.common.MethodChannel
import io.flutter.embedding.engine.FlutterEngine
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
//获取http代理
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"pixes/proxy"
).setMethodCallHandler { _, res ->
res.success(getProxy())
}
}
private fun getProxy(): String{
val host = System.getProperty("http.proxyHost")
val port = System.getProperty("http.proxyPort")
return if(host!=null&&port!=null){
"$host:$port"
}else{
"No Proxy"
}
}
}
================================================
FILE: android/app/src/main/res/drawable/launch_background.xml
================================================
================================================
FILE: android/app/src/main/res/drawable-v21/launch_background.xml
================================================
================================================
FILE: android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
================================================
================================================
FILE: android/app/src/main/res/values/styles.xml
================================================
================================================
FILE: android/app/src/main/res/values-night/styles.xml
================================================
================================================
FILE: android/app/src/profile/AndroidManifest.xml
================================================
================================================
FILE: android/build.gradle
================================================
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
================================================
FILE: android/gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
================================================
FILE: android/gradle.properties
================================================
org.gradle.jvmargs=-Xmx4G
android.useAndroidX=true
android.enableJetifier=true
================================================
FILE: android/settings.gradle
================================================
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}
settings.ext.flutterSdkPath = flutterSdkPath()
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version '8.12.3' apply false
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
}
include ":app"
================================================
FILE: assets/tr.json
================================================
{
"zh_CN": {
"Search": "搜索",
"Downloading": "下载中",
"Downloaded": "已下载",
"Artwork": "插画",
"Explore": "探索",
"Bookmarks": "收藏",
"Following": "关注",
"History": "历史",
"Ranking": "排行",
"Settings": "设置",
"Artworks": "作品",
"Mangas": "漫画",
"Users": "用户",
"Search artwork": "搜索作品",
"Search Settings": "搜索设置",
"Match": "匹配",
"Favorite number": "收藏数",
"Sort": "排序",
"Age limit": "年龄限制",
"Search novel": "搜索小说",
"Search user": "搜索用户",
"Artwork ID": "作品ID",
"Artist ID": "画师ID",
"Novel ID": "小说ID",
"Search artworks": "搜索作品",
"Speed": "速度",
"View": "查看",
"Info": "信息",
"Delete": "删除",
"Are you sure you want to delete?": "确定要删除吗?",
"Yes": "是",
"Views": "浏览数",
"Favorites": "收藏数",
"Private": "私人",
"Share": "分享",
"Link": "链接",
"Unfollow": "取消关注",
"Favorite": "收藏",
"Comment": "评论",
"Comments": "评论",
"Follows: ": "关注:",
"Information": "信息",
"Introduction": "简介",
"Birthday": "生日",
"Job": "职业",
"Gender": "性别",
"Social Network": "社交网络",
"Batch download": "批量下载",
"Maximum number of downloads": "最大下载数",
"Cancel": "取消",
"Continue": "继续",
"Public": "公开",
"All": "全部",
"Daily": "每日",
"Weekly": "每周",
"Monthly": "每月",
"For male": "男性向",
"For female": "女性向",
"Originals": "原创",
"Rookies": "新人",
"Daily Manga": "每日漫画",
"Weekly Manga": "每周漫画",
"Monthly Manga": "每月漫画",
"R18": "R18",
"Account": "账号",
"Logout": "登出",
"Account Settings": "账号设置",
"Edit": "编辑",
"Download": "下载",
"Manage": "管理",
"About": "关于",
"Are you sure you want to logout?": "确定要登出吗?",
"Download Path": "下载路径",
"Confirm": "确认",
"Download subpath": "下载子路径",
"Rule": "规则",
"Weights of the tags": "标签权重",
"Use translated tag name": "使用翻译后的标签名",
"Edit the rule for where to save an image.": "编辑保存图片的规则",
"Note: The rule should include the filename.": "注意:规则应包含文件名",
"Title of the work": "作品标题",
"Name of the author": "作者名",
"Index of the image in the artwork": "作品中的图片序号",
"File extension": "文件扩展名",
"Tags: Tags will be sorted by the \"Weights of tags\" setting and replaced by the following rule:": "标签:标签将按照“标签权重”设置排序,并按照以下规则替换:",
"The final text will be affected by the \"Use translated tag name\" setting.": "最终文本将受“使用翻译后的标签名”设置影响",
"The first tag of the artwork": "作品的第一个标签",
"The second tag of the artwork": "作品的第二个标签",
"Follow": "关注",
"Save to": "保存到",
"Filled with tags. The tags should be separated by a space. The tag in front has higher weight.": "填写标签, 标签应该用空格分隔, 前面的标签权重更高. ",
"It is required to use the original name instead of the translated name.": "必须使用原始名称而不是翻译后的名称",
"Some keywords will be replaced by the following rule:": "一些关键词将按照以下规则替换:",
"Subpath": "子路径",
"Tags partial match": "标签部分匹配",
"Tags exact match": "标签完全匹配",
"Title or description search": "标题或描述搜索",
"Unlimited": "无限制",
"New to old": "新到旧",
"Old to new": "旧到新",
"Popular": "热门",
"Popular(limited)": "热门(受限)",
"Popular(Male)": "热门(男性向)",
"Popular(Female)": "热门(女性向)",
"Start Time": "开始时间",
"End Time": "结束时间",
"Max parallels": "最大并行数",
"Replace with 'AI' if the work was generated by AI, otherwise replace with blank": "替换为'AI'如果作品是由AI生成的, 否则替换为空白",
"Replace with * if the work have tag *, otherwise replace with blank.": "替换为*如果作品包含标签*, 否则替换为空白",
"Multiple path separators will be automatically replaced with a single": "多个路径分隔符将被自动替换为单个",
"Login": "登录",
"You need to complete the login operation in the browser window that will open.": "您需要在打开的浏览器窗口中完成登录操作",
"Waiting..." : "等待中...",
"Waiting for authentication. Please finished in the browser." : "等待验证. 请在浏览器中完成.",
"Back" : "返回",
"Logging in" : "登录中",
"Browse": "浏览",
"Proxy": "代理",
"Appearance": "外观",
"Language": "语言",
"Theme": "主题",
"Pause": "暂停",
"Resume": "继续",
"Paused": "已暂停",
"Delete all": "删除全部",
"Related": "相关",
"Related artworks": "相关作品",
"Related users": "相关用户",
"Replace with '-p${index}' if the work have more than one images, otherwise replace with blank.": "替换为'-p${index}'如果作品有多张图片, 否则替换为空白",
"Recommendation": "推荐",
"Novel": "小说",
"Novels": "小说",
"Reading Settings": "阅读设置",
"Font Size": "字体大小",
"Line Height": "行高",
"Paragraph Spacing": "段间距",
"light": "浅色",
"dark": "深色",
"block": "屏蔽",
"Block": "屏蔽",
"Block(Account)": "屏蔽(账号)",
"Block(Local)": "屏蔽(本地)",
"Add": "添加",
"Submit": "提交",
"Local": "本地",
"Both": "同时",
"This artwork is blocked": "此作品已被屏蔽",
"Delete Invalid Items": "删除无效项目",
"Private Favorite": "私人收藏",
"Shortcuts": "快捷键",
"Page down": "向下翻页",
"Page up": "向上翻页",
"Next work": "下一作品",
"Previous work": "上一作品",
"Add to favorites": "添加收藏",
"Follow the artist": "关注画师",
"Manga": "漫画",
"Actions": "操作",
"Current quantity": "当前数量",
"Display the original image on the details page": "在详情页显示原图",
"Open link": "打开链接",
"Read": "阅读",
"Error": "错误",
"Failed to register URL scheme.": "注册URL协议失败",
"Retry": "重试",
"Network": "网络",
"Save to gallery": "保存到相册",
"Choose a way to login": "选择登录方式",
"Use Webview: you cannot sign in with Google.": "使用Webview: 无法使用Google登录",
"Use an external browser: You can sign in using Google. However, some browsers may not be compatible with the application": "使用外部浏览器: 可以使用Google登录. 但是, 一些浏览器可能与应用程序不兼容",
"External browser": "外部浏览器",
"Show comments": "显示评论",
"Show original image": "显示原图",
"Illustrations": "插画",
"New version available": "新版本可用",
"A new version of Pixes is available. Do you want to update now?" : "Pixes有新版本可用. 您要立即更新吗?",
"Update": "更新",
"Check for updates": "检查更新",
"Check for updates on startup": "启动时检查更新",
"I understand pixes is a free unofficial application.": "我了解Pixes是一个免费的非官方应用程序",
"Related Artworks": "相关作品",
"Emphasize artworks from following artists": "强调关注画师的作品",
"The border of the artworks will be darker": "作品的边框将被加深",
"Initial Page": "初始页面",
"Close the pane to apply the settings": "关闭面板以应用设置",
"No results found": "未找到结果"
},
"zh_TW": {
"Search": "搜索",
"Downloading": "下載中",
"Downloaded": "已下載",
"Artwork": "作品",
"Explore": "探索",
"Bookmarks": "收藏",
"Following": "關注",
"History": "歷史",
"Ranking": "排行",
"Settings": "設置",
"Artworks": "作品",
"Mangas": "漫畫",
"Users": "用戶",
"Search artwork": "搜索作品",
"Search Settings": "搜索設置",
"Match": "匹配",
"Favorite number": "收藏數",
"Sort": "排序",
"Age limit": "年齡限制",
"Search novel": "搜索小說",
"Search user": "搜索用戶",
"Artwork ID": "作品ID",
"Artist ID": "畫師ID",
"Novel ID": "小說ID",
"Search artworks": "搜索作品",
"Speed": "速度",
"View": "查看",
"Info": "信息",
"Delete": "刪除",
"Are you sure you want to delete?": "確定要刪除嗎?",
"Yes": "是",
"Views": "瀏覽數",
"Favorites": "收藏數",
"Private": "私人",
"Share": "分享",
"Link": "鏈接",
"Unfollow": "取消關注",
"Favorite": "收藏",
"Comment": "評論",
"Comments": "評論",
"Follows: ": "關注:",
"Information": "信息",
"Introduction": "簡介",
"Birthday": "生日",
"Job": "職業",
"Gender": "性別",
"Social Network": "社交網絡",
"Batch download": "批量下載",
"Maximum number of downloads": "最大下載數",
"Cancel": "取消",
"Continue": "繼續",
"Public": "公開",
"All": "全部",
"Daily": "每日",
"Weekly": "每周",
"Monthly": "每月",
"For male": "男性向",
"For female": "女性向",
"Originals": "原創",
"Rookies": "新人",
"Daily Manga": "每日漫畫",
"Weekly Manga": "每周漫畫",
"Monthly Manga": "每月漫畫",
"R18": "R18",
"Account": "賬戶",
"Logout": "登出",
"Account Settings": "賬戶設置",
"Edit": "編輯",
"Download": "下載",
"Manage": "管理",
"About": "關於",
"Are you sure you want to logout?": "確定要登出嗎?",
"Download Path": "下載路徑",
"Confirm": "確認",
"Download subpath": "下載子路徑",
"Rule": "規則",
"Weights of the tags": "標籤權重",
"Use translated tag name": "使用翻譯後的標籤名",
"Edit the rule for where to save an image.": "編輯保存圖片的規則",
"Note: The rule should include the filename.": "注意:規則應包含文件名",
"Title of the work": "作品標題",
"Name of the author": "作者名",
"Index of the image in the artwork": "作品中的圖片序號",
"File extension": "文件擴展名",
"Tags: Tags will be sorted by the \"Weights of tags\" setting and replaced by the following rule:": "標籤:標籤將按照“標籤權重”設置排序,並按照以下規則替換:",
"The final text will be affected by the \"Use translated tag name\" setting.": "最終文本將受“使用翻譯後的標籤名”設置影響",
"The first tag of the artwork": "作品的第一個標籤",
"The second tag of the artwork": "作品的第二個標籤",
"Follow": "關注",
"Save to": "保存到",
"Filled with tags. The tags should be separated by a space. The tag in front has higher weight.": "填寫標籤, 標籤應該用空格分隔, 前面的標籤權重更高. ",
"It is required to use the original name instead of the translated name.": "必須使用原始名稱而不是翻譯後的名稱",
"Some keywords will be replaced by the following rule:": "一些關鍵詞將按照以下規則替換:",
"Subpath": "子路徑",
"Tags partial match": "標籤部分匹配",
"Tags exact match": "標籤完全匹配",
"Title or description search": "標題或描述搜索",
"Unlimited": "無限制",
"New to old": "新到舊",
"Old to new": "舊到新",
"Popular": "熱門",
"Popular(limited)": "熱門(受限)",
"Popular(Male)": "熱門(男性)",
"Popular(Female)": "熱門(女性)",
"Start Time": "開始時間",
"End Time": "結束時間",
"Max parallels": "最大並行數",
"Replace with 'AI' if the work was generated by AI, otherwise replace with blank": "替換為'AI'如果作品是由AI生成的, 否則替換為空白",
"Replace with * if the work have tag *, otherwise replace with blank.": "替換為*如果作品包含標籤*, 否則替換為空白",
"Multiple path separators will be automatically replaced with a single": "多個路徑分隔符號將自動替換為單一",
"Login": "登錄",
"You need to complete the login operation in the browser window that will open.": "您需要在打開的瀏覽器窗口中完成登錄操作",
"Waiting..." : "等待中...",
"Waiting for authentication. Please finished in the browser." : "等待驗證. 請在瀏覽器中完成.",
"Back" : "返回",
"Logging in" : "登錄中",
"Browse": "瀏覽",
"Proxy": "代理",
"Appearance": "外觀",
"Language": "語言",
"Theme": "主題",
"Pause": "暫停",
"Resume": "繼續",
"Paused": "已暫停",
"Delete all": "刪除全部",
"Related": "相關",
"Related artworks": "相關作品",
"Related users": "相關用戶",
"Replace with '-p${index}' if the work have more than one images, otherwise replace with blank.": "替換為'-p${index}'如果作品有多張圖片, 否則替換為空白",
"Recommendation": "推薦",
"Novel": "小說",
"Novels": "小說",
"Reading Settings": "閱讀設置",
"Font Size": "字體大小",
"Line Height": "行高",
"Paragraph Spacing": "段間距",
"light": "淺色",
"dark": "深色",
"block": "屏蔽",
"Block": "屏蔽",
"Block(Account)": "屏蔽(賬戶)",
"Block(Local)": "屏蔽(本地)",
"Add": "添加",
"Submit": "提交",
"Local": "本地",
"Both": "同時",
"This artwork is blocked": "此作品已被屏蔽",
"Delete Invalid Items": "刪除無效項目",
"Private Favorite": "私人收藏",
"Shortcuts": "快捷鍵",
"Page down": "向下翻頁",
"Page up": "向上翻頁",
"Next work": "下一作品",
"Previous work": "上一作品",
"Add to favorites": "添加收藏",
"Follow the artist": "關注畫師",
"Manga": "漫畫",
"Actions": "操作",
"Current quantity": "當前數量",
"Display the original image on the details page": "在詳情頁顯示原圖",
"Open link": "打開鏈接",
"Read": "閱讀",
"Error": "錯誤",
"Failed to register URL scheme.": "註冊URL協議失敗",
"Retry": "重試",
"Network": "網絡",
"Save to gallery": "保存到相冊",
"Choose a way to login": "選擇登錄方式",
"Use Webview: you cannot sign in with Google.": "使用Webview: 無法使用Google登錄",
"Use an external browser: You can sign in using Google. However, some browsers may not be compatible with the application": "使用外部瀏覽器: 可以使用Google登錄. 但是, 一些瀏覽器可能與應用程序不兼容",
"External browser": "外部瀏覽器",
"Show comments": "顯示評論",
"Show original image": "顯示原圖",
"Illustrations": "插畫",
"New version available": "新版本可用",
"A new version of Pixes is available. Do you want to update now?" : "Pixes有新版本可用. 您要立即更新嗎?",
"Update": "更新",
"Check for updates": "檢查更新",
"Check for updates on startup": "啟動時檢查更新",
"I understand pixes is a free unofficial application.": "我了解Pixes是一個免費的非官方應用程序",
"Related Artworks": "相關作品",
"Emphasize artworks from following artists": "強調關注畫師的作品",
"The border of the artworks will be darker": "作品的邊框將被加深",
"Initial Page": "初始頁面",
"Close the pane to apply the settings": "關閉面板以應用設置",
"No results found": "未找到結果"
},
"ko_KR": {
"Search": "검색",
"Downloading": "다운로드 중",
"Downloaded": "다운로드 완료",
"Artwork": "작품",
"Explore": "탐색",
"Bookmarks": "북마크",
"Following": "팔로잉",
"History": "기록",
"Ranking": "랭킹",
"Settings": "설정",
"Artworks": "작품",
"Mangas": "만화",
"Users": "사용자",
"Search artwork": "작품 검색",
"Search Settings": "검색 설정",
"Match": "일치",
"Favorite number": "북마크 수",
"Sort": "정렬",
"Age limit": "연령 제한",
"Search novel": "소설 검색",
"Search user": "사용자 검색",
"Artwork ID": "작품 ID",
"Artist ID": "작가 ID",
"Novel ID": "소설 ID",
"Search artworks": "작품 검색",
"Speed": "속도",
"View": "보기",
"Info": "정보",
"Delete": "삭제",
"Are you sure you want to delete?": "정말 삭제하시겠습니까?",
"Yes": "예",
"Views": "조회수",
"Favorites": "북마크 수",
"Private": "비공개",
"Share": "공유",
"Link": "링크",
"Unfollow": "언팔로우",
"Favorite": "북마크",
"Comment": "댓글",
"Comments": "댓글",
"Follows: ": "팔로우: ",
"Information": "정보",
"Introduction": "소개",
"Birthday": "생일",
"Job": "직업",
"Gender": "성별",
"Social Network": "소셜 네트워크",
"Batch download": "일괄 다운로드",
"Maximum number of downloads": "최대 다운로드 수",
"Cancel": "취소",
"Continue": "계속",
"Public": "공개",
"All": "전체",
"Daily": "일간",
"Weekly": "주간",
"Monthly": "월간",
"For male": "남성향",
"For female": "여성향",
"Originals": "오리지널",
"Rookies": "루키",
"Daily Manga": "일간 만화",
"Weekly Manga": "주간 만화",
"Monthly Manga": "월간 만화",
"R18": "R18",
"Account": "계정",
"Logout": "로그아웃",
"Account Settings": "계정 설정",
"Edit": "편집",
"Download": "다운로드",
"Manage": "관리",
"About": "정보",
"Are you sure you want to logout?": "정말 로그아웃하시겠습니까?",
"Download Path": "다운로드 경로",
"Confirm": "확인",
"Download subpath": "다운로드 하위 경로",
"Rule": "규칙",
"Weights of the tags": "태그 가중치",
"Use translated tag name": "번역된 태그 이름 사용",
"Edit the rule for where to save an image.": "이미지를 저장할 위치 규칙을 편집합니다.",
"Note: The rule should include the filename.": "참고: 규칙에 파일 이름이 포함되어야 합니다.",
"Title of the work": "작품 제목",
"Name of the author": "작가 이름",
"Index of the image in the artwork": "작품 내 이미지 인덱스",
"File extension": "파일 확장자",
"Tags: Tags will be sorted by the \"Weights of tags\" setting and replaced by the following rule:": "태그: 태그는 \"태그 가중치\" 설정에 따라 정렬되며 다음 규칙으로 대체됩니다:",
"The final text will be affected by the \"Use translated tag name\" setting.": "최종 텍스트는 \"번역된 태그 이름 사용\" 설정의 영향을 받습니다.",
"The first tag of the artwork": "작품의 첫 번째 태그",
"The second tag of the artwork": "작품의 두 번째 태그",
"Follow": "팔로우",
"Save to": "저장 위치",
"Filled with tags. The tags should be separated by a space. The tag in front has higher weight.": "태그를 입력하세요. 태그는 공백으로 구분해야 하며, 앞의 태그가 가중치가 더 높습니다.",
"It is required to use the original name instead of the translated name.": "번역된 이름 대신 원본 이름을 사용해야 합니다.",
"Some keywords will be replaced by the following rule:": "일부 키워드는 다음 규칙으로 대체됩니다:",
"Subpath": "하위 경로",
"Tags partial match": "태그 부분 일치",
"Tags exact match": "태그 완전 일치",
"Title or description search": "제목 또는 설명 검색",
"Unlimited": "무제한",
"New to old": "최신순",
"Old to new": "오래된 순",
"Popular": "인기",
"Popular(limited)": "인기(제한됨)",
"Popular(Male)": "인기(남성향)",
"Popular(Female)": "인기(여성향)",
"Start Time": "시작 시간",
"End Time": "종료 시간",
"Max parallels": "최대 동시 작업 수",
"Replace with 'AI' if the work was generated by AI, otherwise replace with blank": "AI가 생성한 작품인 경우 'AI'로 대체하고, 그렇지 않으면 공백으로 둡니다.",
"Replace with * if the work have tag *, otherwise replace with blank.": "작품에 * 태그가 있는 경우 *로 대체하고, 그렇지 않으면 공백으로 둡니다.",
"Multiple path separators will be automatically replaced with a single": "다중 경로 구분 기호는 자동으로 하나로 대체됩니다",
"Login": "로그인",
"You need to complete the login operation in the browser window that will open.": "열리는 브라우저 창에서 로그인 작업을 완료해야 합니다.",
"Waiting..." : "대기 중...",
"Waiting for authentication. Please finished in the browser." : "인증 대기 중입니다. 브라우저에서 완료해 주세요.",
"Back" : "뒤로",
"Logging in" : "로그인 중",
"Browse": "둘러보기",
"Proxy": "프록시",
"Appearance": "모양",
"Language": "언어",
"Theme": "테마",
"Pause": "일시 정지",
"Resume": "재개",
"Paused": "일시 정지됨",
"Delete all": "모두 삭제",
"Related": "관련",
"Related artworks": "관련 작품",
"Related users": "관련 사용자",
"Replace with '-p${index}' if the work have more than one images, otherwise replace with blank.": "작품에 이미지가 한 장 이상인 경우 '-p${index}'로 대체하고, 그렇지 않으면 공백으로 둡니다.",
"Recommendation": "추천",
"Novel": "소설",
"Novels": "소설",
"Reading Settings": "읽기 설정",
"Font Size": "글꼴 크기",
"Line Height": "줄 간격",
"Paragraph Spacing": "문단 간격",
"light": "라이트",
"dark": "다크",
"block": "차단",
"Block": "차단",
"Block(Account)": "차단(계정)",
"Block(Local)": "차단(로컬)",
"Add": "추가",
"Submit": "제출",
"Local": "로컬",
"Both": "모두",
"This artwork is blocked": "이 작품은 차단되었습니다",
"Delete Invalid Items": "잘못된 항목 삭제",
"Private Favorite": "비공개 북마크",
"Shortcuts": "단축키",
"Page down": "페이지 다운",
"Page up": "페이지 업",
"Next work": "다음 작품",
"Previous work": "이전 작품",
"Add to favorites": "북마크에 추가",
"Follow the artist": "작가 팔로우",
"Manga": "만화",
"Actions": "작업",
"Current quantity": "현재 수량",
"Display the original image on the details page": "상세 페이지에 원본 이미지 표시",
"Open link": "링크 열기",
"Read": "읽기",
"Error": "오류",
"Failed to register URL scheme.": "URL 스킴 등록에 실패했습니다.",
"Retry": "다시 시도",
"Network": "네트워크",
"Save to gallery": "갤러리에 저장",
"Choose a way to login": "로그인 방식을 선택하세요",
"Use Webview: you cannot sign in with Google.": "Webview 사용: Google로 로그인할 수 없습니다.",
"Use an external browser: You can sign in using Google. However, some browsers may not be compatible with the application": "외부 브라우저 사용: Google 계정으로 로그인할 수 있습니다. 단, 일부 브라우저는 어플리케이션과 호환되지 않을 수 있습니다.",
"External browser": "외부 브라우저",
"Show comments": "댓글 표시",
"Show original image": "원본 이미지 표시",
"Illustrations": "일러스트",
"New version available": "새 버전 사용 가능",
"A new version of Pixes is available. Do you want to update now?" : "Pixes의 새 버전이 출시되었습니다. 지금 업데이트하시겠습니까?",
"Update": "업데이트",
"Check for updates": "업데이트 확인",
"Check for updates on startup": "시작 시 업데이트 확인",
"I understand pixes is a free unofficial application.": "Pixes가 무료 비공식 앱임을 이해합니다.",
"Related Artworks": "관련 작품",
"Emphasize artworks from following artists": "팔로우한 작가의 작품 강조",
"The border of the artworks will be darker": "해당 작품들의 테두리가 더 어두워집니다.",
"Initial Page": "시작 페이지",
"Close the pane to apply the settings": "설정을 적용하려면 창을 닫으세요",
"No results found": "결과를 찾을 수 없음"
}
}
================================================
FILE: debian/build.py
================================================
import subprocess
import sys
arch = sys.argv[1]
debianContent = ''
desktopContent = ''
version = ''
with open('debian/debian.yaml', 'r') as f:
debianContent = f.read()
with open('debian/gui/pixes.desktop', 'r') as f:
desktopContent = f.read()
with open('pubspec.yaml', 'r') as f:
version = str.split(str.split(f.read(), 'version: ')[1], '+')[0]
with open('debian/debian.yaml', 'w') as f:
content = debianContent.replace('{{Version}}', version)
if arch == 'x64':
content = content.replace('{{Arch}}', 'x64')
content = content.replace('{{Architecture}}', 'amd64')
elif arch == 'arm64':
content = content.replace('{{Arch}}', 'arm64')
content = content.replace('{{Architecture}}', 'arm64')
f.write(content)
with open('debian/gui/pixes.desktop', 'w') as f:
f.write(desktopContent.replace('{{Version}}', version))
subprocess.run(["flutter", "build", "linux"])
subprocess.run(["$HOME/.pub-cache/bin/flutter_to_debian"], shell=True)
with open('debian/debian.yaml', 'w') as f:
f.write(debianContent)
with open('debian/gui/pixes.desktop', 'w') as f:
f.write(desktopContent)
================================================
FILE: debian/debian.yaml
================================================
flutter_app:
command: pixes
arch: {{Arch}}
parent: /usr/local/lib
nonInteractive: true
execFieldCodes: u
control:
Package: pixes
Version: {{Version}}
Architecture: {{Architecture}}
Priority: optional
Depends: libwebkit2gtk-4.1-0, libgtk-3-0
Maintainer: nyne
Description: Unofficial pixiv application
#options:
# exec_out_dir: debian/packages
================================================
FILE: debian/gui/pixes.desktop
================================================
[Desktop Entry]
Name=Pixes
GenericName=Pixes
Comment=Unofficial pixiv application
Terminal=false
Type=Application
Categories=Utility
Keywords=Flutter;share;images;
MimeType=x-scheme-handler/pixiv;
Icon=pixes
================================================
FILE: ios/.gitignore
================================================
**/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
================================================
FILE: ios/Flutter/AppFrameworkInfo.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
App
CFBundleIdentifier
io.flutter.flutter.app
CFBundleInfoDictionaryVersion
6.0
CFBundleName
App
CFBundlePackageType
FMWK
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1.0
MinimumOSVersion
12.0
================================================
FILE: ios/Flutter/Debug.xcconfig
================================================
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
================================================
FILE: ios/Flutter/Release.xcconfig
================================================
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
================================================
FILE: ios/Podfile
================================================
# Uncomment this line to define a global platform for your project
# platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
================================================
FILE: ios/Runner/AppDelegate.swift
================================================
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
let methodChannel = FlutterMethodChannel(name: "pixes/proxy", binaryMessenger: controller.binaryMessenger)
methodChannel.setMethodCallHandler { [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
if let proxySettings = CFNetworkCopySystemProxySettings()?.takeUnretainedValue() as NSDictionary?,
let dict = proxySettings.object(forKey: kCFNetworkProxiesHTTPProxy) as? NSDictionary,
let host = dict.object(forKey: kCFNetworkProxiesHTTPProxy) as? String,
let port = dict.object(forKey: kCFNetworkProxiesHTTPPort) as? Int {
let proxyConfig = "\(host):\(port)"
result(proxyConfig)
} else {
result("no proxy")
}
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
================================================
FILE: ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images": [
{
"filename": "AppIcon@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "60x60"
},
{
"filename": "AppIcon@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "60x60"
},
{
"filename": "AppIcon~ipad.png",
"idiom": "ipad",
"scale": "1x",
"size": "76x76"
},
{
"filename": "AppIcon@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "76x76"
},
{
"filename": "AppIcon-83.5@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "83.5x83.5"
},
{
"filename": "AppIcon-40@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "40x40"
},
{
"filename": "AppIcon-40@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "40x40"
},
{
"filename": "AppIcon-40~ipad.png",
"idiom": "ipad",
"scale": "1x",
"size": "40x40"
},
{
"filename": "AppIcon-40@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "40x40"
},
{
"filename": "AppIcon-20@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "20x20"
},
{
"filename": "AppIcon-20@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "20x20"
},
{
"filename": "AppIcon-20~ipad.png",
"idiom": "ipad",
"scale": "1x",
"size": "20x20"
},
{
"filename": "AppIcon-20@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "20x20"
},
{
"filename": "AppIcon-29.png",
"idiom": "iphone",
"scale": "1x",
"size": "29x29"
},
{
"filename": "AppIcon-29@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "29x29"
},
{
"filename": "AppIcon-29@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "29x29"
},
{
"filename": "AppIcon-29~ipad.png",
"idiom": "ipad",
"scale": "1x",
"size": "29x29"
},
{
"filename": "AppIcon-29@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "29x29"
},
{
"filename": "AppIcon-60@2x~car.png",
"idiom": "car",
"scale": "2x",
"size": "60x60"
},
{
"filename": "AppIcon-60@3x~car.png",
"idiom": "car",
"scale": "3x",
"size": "60x60"
},
{
"filename": "AppIcon~ios-marketing.png",
"idiom": "ios-marketing",
"scale": "1x",
"size": "1024x1024"
}
],
"info": {
"author": "iconkitchen",
"version": 1
}
}
================================================
FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
================================================
{
"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"
}
}
================================================
FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
================================================
# 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.
================================================
FILE: ios/Runner/Base.lproj/LaunchScreen.storyboard
================================================
================================================
FILE: ios/Runner/Base.lproj/Main.storyboard
================================================
================================================
FILE: ios/Runner/Info.plist
================================================
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleDisplayName
Pixes
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
pixes
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
CADisableMinimumFrameDurationOnPhone
UIApplicationSupportsIndirectInputEvents
CFBundleURLTypes
CFBundleURLSchemes
pixiv
CFBundleURLName
$(PRODUCT_BUNDLE_IDENTIFIER)
NSPhotoLibraryAddUsageDescription
photo
NSPhotoLibraryUsageDescription
photo
================================================
FILE: ios/Runner/Runner-Bridging-Header.h
================================================
#import "GeneratedPluginRegistrant.h"
================================================
FILE: ios/Runner.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
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 = ""; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
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 */
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "";
};
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 */,
331C8082294A63A400263BE5 /* RunnerTests */,
);
sourceTree = "";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
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 */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C8086294A63A400263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
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 = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
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 */,
331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
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 */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
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;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
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;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
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 = 12.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.github.wgh136.pixes;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.github.wgh136.pixes.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.github.wgh136.pixes.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.github.wgh136.pixes.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
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;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
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 = 12.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;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
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;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
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 = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
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.github.wgh136.pixes;
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.github.wgh136.pixes;
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 */
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
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 */;
}
================================================
FILE: ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
================================================
PreviewsEnabled
================================================
FILE: ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
================================================
================================================
FILE: ios/Runner.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
================================================
PreviewsEnabled
================================================
FILE: ios/RunnerTests/RunnerTests.swift
================================================
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}
================================================
FILE: lib/appdata.dart
================================================
import 'dart:convert';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pixes/utils/io.dart';
import 'foundation/app.dart';
import 'foundation/log.dart';
import 'network/models.dart';
class _Appdata {
static const MethodChannel _macosDownloadPathChannel =
MethodChannel("pixes/macos/download_path");
Account? account;
var searchOptions = SearchOptions();
Map settings = {
"downloadPath": null,
"downloadSubPath": r"/${id}-p${index}.${ext}",
"maxParallels": 3,
"proxy": "",
"darkMode": "System",
"language": "System",
"readingFontSize": 16.0,
"readingLineHeight": 1.5,
"readingParagraphSpacing": 8.0,
"blockTags": [],
"shortcuts": [
LogicalKeyboardKey.arrowDown.keyId,
LogicalKeyboardKey.arrowUp.keyId,
LogicalKeyboardKey.arrowRight.keyId,
LogicalKeyboardKey.arrowLeft.keyId,
LogicalKeyboardKey.enter.keyId,
LogicalKeyboardKey.keyD.keyId,
LogicalKeyboardKey.keyF.keyId,
LogicalKeyboardKey.keyC.keyId,
LogicalKeyboardKey.keyG.keyId,
],
"showOriginalImage": false,
"checkUpdate": true,
"emphasizeArtworksFromFollowingArtists": true,
"initialPage": 4,
};
bool lock = false;
void writeData() async {
while (lock) {
await Future.delayed(const Duration(milliseconds: 20));
}
lock = true;
await File("${App.dataPath}/account.json")
.writeAsString(jsonEncode(account));
await File("${App.dataPath}/settings.json")
.writeAsString(jsonEncode(settings));
lock = false;
}
void writeSettings() async {
while (lock) {
await Future.delayed(const Duration(milliseconds: 20));
}
lock = true;
await File("${App.dataPath}/settings.json")
.writeAsString(jsonEncode(settings));
lock = false;
}
Future readData() async {
final file = File("${App.dataPath}/account.json");
if (file.existsSync()) {
var json = jsonDecode(await file.readAsString());
if (json != null) {
account = Account.fromJson(json);
}
}
final settingsFile = File("${App.dataPath}/settings.json");
if (settingsFile.existsSync()) {
var json = jsonDecode(await settingsFile.readAsString());
for (var key in json.keys) {
if (json[key] != null) {
if (json[key] is List && settings[key] is List) {
for (int i = 0;
i < json[key].length && i < settings[key].length;
i++) {
settings[key][i] = json[key][i];
}
} else {
settings[key] = json[key];
}
}
}
}
settings["downloadPath"] ??= await _defaultDownloadPath;
if (App.isMacOS) {
await _ensureMacOSDownloadPathPermission();
}
}
Future _ensureMacOSDownloadPathPermission() async {
final defaultPath = await _defaultDownloadPath;
final currentPath = settings["downloadPath"] as String? ?? defaultPath;
if (_normalizePath(currentPath) == _normalizePath(defaultPath)) {
settings["downloadPath"] = defaultPath;
return;
}
final restoredPath = await _restoreMacOSDownloadPathAccess(currentPath);
if (restoredPath != null) {
settings["downloadPath"] = restoredPath;
Log.info(
"DownloadPath", "Restored macOS directory access: $restoredPath");
return;
}
Log.warning(
"DownloadPath",
"Failed to restore macOS directory access for $currentPath, requesting permission again.",
);
final selectedPath = await _requestMacOSDownloadPathAccess(currentPath);
if (selectedPath != null) {
settings["downloadPath"] = selectedPath;
writeSettings();
Log.info(
"DownloadPath",
"Re-authorized macOS directory access: $selectedPath",
);
return;
}
settings["downloadPath"] = defaultPath;
writeSettings();
Log.warning(
"DownloadPath",
"macOS directory permission denied or canceled, fallback to default path: $defaultPath",
);
}
Future _restoreMacOSDownloadPathAccess(String? expectedPath) async {
try {
return await _macosDownloadPathChannel.invokeMethod(
"restoreDownloadDirectoryAccess",
{"path": expectedPath},
);
} catch (e) {
Log.warning("DownloadPath", "restoreDownloadDirectoryAccess failed: $e");
return null;
}
}
Future _requestMacOSDownloadPathAccess(String? initialPath) async {
try {
return await _macosDownloadPathChannel.invokeMethod(
"selectDownloadDirectory",
{"initialPath": initialPath},
);
} catch (e) {
Log.warning("DownloadPath", "selectDownloadDirectory failed: $e");
return null;
}
}
String _normalizePath(String path) {
if (!App.isMacOS) {
return path;
}
final home = Platform.environment["HOME"];
if (home != null && path.startsWith("~")) {
return path.replaceFirst("~", home);
}
return path;
}
Future get _defaultDownloadPath async {
if (App.isAndroid) {
String? downloadPath = "/storage/emulated/0/download";
if (!Directory(downloadPath).havePermission()) {
downloadPath = null;
}
var res = downloadPath;
res ??= (await getExternalStorageDirectory())!.path;
return "$res/pixes";
} else if (App.isWindows) {
var res =
await const MethodChannel("pixes/picture_folder").invokeMethod("");
if (res != "error") {
return res + "/pixes";
}
} else if (App.isLinux) {
var downloadPath = (await getDownloadsDirectory())?.path;
if (downloadPath != null && Directory(downloadPath).havePermission()) {
return "$downloadPath/pixes";
}
} else if (App.isMacOS) {
if (Directory("~/Pictures").havePermission()) {
return "~/Pictures/pixes";
}
try {
Directory("~/Downloads/pixes").createSync(recursive: true);
return "~/Downloads/pixes";
} catch (e) {
return "${App.dataPath}/download";
}
}
return "${App.dataPath}/download";
}
}
final appdata = _Appdata();
================================================
FILE: lib/components/animated_image.dart
================================================
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
class AnimatedImage extends StatefulWidget {
/// show animation when loading is complete.
AnimatedImage({
required ImageProvider image,
super.key,
double scale = 1.0,
this.semanticLabel,
this.excludeFromSemantics = false,
this.width,
this.height,
this.color,
this.opacity,
this.colorBlendMode,
this.fit,
this.alignment = Alignment.center,
this.repeat = ImageRepeat.noRepeat,
this.centerSlice,
this.matchTextDirection = false,
this.gaplessPlayback = false,
this.filterQuality = FilterQuality.low,
this.isAntiAlias = false,
Map? headers,
int? cacheWidth,
int? cacheHeight,
}
): image = ResizeImage.resizeIfNeeded(cacheWidth, cacheHeight, image),
assert(cacheWidth == null || cacheWidth > 0),
assert(cacheHeight == null || cacheHeight > 0);
final ImageProvider image;
final String? semanticLabel;
final bool excludeFromSemantics;
final double? width;
final double? height;
final bool gaplessPlayback;
final bool matchTextDirection;
final Rect? centerSlice;
final ImageRepeat repeat;
final AlignmentGeometry alignment;
final BoxFit? fit;
final BlendMode? colorBlendMode;
final FilterQuality filterQuality;
final Animation? opacity;
final Color? color;
final bool isAntiAlias;
static void clear() => _AnimatedImageState.clear();
@override
State createState() => _AnimatedImageState();
}
class _AnimatedImageState extends State with WidgetsBindingObserver {
ImageStream? _imageStream;
ImageInfo? _imageInfo;
ImageChunkEvent? _loadingProgress;
bool _isListeningToStream = false;
late bool _invertColors;
int? _frameNumber;
bool _wasSynchronouslyLoaded = false;
late DisposableBuildContext> _scrollAwareContext;
Object? _lastException;
ImageStreamCompleterHandle? _completerHandle;
static final Map _cache = {};
static clear() => _cache.clear();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_scrollAwareContext = DisposableBuildContext>(this);
}
@override
void dispose() {
assert(_imageStream != null);
WidgetsBinding.instance.removeObserver(this);
_stopListeningToStream();
_completerHandle?.dispose();
_scrollAwareContext.dispose();
_replaceImage(info: null);
super.dispose();
}
@override
void didChangeDependencies() {
_updateInvertColors();
_resolveImage();
if (TickerMode.of(context)) {
_listenToStream();
} else {
_stopListeningToStream(keepStreamAlive: true);
}
super.didChangeDependencies();
}
@override
void didUpdateWidget(AnimatedImage oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.image != oldWidget.image) {
_resolveImage();
}
}
@override
void didChangeAccessibilityFeatures() {
super.didChangeAccessibilityFeatures();
setState(() {
_updateInvertColors();
});
}
@override
void reassemble() {
_resolveImage(); // in case the image cache was flushed
super.reassemble();
}
void _updateInvertColors() {
_invertColors = MediaQuery.maybeInvertColorsOf(context)
?? SemanticsBinding.instance.accessibilityFeatures.invertColors;
}
void _resolveImage() {
final ScrollAwareImageProvider provider = ScrollAwareImageProvider