Repository: ComicSparks/pikapika
Branch: master
Commit: def75a101a65
Files: 319
Total size: 1.3 MB
Directory structure:
gitextract_rinrtcf6/
├── .fvmrc
├── .github/
│ └── workflows/
│ ├── Package.core.yml
│ ├── Package.yml
│ ├── Release.core.yml
│ └── Release.yml
├── .gitignore
├── .metadata
├── README-zh_CN.md
├── README.md
├── analysis_options.yaml
├── android/
│ ├── .gitignore
│ ├── app/
│ │ ├── build.gradle
│ │ └── src/
│ │ ├── debug/
│ │ │ └── AndroidManifest.xml
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin/
│ │ │ │ └── opensource/
│ │ │ │ └── pic2acg/
│ │ │ │ └── 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
├── ci/
│ ├── cmd/
│ │ ├── check_asset/
│ │ │ └── main.go
│ │ ├── check_asset_core/
│ │ │ └── main.go
│ │ ├── check_release/
│ │ │ └── main.go
│ │ ├── send_to_community/
│ │ │ └── main.go
│ │ ├── upload_asset/
│ │ │ └── main.go
│ │ └── upload_asset_core/
│ │ └── main.go
│ ├── commons/
│ │ ├── funcs.go
│ │ └── types.go
│ ├── go.mod
│ ├── go.sum
│ ├── linux_font.yaml
│ ├── version.code.txt
│ └── version.info.txt
├── 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
├── lib/
│ ├── assets/
│ │ └── translations/
│ │ ├── en-US.json
│ │ ├── ja-JP.json
│ │ ├── ko-KR.json
│ │ ├── zh-CN.json
│ │ └── zh-TW.json
│ ├── basic/
│ │ ├── Channels.dart
│ │ ├── Common.dart
│ │ ├── Cross.dart
│ │ ├── Entities.dart
│ │ ├── Method.dart
│ │ ├── Navigator.dart
│ │ ├── config/
│ │ │ ├── Address.dart
│ │ │ ├── AndroidDisplayMode.dart
│ │ │ ├── AndroidSecureFlag.dart
│ │ │ ├── AppOrientation.dart
│ │ │ ├── Authentication.dart
│ │ │ ├── AutoClean.dart
│ │ │ ├── AutoDeleteDownloadOnUnfavorite.dart
│ │ │ ├── AutoDownloadOnFavorite.dart
│ │ │ ├── AutoFullScreen.dart
│ │ │ ├── AutoFullScreenOnForward.dart
│ │ │ ├── CategoriesColumnCount.dart
│ │ │ ├── CategoriesSort.dart
│ │ │ ├── ChooserRoot.dart
│ │ │ ├── ContentFailedReloadAction.dart
│ │ │ ├── CopyFullName.dart
│ │ │ ├── CopyFullNameTemplate.dart
│ │ │ ├── CopySkipConfirm.dart
│ │ │ ├── DisableAutoDownloadOnMobile.dart
│ │ │ ├── DownloadAndExportPath.dart
│ │ │ ├── DownloadCachePath.dart
│ │ │ ├── DownloadThreadCount.dart
│ │ │ ├── DragRegionLock.dart
│ │ │ ├── EBookScrolling.dart
│ │ │ ├── EBookScrollingRange.dart
│ │ │ ├── EBookScrollingTrigger.dart
│ │ │ ├── ExportPath.dart
│ │ │ ├── ExportRename.dart
│ │ │ ├── FullScreenAction.dart
│ │ │ ├── FullScreenUI.dart
│ │ │ ├── GalleryPreloadCount.dart
│ │ │ ├── GestureSpeed.dart
│ │ │ ├── HiddenFdIcon.dart
│ │ │ ├── HiddenSearchPersion.dart
│ │ │ ├── HiddenSubIcon.dart
│ │ │ ├── HiddenViewed.dart
│ │ │ ├── HiddenWords.dart
│ │ │ ├── HideOnlineFavorite.dart
│ │ │ ├── IconLoading.dart
│ │ │ ├── IgnoreInfoHistory.dart
│ │ │ ├── IgnoreUpgradeConfirm.dart
│ │ │ ├── ImageAddress.dart
│ │ │ ├── ImageFilter.dart
│ │ │ ├── ImportNotice.dart
│ │ │ ├── IsPro.dart
│ │ │ ├── KeyboardController.dart
│ │ │ ├── ListLayout.dart
│ │ │ ├── LocalHistorySync.dart
│ │ │ ├── NoAnimation.dart
│ │ │ ├── PagerAction.dart
│ │ │ ├── Platform.dart
│ │ │ ├── Proxy.dart
│ │ │ ├── Quality.dart
│ │ │ ├── ReaderBackgroundColor.dart
│ │ │ ├── ReaderDirection.dart
│ │ │ ├── ReaderScrollByScreenPercentage.dart
│ │ │ ├── ReaderSliderPosition.dart
│ │ │ ├── ReaderTwoPageDirection.dart
│ │ │ ├── ReaderType.dart
│ │ │ ├── ReaderZoomScale.dart
│ │ │ ├── RecommendLinks.dart
│ │ │ ├── ShadowCategories.dart
│ │ │ ├── ShadowCategoriesEvent.dart
│ │ │ ├── ShadowCategoriesMode.dart
│ │ │ ├── ShowCommentAtDownload.dart
│ │ │ ├── StartupPic.dart
│ │ │ ├── Themes.dart
│ │ │ ├── ThreeKeepRight.dart
│ │ │ ├── TimeOffsetHour.dart
│ │ │ ├── TimeoutLock.dart
│ │ │ ├── UseApiLoadImage.dart
│ │ │ ├── UsingRightClickPop.dart
│ │ │ ├── Version.dart
│ │ │ ├── VolumeController.dart
│ │ │ ├── VolumeNextChapter.dart
│ │ │ ├── WebDav.dart
│ │ │ ├── WebToonScrollMode.dart
│ │ │ ├── WillPopNotice.dart
│ │ │ ├── i18n.dart
│ │ │ └── passed.dart
│ │ ├── connect.dart
│ │ ├── define.dart
│ │ ├── enum/
│ │ │ ├── ErrorTypes.dart
│ │ │ └── Sort.dart
│ │ └── store/
│ │ └── Categories.dart
│ ├── i18.dart
│ ├── i18b.dart
│ ├── main.dart
│ ├── main_desktop.dart
│ └── screens/
│ ├── AboutScreen.dart
│ ├── AccessKeyReplaceScreen.dart
│ ├── AccountScreen.dart
│ ├── AppScreen.dart
│ ├── CategoriesScreen.dart
│ ├── CategoriesSortScreen.dart
│ ├── CleanScreen.dart
│ ├── CloseAppScreen.dart
│ ├── ComicCollectionsScreen.dart
│ ├── ComicInfoScreen.dart
│ ├── ComicReaderScreen.dart
│ ├── ComicSubscribesScreen.dart
│ ├── ComicsScreen.dart
│ ├── CommentScreen.dart
│ ├── DesktopAuthenticationScreen.dart
│ ├── DownloadConfirmScreen.dart
│ ├── DownloadExportGroupScreen.dart
│ ├── DownloadExportToFileScreen.dart
│ ├── DownloadExportToSocketScreen.dart
│ ├── DownloadExportingGroupScreen.dart
│ ├── DownloadImportScreen.dart
│ ├── DownloadInfoScreen.dart
│ ├── DownloadListScreen.dart
│ ├── DownloadOnlyImportScreen.dart
│ ├── DownloadReaderScreen.dart
│ ├── FavouritePaperScreen.dart
│ ├── FilePhotoViewScreen.dart
│ ├── ForgotPasswordScreen.dart
│ ├── GameDownloadScreen.dart
│ ├── GameInfoScreen.dart
│ ├── GamesScreen.dart
│ ├── HiddenWordsScreen.dart
│ ├── ImportFromOffScreen.dart
│ ├── InitScreen.dart
│ ├── LocalFavoriteScreen.dart
│ ├── MigrateScreen.dart
│ ├── ModifyPasswordScreen.dart
│ ├── NetworkSettingsScreen.dart
│ ├── PkzArchiveScreen.dart
│ ├── PkzComicInfoScreen.dart
│ ├── PkzReaderScreen.dart
│ ├── ProScreen.dart
│ ├── RandomComicsScreen.dart
│ ├── RankingsScreen.dart
│ ├── RegisterScreen.dart
│ ├── SearchAuthorScreen.dart
│ ├── SearchScreen.dart
│ ├── SettingsScreen.dart
│ ├── SpaceScreen.dart
│ ├── ThemeScreen.dart
│ ├── ViewLogsScreen.dart
│ ├── WebServerScreen.dart
│ ├── calculator_screen.dart
│ └── components/
│ ├── Avatar.dart
│ ├── Badge.dart
│ ├── BottomSheetInput.dart
│ ├── ComicDescriptionCard.dart
│ ├── ComicInfoCard.dart
│ ├── ComicList.dart
│ ├── ComicListBuilder.dart
│ ├── ComicPager.dart
│ ├── ComicTagsCard.dart
│ ├── CommentItem.dart
│ ├── CommentList.dart
│ ├── CommentMainType.dart
│ ├── Common.dart
│ ├── CommonData.dart
│ ├── ContentBuilder.dart
│ ├── ContentError.dart
│ ├── ContentLoading.dart
│ ├── ContentMessage.dart
│ ├── ContinueReadButton.dart
│ ├── DesktopCropper.dart
│ ├── DownloadComicsScreen.dart
│ ├── DownloadInfoCard.dart
│ ├── FitButton.dart
│ ├── GameTitleCard.dart
│ ├── GoDownloadSelect.dart
│ ├── ImageReader.dart
│ ├── Images.dart
│ ├── ItemBuilder.dart
│ ├── LinkToComicInfo.dart
│ ├── ListView.dart
│ ├── MouseAndTouchScrollBehavior.dart
│ ├── NetworkSetting.dart
│ ├── PkzComicInfoCard.dart
│ ├── PkzImages.dart
│ ├── RecommendLinksPanel.dart
│ ├── Recommendation.dart
│ ├── RightClickPop.dart
│ ├── TimeoutLock.dart
│ ├── UserProfileCard.dart
│ ├── flutter_search_bar.dart
│ └── gesture_zoom_box.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
├── pubspec.yaml
├── scripts/
│ ├── README.md
│ ├── bind-android-arm64.sh
│ ├── bind-android-debug.sh
│ ├── bind-ios-arm64.sh
│ ├── bind-ios.sh
│ ├── build-apk-arm.sh
│ ├── build-apk-arm64.sh
│ ├── build-apk-x64.sh
│ ├── build-apk-x86.sh
│ ├── build-ipa.sh
│ ├── build-linux.sh
│ ├── build-macos-dmg.sh
│ ├── json_compairer.py
│ ├── sign-apk-github-actions.sh
│ ├── thin-payload.sh
│ └── version.sh
├── test/
│ └── widget_test.dart
└── windows/
├── .gitignore
├── CMakeLists.txt
├── flutter/
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
└── runner/
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── run_loop.cpp
├── run_loop.h
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
================================================
FILE CONTENTS
================================================
================================================
FILE: .fvmrc
================================================
{
"flutter": "3.13.9"
}
================================================
FILE: .github/workflows/Package.core.yml
================================================
name: Package-core
on:
workflow_dispatch:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GO_VERSION: "1.24"
NDK_VERSION: "23.1.7779620"
jobs:
ci-pass:
name: CI is green
runs-on: ubuntu-latest
needs:
- build_release_assets
steps:
- run: exit 0
build_release_assets:
name: Build and upload assets
strategy:
fail-fast: false
matrix:
config:
- target: ios
host: macos-latest
- target: android
host: ubuntu-latest
runs-on: ${{ matrix.config.host }}
env:
TARGET: ${{ matrix.config.target }}
steps:
- name: Setup golang
uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- name: Cache go modules (Linux)
if: matrix.config.host == 'ubuntu-latest'
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ matrix.config.host }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.config.host }}-go-
- name: Cache go modules (macOS)
if: matrix.config.host == 'macos-latest'
uses: actions/cache@v3
with:
path: |
~/Library/Caches/go-build
~/go/pkg/mod
key: ${{ matrix.config.host }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.config.host }}-go-
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ env.BRANCH }}
- name: Checkout core
uses: actions/checkout@v3
with:
repository: 'niuhuan/pikapika-go-core'
token: ${{ secrets.CORE_TOKEN }}
path: 'go'
- name: Install go mobile (mobile)
if: matrix.config.target == 'ios' || matrix.config.target == 'android'
run: |
go install golang.org/x/mobile/cmd/gomobile@latest
- name: Build (ios)
if: matrix.config.target == 'ios'
run: |
sh scripts/bind-ios.sh
- name: Setup java (Android)
if: matrix.config.target == 'android'
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
- name: Setup android tools (Android)
if: matrix.config.target == 'android'
uses: android-actions/setup-android@v3
with:
cmdline-tools-version: 8512546
packages: 'platform-tools platforms;android-32 build-tools;30.0.2 ndk;${{ env.NDK_VERSION}}'
- name: Build (android)
if: matrix.config.target == 'android'
run: |
export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/${{ env.NDK_VERSION }}
bash scripts/bind-android-debug.sh
- name: Upload Asset (All)
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.config.target }}-${{ github.run_number }}
path: 'go/mobile/lib'
retention-days: 3
================================================
FILE: .github/workflows/Package.yml
================================================
name: Build
on:
workflow_dispatch:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANDROID_NDK_VERSION: "23.1.7779620"
GO_MOBILE_VERSION: v0.0.0-20241213221354-a87c1cf6cf46 # v0.0.0-20220722155234-aaac322e2105
jobs:
ci-pass:
name: CI is green
runs-on: ubuntu-latest
needs:
- build_release_assets
steps:
- run: exit 0
build_release_assets:
name: Build release assets
strategy:
fail-fast: false
matrix:
sources:
- branch: master
config:
- target: windows
host: windows-latest
flutter_version: '2.10.3'
go_version: '1.23'
- target: macos
host: macos-latest
flutter_version: '2.10.3'
go_version: '1.23'
- target: linux
host: ubuntu-latest
flutter_version: '2.10.3'
go_version: '1.23'
- target: ios
host: macos-latest
flutter_version: '3.13.9'
go_version: '1.24'
- target: android-arm32
host: ubuntu-latest
flutter_version: '3.13.9'
go_version: '1.24'
java: '11'
- target: android-arm64
host: ubuntu-latest
flutter_version: '3.13.9'
go_version: '1.24'
java: '11'
- target: android-x86_64
host: ubuntu-latest
flutter_version: '3.13.9'
go_version: '1.24'
java: '11'
runs-on: ${{ matrix.config.host }}
env:
TARGET: ${{ matrix.config.target }}
FLUTTER_VERSION: ${{ matrix.config.flutter_version }}
BRANCH: ${{ matrix.sources.branch }}
go_version: ${{ matrix.config.go_version }}
steps:
# Setup golang env and cache go module
- name: Setup golang
uses: actions/setup-go@v2
with:
go-version: ${{ env.go_version }}
- name: Cache go modules (Windows)
if: matrix.config.host == 'windows-latest'
uses: actions/cache@v3
with:
path: |
~\AppData\Local\go-build
~\go\pkg\mod
key: ${{ matrix.config.host }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.config.host }}-go-
- name: Cache go modules (Linux)
if: matrix.config.host == 'ubuntu-latest'
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ matrix.config.host }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.config.host }}-go-
- name: Cache go modules (macOS)
if: matrix.config.host == 'macos-latest'
uses: actions/cache@v3
with:
path: |
~/Library/Caches/go-build
~/go/pkg/mod
key: ${{ matrix.config.host }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.config.host }}-go-
# checkout
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ env.BRANCH }}
# check_access
- id: check_asset
name: Check asset
run: |
echo "::set-output name=skip_build::false"
#
- name: Check core
if: steps.check_asset.outputs.skip_build != 'true'
uses: actions/checkout@v3
with:
repository: 'niuhuan/pikapika-go-core'
token: ${{ secrets.CORE_TOKEN }}
path: 'go'
- name: Setup flutter
if: steps.check_asset.outputs.skip_build != 'true'
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
architecture: x64
- name: Cache Flutter dependencies (Linux/Android)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' || matrix.config.target == 'linux' )
uses: actions/cache@v3
with:
path: /opt/hostedtoolcache/flutter
key: ${{ runner.os }}-flutter
- name: Cache Flutter dependencies (Mac host)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'ios' || matrix.config.target == 'macos' )
uses: actions/cache@v3
with:
path: /Users/runner/hostedtoolcache/flutter
key: ${{ runner.os }}-flutter
- name: Cache Gradle dependencies (Android)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' )
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Setup java (Android)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' ) && startsWith(matrix.config.flutter_version, '3.24.2') == false
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.config.java }}
distribution: 'temurin'
- name: Setup java (Android)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' ) && startsWith(matrix.config.flutter_version, '3.24.2')
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Setup android tools (Android)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' )
uses: android-actions/setup-android@v3
with:
cmdline-tools-version: 8512546
packages: 'platform-tools platforms;android-32 build-tools;30.0.2 ndk;${{ env.ANDROID_NDK_VERSION }}'
- name: Setup msys2 (Windows)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'windows'
uses: msys2/setup-msys2@v2
with:
install: gcc make
- name: Install dependencies (Linux)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'linux'
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
run: |
curl -JOL https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
chmod a+x appimagetool-x86_64.AppImage
mkdir -p ${GITHUB_WORKSPACE}/bin
mv appimagetool-x86_64.AppImage ${GITHUB_WORKSPACE}/bin/appimagetool
echo ::add-path::${GITHUB_WORKSPACE}/bin
sudo apt-get update
sudo apt-get install -y libgl1-mesa-dev xorg-dev libfuse2 locate
- name: Install hover (desktop)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'linux' || matrix.config.target == 'windows' || matrix.config.target == 'macos')
run: |
go install github.com/go-flutter-desktop/hover@latest
- name: Install go mobile (mobile)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'ios' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-arm32' || matrix.config.target == 'android-x86_64' )
run: |
go install golang.org/x/mobile/cmd/gomobile@${{ env.GO_MOBILE_VERSION }}
- name: Set-Version (All)
if: steps.check_asset.outputs.skip_build != 'true'
run: |
cd ci
cp version.code.txt ../lib/assets/version.txt
- name: Upgrade deps version (flutter2 non-mac)
if: steps.check_asset.outputs.skip_build != 'true' && startsWith(matrix.config.host, 'macos-') == false && startsWith(matrix.config.flutter_version, '2')
run: |
sed -i "s/another_xlider: ^1.0.1+2/another_xlider: 1.0.1+2/g" pubspec.yaml
sed -i "s/flutter_styled_toast: ^2.0.0/flutter_styled_toast: 2.0.0/g" pubspec.yaml
sed -i "s/filesystem_picker: ^3.0.0-beta.1/filesystem_picker: 2.0.0/g" pubspec.yaml
sed -i "s/file_picker: 5.2.5/file_picker: 4.6.1/g" pubspec.yaml
sed -i "s/multi_select_flutter: ^4.0.0/multi_select_flutter: 4.1.2/g" pubspec.yaml
sed -i "s/modal_bottom_sheet: ^3.0.0-pre/modal_bottom_sheet: 2.0.1/g" pubspec.yaml
sed -i "s/Icons.energy_savings_leaf/Icons.ad_units/g" lib/screens/SettingsScreen.dart
sed -i "s/gradle-7.5-bin.zip/gradle-6.7.1-all.zip/g" android/gradle/wrapper/gradle-wrapper.properties
sed -i "s/com.android.tools.build:gradle:7.2.0/com.android.tools.build:gradle:4.1.0/g" android/build.gradle
sed -i "s/1.7.10/1.3.50/g" android/app/build.gradle
sed -i "s/fontFamilyFallback/\/\/fontFamilyFallback/g" lib/basic/config/Themes.dart
sed -i "s/easy_localization: ^3.0.7+1/easy_localization: ^3.0.0/g" pubspec.yaml
sed -i "s/thumbVisibility: true/isAlwaysShown: true/g" lib/basic/config/ShadowCategories.dart
flutter pub get
- name: Upgrade deps version (flutter2 mac)
if: steps.check_asset.outputs.skip_build != 'true' && startsWith(matrix.config.host, 'macos-') && startsWith(matrix.config.flutter_version, '2')
run: |
brew install gnu-sed
gsed -i "s/another_xlider: ^1.0.1+2/another_xlider: 1.0.1+2/g" pubspec.yaml
gsed -i "s/flutter_styled_toast: ^2.0.0/flutter_styled_toast: 2.0.0/g" pubspec.yaml
gsed -i "s/filesystem_picker: ^3.0.0-beta.1/filesystem_picker: 2.0.0/g" pubspec.yaml
gsed -i "s/file_picker: 5.2.5/file_picker: 4.6.1/g" pubspec.yaml
gsed -i "s/multi_select_flutter: ^4.0.0/multi_select_flutter: 4.1.2/g" pubspec.yaml
gsed -i "s/modal_bottom_sheet: ^3.0.0-pre/modal_bottom_sheet: 2.0.1/g" pubspec.yaml
gsed -i "s/Icons.energy_savings_leaf/Icons.ad_units/g" lib/screens/SettingsScreen.dart
gsed -i "s/fontFamilyFallback/\/\/fontFamilyFallback/g" lib/basic/config/Themes.dart
gsed -i "s/easy_localization: ^3.0.7+1/easy_localization: ^3.0.0/g" pubspec.yaml
gsed -i "s/thumbVisibility: true/isAlwaysShown: true/g" lib/basic/config/ShadowCategories.dart
flutter pub get
- name: Build (windows)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'windows'
run: |
hover build windows
curl -JOL https://github.com/ComicSparks/build-tools/releases/download/storage/Resource_Hacker_5.1.8.zip
Expand-Archive .\Resource_Hacker_5.1.8.zip
cmd /c "Resource_Hacker_5.1.8\ResourceHacker.exe" -open go\build\outputs\windows-release\pikapika.exe -save go\build\outputs\windows-release\pikapika.exe -action addskip -res go/assets/icon.ico -mask ICONGROUP,MAINICON,0
cd go\build\outputs\windows-release
DEL flutter_engine.pdb
DEL flutter_engine.exp
DEL flutter_engine.lib
Compress-Archive * ../../../../build/build.zip
- name: Build (macos)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'macos'
run: |
hover build darwin-dmg
mv go/build/outputs/darwin-dmg-release/*.dmg build/build.dmg
- name: Build (linux)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'linux'
run: |
curl -JOL https://github.com/junmer/source-han-serif-ttf/raw/master/SubsetTTF/CN/SourceHanSerifCN-Regular.ttf
mkdir -p fonts
mv SourceHanSerifCN-Regular.ttf fonts/Roboto.ttf
cat ci/linux_font.yaml >> pubspec.yaml
hover build linux-appimage
mv go/build/outputs/linux-appimage-release/*.AppImage build/build.AppImage
- name: Append application-identifier (ios)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'ios'
run: |
/usr/libexec/PlistBuddy -c 'Add :application-identifier string opensource.pikapika' ios/Runner/Info.plist
- name: Build (ios)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'ios'
run: |
sh scripts/build-ipa.sh
- name: Build (android-arm32)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'android-arm32'
run: |
export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/${{ env.ANDROID_NDK_VERSION }}
sh scripts/build-apk-arm.sh
- name: Build (android-arm64)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'android-arm64'
run: |
export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/${{ env.ANDROID_NDK_VERSION }}
sh scripts/build-apk-arm64.sh
- name: Build (android-x86_64)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'android-x86_64'
run: |
export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/${{ env.ANDROID_NDK_VERSION }}
sh scripts/build-apk-x64.sh
- name: Sign APK (Android)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' )
env:
KEY_FILE_BASE64: ${{ secrets.KEY_FILE_BASE64 }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: |
sh scripts/sign-apk-github-actions.sh
- if: steps.need_build.outputs.skip_build != 'true' && matrix.config.target == 'ios'
name: 'Upload Artifact (iOS)'
uses: actions/upload-artifact@v4
with:
name: 'nosign.ipa'
path: 'build/nosign.ipa'
retention-days: 3
- if: steps.need_build.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' )
name: 'Upload Artifact (Android)'
uses: actions/upload-artifact@v4
with:
name: 'app-release-${{ matrix.config.target }}.apk'
path: 'build/app/outputs/flutter-apk/app-release.apk'
retention-days: 3
- if: steps.need_build.outputs.skip_build != 'true' && matrix.config.target == 'linux'
name: 'Upload Artifact (Linux)'
uses: actions/upload-artifact@v4
with:
name: 'build.AppImage'
path: 'build/build.AppImage'
retention-days: 3
- if: steps.need_build.outputs.skip_build != 'true' && matrix.config.target == 'macos'
name: 'Upload Artifact (MacOS)'
uses: actions/upload-artifact@v4
with:
name: 'build.dmg'
path: 'build/build.dmg'
================================================
FILE: .github/workflows/Release.core.yml
================================================
name: Release-core
permissions:
contents: write
on:
workflow_dispatch:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GO_VERSION: "1.24"
GO_MOBILE_VERSION: v0.0.0-20241213221354-a87c1cf6cf46
jobs:
ci-pass:
name: CI is green
runs-on: ubuntu-latest
needs:
- build_release_assets
steps:
- run: exit 0
build_release_assets:
name: Build and upload assets
strategy:
fail-fast: false
matrix:
config:
- target: ios
host: macos-latest
- target: android
host: ubuntu-latest
runs-on: ${{ matrix.config.host }}
env:
TARGET: ${{ matrix.config.target }}
steps:
- name: Setup golang
uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- name: Cache go modules (Linux)
if: matrix.config.host == 'ubuntu-latest'
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ matrix.config.host }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.config.host }}-go-
- name: Cache go modules (macOS)
if: matrix.config.host == 'macos-latest'
uses: actions/cache@v3
with:
path: |
~/Library/Caches/go-build
~/go/pkg/mod
key: ${{ matrix.config.host }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.config.host }}-go-
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ env.BRANCH }}
- id: check_asset
name: Check asset
run: |
cd ci
go run ./cmd/check_asset_core
- name: Checkout core
if: steps.check_asset.outputs.skip_build != 'true'
uses: actions/checkout@v3
with:
repository: 'niuhuan/pikapika-go-core'
token: ${{ secrets.CORE_TOKEN }}
path: 'go'
- if: steps.check_asset.outputs.skip_build != 'true'
name: Install go mobile (mobile)
run: |
go install golang.org/x/mobile/cmd/gomobile@${{ env.GO_MOBILE_VERSION }}
- name: Build (ios)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'ios'
run: |
sh scripts/bind-ios.sh
- name: Setup java (Android)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'android'
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
- name: Setup android tools (Android)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'android'
uses: android-actions/setup-android@v3
with:
cmdline-tools-version: 8512546
packages: 'platform-tools platforms;android-32 build-tools;30.0.2 ndk;23.1.7779620'
- name: Build (android)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'android'
run: |
sh scripts/bind-android-debug.sh
- name: Upload Asset (All)
if: steps.check_asset.outputs.skip_build != 'true'
run: |
zip -r core.zip go/mobile/lib
cd ci
go run ./cmd/upload_asset_core
================================================
FILE: .github/workflows/Release.yml
================================================
name: Release
permissions:
contents: write
on:
workflow_dispatch:
inputs:
skip_community_notification:
description: 'skip_community_notification'
type: boolean
required: false
default: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANDROID_NDK_VERSION: "23.1.7779620"
GO_MOBILE_VERSION: v0.0.0-20241213221354-a87c1cf6cf46
jobs:
ci-pass:
name: CI is green
runs-on: ubuntu-latest
needs:
- check_release
- build_release_assets
- send_to_community
steps:
- run: exit 0
check_release:
name: Check release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
repository: ${{ github.event.inputs.repo }}
ref: 'master'
- uses: actions/setup-go@v2
with:
go-version: ${{ env.go_version }}
- name: Cache go modules
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ubuntu-latest-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
ubuntu-latest-go-
- name: Check release
run: |
cd ci
go run ./cmd/check_release
build_release_assets:
name: Build release assets
needs:
- check_release
strategy:
fail-fast: false
matrix:
sources:
- branch: master
config:
- target: windows
host: windows-latest
flutter_version: '2.10.3'
go_version: '1.23'
- target: macos
host: macos-latest
flutter_version: '2.10.3'
go_version: '1.23'
- target: linux
host: ubuntu-latest
flutter_version: '2.10.3'
go_version: '1.23'
- target: ios
host: macos-14
flutter_version: '3.13.9'
go_version: '1.24'
- target: android-arm32
host: ubuntu-latest
flutter_version: '3.13.9'
go_version: '1.24'
java: '11'
- target: android-arm64
host: ubuntu-latest
flutter_version: '3.13.9'
go_version: '1.24'
java: '11'
- target: android-x86_64
host: ubuntu-latest
flutter_version: '3.13.9'
go_version: '1.24'
java: '11'
runs-on: ${{ matrix.config.host }}
env:
TARGET: ${{ matrix.config.target }}
FLUTTER_VERSION: ${{ matrix.config.flutter_version }}
BRANCH: ${{ matrix.sources.branch }}
go_version: ${{ matrix.config.go_version }}
steps:
# Setup golang env and cache go module
- name: Setup golang
uses: actions/setup-go@v2
with:
go-version: ${{ env.go_version }}
- name: Cache go modules (Windows)
if: matrix.config.host == 'windows-latest'
uses: actions/cache@v3
with:
path: |
~\AppData\Local\go-build
~\go\pkg\mod
key: ${{ matrix.config.host }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.config.host }}-go-
- name: Cache go modules (Linux)
if: matrix.config.host == 'ubuntu-latest'
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ matrix.config.host }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.config.host }}-go-
- name: Cache go modules (macOS)
if: startsWith(matrix.config.host, 'macos-')
uses: actions/cache@v3
with:
path: |
~/Library/Caches/go-build
~/go/pkg/mod
key: ${{ matrix.config.host }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.config.host }}-go-
# checkout
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ env.BRANCH }}
# check_access
- id: check_asset
name: Check asset
run: |
cd ci
go run ./cmd/check_asset
#
- name: Check core
if: steps.check_asset.outputs.skip_build != 'true'
uses: actions/checkout@v3
with:
repository: 'niuhuan/pikapika-go-core'
token: ${{ secrets.CORE_TOKEN }}
path: 'go'
- name: Setup flutter
if: steps.check_asset.outputs.skip_build != 'true'
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
architecture: x64
- name: Check core
if: steps.check_asset.outputs.skip_build != 'true'
uses: actions/checkout@v3
with:
repository: 'niuhuan/pikapika-go-core'
token: ${{ secrets.CORE_TOKEN }}
path: 'go'
- name: Cache Flutter dependencies (Linux/Android)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' || matrix.config.target == 'linux' )
uses: actions/cache@v3
with:
path: /opt/hostedtoolcache/flutter
key: ${{ runner.os }}-flutter
- name: Cache Flutter dependencies (Mac host)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'ios' || matrix.config.target == 'macos' )
uses: actions/cache@v3
with:
path: /Users/runner/hostedtoolcache/flutter
key: ${{ runner.os }}-flutter
- name: Cache Gradle dependencies (Android)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' )
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Setup java (Android)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' ) && startsWith(matrix.config.flutter_version, '3.24.2') == false
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.config.java }}
distribution: 'temurin'
- name: Setup java (Android)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' ) && startsWith(matrix.config.flutter_version, '3.24.2')
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Setup android tools (Android)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' )
uses: android-actions/setup-android@v3
with:
cmdline-tools-version: 8512546
packages: 'platform-tools platforms;android-32 build-tools;30.0.2 ndk;${{ env.ANDROID_NDK_VERSION }}'
- name: Setup msys2 (Windows)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'windows'
uses: msys2/setup-msys2@v2
with:
install: gcc make
- name: Install dependencies (Linux)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'linux'
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
run: |
curl -JOL https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
chmod a+x appimagetool-x86_64.AppImage
mkdir -p ${GITHUB_WORKSPACE}/bin
mv appimagetool-x86_64.AppImage ${GITHUB_WORKSPACE}/bin/appimagetool
echo ::add-path::${GITHUB_WORKSPACE}/bin
sudo apt-get update
sudo apt-get install -y libgl1-mesa-dev xorg-dev libfuse2 locate
- name: Install hover (desktop)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'linux' || matrix.config.target == 'windows' || matrix.config.target == 'macos')
run: |
go install github.com/go-flutter-desktop/hover@latest
- name: Install go mobile (mobile)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'ios' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-arm32' || matrix.config.target == 'android-x86_64' )
run: |
go install golang.org/x/mobile/cmd/gomobile@${{ env.GO_MOBILE_VERSION }}
- name: Set-Version (All)
if: steps.check_asset.outputs.skip_build != 'true'
run: |
cd ci
cp version.code.txt ../lib/assets/version.txt
- name: Upgrade deps version (flutter2 non-mac)
if: steps.check_asset.outputs.skip_build != 'true' && startsWith(matrix.config.host, 'macos-') == false && startsWith(matrix.config.flutter_version, '2')
run: |
sed -i "s/another_xlider: ^1.0.1+2/another_xlider: 1.0.1+2/g" pubspec.yaml
sed -i "s/flutter_styled_toast: ^2.0.0/flutter_styled_toast: 2.0.0/g" pubspec.yaml
sed -i "s/filesystem_picker: ^3.0.0-beta.1/filesystem_picker: 2.0.0/g" pubspec.yaml
sed -i "s/file_picker: 5.2.5/file_picker: 4.6.1/g" pubspec.yaml
sed -i "s/multi_select_flutter: ^4.0.0/multi_select_flutter: 4.1.2/g" pubspec.yaml
sed -i "s/modal_bottom_sheet: ^3.0.0-pre/modal_bottom_sheet: 2.0.1/g" pubspec.yaml
sed -i "s/Icons.energy_savings_leaf/Icons.ad_units/g" lib/screens/SettingsScreen.dart
sed -i "s/gradle-7.5-bin.zip/gradle-6.7.1-all.zip/g" android/gradle/wrapper/gradle-wrapper.properties
sed -i "s/com.android.tools.build:gradle:7.2.0/com.android.tools.build:gradle:4.1.0/g" android/build.gradle
sed -i "s/1.7.10/1.3.50/g" android/app/build.gradle
sed -i "s/fontFamilyFallback/\/\/fontFamilyFallback/g" lib/basic/config/Themes.dart
sed -i "s/easy_localization: ^3.0.7+1/easy_localization: ^3.0.0/g" pubspec.yaml
sed -i "s/thumbVisibility: true/isAlwaysShown: true/g" lib/basic/config/ShadowCategories.dart
flutter pub get
- name: Upgrade deps version (flutter2 mac)
if: steps.check_asset.outputs.skip_build != 'true' && startsWith(matrix.config.host, 'macos-') && startsWith(matrix.config.flutter_version, '2')
run: |
brew install gnu-sed
gsed -i "s/another_xlider: ^1.0.1+2/another_xlider: 1.0.1+2/g" pubspec.yaml
gsed -i "s/flutter_styled_toast: ^2.0.0/flutter_styled_toast: 2.0.0/g" pubspec.yaml
gsed -i "s/filesystem_picker: ^3.0.0-beta.1/filesystem_picker: 2.0.0/g" pubspec.yaml
gsed -i "s/file_picker: 5.2.5/file_picker: 4.6.1/g" pubspec.yaml
gsed -i "s/multi_select_flutter: ^4.0.0/multi_select_flutter: 4.1.2/g" pubspec.yaml
gsed -i "s/modal_bottom_sheet: ^3.0.0-pre/modal_bottom_sheet: 2.0.1/g" pubspec.yaml
gsed -i "s/Icons.energy_savings_leaf/Icons.ad_units/g" lib/screens/SettingsScreen.dart
gsed -i "s/fontFamilyFallback/\/\/fontFamilyFallback/g" lib/basic/config/Themes.dart
gsed -i "s/easy_localization: ^3.0.7+1/easy_localization: ^3.0.0/g" pubspec.yaml
gsed -i "s/thumbVisibility: true/isAlwaysShown: true/g" lib/basic/config/ShadowCategories.dart
flutter pub get
- name: Build (windows)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'windows'
run: |
hover build windows
curl -JOL https://github.com/ComicSparks/build-tools/releases/download/storage/Resource_Hacker_5.1.8.zip
Expand-Archive .\Resource_Hacker_5.1.8.zip
cmd /c "Resource_Hacker_5.1.8\ResourceHacker.exe" -open go\build\outputs\windows-release\pikapika.exe -save go\build\outputs\windows-release\pikapika.exe -action addskip -res go/assets/icon.ico -mask ICONGROUP,MAINICON,0
cd go\build\outputs\windows-release
DEL flutter_engine.pdb
DEL flutter_engine.exp
DEL flutter_engine.lib
Compress-Archive * ../../../../build/build.zip
- name: Build (macos)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'macos'
run: |
hover build darwin-dmg
mv go/build/outputs/darwin-dmg-release/*.dmg build/build.dmg
- name: Build (linux)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'linux'
run: |
curl -JOL https://github.com/junmer/source-han-serif-ttf/raw/master/SubsetTTF/CN/SourceHanSerifCN-Regular.ttf
mkdir -p fonts
mv SourceHanSerifCN-Regular.ttf fonts/Roboto.ttf
cat ci/linux_font.yaml >> pubspec.yaml
hover build linux-appimage
mv go/build/outputs/linux-appimage-release/*.AppImage build/build.AppImage
- name: Append application-identifier (ios)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'ios'
run: |
/usr/libexec/PlistBuddy -c 'Add :application-identifier string opensource.pikapika' ios/Runner/Info.plist
- name: Build (ios)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'ios'
run: |
sh scripts/build-ipa.sh
- name: Build (android-arm32)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'android-arm32'
run: |
export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/${{ env.ANDROID_NDK_VERSION }}
sh scripts/build-apk-arm.sh
- name: Build (android-arm64)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'android-arm64'
run: |
export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/${{ env.ANDROID_NDK_VERSION }}
sh scripts/build-apk-arm64.sh
- name: Build (android-x86_64)
if: steps.check_asset.outputs.skip_build != 'true' && matrix.config.target == 'android-x86_64'
run: |
export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/${{ env.ANDROID_NDK_VERSION }}
sh scripts/build-apk-x64.sh
- name: Sign APK (Android)
if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' )
env:
KEY_FILE_BASE64: ${{ secrets.KEY_FILE_BASE64 }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: |
sh scripts/sign-apk-github-actions.sh
- name: Upload Asset (All)
if: steps.check_asset.outputs.skip_build != 'true'
run: |
cd ci
go run ./cmd/upload_asset
send_to_community:
if: github.event.inputs.skip_community_notification != 'true'
needs:
- check_release
- build_release_assets
name: Send message to community
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
repository: ${{ github.event.inputs.repo }}
ref: 'master'
- uses: actions/setup-go@v2
with:
go-version: ${{ env.go_version }}
- name: Cache go modules
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Send to community
env:
TG_BOT_TOKEN: ${{ secrets.TG_BOT_TOKEN }}
TG_CHAT_IDS: ${{ secrets.TG_CHAT_IDS }}
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
DISCORD_CHAT_IDS: ${{ secrets.DISCORD_CHAT_IDS }}
run: |
cd ci
go run ./cmd/send_to_community
================================================
FILE: .gitignore
================================================
# 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/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# 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
# PROJECT
/go/mobile/lib/*.aar
/go/mobile/lib/*.jar
/go/mobile/lib/*.framework/
/go/mobile/lib/*.xcframework/
/go/vendor/
ios/build/
# IDE
*.iml
.vscode/
# APP
/lib/assets/version.txt
go.work
# FVM Version Cache
.fvm/
tmp/
.tmp/
================================================
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: f4abaa0735eba4dfd8f33f73363911d63931fe03
channel: stable
project_type: app
================================================
FILE: README-zh_CN.md
================================================
Pikapika
[](https://raw.githubusercontent.com/ComicSparks/pikapika/master/LICENSE)
[](https://github.com/ComicSparks/pikapika/releases)
- 美观易用且无广告的漫画客户端, 能运行在Windows/MacOS/Linux/Android/IOS中。
- 此APP内容存在限制级别内容(例如 露骨/血腥/暴力/吸毒),18岁以下的用户需在监护人陪同下使用,并请您在遵守当地法律法规。
- 您的star和issue是对开发者的莫大鼓励, 可以源仓库下载最新的源码/安装包, 表示支持/提出建议。
- 源仓库地址 [https://github.com/ComicSparks/pikapika](https://github.com/ComicSparks/pikapika)
## 界面 / 功能

### 分流
VPN->代理->分流, 这三个功能如果同时设置, 您会在您手机的VPN上访问代理, 使用代理请求分流服务器。
### 漫画分类/搜索
 
### 漫画阅读/下载/导入/导出
您可以导出任意已经完成的下载到zip, 从另外一台设备导入。 导出的zip解压后可以直接使用其中的HTML进行阅读


### 游戏


## 特性
- [x] 用户
- [x] 登录 / 注册 / 获取个人信息 / 自动打卡
- [x] 修改密码 / 修改签名 / 修改头像
- [x] 漫画
- [x] 分类 / 搜索 / 随机本子 / 看此本子的也在看 / 排行榜
- [x] 在分类中搜索 / 按 "分类 / 标签 / 创建人 / 汉化组" 检索
- [x] 漫画详情 / 章节 / 看图 / 将图片保存到相册
- [x] 收藏 / 喜欢
- [x] 获取评论 / 评论 / 评论回复 (社区评论后无法删除, 请谨慎使用)
- [x] 更新提示
- [x] 游戏
- [x] 列表 / 详情 / 无广告下载
- [x] 下载
- [x] 导入导出 / 无线共享 / 移动设备与PC设备传输
- [x] 导出到加密的归档文件 / 直接观看加密的归档文件
- [ ] 聊天室
- [x] 缓存 / 自动清理
- [x] 设备支持
- [x] 移动端
- [x] 文件关联
- [x] 自定义超链接
- [x] 安卓
- [x] 高刷新频率屏幕适配 (90/120/144... Hz)
- [x] 安卓10以上随系统进入深色/夜间模式
## 其他说明
数据资料存储位置
- ios/android : 程序自身数据目录中, 删除就会清理
- windows : 程序同一目录中data文件夹下
- macos : ~/Library/Application\ Support/pikapika
- linux : ~/.pikapika
## 技术架构
### 多平台适配
这个应用程序使用golang和dart(flutter)作为主要语言, 可以兼容Windows, linux, MacOS, Android, IOS
使用了不同的框架桥接到桌面和移动平台上
- go-flutter => Windows / MacOS / Linux
- gomobile => Android / IOS

### 构建环境
(桌面端/移动端)
- [golang](https://golang.org/) (1.17/1.18)
- [flutter](https://flutter.dev/) (2.10.3/3.7.3)
## 请您遵守使用规则
软件副本分发以及代码使用规则
- 本软件的代码在未经允许的情况下可以自用但不允许释放任何releases, 个人或企业不可用于商业用途, 不可上架任何商店。
- 不要在任何其他 **二次元软件** 的 **聊天社区** 或 **开发社区** 内, 发布有关本软件的链接或信息, 对于观点不同产生的分歧作者不站队任何立场。
- 不要发送本软件安装包到 **任何社区内** , 不要将APK/IPA/ZIP/DMG发送包括任何聊天软件内的群聊功能。 请使用Github中提供的Releases页面的链接。
- 对本仓库的fork需要保留本仓库的链接, 以引导用户在主要仓库进行讨论。
责任声明
- 作者仅分享编程技术, 不分发软件, 不对分发软件承担任何后果。 因传播载造成的法律问题或纠纷, 需行为人自行承担, 请您遵守当地法以及副本接受方(社区或人)所在地区的法律。
================================================
FILE: README.md
================================================
Pikapika
[](https://raw.githubusercontent.com/ComicSparks/pikapika/master/LICENSE)
[](https://github.com/ComicSparks/pikapika/releases)
- A visually appealing, easy-to-use, ad-free manga client that runs on Windows/MacOS/Linux/Android/iOS.
- This app contains restricted content (such as explicit, gory, violent, drug-related scenes). Users under 18 should use it under parental supervision, and please comply with local laws and regulations.
- Your stars and issues are a great encouragement to the developers. You can download the latest source code/installation package from the source repository to show support/offer suggestions.
- Source Repository URL is [https://github.com/ComicSparks/pikapika](https://github.com/ComicSparks/pikapika)
## Interface / Functions

### Traffic Diversion
VPN -> Proxy -> Traffic Diversion: If these three functions are set simultaneously, you will access the proxy through the VPN on your phone, using the proxy to request the traffic diversion server.
### Comic categories/search
Search comics in categories
### Comic reader/download/imports/exports
You can export any completed downloads to a zip file and import it from another device. After extracting the exported zip, you can directly use the HTML files within for reading.
### Games
You can download games without ads.
## Features
- [x] Users
- [x] Login / Register / Get personal information / Auto check-in
- [x] Change password / Signature / Avatar
- [x] Comics
- [x] Categories / Search / Random comic / Also reading this comic / Rankings
- [x] Search in categories / Search by "category / tag / creator / translation group"
- [x] Comic details / Chapters / View images / Save images to the album
- [x] Favorites / Likes
- [x] Get comments / Comment / Comment reply (comments in the community cannot be deleted, please use with caution)
- [x] Update notification
- [x] Games
- [x] List / Details / Ad-free download
- [x] Downloads
- [x] Import/export / Wireless sharing / Transfer between mobile and PC devices
- [x] Export to encrypted archive file / Directly view encrypted archive file
- [ ] Chat room
- [x] Cache / Auto clean
- [x] Device support
- [x] Mobile
- [x] File association
- [x] Custom hyperlinks
- [x] Android
- [x] High refresh rate screen adaptation (90/120/144... Hz)
- [x] Android 10 and above automatically switch to dark/night mode with the system
## Other tips
Data storage location
- ios/android: In the program's own data directory, deleting it will clear it
- windows: In the data folder in the same directory as the program
- macos: ~/Library/Application\ Support/pikapika
- linux: ~/.pikapika
## Technology Stack
### Multi-platform adaptation
This application uses golang and dart (flutter) as the main languages and is compatible with Windows, Linux, MacOS, Android, and iOS.
Different frameworks are used to bridge to desktop and mobile platforms
- go-flutter => Windows / MacOS / Linux
- gomobile => Android / iOS

### Build environment
(Desktop/Mobile)
- [golang](https://golang.org/) (1.17/1.18)
- [flutter](https://flutter.dev/) (2.10.3/3.7.3)
## Please follow the usage rules.
Software copy distribution and code usage rules
- The code of this software can be used for personal use without permission, but no releases are allowed, and it cannot be used for commercial purposes by individuals or companies, nor can it be put on any store.
- Do not post links or information about this software in any **two-dimensional** chat community or development community. The author does not take any stance on any views that differ.
- Do not send the software installation package to **any community**, and do not send APK/IPA/ZIP/DMG to any group chat function in any chat software. Please use the link provided on the Releases page in Github.
- Forks of this repository must retain the link to this repository to guide users to discuss in the main repository.
Disclaimer
- The author only shares programming technology and does not distribute software. The person who spreads the content is responsible for any legal issues or disputes caused by the spread. Please comply with local laws and the laws of the recipient (community or individual) region.
================================================
FILE: analysis_options.yaml
================================================
include: package:flutter_lints/flutter.yaml
linter:
rules:
avoid_print: false
unnecessary_this: false
file_names: false
constant_identifier_names: false
no_logic_in_create_state: false
================================================
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
================================================
FILE: android/app/build.gradle
================================================
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 33 // flutter.compileSdkVersion
// ndkVersion flutter.ndkVersion
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 "opensource.pic2acg"
// 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 21 // flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
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"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
implementation fileTree(dir: "../../go/mobile/lib", include: ["*.jar", "*.aar"])
}
================================================
FILE: android/app/src/debug/AndroidManifest.xml
================================================
================================================
FILE: android/app/src/main/AndroidManifest.xml
================================================
================================================
FILE: android/app/src/main/kotlin/opensource/pic2acg/MainActivity.kt
================================================
package opensource.pic2acg
import android.content.ContentValues
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.hardware.biometrics.BiometricPrompt
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.*
import android.provider.MediaStore
import android.util.Log
import android.view.Display
import android.view.KeyEvent
import android.view.WindowManager
import androidx.annotation.NonNull
import androidx.annotation.RequiresApi
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodChannel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.newSingleThreadContext
import kotlinx.coroutines.sync.Mutex
import mobile.Mobile
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.file.Files
import java.util.concurrent.Executors
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit
class MainActivity : FlutterActivity() {
// 为什么换成换成线程池而不继续使用携程 : 下载图片速度慢会占满携程造成拥堵, 接口无法请求
private val pool = Executors.newCachedThreadPool { runnable ->
Thread(runnable).also { it.isDaemon = true }
}
private val uiThreadHandler = Handler(Looper.getMainLooper())
private val scope = CoroutineScope(newSingleThreadContext("worker-scope"))
private val notImplementedToken = Any()
private fun MethodChannel.Result.withCoroutine(exec: () -> Any?) {
pool.submit {
try {
val data = exec()
uiThreadHandler.post {
when (data) {
notImplementedToken -> {
notImplemented()
}
is Unit, null -> {
success(null)
}
else -> {
success(data)
}
}
}
} catch (e: Exception) {
Log.e("Method", "Exception", e)
uiThreadHandler.post {
error("", e.message, "")
}
}
}
}
@RequiresApi(Build.VERSION_CODES.KITKAT)
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
Mobile.initApplication(androidDataLocal())
// Method Channel
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"method"
).setMethodCallHandler { call, result ->
result.withCoroutine {
when (call.method) {
"flatInvoke" -> {
Mobile.flatInvoke(
call.argument("method")!!,
call.argument("params")!!
)
}
"androidSaveFileToImage" -> {
saveImage(call.argument("path")!!)
}
"androidGetModes" -> {
modes()
}
"androidSetMode" -> {
setMode(call.argument("mode")!!)
}
"androidGetVersion" -> Build.VERSION.SDK_INT
// 现在的文件储存路径, 默认路径返回空字符串 ""
"dataLocal" -> androidDataLocal()
// 迁移到那个地方, 如果是空字符串则迁移会默认位置
"migrate" -> androidMigrate(call.argument("path")!!)
// 获取可以迁移数据地址
"androidGetExtendDirs" -> androidGetExtendDirs()
"androidSecureFlag" -> androidSecureFlag(call.argument("flag")!!)
"verifyAuthentication" -> auth()
"androidStorageRoot" -> storageRoot()
"androidDefaultExportsDir" -> androidDefaultExportsDir().absolutePath
"androidMkdirs" -> androidMkdirs(
call.arguments() ?: throw Exception("need arg")
)
else -> {
notImplementedToken
}
}
}
}
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"network"
).setMethodCallHandler { call, result ->
result.withCoroutine {
when (call.method) {
"getNetworkType" -> getNetworkType()
"getIsMobile" -> isMobileNetwork()
else -> notImplementedToken
}
}
}
//
val eventMutex = Mutex()
var eventSink: EventChannel.EventSink? = null
EventChannel(flutterEngine.dartExecutor.binaryMessenger, "flatEvent")
.setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
events?.let { events ->
scope.launch {
eventMutex.lock()
eventSink = events
eventMutex.unlock()
}
}
}
override fun onCancel(arguments: Any?) {
scope.launch {
eventMutex.lock()
eventSink = null
eventMutex.unlock()
}
}
})
Mobile.eventNotify { message ->
scope.launch {
eventMutex.lock()
try {
eventSink?.let {
uiThreadHandler.post {
it.success(message)
}
}
} finally {
eventMutex.unlock()
}
}
}
//
EventChannel(flutterEngine.dartExecutor.binaryMessenger, "volume_button")
.setStreamHandler(volumeStreamHandler)
}
private fun androidDataLocal(): String {
val localFile = File(context!!.filesDir.absolutePath, "data.local")
if (localFile.exists()) {
val path = String(FileInputStream(localFile).use { it.readBytes() })
if (File(path).isDirectory) {
return path
}
}
return context!!.filesDir.absolutePath
}
private fun androidGetExtendDirs(): String {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
val result = context!!.getExternalFilesDirs("")?.toMutableList()?.also {
it.add(context!!.filesDir.absoluteFile)
}?.joinToString("|")
if (result != null) {
return result
}
}
throw Exception("System version too low")
}
private fun androidMigrate(path: String) {
val current = androidDataLocal()
if (current == path) {
return
}
// 删除位置配置文件
if (File(current, "data.local").exists()) {
File(current, "data.local").delete()
}
// 目标位置文件夹不存在就创建,存在则清理
val target = File(path)
if (!target.exists()) {
target.mkdirs()
}
target.listFiles().forEach { delete(it) }
// 移动所有文件夹
File(current).listFiles().forEach {
move(it, File(target, it.name))
}
val localFile = File(context!!.filesDir.absolutePath, "data.local")
if (path == context!!.filesDir.absolutePath) {
localFile.delete()
} else {
FileOutputStream(localFile).use { it.write(path.toByteArray()) }
}
}
private fun delete(f: File) {
f.delete()
}
private fun move(f: File, t: File) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (f.isDirectory) {
Files.createDirectories(t.toPath())
f.listFiles().forEach { move(it, File(t, it.name)) }
Files.delete(f.toPath())
} else {
Files.move(f.toPath(), t.toPath())
}
} else {
if (f.isDirectory) {
t.mkdirs()
f.listFiles().forEach { move(it, File(t, it.name)) }
f.delete()
} else {
FileOutputStream(t).use { o ->
FileInputStream(f).use { i ->
o.write(i.readBytes())
}
}
f.delete()
}
}
}
// save_image
private fun saveImage(path: String) {
BitmapFactory.decodeFile(path)?.let { bitmap ->
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, System.currentTimeMillis().toString())
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { //this one
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
put(MediaStore.MediaColumns.IS_PENDING, 1)
}
}
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
?.let { uri ->
contentResolver.openOutputStream(uri)?.use { fos ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { //this one
contentValues.clear()
contentValues.put(MediaStore.Video.Media.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
}
}
}
}
// fps mods
private fun mixDisplay(): Display? {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
display?.let {
return it
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
windowManager.defaultDisplay?.let {
return it
}
}
return null
}
private fun modes(): List {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mixDisplay()?.let { display ->
return display.supportedModes.map { mode ->
mode.toString()
}
}
}
return ArrayList()
}
private fun setMode(string: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mixDisplay()?.let { display ->
if (string == "") {
uiThreadHandler.post {
window.attributes = window.attributes.also { attr ->
attr.preferredDisplayModeId = 0
}
}
return
}
return display.supportedModes.forEach { mode ->
if (mode.toString() == string) {
uiThreadHandler.post {
window.attributes = window.attributes.also { attr ->
attr.preferredDisplayModeId = mode.modeId
}
}
return
}
}
}
}
}
// volume_buttons
private var volumeEvents: EventChannel.EventSink? = null
private val volumeStreamHandler = object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
volumeEvents = events
}
override fun onCancel(arguments: Any?) {
volumeEvents = null
}
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
volumeEvents?.let {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
uiThreadHandler.post {
it.success("DOWN")
}
return true
}
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
uiThreadHandler.post {
it.success("UP")
}
return true
}
}
return super.onKeyDown(keyCode, event)
}
private fun androidSecureFlag(flag: Boolean) {
uiThreadHandler.post {
if (flag) {
window.setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
}
}
// withCoroutine -> queue
private fun auth(): Boolean {
var queue = LinkedBlockingQueue()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
var mBiometricPrompt = BiometricPrompt.Builder(this)
.setTitle("验证身份")
.setDescription("需要验证您的身份")
.setNegativeButton(
"取消", mainExecutor
) { _, _ -> queue.add(false) }
.build()
var mCancellationSignal = CancellationSignal()
mCancellationSignal.setOnCancelListener {
queue.add(false)
}
var mAuthenticationCallback = object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
super.onAuthenticationError(errorCode, errString)
queue.add(false)
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
queue.add(false)
}
override fun onAuthenticationSucceeded(result1: BiometricPrompt.AuthenticationResult?) {
super.onAuthenticationSucceeded(result1)
queue.add(true)
}
}
mBiometricPrompt.authenticate(
mCancellationSignal,
mainExecutor,
mAuthenticationCallback
)
} else {
queue.add(false)
}
return queue.poll(5, TimeUnit.MINUTES) ?: false
}
fun storageRoot(): String {
return Environment.getExternalStorageDirectory().absolutePath
}
private fun downloadsDir(): File {
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
?: throw java.lang.IllegalStateException()
}
private fun defaultAppDir(): File {
return File(downloadsDir(), "pic2acg")
}
private fun androidDefaultExportsDir(): File {
return File(defaultAppDir(), "exports")
}
private fun androidMkdirs(path: String) {
val dir = File(path)
if (!dir.exists()) {
dir.mkdirs()
}
}
private fun getNetworkType(): String {
val ctx = context ?: return "none"
val cm = ctx.getSystemService(ConnectivityManager::class.java) ?: return "none"
val active = cm.activeNetwork ?: return "none"
val caps = cm.getNetworkCapabilities(active) ?: return "none"
return when {
caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> "mobile"
caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> "wifi"
caps.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> "ethernet"
caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> findNonVpnTransport(cm) ?: "vpn"
else -> "other"
}
}
private fun isMobileNetwork(): Boolean {
val ctx = context ?: return false
val cm = ctx.getSystemService(ConnectivityManager::class.java) ?: return false
val active = cm.activeNetwork ?: return false
val caps = cm.getNetworkCapabilities(active) ?: return false
if (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return true
}
if (caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
return findNonVpnTransport(cm) == "mobile"
}
return false
}
private fun findNonVpnTransport(cm: ConnectivityManager): String? {
for (network in cm.allNetworks) {
val caps = cm.getNetworkCapabilities(network) ?: continue
if (!caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
continue
}
if (caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
continue
}
if (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return "mobile"
}
if (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return "wifi"
}
if (caps.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
return "ethernet"
}
}
return null
}
}
================================================
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
================================================
buildscript {
ext.kotlin_version = '1.7.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
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
================================================
#Fri Oct 29 09:53:43 CST 2021
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
================================================
FILE: android/gradle.properties
================================================
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
================================================
FILE: android/settings.gradle
================================================
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"
================================================
FILE: ci/cmd/check_asset/main.go
================================================
package main
import (
"ci/commons"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
)
func main() {
// get ghToken
ghToken := os.Getenv("GITHUB_TOKEN")
if ghToken == "" {
println("Env ${GITHUB_TOKEN} is not set")
os.Exit(1)
}
// get version
version := commons.LoadVersion()
// get TARGET
target := os.Getenv("TARGET")
if target == "" {
println("Env ${TARGET} is not set")
os.Exit(1)
}
// get FLUTTER_VERSION
flutterVersion := os.Getenv("FLUTTER_VERSION")
if target == "" {
println("Env ${FLUTTER_VERSION} is not set")
os.Exit(1)
}
// get BRANCH
branch := os.Getenv("BRANCH")
if target == "" {
println("Env ${BRANCH} is not set")
os.Exit(1)
}
//
var releaseFileName = commons.AssetName(version, flutterVersion, target, branch)
// get version
githubRepository := os.Getenv("GITHUB_REPOSITORY")
if githubRepository == "" {
println("Env ${GITHUB_REPOSITORY} is not set")
os.Exit(1)
}
getReleaseRequest, err := http.NewRequest(
"GET",
fmt.Sprintf("https://api.github.com/repos/%v/releases/tags/%v", githubRepository, version.Code),
nil,
)
if err != nil {
panic(err)
}
getReleaseRequest.Header.Set("User-Agent", commons.Ua)
getReleaseRequest.Header.Set("Authorization", "token "+ghToken)
getReleaseResponse, err := http.DefaultClient.Do(getReleaseRequest)
if err != nil {
panic(err)
}
defer getReleaseResponse.Body.Close()
if getReleaseResponse.StatusCode == 404 {
panic("NOT FOUND RELEASE")
}
buff, err := ioutil.ReadAll(getReleaseResponse.Body)
if err != nil {
panic(err)
}
var release commons.Release
err = json.Unmarshal(buff, &release)
if err != nil {
println(string(buff))
panic(err)
}
for _, asset := range release.Assets {
if asset.Name == releaseFileName {
println("::set-output name=skip_build::true")
os.Exit(0)
}
}
print("::set-output name=skip_build::false")
}
================================================
FILE: ci/cmd/check_asset_core/main.go
================================================
package main
import (
"ci/commons"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
)
func main() {
// get ghToken
ghToken := os.Getenv("GITHUB_TOKEN")
if ghToken == "" {
println("Env ${GITHUB_TOKEN} is not set")
os.Exit(1)
}
// get version
version := commons.LoadVersion()
// get TARGET
target := os.Getenv("TARGET")
if target == "" {
println("Env ${TARGET} is not set")
os.Exit(1)
}
//
var releaseFileName = fmt.Sprintf("core-%v-%v.zip", version.Code, target)
// get version
githubRepository := os.Getenv("GITHUB_REPOSITORY")
if githubRepository == "" {
println("Env ${GITHUB_REPOSITORY} is not set")
os.Exit(1)
}
getReleaseRequest, err := http.NewRequest(
"GET",
fmt.Sprintf("https://api.github.com/repos/%v/releases/tags/%v", githubRepository, version.Code),
nil,
)
if err != nil {
panic(err)
}
getReleaseRequest.Header.Set("User-Agent", commons.Ua)
getReleaseRequest.Header.Set("Authorization", "token "+ghToken)
getReleaseResponse, err := http.DefaultClient.Do(getReleaseRequest)
if err != nil {
panic(err)
}
defer getReleaseResponse.Body.Close()
if getReleaseResponse.StatusCode == 404 {
panic("NOT FOUND RELEASE")
}
buff, err := ioutil.ReadAll(getReleaseResponse.Body)
if err != nil {
panic(err)
}
var release commons.Release
err = json.Unmarshal(buff, &release)
if err != nil {
println(string(buff))
panic(err)
}
for _, asset := range release.Assets {
if asset.Name == releaseFileName {
println("::set-output name=skip_build::true")
os.Exit(0)
}
}
print("::set-output name=skip_build::false")
}
================================================
FILE: ci/cmd/check_release/main.go
================================================
package main
import (
"bytes"
"ci/commons"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
)
func main() {
// get ghToken
ghToken := os.Getenv("GITHUB_TOKEN")
if ghToken == "" {
println("Env ${GITHUB_TOKEN} is not set")
os.Exit(1)
}
// get version
version := commons.LoadVersion()
// get version
githubRepository := os.Getenv("GITHUB_REPOSITORY")
if githubRepository == "" {
println("Env ${GITHUB_REPOSITORY} is not set")
os.Exit(1)
}
getReleaseRequest, err := http.NewRequest(
"GET",
fmt.Sprintf("https://api.github.com/repos/%v/releases/tags/%v", githubRepository, version.Code),
nil,
)
if err != nil {
panic(nil)
}
getReleaseRequest.Header.Set("User-Agent", commons.Ua)
getReleaseRequest.Header.Set("Authorization", "token "+ghToken)
getReleaseResponse, err := http.DefaultClient.Do(getReleaseRequest)
if err != nil {
panic(nil)
}
defer getReleaseResponse.Body.Close()
if getReleaseResponse.StatusCode == 404 {
url := fmt.Sprintf("https://api.github.com/repos/%v/releases", githubRepository)
body := map[string]interface{}{
"tag_name": version.Code,
"target_commitish": commons.MainBranch,
"name": version.Code,
"body": version.Info,
}
var buff []byte
buff, err = json.Marshal(&body)
if err != nil {
panic(err)
}
var createReleaseRequest *http.Request
createReleaseRequest, err = http.NewRequest("POST", url, bytes.NewBuffer(buff))
if err != nil {
panic(nil)
}
createReleaseRequest.Header.Set("User-Agent", commons.Ua)
createReleaseRequest.Header.Set("Authorization", "token "+ghToken)
var createReleaseResponse *http.Response
createReleaseResponse, err = http.DefaultClient.Do(createReleaseRequest)
if err != nil {
panic(nil)
}
defer createReleaseResponse.Body.Close()
if createReleaseResponse.StatusCode != 201 {
buff, err = ioutil.ReadAll(createReleaseResponse.Body)
if err != nil {
panic(err)
}
println(string(buff))
panic("NOT 201")
}
}
}
================================================
FILE: ci/cmd/send_to_community/main.go
================================================
package main
import (
"ci/commons"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
"github.com/andersfylling/disgord"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)
func main() {
// get version
var version commons.Version
codeFile, err := ioutil.ReadFile("version.code.txt")
if err != nil {
panic(err)
}
version.Code = strings.TrimSpace(string(codeFile))
infoFile, err := ioutil.ReadFile("version.info.txt")
if err != nil {
panic(err)
}
version.Info = strings.TrimSpace(string(infoFile))
// message
githubRepository := os.Getenv("GITHUB_REPOSITORY")
if githubRepository == "" {
println("Env ${GITHUB_REPOSITORY} is not set")
os.Exit(1)
}
var message = fmt.Sprintf(
"%v 版本 %v 发布! \n\n"+
"更新内容:\n"+
"%v\n\n"+
"https://github.com/%v/%v/releases/tag/%v",
githubRepository, version.Code, version.Info, githubRepository, githubRepository, version.Code,
)
// get accounts
tgToken := os.Getenv("TG_BOT_TOKEN")
tgChatIdsStr := os.Getenv("TG_CHAT_IDS")
discordToken := os.Getenv("DISCORD_BOT_TOKEN")
discordChatIdsStr := os.Getenv("DISCORD_CHAT_IDS")
if tgToken != "" && tgChatIdsStr != "" {
var tgChatIds []int64
json.Unmarshal([]byte(tgChatIdsStr), &tgChatIds)
if len(tgChatIds) > 0 {
sendMessageToTg(tgToken, tgChatIds, message)
}
}
if discordToken != "" && discordChatIdsStr != "" {
var discordChatIds []uint64
json.Unmarshal([]byte(discordChatIdsStr), &discordChatIds)
if len(discordChatIds) > 0 {
sendMessageToDiscord(discordToken, discordChatIds, message)
}
}
}
func sendMessageToTg(token string, ids []int64, message string) {
bot, err := tgbotapi.NewBotAPI(token)
if err != nil {
log.Panic(err)
}
for _, id := range ids {
msg := tgbotapi.NewMessage(id, message)
_, err = bot.Send(msg)
if err != nil {
fmt.Sprintf("Send message to tg chat : %v (error : %v)", id, err.Error())
} else {
fmt.Sprintf("Send message to tg chat : %v (success)", id)
}
}
}
func sendMessageToDiscord(token string, ids []uint64, message string) {
client, err := disgord.NewClient(context.Background(), disgord.Config{
BotToken: token,
})
if err != nil {
fmt.Sprintf("discord login failed : %v", err.Error())
return
}
for _, id := range ids {
_, err = client.SendMsg(disgord.Snowflake(id), message)
if err != nil {
fmt.Sprintf("Send message to tg chat : %v (error : %v)", id, err.Error())
} else {
fmt.Sprintf("Send message to tg chat : %v (success)", id)
}
}
}
================================================
FILE: ci/cmd/upload_asset/main.go
================================================
package main
import (
"ci/commons"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"path"
)
func main() {
// get ghToken
ghToken := os.Getenv("GITHUB_TOKEN")
if ghToken == "" {
println("Env ${GITHUB_TOKEN} is not set")
os.Exit(1)
}
// get version
version := commons.LoadVersion()
// get TARGET
target := os.Getenv("TARGET")
if target == "" {
println("Env ${TARGET} is not set")
os.Exit(1)
}
// get FLUTTER_VERSION
flutterVersion := os.Getenv("FLUTTER_VERSION")
if target == "" {
println("Env ${FLUTTER_VERSION} is not set")
os.Exit(1)
}
// get BRANCH
branch := os.Getenv("BRANCH")
if target == "" {
println("Env ${BRANCH} is not set")
os.Exit(1)
}
//
var releaseFileName = commons.AssetName(version, flutterVersion, target, branch)
//
var releaseFilePath string
var contentType string
var contentLength int64
switch target {
case "macos":
releaseFilePath = "build/build.dmg"
contentType = "application/octet-stream"
case "ios":
releaseFilePath = "build/nosign.ipa"
contentType = "application/octet-stream"
case "windows":
releaseFilePath = "build/build.zip"
contentType = "application/octet-stream"
case "linux":
releaseFilePath = "build/build.AppImage"
contentType = "application/octet-stream"
case "android-arm32":
releaseFilePath = "build/app/outputs/flutter-apk/app-release.apk"
contentType = "application/octet-stream"
case "android-arm64":
releaseFilePath = "build/app/outputs/flutter-apk/app-release.apk"
contentType = "application/octet-stream"
case "android-x86_64":
releaseFilePath = "build/app/outputs/flutter-apk/app-release.apk"
contentType = "application/octet-stream"
}
releaseFilePath = path.Join("..", releaseFilePath)
info, err := os.Stat(releaseFilePath)
if err != nil {
panic(err)
}
contentLength = info.Size()
if contentLength == 166 {
panic("NOT FOUND RELEASE FILE")
}
// get githubRepository
githubRepository := os.Getenv("GITHUB_REPOSITORY")
if githubRepository == "" {
println("Env ${GITHUB_REPOSITORY} is not set")
os.Exit(1)
}
// get version
getReleaseRequest, err := http.NewRequest(
"GET",
fmt.Sprintf("https://api.github.com/repos/%v/releases/tags/%v", githubRepository, version.Code),
nil,
)
if err != nil {
panic(err)
}
getReleaseRequest.Header.Set("User-Agent", commons.Ua)
getReleaseRequest.Header.Set("Authorization", "token "+ghToken)
getReleaseResponse, err := http.DefaultClient.Do(getReleaseRequest)
if err != nil {
panic(err)
}
defer getReleaseResponse.Body.Close()
if getReleaseResponse.StatusCode == 404 {
panic("NOT FOUND RELEASE")
}
buff, err := ioutil.ReadAll(getReleaseResponse.Body)
if err != nil {
panic(err)
}
var release commons.Release
err = json.Unmarshal(buff, &release)
if err != nil {
println(string(buff))
panic(err)
}
file, err := os.Open(releaseFilePath)
if err != nil {
panic(err)
}
defer file.Close()
uploadUrl := fmt.Sprintf("https://uploads.github.com/repos/%v/releases/%v/assets?name=%v", githubRepository, release.Id, releaseFileName)
uploadRequest, err := http.NewRequest("POST", uploadUrl, file)
if err != nil {
panic(err)
}
uploadRequest.Header.Set("User-Agent", commons.Ua)
uploadRequest.Header.Set("Authorization", "token "+ghToken)
uploadRequest.Header.Set("Content-Type", contentType)
uploadRequest.ContentLength = contentLength
uploadResponse, err := http.DefaultClient.Do(uploadRequest)
if err != nil {
panic(err)
}
if uploadResponse.StatusCode != 201 {
buff, err = ioutil.ReadAll(uploadResponse.Body)
if err != nil {
panic(err)
}
println(string(buff))
panic("NOT 201")
}
}
================================================
FILE: ci/cmd/upload_asset_core/main.go
================================================
package main
import (
"ci/commons"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"path"
)
func main() {
// get ghToken
ghToken := os.Getenv("GITHUB_TOKEN")
if ghToken == "" {
println("Env ${GITHUB_TOKEN} is not set")
os.Exit(1)
}
// get version
version := commons.LoadVersion()
// get TARGET
target := os.Getenv("TARGET")
if target == "" {
println("Env ${TARGET} is not set")
os.Exit(1)
}
//
var releaseFileName = fmt.Sprintf("core-%v-%v.zip", version.Code, target)
var releaseFilePath = "core.zip"
var contentLength int64
releaseFilePath = path.Join("..", releaseFilePath)
info, err := os.Stat(releaseFilePath)
if err != nil {
panic(err)
}
contentLength = info.Size()
// get version
githubRepository := os.Getenv("GITHUB_REPOSITORY")
if githubRepository == "" {
println("Env ${GITHUB_REPOSITORY} is not set")
os.Exit(1)
}
getReleaseRequest, err := http.NewRequest(
"GET",
fmt.Sprintf("https://api.github.com/repos/%v/releases/tags/%v", githubRepository, version.Code),
nil,
)
if err != nil {
panic(err)
}
getReleaseRequest.Header.Set("User-Agent", commons.Ua)
getReleaseRequest.Header.Set("Authorization", "token "+ghToken)
getReleaseResponse, err := http.DefaultClient.Do(getReleaseRequest)
if err != nil {
panic(err)
}
defer getReleaseResponse.Body.Close()
if getReleaseResponse.StatusCode == 404 {
panic("NOT FOUND RELEASE")
}
buff, err := ioutil.ReadAll(getReleaseResponse.Body)
if err != nil {
panic(err)
}
var release commons.Release
err = json.Unmarshal(buff, &release)
if err != nil {
println(string(buff))
panic(err)
}
file, err := os.Open(releaseFilePath)
if err != nil {
panic(err)
}
defer file.Close()
uploadUrl := fmt.Sprintf("https://uploads.github.com/repos/%v/releases/%v/assets?name=%v", githubRepository, release.Id, releaseFileName)
uploadRequest, err := http.NewRequest("POST", uploadUrl, file)
if err != nil {
panic(err)
}
uploadRequest.Header.Set("User-Agent", commons.Ua)
uploadRequest.Header.Set("Authorization", "token "+ghToken)
uploadRequest.Header.Set("Content-Type", "application/octet-stream")
uploadRequest.ContentLength = contentLength
uploadResponse, err := http.DefaultClient.Do(uploadRequest)
if err != nil {
panic(err)
}
if uploadResponse.StatusCode != 201 {
buff, err = ioutil.ReadAll(uploadResponse.Body)
if err != nil {
panic(err)
}
println(string(buff))
panic("NOT 201")
}
}
================================================
FILE: ci/commons/funcs.go
================================================
package commons
import (
"fmt"
"io/ioutil"
"strings"
)
const Ua = "pikapika ci"
const MainBranch = "master"
func LoadVersion() Version {
var version Version
codeFile, err := ioutil.ReadFile("version.code.txt")
if err != nil {
panic(err)
}
version.Code = strings.TrimSpace(string(codeFile))
infoFile, err := ioutil.ReadFile("version.info.txt")
if err != nil {
panic(err)
}
version.Info = strings.TrimSpace(string(infoFile))
return version
}
func AssetName(version Version, flutterVersion, target, branch string) string {
releaseFileName := fmt.Sprintf("pikapika-%v", version.Code)
switch target {
case "macos":
releaseFileName += "-macos-intel"
releaseFileName += "-flutter_" + flutterVersion
releaseFileName += ".dmg"
case "ios":
releaseFileName += "-ios_nosign"
releaseFileName += "-flutter_" + flutterVersion
releaseFileName += ".ipa"
case "windows":
releaseFileName += "-windows-x86_64"
releaseFileName += "-flutter_" + flutterVersion
releaseFileName += ".zip"
case "linux":
releaseFileName += "-linux-x86_64"
releaseFileName += "-flutter_" + flutterVersion
releaseFileName += ".AppImage"
case "android-arm32":
releaseFileName += "-android-arm32"
releaseFileName += "-flutter_" + flutterVersion
releaseFileName += ".apk"
case "android-arm64":
releaseFileName += "-android-arm64"
releaseFileName += "-flutter_" + flutterVersion
releaseFileName += ".apk"
case "android-x86_64":
releaseFileName += "-android-x86_64"
releaseFileName += "-flutter_" + flutterVersion
releaseFileName += ".apk"
}
if branch != "master" && branch != "main" {
releaseFileName = branch + "-" + releaseFileName
}
return releaseFileName
}
================================================
FILE: ci/commons/types.go
================================================
package commons
import "time"
type Version struct {
Code string `json:"code"`
Info string `json:"info"`
}
type Release struct {
Url string `json:"url"`
HtmlUrl string `json:"html_url"`
AssetsUrl string `json:"assets_url"`
UploadUrl string `json:"upload_url"`
TarballUrl string `json:"tarball_url"`
ZipballUrl string `json:"zipball_url"`
DiscussionUrl string `json:"discussion_url"`
Id int `json:"id"`
NodeId string `json:"node_id"`
TagName string `json:"tag_name"`
TargetCommitish string `json:"target_commitish"`
Name string `json:"name"`
Body string `json:"body"`
Draft bool `json:"draft"`
Prerelease bool `json:"prerelease"`
CreatedAt time.Time `json:"created_at"`
PublishedAt time.Time `json:"published_at"`
Author struct {
Login string `json:"login"`
Id int `json:"id"`
NodeId string `json:"node_id"`
AvatarUrl string `json:"avatar_url"`
GravatarId string `json:"gravatar_id"`
Url string `json:"url"`
HtmlUrl string `json:"html_url"`
FollowersUrl string `json:"followers_url"`
FollowingUrl string `json:"following_url"`
GistsUrl string `json:"gists_url"`
StarredUrl string `json:"starred_url"`
SubscriptionsUrl string `json:"subscriptions_url"`
OrganizationsUrl string `json:"organizations_url"`
ReposUrl string `json:"repos_url"`
EventsUrl string `json:"events_url"`
ReceivedEventsUrl string `json:"received_events_url"`
Type string `json:"type"`
SiteAdmin bool `json:"site_admin"`
} `json:"author"`
Assets []struct {
Url string `json:"url"`
BrowserDownloadUrl string `json:"browser_download_url"`
Id int `json:"id"`
NodeId string `json:"node_id"`
Name string `json:"name"`
Label string `json:"label"`
State string `json:"state"`
ContentType string `json:"content_type"`
Size int `json:"size"`
DownloadCount int `json:"download_count"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Uploader struct {
Login string `json:"login"`
Id int `json:"id"`
NodeId string `json:"node_id"`
AvatarUrl string `json:"avatar_url"`
GravatarId string `json:"gravatar_id"`
Url string `json:"url"`
HtmlUrl string `json:"html_url"`
FollowersUrl string `json:"followers_url"`
FollowingUrl string `json:"following_url"`
GistsUrl string `json:"gists_url"`
StarredUrl string `json:"starred_url"`
SubscriptionsUrl string `json:"subscriptions_url"`
OrganizationsUrl string `json:"organizations_url"`
ReposUrl string `json:"repos_url"`
EventsUrl string `json:"events_url"`
ReceivedEventsUrl string `json:"received_events_url"`
Type string `json:"type"`
SiteAdmin bool `json:"site_admin"`
} `json:"uploader"`
} `json:"assets"`
}
================================================
FILE: ci/go.mod
================================================
module ci
go 1.17
require (
github.com/andersfylling/disgord v0.35.1
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
)
require (
github.com/andersfylling/snowflake/v5 v5.0.1 // indirect
github.com/klauspost/compress v1.15.1 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect
nhooyr.io/websocket v1.8.7 // indirect
)
================================================
FILE: ci/go.sum
================================================
github.com/andersfylling/disgord v0.35.1 h1:auhxW9z96/uSF7MYwfuv8AP71AVIc0+jZQWjZdwIqNE=
github.com/andersfylling/disgord v0.35.1/go.mod h1:gTzujw2mWxJWxAPo3LwxG5+a4/n4ikdD+JMb1mONmUM=
github.com/andersfylling/snowflake/v5 v5.0.1 h1:unXbYSij6tRCGJzoLz9zl3nJsqd9hu7bbYSgB8K8/i0=
github.com/andersfylling/snowflake/v5 v5.0.1/go.mod h1:AdhrB+kewjnQInv8cR7ABe2SGoVXh79njnipUnz1HFc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc=
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
k8s.io/gengo v0.0.0-20220307231824-4627b89bbf1b/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
================================================
FILE: ci/linux_font.yaml
================================================
fonts:
- family: Roboto
fonts:
- asset: fonts/Roboto.ttf
================================================
FILE: ci/version.code.txt
================================================
v1.8.19
================================================
FILE: ci/version.info.txt
================================================
v1.8.19
================================================
FILE: ios/.gitignore
================================================
*.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, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings["IPHONEOS_DEPLOYMENT_TARGET"] = "11.0"
end
end
end
================================================
FILE: ios/Runner/AppDelegate.swift
================================================
import UIKit
import Flutter
import Mobile
import LocalAuthentication
import Network
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
private let networkMonitor = NWPathMonitor()
private var latestPath: NWPath?
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let applicationSupportsPath = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true)[0]
MobileMigration(documentsPath, applicationSupportsPath)
MobileInitApplication(applicationSupportsPath)
let monitorQueue = DispatchQueue(label: "network.monitor")
networkMonitor.pathUpdateHandler = { [weak self] path in
self?.latestPath = path
}
networkMonitor.start(queue: monitorQueue)
let controller = self.window.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel.init(name: "method", binaryMessenger: controller as! FlutterBinaryMessenger)
channel.setMethodCallHandler { (call, result) in
Thread {
if call.method == "flatInvoke" {
if let args = call.arguments as? Dictionary,
let method = args["method"] as? String,
let params = args["params"] as? String{
var error: NSError?
let data = MobileFlatInvoke(method, params, &error)
if error != nil {
result(FlutterError(code: "", message: error?.localizedDescription, details: ""))
}else{
result(data)
}
}else{
result(FlutterError(code: "", message: "params error", details: ""))
}
}
else if call.method == "verifyAuthentication"{
let context = LAContext()
let can = context.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil)
guard can == true else {
result(false)
return
}
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: "身份验证") { (success, error) in
result(success)
}
}
else if call.method == "iosSaveFileToImage"{
if let args = call.arguments as? Dictionary,
let path = args["path"] as? String{
do {
let fileURL: URL = URL(fileURLWithPath: path)
let imageData = try Data(contentsOf: fileURL)
if let uiImage = UIImage(data: imageData) {
UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
result("OK")
}else{
result(FlutterError(code: "", message: "Error loading image ", details: ""))
}
} catch {
result(FlutterError(code: "", message: "Error loading image : \(error)", details: ""))
}
}else{
result(FlutterError(code: "", message: "params error", details: ""))
}
}
else if call.method == "iosGetDocumentDir" {
result(documentsPath)
}
else if call.method == "dataLocal" {
result(applicationSupportsPath)
}
else if call.method == "fontList" {
result(UIFont.familyNames)
}
else {
result(FlutterMethodNotImplemented)
}
}.start()
}
let networkChannel = FlutterMethodChannel(name: "network", binaryMessenger: controller as! FlutterBinaryMessenger)
networkChannel.setMethodCallHandler { [weak self] call, result in
let path = self?.latestPath ?? self?.networkMonitor.currentPath
guard let path = path, path.status == .satisfied else {
result(call.method == "getIsMobile" ? false : "none")
return
}
if call.method == "getIsMobile" {
result(path.usesInterfaceType(.cellular))
return
}
guard call.method == "getNetworkType" else {
result(FlutterMethodNotImplemented)
return
}
if path.usesInterfaceType(.wifi) {
result("wifi")
return
}
if path.usesInterfaceType(.cellular) {
result("mobile")
return
}
if path.usesInterfaceType(.wiredEthernet) {
result("ethernet")
return
}
result("other")
}
//
let eventChannel = FlutterEventChannel.init(name: "flatEvent", binaryMessenger: controller as! FlutterBinaryMessenger)
class EventChannelHandler:NSObject, FlutterStreamHandler {
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
objc_sync_enter(mutex)
sink = events
objc_sync_exit(mutex)
return nil
}
func onCancel(withArguments arguments: Any?) -> FlutterError? {
objc_sync_enter(mutex)
sink = nil
objc_sync_exit(mutex)
return nil
}
}
class EventNotifyHandler:NSObject, MobileEventNotifyHandlerProtocol {
func onNotify(_ message: String?) {
objc_sync_enter(mutex)
if sink != nil {
sink?(message)
}
objc_sync_exit(mutex)
}
}
eventChannel.setStreamHandler(EventChannelHandler.init())
MobileEventNotify(EventNotifyHandler.init())
//
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
var sink : FlutterEventSink?
let mutex = NSObject.init()
================================================
FILE: ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"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"
}
}
================================================
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
================================================
CADisableMinimumFrameDurationOnPhone
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleDisplayName
pikapika
CFBundleDocumentTypes
CFBundleTypeName
PKZ Archive
LSHandlerRank
Owner
LSItemContentTypes
opensource.pkz
pkz
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleLocalizations
zh_TW
zh_CN
en_US
ja_JP
ko_KR
CFBundleName
pikapika
CFBundlePackageType
APPL
CFBundleShortVersionString
$(FLUTTER_BUILD_NAME)
CFBundleSignature
????
CFBundleURLTypes
CFBundleURLSchemes
pika
CFBundleVersion
$(FLUTTER_BUILD_NUMBER)
LSApplicationCategoryType
public.app-category.entertainment
LSRequiresIPhoneOS
LSSupportsOpeningDocumentsInPlace
NSFaceIDUsageDescription
Authenticating using face id
NSPhotoLibraryAddUsageDescription
Save images
NSPhotoLibraryUsageDescription
Usage images
UIApplicationSupportsIndirectInputEvents
UIFileSharingEnabled
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
Main
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UIViewControllerBasedStatusBarAppearance
UTExportedTypeDeclarations
UTTypeConformsTo
public.data
public.content
com.apple.package
UTTypeDescription
PKZ Archive
UTTypeIdentifier
opensource.pkz
UTTypeTagSpecification
public.filename-extension
pkz
pki
zip
public.mime-type
text/vnd.opensource.pkz
text/vnd.opensource.pki
text/vnd.opensource.zip
================================================
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 */
0E44DEFD92B805627806403C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 605DB0C59210B25A843453FD /* Pods_Runner.framework */; };
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 */; };
DD1F548D273CB9A900B04493 /* Mobile.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD1F548C273CB9A900B04493 /* Mobile.xcframework */; };
/* 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 */
1001C50AAB0DFA884ACAD48C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
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 = ""; };
3742BDBA4B7EA3162E2CDC75 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
605DB0C59210B25A843453FD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
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 = ""; };
CA7EB5DA1FDE22BAC5B01D77 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
DD1F548C273CB9A900B04493 /* Mobile.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Mobile.xcframework; path = ../go/mobile/lib/Mobile.xcframework; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0E44DEFD92B805627806403C /* Pods_Runner.framework in Frameworks */,
DD1F548D273CB9A900B04493 /* Mobile.xcframework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
6CBB90743F7578DFC9C6BF75 /* Pods */ = {
isa = PBXGroup;
children = (
3742BDBA4B7EA3162E2CDC75 /* Pods-Runner.debug.xcconfig */,
1001C50AAB0DFA884ACAD48C /* Pods-Runner.release.xcconfig */,
CA7EB5DA1FDE22BAC5B01D77 /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
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 = (
DD1F548C273CB9A900B04493 /* Mobile.xcframework */,
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
6CBB90743F7578DFC9C6BF75 /* Pods */,
F6DB48AA376F5D49016BEA7A /* Frameworks */,
);
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 = "";
};
F6DB48AA376F5D49016BEA7A /* Frameworks */ = {
isa = PBXGroup;
children = (
605DB0C59210B25A843453FD /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
6D683F8ECDB7CFFB7E7E554B /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
774454864019DA9867B5A218 /* [CP] Embed Pods Frameworks */,
);
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 = 1430;
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";
};
6D683F8ECDB7CFFB7E7E554B /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
774454864019DA9867B5A218 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
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\n";
};
/* 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;
FRAMEWORK_SEARCH_PATHS = "../go/mobile/lib/**";
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 = 43;
DEVELOPMENT_TEAM = SSSSSSSSSS;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.8.19;
PRODUCT_BUNDLE_IDENTIFIER = opensource.pikapika;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
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;
FRAMEWORK_SEARCH_PATHS = "../go/mobile/lib/**";
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;
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;
FRAMEWORK_SEARCH_PATHS = "../go/mobile/lib/**";
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 = 43;
DEVELOPMENT_TEAM = SSSSSSSSSS;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.8.19;
PRODUCT_BUNDLE_IDENTIFIER = opensource.pikapika;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
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 = 43;
DEVELOPMENT_TEAM = SSSSSSSSSS;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.8.19;
PRODUCT_BUNDLE_IDENTIFIER = opensource.pikapika;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
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 */;
}
================================================
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: lib/assets/translations/en-US.json
================================================
{
"language": {
"title": "Language",
"name": "English - United States"
},
"app": {
"categories": "Categories",
"my": "My",
"copied_to_clipboard": "Copied to clipboard",
"not_supported_platform": "Not supported platform",
"cancel": "Cancel",
"confirm": "Confirm",
"save_cancel": "Save canceled",
"save_success": "Save success",
"save_failed": "Save failed",
"pro": "Pro",
"pro_required": "Please upgrade to Pro to use this feature",
"choose_folder": "Choose a folder to save the file",
"permission_denied": "Permission denied",
"loading": "Loading",
"error": "Error",
"pat": {
"success": "Your sponsor login success, please return",
"title": "Replace PAT account"
},
"previous_page": "Previous page",
"next_page": "Next page",
"page": "Page",
"please_enter_page_number": "Please enter page number:",
"select_all": "Select all",
"load_failed": "Load failed",
"all": "All",
"delete": "Delete",
"save_image": "Save image",
"preview_image": "Preview image",
"please_select": "Please select",
"refresh": "Refresh",
"initializing": "Initializing",
"like_failed": "Like failed",
"network_error": "Network error, please check your network",
"no_permission": "No permission or path is not available",
"check_device_time": "Please check your device time",
"resource_not_available": "Resource not available",
"something_went_wrong": "Something went wrong",
"click_refresh": "Click refresh",
"pull_down_refresh": "Pull down refresh",
"continue_reading": "Continue reading",
"start_reading": "Start reading",
"image_crop": "Image crop",
"download": "Download",
"download_failed": "Download failed",
"download_finished": "Download finished",
"downloading": "Downloading",
"queue": "Queue",
"deleting": "Deleting",
"please_select_comic": "Please select comic",
"please_choose": "Please choose",
"last_viewed": "Last viewed",
"auto_punch": "Auto punch",
"yes": "Yes",
"no": "No",
"confirm_download": "Confirm download",
"copy": "Copy"
},
"net": {
"no_address": "No address",
"address": "Address",
"address_sync": "Address sync",
"address_sync_from_server": "Get the latest address from the server",
"address_sync_reset": "Reset the address to the default value",
"address_sync_success": "Address sync success",
"address_sync_failed": "Address sync failed",
"address_sync_reset_success": "Address sync reset success",
"address_sync_reset_failed": "Address sync reset failed",
"choose_address": "Choose address",
"image_address": "Image address",
"use_api_load_image": "Use API to load image",
"ping_testing": "Testing",
"ping_failed": "Failed"
},
"categories": {
"all": "All",
"recommend": "Recommend",
"rankings": "Rankings",
"random": "Random",
"game": "Game"
},
"settings": {
"settings": "Settings",
"interface": "Interface",
"network": "Network",
"seal": "Seal",
"interaction": "Interaction",
"reading": "Reading",
"download": "Downloads",
"auto_download_on_favorite": "Auto download on favorite",
"disable_auto_download_on_mobile": "Disable auto download on mobile data",
"auto_delete_download_on_unfavorite": "Auto delete download on unfavorite",
"web_server": "Web Server",
"web_server_subtitle": "Let devices in the local network view the downloaded comics through the browser",
"sync": "Sync",
"history_sync": "History Sync",
"local_favorite_sync_title": "Local Favorites Sync",
"use_local_favorite": "Use Local Favorites",
"use_local_favorite_desc": "Manage favorites locally with folder organization",
"account": "Account",
"modify_password": "Modify password",
"ebook": "E-book",
"system": "System",
"clear_cache": "Clear cache",
"migrate": "Migrate",
"migrate_subtitle": "Change your data folder to the memory card",
"migrate_confirm": "This feature will be saved after restarting the program, are you sure",
"app_orientation": {
"title": "App orientation",
"choose": "Choose app orientation",
"normal": "Normal",
"landscape": "Landscape",
"portrait": "Portrait"
},
"will_pop_notice": "Press the back key twice in a row to exit the app",
"android_secure_flag": "Disable screenshot/disable display in task view",
"android_display_mode": {
"title": "Screen refresh rate (Android)",
"dialog_title": "Android screen refresh rate \n(No high refresh in power saving mode)"
},
"authentication": "Authentication when entering the app (if the system has already entered the password or fingerprint)",
"set_password": "Set application password",
"auto_clean": {
"title": "Auto clean cache",
"one_month_ago": "One month ago",
"one_week_ago": "One week ago",
"one_day_ago": "One day ago",
"no_auto_clean": "No auto clean"
},
"categories_column_count": {
"title": "Categories column count",
"choose": "Choose categories column count",
"auto": "Auto"
},
"categories_sort": {
"title": "Categories sort"
},
"chooser_root": {
"title": "Chooser root",
"hint": "Enter the folder selector root path",
"desc": "The default path for selecting the directory when exporting, also the root path, you can try to set this option if the export is not normal"
},
"content_failed_reload_action": {
"title": "Content failed reload action",
"choose": "Choose content failed reload action",
"pull_down": "Pull down",
"touch_loader": "Touch loader"
},
"copy_full_name": {
"title": "Copy full name"
},
"copy_full_name_template": {
"title": "Copy full name template",
"hint": "Enter the copy full name template"
},
"copy_skip_confirm": {
"title": "Copy skip confirm"
},
"download_and_export_path": {
"title": "Download and export path",
"confirm": "Download and export",
"desc": "You will select a directory, if the file system is writable, the download will be automatically exported"
},
"download_cache_path": {
"title": "Download cache path",
"confirm": "Download cache",
"desc": "You will select a directory, this directory is copied from the following directory to use. The download will be read as a cache folder first.",
"cancel_desc": "Are you sure you want to cancel the function of downloading content acceleration with other software? You can set it again after canceling",
"import_view_log_from_off": {
"title": "Import other program's history record",
"desc": "You will select a file, this file is copied from the following path to use.",
"choose_file_dialog_title": "Choose the file to import"
}
},
"download_thread_count": {
"title": "Download thread count",
"choose": "Choose download thread count"
},
"ebook_scrolling": {
"title": "E-book scrolling UI"
},
"ebook_scrolling_range": {
"title": "E-book scrolling UI",
"desc": "Scrolling range",
"screen_height": "Screen height"
},
"ebook_scrolling_trigger": {
"title": "E-book scrolling UI",
"desc": "Trigger distance",
"cm": "cm"
},
"export_path": {
"ios_desc": "You can find the exported content in the file manager",
"ios_desc2": "You are using an iOS device:\nPlease open the system's built-in file manager to browse the exported content",
"export_path_desc": "Export path (click to modify)",
"android_desc": "You are using an Android device:\nIf the export fails and prompts insufficient permissions, you can try to create a subdirectory under Download or Document for export"
},
"export_rename": {
"title": "Export with renaming"
},
"yes": "Yes",
"no": "No",
"full_screen_action": {
"title": "Control method",
"choose": "Choose control method",
"touch_once": "Touch once to fullscreen",
"controller": "Use controller to fullscreen",
"touch_double": "Double click to fullscreen",
"touch_double_once_next": "Double click to fullscreen + click once to next page",
"three_area": "Divide the screen into three areas (previous page, next page, fullscreen)"
},
"full_screen_ui": {
"title": "Full screen UI",
"choose": "Choose full screen UI",
"no": "Not use",
"hidden_bottom": "Remove virtual controller",
"all": "Full screen"
},
"auto_full_screen": {
"title": "Enter reader automatically full screen"
},
"auto_full_screen_on_forward": {
"title": "Auto Fullscreen on Forward"
},
"ignore_info_history": {
"title": "Ignore info history"
},
"icon_loading": {
"title": "Minimize UI animation"
},
"ignore_upgrade_confirm": {
"title": "Close upgrade popup"
},
"hidden_fd_icon": {
"title": "Hide personal space's power icon"
},
"hidden_search_persion": {
"title": "Hide search by author"
},
"hidden_viewed": {
"title": "Hide viewed comics"
},
"hidden_sub_icon": {
"title": "Hide subscription"
},
"hide_online_favorite": {
"title": "Hide online favorites",
"desc": "Hide online favorites entry and favorite button"
},
"hidden_words": {
"title": "Hide by keyword",
"clear_all": "Confirm clear",
"clear_all_desc": "Are you sure you want to clear all keywords?",
"input_hint": "Enter the keyword to hide",
"no_words": "No keywords"
},
"image_address": {
"title": "Image address",
"pinging": "Pinging",
"failed": "Failed"
},
"image_filter": {
"title": "Reader image filter",
"normal": "Normal",
"gray": "Gray",
"brown": "Brown",
"choose": "Choose reader image filter"
},
"import_notice": {
"android_desc": "You are using an Android device:\nIf you cannot import and export and prompt insufficient permissions, you can try to create a subdirectory under Download or Document for import"
},
"keyboard_controller": {
"title": "Reader keyboard page (only PC)"
},
"list_layout": {
"choose": "Choose layout",
"info_card": "Info",
"only_image": "Cover",
"cover_and_title": "Cover + Title"
},
"local_history_sync": {
"sync_to_local": "Sync history to local",
"not_set": "Not set",
"sync_success": "Sync success",
"sync_failed": "Sync failed",
"auto_sync": "Auto sync history to local",
"auto_sync_desc": "After opening the application, the history will be automatically backed up",
"choose_dir": "Choose directory",
"clear_path": "Clear path",
"clear_path_desc": "Are you sure you want to clear the path?"
},
"local_favorite_sync": {
"auto_sync": "Auto sync local favorites",
"auto_sync_desc": "Auto sync local favorites with WebDAV",
"manual_sync": "Manual sync local favorites",
"sync_success": "Sync success",
"sync_failed": "Sync failed"
},
"no_animation": {
"title": "Cancel page animation (tap screen, volume key, keyboard)"
},
"pager_action": {
"title": "List page loading method",
"choose": "Choose list page loading method",
"controller": "Use button",
"stream": "Stream"
},
"proxy": {
"title": "Proxy server",
"hint": "Enter proxy server",
"desc": " ( e.g. socks5://127.0.0.1:1080/ ) ",
"no_proxy": "Not set"
},
"quality": {
"title": "Image quality when browsing",
"choose": "Choose image quality",
"original": "Original",
"low": "Low",
"medium": "Medium",
"high": "High"
},
"reader_background_color": {
"title": "Reader background color",
"choose": "Choose reader background color",
"black": "Black",
"gray": "Gray",
"white": "White"
},
"reader_direction": {
"title": "Reader direction",
"choose": "Choose reader direction",
"top_to_bottom": "Top to bottom",
"left_to_right": "Left to right",
"right_to_left": "Right to left"
},
"reader_scroll_by_screen_percentage": {
"title": "Flip distance by distance",
"screen_size": "Screen size"
},
"web_toon_scroll_mode": {
"title": "WebToon Flip Mode",
"choose": "Choose WebToon Flip Mode",
"image": "Image",
"screen": "Distance"
},
"reader_zoom": {
"out_title": "Zoom out multiplier (min scale)",
"in_title": "Zoom in multiplier (max scale)",
"double_tap_title": "Double tap zoom scale"
},
"drag_region_lock": {
"title": "Lock Drag Boundary"
},
"gesture_speed": {
"title": "Gesture Speed Multiplier"
},
"reader_slider_position": {
"title": "Slider position",
"choose": "Choose slider position",
"bottom": "Bottom",
"right": "Right",
"left": "Left"
},
"reader_two_page_direction": {
"title": "Two page reader content arrangement",
"choose": "Choose two page reader content arrangement",
"close_to": "Close to",
"pull_away": "Pull away",
"each_centered": "Each centered"
},
"reader_type": {
"title": "Reader mode",
"choose": "Choose reader mode",
"web_toon": "WebToon (Default)",
"web_toon_zoom": "WebToon (Double click to zoom)",
"gallery": "Gallery",
"web_toon_free_zoom": "WebToon (ListView double click to zoom)\n(This mode progress bar is invalid)",
"two_page_gallery": "Two page mode\n(Experimental)",
"left_to_right": "Left to right",
"right_to_left": "Right to left",
"two_page_direction": "Two page direction",
"two_page_direction_choose": "Choose two page direction"
},
"shadow_categories": {
"title": "Seal",
"search_hint": "Search"
},
"shadow_categories_mode": {
"title": "Seal mode",
"black_list": "Black list",
"white_list": "White list"
},
"startup_pic": {
"title": "Set startup picture",
"subtitle": "Set the picture displayed when the application starts",
"clear_title": "Clear startup picture",
"clear_subtitle": "Clear the picture displayed when the application starts",
"clear_success": "Startup picture cleared",
"update_success": "Startup picture updated"
},
"show_comment_at_download": {
"title": "Show comment at download"
},
"font": {
"title": "Font",
"hint": "Please enter the font",
"input_hint": "Please enter the font name and use English commas to separate, for example \"Songti, Heiti\", if you save it and it doesn't change, it means the font cannot be used or the name is wrong, you can refer to C:\\Windows\\Fonts to find your font. If you are using the flutter2 engine version, only the first font will take effect.",
"choose_hint": "You need to select multiple fonts until you click the background area"
},
"theme": {
"origin": "Origin",
"pink": "Pink",
"black": "Black",
"dark": "Dark",
"dusty_blue": "Dusty blue",
"dark_black": "Dark black",
"choose_theme": "Choose theme",
"book": "Book",
"enable_status_bar_color": "Enable status bar color",
"enable_status_restart_hint": "When disabled, you need to restart the application to refresh the status bar color"
},
"three_keep_right": {
"title": "Three area mode page always to the right"
},
"time_zone": {
"title": "Time zone"
},
"timeout_lock": {
"title": "Auto lock",
"notice": "Note: Auto lock only supports timeout after minimizing on desktop, and supports timeout after background and screen lock on mobile. If no password is set, auto lock is invalid. Android and desktop only lock the desktop, not the download, iOS is not tested, you need to manually enable background activity.",
"1_hour": "One hour",
"10_minutes": "Ten minutes",
"3_minutes": "Three minutes",
"1_minute": "One minute",
"10_seconds": "Ten seconds",
"1_second": "One second",
"no_lock": "No lock"
},
"using_right_click_pop": {
"title": "Mouse right click to return to the previous page"
},
"volume_controller": {
"title": "Reader volume button page turn"
},
"volume_next_chapter": {
"title": "Double click volume/keyboard/controller to next chapter"
},
"webdav": {
"title": "WebDav",
"not_set": "Not set",
"path": "WebDav path",
"path_hint": "Please enter the WebDav path",
"username": "WebDav username",
"username_hint": "Please enter the WebDav username",
"password": "WebDav password",
"password_hint": "Please enter the WebDav password",
"auto_sync_history_to_webdav": "Auto sync history to WebDav",
"sync_history_to_webdav": "Sync history to WebDAV",
"upload_history_to_webdav": "Upload history to WebDAV",
"upload_history_to_webdav_desc": "If there are multiple devices, please note the automatic synchronization function",
"sync_success": "Sync success",
"sync_failed": "Sync failed"
}
},
"local_favorite": {
"title": "Local Favorites",
"all_folders": "All",
"new_folder": "New Folder",
"select_mode": "Select",
"cancel_select_mode": "Cancel select",
"select_all": "Select all",
"delete_folder": "Delete Folder",
"move_to_folder": "Move to Folder",
"remove_selected": "Remove selected",
"remove_selected_confirm": "Remove selected comics from local favorites?",
"remove_selected_success": "Removed",
"remove_selected_failed": "Remove failed",
"select_comics": "Please select comics first",
"folder_limit_reached": "Free version allows up to 3 folders. Upgrade to Pro for unlimited folders",
"batch_download": "Batch Download",
"select_folder": "Select Folder",
"folder_name": "Folder Name",
"delete_confirm": "Confirm delete folder?",
"empty_folder": "No favorites yet",
"no_folders": "No folders yet, please create one first",
"remove_confirm_title": "Remove from Favorites",
"remove_confirm_content": "Are you sure you want to remove this comic from local favorites?",
"remove_failed": "Remove failed",
"load_failed": "Load failed",
"add_success": "Added to local favorites",
"add_failed": "Add failed",
"create_folder_failed": "Create folder failed",
"create_success": "Created successfully",
"delete_success": "Deleted successfully",
"delete_failed": "Delete failed",
"move_success": "Moved successfully",
"move_failed": "Move failed",
"select_comics_to_download": "Please select comics to download",
"download_started": "Download started",
"download_failed": "Download failed"
},
"screen": {
"about": {
"title": "About",
"version": "Software version",
"check_update": "Check update",
"tips": "Tips : \n1. The author/uploader/category/tag on the detail page can be clicked\n2. The author/uploader/title on the detail page can be copied by long press\n3. Using pagination instead of waterfall flow can quickly flip pages\n4. Download means caching to the local, you need to export to share\n5. Download long press can delete",
"download_new_version": "Please download the new version from the channel",
"no_new_version": "No new version detected",
"download_release_version": "Download RELEASE version",
"update_content": "Update content",
"go_to_release_repository": "Go to RELEASE repository"
},
"account": {
"title": "Account",
"username": "Username",
"username_hint": "Please enter the username",
"password": "Password",
"password_hint": "Please enter the password",
"no_account_register": "No account, I want to register",
"password_reset": "Password reset",
"check_username_password_or_network": "Please check the username and password or network environment",
"check_device_time": "Please check the device time",
"username_or_password_error": "Username or password error",
"login_failed": "Login failed",
"not_set": "Not set"
},
"app": {
"will_pop_notice": "Press the back key twice in a row to exit the app"
},
"categories": {
"search_hint": "Search"
},
"clean": {
"title": "Clean",
"cleaning": "Cleaning",
"clean_network_cache": "Clean network cache",
"clean_image_cache": "Clean image cache",
"clean_all_cache": "Clean all cache",
"clean_success": "Clean success",
"clean_failed": "Clean failed"
},
"close_app": {
"title": "Tips",
"close_app": "Please close the app and reopen"
},
"comic_collections": {
"no_resource": "There is no resource here"
},
"comic_info": {
"chapter": "Chapter",
"comment": "Comment",
"recommend": "Recommend"
},
"comics": {
"search_hint": "Search category",
"choose_category": "Please choose category"
},
"comic_subscribes": {
"update_reminder": "Update reminder",
"check_update": "Check update",
"cancel_all_update_reminder": "Cancel all update reminder"
},
"comment": {
"title": "Comment",
"hint_text": "Please enter the comment content",
"success": "Comment success",
"i_have_something_to_say": "I have something to say",
"please_enter_comment": "Please enter the comment content"
},
"desktop_authentication": {
"current_password": "Current password",
"password_error": "Password error",
"password_initialization": "Password initialization",
"password": "Password",
"re_enter_password": "Re-enter password",
"password_mismatch": "The two passwords entered are different",
"set_password": "Set password"
},
"download_confirm": {
"please_select_ep": "Please select the EP to download",
"already_added_to_download_list": "Already added to download list"
},
"download_export_group": {
"title": "Batch export",
"please_select_content": "Please select the content to export",
"exporting": "Exporting",
"export_failed": "Export failed",
"export_success": "Export success",
"export_to_pkz": "Export to PKZ\n(Encrypted mode, prevent web detection, can be opened with pikapika)",
"export_to_pki": "Export to PKI\n(Encrypted mode, prevent web detection, can be imported with pikapika)",
"export_to_zip": "Export to ZIP\n(Unencrypted mode, can be imported or viewed with pikapika)",
"export_to_jpeg_zip": "Export to ZIP+JPEG\n(Can be used directly with other readers, cannot be imported again)",
"export_to_jpeg_folder": "Export to folder+JPEG",
"export_to_pdf": "Export to PDF",
"export_to_epub": "Export to EPUB",
"export_to_pdf_folder": "Export to folder, each chapter one PDF",
"export_to_cbz": "Export to cbz",
"after_power_use": "After power use",
"input_save_name": "Please enter the saved name",
"export_confirm": "Export confirm",
"export_to_pkz_title": "Export the selected comics to a PKZ",
"export_to_pki_title": "Export the selected comics to separate PKI",
"please_power_up": "Please power up first",
"export_to_zip_title": "Export the selected comics to ZIP",
"export_to_jpeg_zip_title": "Export the selected comics to ZIP+JPEG",
"export_to_jpeg_zip_title_not_down_over": "Export the selected comics to ZIP+JPEG\n(Even if the download is not successful, it can be used)",
"export_to_jpeg_folder_title": "Export the selected comics to folder+JPEG",
"export_to_pdf_title": "Export the selected comics to PDF",
"export_to_epub_title": "Export the selected comics to EPUB",
"export_to_pdf_folder_title": "Export the selected comics to folder, each chapter one PDF",
"export_to_cbz_title": "Export the selected comics to cbz",
"exporting_please_wait": "Exporting, please wait"
},
"download_export_to_file": {
"title": "Export",
"transfer_to_other_device": "Transfer to other device",
"input_save_name": "Please enter the saved name",
"export_confirm": "Export confirm",
"export_to_pkz_title": "Export the selected comics to a PKZ",
"export_to_pkz_desc": "Export to xxx.pkz\n(Encrypted mode, prevent web detection, can be opened with pikapika)",
"export_to_pki_title": "Export the selected comics to separate PKI",
"export_to_pki_desc": "Export to xxx.pki\n(Encrypted mode, prevent web detection, can be imported with pikapika)",
"export_to_zip_title": "Export the selected comics to ZIP",
"export_to_zip_desc": "Export to xxx.zip\n(Unencrypted mode, can be imported or viewed with pikapika)",
"export_to_jpeg_zip_title": "Export the selected comics to ZIP+JPEG",
"export_to_jpeg_zip_desc": "Export to xxx.jpeg\n(Can be used directly with other readers, cannot be imported again)",
"export_to_pdf_title": "Export the selected comics to PDF",
"export_to_pdf_desc": "Export to xxx.pdf\n(Even if the download is not successful, it can be used, and the failed image will be skipped)\n(Can be opened directly in the photo album)",
"export_to_pdf_folder_title": "Export the selected comics to folder, each chapter one PDF",
"export_to_pdf_folder_desc": "Export to xxx.pdf\n(Even if the download is not successful, it can be used, and the failed image will be skipped)\n(Can be opened directly in the photo album)",
"export_to_epub_title": "Export the selected comics to EPUB",
"export_to_epub_desc": "Export to xxx.epub\n(Can be opened directly in the reader)",
"export_to_jpeg_folder_title": "Export the selected comics to JPEGS.zip",
"export_to_jpeg_folder_desc": "Export to JPGS.zip\n(Cannot be imported again)",
"export_to_cbz_title": "Export the selected comics to cbk.zip",
"export_to_cbz_desc": "Export to xxx.cbz, reader can use it directly (cannot be imported again)"
},
"download_export_to_socket": {
"title": "Network export",
"loading": "Loading",
"tips": "Do not exit the page before the transfer is successful, only one device can be exported at a time, the two devices need to be in the same network segment or infinite LAN, please enter IP:port on the other device, if there is only one IP, please select the IP of the infinite LAN, usually 192.168 starts",
"get_ip_failed": "Get IP failed",
"getting_ip": "Getting IP",
"port": "Port"
},
"download_import": {
"title": "Import",
"open_file": "Open file",
"select_file": "Select the file to import",
"import_success": "Import success",
"import_failed": "Import failed",
"select_file_desc": "Select zip file to import\nSelect pki file to import\nSelect pkz file to read",
"input_address": "Please enter the address provided by the export device\nFor example \"192.168.1.2:50000\"",
"import_from_other_device": "Import from other device",
"select_folder_desc": "Select folder\n(Import all zip/pki in the folder)\n(After power use)"
},
"download_info": {
"loading": "Loading",
"chapter": "Chapter",
"comment": "Comment",
"recommend": "Recommend"
},
"download_list": {
"search_download": "Search download",
"multi_select_operation": "Multi select operation",
"download_list": "Download list",
"search": "Search",
"select_folder": "Select folder",
"download_already_in_delete_queue": "The download is already in the delete queue",
"import": "Import",
"export": "Export",
"file": "File",
"download_task": "Download task",
"pause_download": "Pause download?",
"start_download": "Start download?",
"resume_failed": "Resume failed task",
"resume_failed_desc": "All failed downloads have been resumed",
"downloading": "Downloading",
"paused": "Paused",
"move_download": "Move download",
"select_download_to_move": "Please select the download to move",
"select_download_to_delete": "Please select the download to delete",
"input_name": "==> Input name <==",
"empty_folder_will_be_deleted": "(Empty folder will be automatically deleted, next time you need to manually input)",
"folder_name": "Folder name",
"please_input_folder_name": "Please input folder name",
"delete_download": "Delete download",
"delete_selected_download": "Delete selected download?",
"multi_select": "Multi select"
},
"download_only_import": {
"importing": "Importing",
"import_success": "Import success",
"import_failed": "Import failed",
"click_import_file": "Click import file",
"importing_please_wait": "Importing, please wait"
},
"favourite_paper": {
"favourite": "Favourite"
},
"forgot_password": {
"title": "Password Recovery",
"username": "Username",
"not_set": "Not set",
"confirm": "Confirm",
"please_enter_username": "Please enter username",
"question_1": "Question 1",
"question_2": "Question 2",
"question_3": "Question 3",
"answer_1": "Answer 1",
"answer_2": "Answer 2",
"answer_3": "Answer 3",
"please_enter_answer_1": "Please enter answer 1",
"please_enter_answer_2": "Please enter answer 2",
"please_enter_answer_3": "Please enter answer 3",
"use_answer_1_recover": "Use answer 1 to recover password",
"use_answer_2_recover": "Use answer 2 to recover password",
"use_answer_3_recover": "Use answer 3 to recover password",
"please_enter_answer": "Please enter answer",
"new_password_copied": "New password is being copied to clipboard",
"answer_incorrect": "Answer is incorrect",
"password": "Password"
},
"game_download": {
"title": "Download",
"download_links_obtained": "Download links obtained, you just need to choose one of them"
},
"game_info": {
"download": "Download",
"details": "Details",
"comments": "Comments"
},
"games": {
"title": "Games"
},
"import_from_off": {
"title": "Import",
"import_success": "Import success",
"import_failed": "Import failed"
},
"modify_password": {
"title": "Modify password",
"please_wait": "Please wait",
"old_password": "Old password",
"new_password": "New password",
"repeat_new_password": "Repeat new password",
"not_filled": "Not filled",
"please_enter_old_password": "Please enter old password",
"please_enter_new_password": "Please enter new password",
"please_repeat_new_password": "Please repeat new password",
"new_password_mismatch": "New passwords do not match",
"modify_success": "Modify success",
"failed": "Failed",
"confirm": "Confirm"
},
"network_settings": {
"title": "Network Settings"
},
"pkz_reader": {
"reading_downloaded_comic": "You are reading a downloaded comic"
},
"pro": {
"title": "Power Center",
"power_center": "Power Center",
"power_status": "Power Status",
"powered": "Powered",
"not_powered": "Not Powered",
"pat_membership": "PAT Membership",
"pat_status": "PAT Status",
"pat_normal": "PAT Normal",
"pat_bind_hint": "Please click here to bind to current account for power",
"pat_rebind_hint": "Please click to rebind to current account for power",
"pat_not_detected": "No membership detected, please go to download page to join",
"i_have_powered": "I have powered before",
"i_just_powered": "I just powered",
"enter_code": "Enter code",
"power_method": "Power Method",
"wind_power": "Wind Power",
"hydro_power": "Hydro Power",
"solar_power": "Solar Power",
"nuclear_power": "Nuclear Power",
"choose_power_method": "Choose power method",
"sign_in_exchange": "Sign in/Exchange",
"click_pat_to_change": "Click PAT membership below to change",
"update_pat_status": "Update PAT power status",
"bind_to_account": "Bind to this account",
"change_pat_key": "Change PAT key",
"clear_pat_info": "Clear PAT info",
"click_to_bind": "Click to bind",
"enter_auth_code": "Please enter authorization code",
"please_wait": "Please wait",
"key_recorded": "Key: Recorded",
"pat_account": "PAT Account",
"bind_pika_account": "Bind PIKA Account",
"bind_account_time": "Bind account time",
"rebind_time": "Rebind available time",
"power_features": "Power features: Multi-thread download / Batch import/export download",
"power_guide": "Go to \"About\" page to find maintenance address for power guide\n\n \"I have powered before\" can sync corresponding power status\n \"I just powered\" exchange mysterious code\n \"Power method\" can be changed when network is not working\n \"PAT membership\" is independent power method"
},
"rankings": {
"title": "Rankings",
"day": "Day",
"week": "Week",
"month": "Month",
"knight": "Knight",
"refresh": "Refresh",
"comics_count": "comics"
},
"random_comics": {
"title": "Random Comics"
},
"register": {
"title": "Register",
"registering": "Registering",
"register_success": "Register Success",
"register_failed": "Register Failed",
"account_exists": "Account already exists",
"name_exists": "Name already exists",
"check_form": "Please check form, no empty fields allowed",
"account": "Account",
"password": "Password",
"nickname": "Nickname",
"gender": "Gender",
"birthday": "Birthday",
"question_1": "Question 1",
"answer_1": "Answer 1",
"question_2": "Question 2",
"answer_2": "Answer 2",
"question_3": "Question 3",
"answer_3": "Answer 3",
"not_set": "Not set",
"please_enter_account": "Please enter account",
"please_enter_password": "Please enter password",
"please_enter_nickname": "Please enter nickname",
"please_enter_question_1": "Please enter question 1",
"please_enter_answer_1": "Please enter answer 1",
"please_enter_question_2": "Please enter question 2",
"please_enter_answer_2": "Please enter answer 2",
"please_enter_question_3": "Please enter question 3",
"please_enter_answer_3": "Please enter answer 3",
"account_desc": "(lowercase letters + numbers / for login)",
"password_desc": "(uppercase and lowercase letters + numbers / 8 or more characters)",
"nickname_desc": "(Chinese allowed / 2-50 characters)",
"choose_gender": "Choose your gender",
"futa": "Futa",
"male": "Male",
"female": "Female",
"register_success_desc": "You have registered successfully, please return to login",
"account_label": "Account",
"nickname_label": "Nickname"
},
"search": {
"title": "Search",
"search_hint": "Search",
"choose_category": "Please choose category"
},
"search_author": {
"title": "Search by Author",
"search_hint": "Search by author + ",
"by_author": "By author: "
},
"space": {
"title": "My",
"logout": "Logout",
"logout_confirm": "Are you sure you want to logout from current account?",
"my_favourites": "My Favourites",
"view_history": "View History",
"my_downloads": "My Downloads"
},
"theme": {
"title": "Theme Settings",
"theme": "Theme",
"dark_mode_different_theme": "Use different theme in dark mode",
"dark_mode_theme": "Theme (Dark Mode)"
},
"view_logs": {
"title": "View History",
"clear_all": "Do you want to clear all view history?",
"clear_all_desc": "Reading progress will also be deleted!",
"clear_one": "Do you want to clear this view history?",
"clear_one_desc": "Reading progress will also be deleted!",
"clear_selected": "Do you want to clear selected view history?",
"clear_selected_desc": "Reading progress will also be deleted!",
"categories": "Categories"
},
"web_server": {
"title": "Download - Web Server",
"loading": "Loading",
"get_ip_failed": "Get IP failed",
"getting_ip": "Getting IP",
"port": "Port: 8080",
"usage_instruction": "Enter \"http://device_ip:8080/\" in browser to access downloaded comics",
"leave_notice": "Server will close after leaving this page"
}
},
"components": {
"comic_info_card": {
"categories": "Categories",
"finished": "Finished",
"viewed": "Viewed"
},
"comic_list": {
"shadow": "Shadowed Comics"
},
"common": {
"display_mode": "Display Mode",
"shadow_mode": "Shadow Mode",
"shadow_list": "Shadow List",
"batch_download": "Batch Download"
},
"image_reader": {
"already_at_the_end": "Already at the end",
"click_to_next_chapter": "Click to next chapter",
"reload_page": "Reload page",
"next_chapter": "Next chapter",
"end_reading": "End reading",
"reload_image": "Reload image",
"save_image_in_this_page": "Save image in this page",
"image_load_failed": "Image load failed"
}
}
}
================================================
FILE: lib/assets/translations/ja-JP.json
================================================
{
"language": {
"title": "言語",
"name": "日本語 - 日本"
},
"app": {
"categories": "カテゴリ",
"my": "マイ",
"copied_to_clipboard": "クリップボードにコピーしました",
"not_supported_platform": "サポートされていないプラットフォーム",
"cancel": "キャンセル",
"confirm": "確認",
"save_cancel": "保存がキャンセルされました",
"save_success": "保存に成功しました",
"save_failed": "保存に失敗しました",
"pro": "プロ",
"pro_required": "この機能を使用するにはプロにアップグレードしてください",
"choose_folder": "ファイルを保存するフォルダを選択してください",
"permission_denied": "権限が拒否されました",
"loading": "読み込み中",
"error": "エラー",
"pat": {
"success": "スポンサーログインが成功しました。戻ってください",
"title": "PATアカウントを置き換え"
},
"previous_page": "前のページ",
"next_page": "次のページ",
"page": "ページ",
"please_enter_page_number": "ページ番号を入力してください:",
"select_all": "すべて選択",
"load_failed": "読み込みに失敗しました",
"all": "すべて",
"delete": "削除",
"save_image": "画像を保存",
"preview_image": "画像をプレビュー",
"please_select": "選択してください",
"refresh": "更新",
"initializing": "初期化中",
"like_failed": "いいねに失敗しました",
"network_error": "ネットワークエラーです。ネットワークを確認してください",
"no_permission": "権限がないか、パスが利用できません",
"check_device_time": "デバイスの時間を確認してください",
"resource_not_available": "リソースが利用できません",
"something_went_wrong": "何かが間違っています",
"click_refresh": "クリックして更新",
"pull_down_refresh": "下にプルして更新",
"continue_reading": "読み続ける",
"start_reading": "読み始める",
"image_crop": "画像トリミング",
"download": "ダウンロード",
"download_failed": "ダウンロードに失敗しました",
"download_finished": "ダウンロード完了",
"downloading": "ダウンロード中",
"queue": "キュー中",
"deleting": "削除中",
"please_select_comic": "漫画を選択してください",
"please_choose": "選択してください",
"last_viewed": "最後に見た",
"auto_punch": "自動チェックイン",
"yes": "はい",
"no": "いいえ",
"confirm_download": "ダウンロード確認",
"copy": "コピー"
},
"net": {
"no_address": "アドレスなし",
"address": "アドレス",
"address_sync": "アドレス同期",
"address_sync_from_server": "サーバーから最新のアドレスを取得",
"address_sync_reset": "アドレスをデフォルト値にリセット",
"address_sync_success": "アドレス同期に成功しました",
"address_sync_failed": "アドレス同期に失敗しました",
"address_sync_reset_success": "アドレス同期リセットに成功しました",
"address_sync_reset_failed": "アドレス同期リセットに失敗しました",
"choose_address": "アドレスを選択",
"image_address": "画像アドレス",
"use_api_load_image": "APIを使用して画像を読み込む",
"ping_testing": "テスト中",
"ping_failed": "失敗しました"
},
"categories": {
"all": "すべて",
"recommend": "おすすめ",
"rankings": "ランキング",
"random": "ランダム",
"game": "ゲーム"
},
"settings": {
"settings": "設定",
"interface": "インターフェース",
"network": "ネットワーク",
"seal": "封印",
"interaction": "インタラクション",
"reading": "読書",
"download": "ダウンロード",
"auto_download_on_favorite": "お気に入り時に自動ダウンロード",
"disable_auto_download_on_mobile": "モバイル通信時は自動ダウンロードしない",
"auto_delete_download_on_unfavorite": "お気に入り解除で自動削除",
"web_server": "ウェブサーバー",
"web_server_subtitle": "ローカルネットワーク内のデバイスがブラウザを通じてダウンロードした漫画を閲覧できるようにします",
"sync": "同期",
"account": "アカウント",
"modify_password": "Modify password",
"ebook": "電子書籍",
"system": "システム",
"clear_cache": "キャッシュをクリア",
"migrate": "移行",
"migrate_subtitle": "データフォルダをメモリカードに変更",
"migrate_confirm": "この機能はプログラムを再起動した後に保存されます。よろしいですか",
"app_orientation": {
"title": "アプリの向き",
"choose": "アプリの向きを選択",
"normal": "通常",
"landscape": "横向き",
"portrait": "縦向き"
},
"will_pop_notice": "戻るキーを2回連続で押すとアプリを終了します",
"android_secure_flag": "スクリーンショットを無効化/タスクビューでの表示を無効化",
"android_display_mode": {
"title": "画面リフレッシュレート(Android)",
"dialog_title": "Android画面リフレッシュレート \n(省電力モードでは高リフレッシュレートになりません)"
},
"authentication": "アプリに入る際の認証(システムが既にパスワードまたは指紋を入力している場合)",
"set_password": "アプリケーションパスワードを設定",
"auto_clean": {
"title": "自動キャッシュクリア",
"one_month_ago": "1ヶ月前",
"one_week_ago": "1週間前",
"one_day_ago": "1日前",
"no_auto_clean": "自動クリアしない"
},
"categories_column_count": {
"title": "カテゴリの列数",
"choose": "カテゴリの列数を選択",
"auto": "自動"
},
"categories_sort": {
"title": "カテゴリソート"
},
"chooser_root": {
"title": "フォルダセレクタルートパス",
"hint": "フォルダセレクタルートパスを入力してください",
"desc": "エクスポート時にディレクトリを選択するデフォルトパス、またルートパスでもあります。エクスポートが正常に動作しない場合は、このオプションを設定してみてください。"
},
"content_failed_reload_action": {
"title": "コンテンツ読み込み失敗時の再読み込み方法",
"choose": "コンテンツ読み込み失敗時の再読み込み方法を選択",
"pull_down": "プルダウン",
"touch_loader": "画面タッチ"
},
"copy_full_name": {
"title": "漫画名コピー時にテンプレートを使用"
},
"copy_full_name_template": {
"title": "漫画名コピーテンプレート",
"hint": "漫画名コピーテンプレートを入力してください"
},
"copy_skip_confirm": {
"title": "長押しコピー時に確認しない"
},
"download_and_export_path": {
"title": "ダウンロードと同時にファイルシステムへエクスポート",
"confirm": "ダウンロードと同時にファイルシステムへエクスポート",
"desc": "ディレクトリを選択すると、ファイルシステムが書き込み可能な場合、ダウンロードと同時に自動的にエクスポートされます"
},
"download_cache_path": {
"title": "他のプログラムのキャッシュを使用してダウンロード加速",
"confirm": "他のプログラムのキャッシュを使用してダウンロード加速",
"desc": "ディレクトリを選択すると、このディレクトリは次のディレクトリからコピーされたものでなければ使用できません。ダウンロード時にキャッシュフォルダとして優先的に読み込まれます。",
"cancel_desc": "他のソフトウェアのダウンロードコンテンツ加速機能をキャンセルしますか?キャンセル後に再度設定することができます",
"import_view_log_from_off": {
"title": "他のプログラムの履歴記録をインポート",
"desc": "ファイルを選択すると、このファイルは次のパスからコピーされたものでなければ使用できません。",
"choose_file_dialog_title": "インポートするファイルを選択"
}
},
"download_thread_count": {
"title": "ダウンロードスレッド数",
"choose": "ダウンロードスレッド数を選択"
},
"ebook_scrolling": {
"title": "電子書籍モードスクロールUI"
},
"ebook_scrolling_range": {
"title": "電子書籍モードスクロールUI",
"desc": "スクロール範囲",
"screen_height": "画面の高さ"
},
"ebook_scrolling_trigger": {
"title": "電子書籍モードスクロールUI",
"desc": "トリガー距離",
"cm": "センチメートル"
},
"export_path": {
"ios_desc": "ファイルマネージャーでエクスポートしたコンテンツを見つけることができます",
"ios_desc2": "iOS デバイスを使用しています:\nファイルにエクスポートしたコンテンツは、システム内蔵のファイルマネージャーを開いてご覧ください",
"export_path_desc": "エクスポートパス(クリックして変更)",
"android_desc": "Android デバイスを使用しています:\nエクスポートが失敗して権限不足のエラーが発生した場合、Download または Document の下にサブディレクトリを作成してエクスポートを試してみてください"
},
"export_rename": {
"title": "エクスポート時に名前を変更"
},
"yes": "はい",
"no": "いいえ",
"full_screen_action": {
"title": "操作方法",
"choose": "操作方法を選択",
"touch_once": "画面を一度タッチしてフルスクリーン",
"controller": "コントローラーを使用してフルスクリーン",
"touch_double": "画面をダブルクリックしてフルスクリーン",
"touch_double_once_next": "画面をダブルクリックしてフルスクリーン + 一度クリックで次のページ",
"three_area": "画面を3つの領域に分割(前のページ、次のページ、フルスクリーン)"
},
"full_screen_ui": {
"title": "全屏UI",
"choose": "全屏UIを選択",
"no": "使用しない",
"hidden_bottom": "仮想コントローラーを削除",
"all": "フルスクリーン"
},
"auto_full_screen": {
"title": "リーダーに入ったら自動フルスクリーン"
},
"auto_full_screen_on_forward": {
"title": "前へ進むときに自動全画面表示"
},
"ignore_info_history": {
"title": "詳細ページの履歴記録を除外"
},
"icon_loading": {
"title": "UI アニメーションを最小化"
},
"ignore_upgrade_confirm": {
"title": "アップグレードポップアップを閉じる"
},
"hidden_fd_icon": {
"title": "個人スペースの電源アイコンを非表示"
},
"hidden_search_persion": {
"title": "作者別検索機能を非表示"
},
"hidden_viewed": {
"title": "読んだ漫画を非表示"
},
"hidden_sub_icon": {
"title": "購読機能を非表示"
},
"hide_online_favorite": {
"title": "オンライン收藏を隠す",
"desc": "オンライン收藏の入口と收藏ボタンを隠す"
},
"hidden_words": {
"title": "キーワードで非表示",
"clear_all": "クリア確認",
"clear_all_desc": "すべてのキーワードをクリアしますか?",
"input_hint": "非表示にするキーワードを入力",
"no_words": "キーワードなし"
},
"image_address": {
"title": "画像アドレス",
"pinging": "Ping中",
"failed": "失敗"
},
"image_filter": {
"title": "リーダー画像フィルタ",
"normal": "通常",
"gray": "グレー",
"brown": "ブラウン",
"choose": "リーダー画像フィルタを選択"
},
"import_notice": {
"android_desc": "Android デバイスを使用しています:\nインポート/エクスポートができず、権限不足のエラーが発生した場合、Download または Document の下にサブディレクトリを作成してインポートを試してみてください"
},
"keyboard_controller": {
"title": "リーダーキーボードページ(PC のみ)"
},
"list_layout": {
"choose": "レイアウトを選択",
"info_card": "情報",
"only_image": "表紙",
"cover_and_title": "表紙 + タイトル"
},
"local_history_sync": {
"sync_to_local": "履歴をローカルに同期",
"not_set": "設定されていません",
"sync_success": "同期成功",
"sync_failed": "同期失敗",
"auto_sync": "履歴をローカルに自動同期",
"auto_sync_desc": "アプリケーションを開いた後、履歴が自動的にバックアップされます",
"choose_dir": "ディレクトリを選択",
"clear_path": "パスをクリア",
"clear_path_desc": "パスをクリアしますか?"
},
"history_sync": "履歴同期",
"local_favorite_sync_title": "ローカル收藏同期",
"use_local_favorite": "ローカル收藏を使用",
"use_local_favorite_desc": "ローカルで收藏を管理し、フォルダー分類に対応",
"local_favorite_sync": {
"auto_sync": "ローカル收藏を自動同期",
"auto_sync_desc": "WebDAVでローカル收藏を自動同期",
"manual_sync": "ローカル收藏を手動同期",
"sync_success": "同期成功",
"sync_failed": "同期失敗"
},
"no_animation": {
"title": "ページアニメーションをキャンセル(画面タップ、音量キー、キーボード)"
},
"pager_action": {
"title": "リストページの読み込み方法",
"choose": "リストページの読み込み方法を選択",
"controller": "ボタンを使用",
"stream": "ストリーム"
},
"proxy": {
"title": "プロキシサーバー",
"hint": "プロキシサーバーを入力",
"desc": " ( 例:socks5://127.0.0.1:1080/ ) ",
"no_proxy": "設定されていません"
},
"quality": {
"title": "閲覧時の画像品質",
"choose": "画像品質を選択",
"original": "オリジナル",
"low": "低",
"medium": "中",
"high": "高"
},
"reader_background_color": {
"title": "リーダー背景色",
"choose": "リーダー背景色を選択",
"black": "黒",
"gray": "グレー",
"white": "白"
},
"reader_direction": {
"title": "リーダー方向",
"choose": "リーダー方向を選択",
"top_to_bottom": "上から下へ",
"left_to_right": "左から右へ",
"right_to_left": "右から左へ"
},
"reader_scroll_by_screen_percentage": {
"title": "距離でページをめくる長さ",
"screen_size": "画面サイズ"
},
"web_toon_scroll_mode": {
"title": "WebToon ページめくりモード",
"choose": "WebToon ページめくりモードを選択",
"image": "画像",
"screen": "距離"
},
"reader_zoom": {
"out_title": "縮小倍率(最小ズーム)",
"in_title": "拡大倍率(最大ズーム)",
"double_tap_title": "ダブルタップズーム倍率"
},
"drag_region_lock": {
"title": "ドラッグ境界をロック"
},
"gesture_speed": {
"title": "ジェスチャー速度倍率"
},
"reader_slider_position": {
"title": "スライダー位置",
"choose": "スライダー位置を選択",
"bottom": "下",
"right": "右",
"left": "左"
},
"reader_two_page_direction": {
"title": "2ページリーダーコンテンツ配置",
"choose": "2ページリーダーコンテンツ配置を選択",
"close_to": "近づく",
"pull_away": "離れる",
"each_centered": "それぞれ中央"
},
"reader_type": {
"title": "リーダーモード",
"choose": "リーダーモードを選択",
"web_toon": "WebToon(デフォルト)",
"web_toon_zoom": "WebToon(ダブルクリックでズーム)",
"gallery": "ギャラリー",
"web_toon_free_zoom": "WebToon(ListViewダブルクリックでズーム)\n(このモードはプログレスバーが無効)",
"two_page_gallery": "2ページモード\n(実験的)",
"left_to_right": "左から右へ",
"right_to_left": "右から左へ",
"two_page_direction": "2ページ方向",
"two_page_direction_choose": "2ページ方向を選択"
},
"shadow_categories": {
"title": "封印",
"search_hint": "検索"
},
"shadow_categories_mode": {
"title": "封印モード",
"black_list": "ブラックリスト",
"white_list": "ホワイトリスト"
},
"startup_pic": {
"title": "起動画面設定",
"subtitle": "アプリケーション起動時に表示される画像を設定",
"clear_title": "起動画面をクリア",
"clear_subtitle": "アプリケーション起動時に表示される画像をクリア",
"clear_success": "起動画面がクリアされました",
"update_success": "起動画面が更新されました"
},
"show_comment_at_download": {
"title": "ダウンロードでコメントを表示"
},
"font": {
"title": "フォント",
"hint": "フォントを入力してください",
"input_hint": "フォント名を入力し、英語のカンマで区切ってください。例:\"MS ゴシック, メイリオ\"、保存後に変更されない場合は、フォントが使用できないか名前が間違っていることを意味します。C:\\Windows\\Fonts を参照してフォントを見つけることができます。flutter2 エンジンバージョンを使用している場合、最初のフォントのみが有効になります。",
"choose_hint": "背景エリアをクリックするまで複数のフォントを選択する必要があります"
},
"theme": {
"origin": "オリジナル",
"pink": "ピンク",
"black": "ブラック",
"dark": "ダーク",
"dusty_blue": "ダスティブルー",
"dark_black": "ダークブラック",
"choose_theme": "テーマを選択",
"book": "本",
"enable_status_bar_color": "ステータスバーの色を有効にする",
"enable_status_restart_hint": "無効になった場合、ステータスバーの色を更新するにはアプリケーションを再起動する必要があります"
},
"three_keep_right": {
"title": "3領域モードページを常に右に"
},
"time_zone": {
"title": "タイムゾーン"
},
"timeout_lock": {
"title": "自動ロック",
"notice": "注意:自動ロックは、デスクトップでは最小化後のタイムアウトのみをサポートし、モバイルではバックグラウンドおよび画面ロック後のタイムアウトをサポートします。パスワードが設定されていない場合、自動ロックは無効です。Android およびデスクトップはデスクトップのみをロックし、ダウンロードはロックしません。iOS はテストされていないため、バックグラウンドアクティビティを手動で有効にする必要があります。",
"1_hour": "1時間",
"10_minutes": "10分",
"3_minutes": "3分",
"1_minute": "1分",
"10_seconds": "10秒",
"1_second": "1秒",
"no_lock": "ロックしない"
},
"using_right_click_pop": {
"title": "マウス右クリックで前のページに戻る"
},
"volume_controller": {
"title": "リーダー音量ボタンページめくり"
},
"volume_next_chapter": {
"title": "音量/キーボード/コントローラーのダブルクリックで次のチャプター"
},
"webdav": {
"title": "WebDav",
"not_set": "未設定",
"path": "WebDav パス",
"path_hint": "WebDav パスを入力してください",
"username": "WebDav ユーザー名",
"username_hint": "WebDav ユーザー名を入力してください",
"password": "WebDav パスワード",
"password_hint": "WebDav パスワードを入力してください",
"auto_sync_history_to_webdav": "履歴を WebDav に自動同期",
"sync_history_to_webdav": "履歴を WebDAV に同期",
"upload_history_to_webdav": "WebDAV の履歴を上書き",
"upload_history_to_webdav_desc": "複数のデバイスがある場合、自動同期機能に注意してください",
"sync_success": "同期成功",
"sync_failed": "同期失敗"
}
},
"local_favorite": {
"title": "ローカル收藏",
"all_folders": "すべて",
"new_folder": "新しいフォルダー",
"select_mode": "選択",
"cancel_select_mode": "選択を終了",
"select_all": "すべて選択",
"delete_folder": "フォルダーを削除",
"move_to_folder": "フォルダーへ移動",
"remove_selected": "選択した收藏を削除",
"remove_selected_confirm": "選択した漫画をローカル收藏から削除しますか?",
"remove_selected_success": "削除しました",
"remove_selected_failed": "削除に失敗しました",
"select_comics": "先に漫画を選択してください",
"folder_limit_reached": "無料版は最大3つのフォルダーまでです。Proにアップグレードすると無制限になります",
"batch_download": "一括ダウンロード",
"select_folder": "フォルダーを選択",
"folder_name": "フォルダー名",
"delete_confirm": "フォルダーを削除しますか?",
"empty_folder": "まだ收藏がありません",
"no_folders": "フォルダーがありません。先に作成してください",
"remove_confirm_title": "收藏から削除",
"remove_confirm_content": "この漫画をローカル收藏から削除しますか?",
"remove_failed": "削除に失敗しました",
"load_failed": "読み込みに失敗しました",
"add_success": "ローカル收藏に追加しました",
"add_failed": "追加に失敗しました",
"create_folder_failed": "フォルダー作成に失敗しました",
"create_success": "作成しました",
"delete_success": "削除しました",
"delete_failed": "削除に失敗しました",
"move_success": "移動しました",
"move_failed": "移動に失敗しました",
"select_comics_to_download": "ダウンロードする漫画を選択してください",
"download_started": "ダウンロードを開始しました",
"download_failed": "ダウンロードに失敗しました"
},
"screen": {
"about": {
"title": "バージョン情報",
"version": "ソフトウェアバージョン",
"check_update": "アップデートを確認",
"tips": "ヒント : \n1. 詳細ページの作者/アップローダー/カテゴリ/タグはクリックできます\n2. 詳細ページの作者/アップローダー/タイトルは長押しでコピーできます\n3. ウォーターフォールフローの代わりにページネーションを使用すると、すばやくページをめくることができます\n4. ダウンロードはローカルにキャッシュすることを意味し、共有するにはエクスポートする必要があります\n5. ダウンロードは長押しで削除できます",
"download_new_version": "チャネルから新しいバージョンをダウンロードしてください",
"no_new_version": "新しいバージョンは検出されませんでした",
"download_release_version": "RELEASE版をダウンロード",
"update_content": "更新内容",
"go_to_release_repository": "RELEASEリポジトリへ移動"
},
"account": {
"title": "アカウント",
"username": "ユーザー名",
"username_hint": "ユーザー名を入力してください",
"password": "パスワード",
"password_hint": "パスワードを入力してください",
"no_account_register": "アカウントがありません、登録したいです",
"password_reset": "パスワードをリセット",
"check_username_password_or_network": "ユーザー名とパスワードまたはネットワーク環境を確認してください",
"check_device_time": "デバイスの時刻を確認してください",
"username_or_password_error": "ユーザー名またはパスワードが間違っています",
"login_failed": "ログインに失敗しました",
"not_set": "未設定"
},
"app": {
"will_pop_notice": "戻るキーを2回連続で押すとアプリを終了します"
},
"categories": {
"search_hint": "検索"
},
"clean": {
"title": "クリーン",
"cleaning": "クリーニング中",
"clean_network_cache": "ネットワークキャッシュをクリーン",
"clean_image_cache": "画像キャッシュをクリーン",
"clean_all_cache": "すべてのキャッシュをクリーン",
"clean_success": "クリーン成功",
"clean_failed": "クリーン失敗"
},
"close_app": {
"title": "ヒント",
"close_app": "アプリを閉じて再度開いてください"
},
"comic_collections": {
"no_resource": "ここにはリソースがありません"
},
"comic_info": {
"chapter": "チャプター",
"comment": "コメント",
"recommend": "おすすめ"
},
"comics": {
"search_hint": "カテゴリを検索",
"choose_category": "カテゴリを選択してください"
},
"comic_subscribes": {
"update_reminder": "更新リマインダー",
"check_update": "更新を確認",
"cancel_all_update_reminder": "すべての更新リマインダーをキャンセル"
},
"comment": {
"title": "コメント",
"hint_text": "コメント内容を入力してください",
"success": "コメント成功",
"i_have_something_to_say": "言いたいことがあります",
"please_enter_comment": "コメント内容を入力してください"
},
"desktop_authentication": {
"current_password": "現在のパスワード",
"password_error": "パスワードが間違っています",
"password_initialization": "パスワードの初期化",
"password": "パスワード",
"re_enter_password": "パスワードを再入力",
"password_mismatch": "入力された2つのパスワードが異なります",
"set_password": "パスワードを設定"
},
"download_confirm": {
"please_select_ep": "ダウンロードするEPを選択してください",
"already_added_to_download_list": "すでにダウンロードリストに追加されています"
},
"download_export_group": {
"title": "一括エクスポート",
"please_select_content": "エクスポートするコンテンツを選択してください",
"exporting": "エクスポート中",
"export_failed": "エクスポート失敗",
"export_success": "エクスポート成功",
"export_to_pkz": "PKZにエクスポート\n(暗号化モード、ウェブ検出を防止、pikapikaで開くことができます)",
"export_to_pki": "PKIにエクスポート\n(暗号化モード、ウェブ検出を防止、pikapikaでインポートできます)",
"export_to_zip": "ZIPにエクスポート\n(非暗号化モード、pikapikaでインポートまたは表示できます)",
"export_to_jpeg_zip": "ZIP+JPEGにエクスポート\n(他のリーダーで直接使用できますが、再インポートはできません)",
"export_to_jpeg_folder": "フォルダ+JPEGにエクスポート",
"export_to_pdf": "PDFにエクスポート",
"export_to_epub": "EPUBにエクスポート",
"export_to_pdf_folder": "フォルダにエクスポート、各章ごとに1つのPDF",
"export_to_cbz": "cbzにエクスポート",
"after_power_use": "パワー使用後",
"input_save_name": "保存名を入力してください",
"export_confirm": "エクスポートの確認",
"export_to_pkz_title": "選択した漫画をPKZにエクスポート",
"export_to_pki_title": "選択した漫画を個別のPKIにエクスポート",
"please_power_up": "最初にパワーアップしてください",
"export_to_zip_title": "選択した漫画をZIPにエクスポート",
"export_to_jpeg_zip_title": "選択した漫画をZIP+JPEGにエクスポート",
"export_to_jpeg_zip_title_not_down_over": "選択した漫画をZIP+JPEGにエクスポート\n(ダウンロードが成功しなくても使用できます)",
"export_to_jpeg_folder_title": "選択した漫画をフォルダ+JPEGにエクスポート",
"export_to_pdf_title": "選択した漫画をPDFにエクスポート",
"export_to_epub_title": "選択した漫画をEPUBにエクスポート",
"export_to_pdf_folder_title": "選択した漫画をフォルダにエクスポート、各章ごとに1つのPDF",
"export_to_cbz_title": "選択した漫画をcbzにエクスポート",
"exporting_please_wait": "エクスポート中です、しばらくお待ちください"
},
"download_export_to_file": {
"title": "エクスポート",
"transfer_to_other_device": "他のデバイスに転送",
"input_save_name": "保存名を入力してください",
"export_confirm": "エクスポートの確認",
"export_to_pkz_title": "選択した漫画をPKZにエクスポート",
"export_to_pkz_desc": "xxx.pkzにエクスポート\n(暗号化モード、ウェブ検出を防止、pikapikaで開くことができます)",
"export_to_pki_title": "選択した漫画を個別のPKIにエクスポート",
"export_to_pki_desc": "xxx.pkiにエクスポート\n(暗号化モード、ウェブ検出を防止、pikapikaでインポートできます)",
"export_to_zip_title": "選択した漫画をZIPにエクスポート",
"export_to_zip_desc": "xxx.zipにエクスポート\n(非暗号化モード、pikapikaでインポートまたは表示できます)",
"export_to_jpeg_zip_title": "選択した漫画をZIP+JPEGにエクスポート",
"export_to_jpeg_zip_desc": "xxx.jpegにエクスポート\n(他のリーダーで直接使用できますが、再インポートはできません)",
"export_to_pdf_title": "選択した漫画をPDFにエクスポート",
"export_to_pdf_desc": "xxx.pdfにエクスポート\n(ダウンロードが成功しなくても使用でき、失敗した画像はスキップされます)\n(フォトアルバムで直接開くことができます)",
"export_to_pdf_folder_title": "選択した漫画をフォルダにエクスポート、各章ごとに1つのPDF",
"export_to_pdf_folder_desc": "xxx.pdfにエクスポート\n(ダウンロードが成功しなくても使用でき、失敗した画像はスキップされます)\n(フォトアルバムで直接開くことができます)",
"export_to_epub_title": "選択した漫画をEPUBにエクスポート",
"export_to_epub_desc": "xxx.epubにエクスポート\n(リーダーで直接開くことができます)",
"export_to_jpeg_folder_title": "選択した漫画をJPEGS.zipにエクスポート",
"export_to_jpeg_folder_desc": "JPGS.zipにエクスポート\n(再インポートはできません)",
"export_to_cbz_title": "選択した漫画をcbk.zipにエクスポート",
"export_to_cbz_desc": "xxx.cbzにエクスポート、リーダーで直接使用できます(再インポートはできません)"
},
"download_export_to_socket": {
"title": "ネットワークエクスポート",
"loading": "読み込み中",
"tips": "転送が成功するまでページを終了しないでください。一度に1つのデバイスしかエクスポートできず、2つのデバイスは同じネットワークセグメントまたは無限LANにある必要があります。他のデバイスでIP:portを入力してください。IPが1つしかない場合は、無限LANのIPを選択してください。通常は192.168で始まります",
"get_ip_failed": "IP取得失敗",
"getting_ip": "IP取得中",
"port": "ポート"
},
"download_import": {
"title": "インポート",
"open_file": "ファイルを開く",
"select_file": "インポートするファイルを選択",
"import_success": "インポート成功",
"import_failed": "インポート失敗",
"select_file_desc": "インポートするzipファイルを選択\nインポートするpkiファイルを選択\n読むpkzファイルを選択",
"input_address": "エクスポートデバイスから提供されたアドレスを入力してください\n例:「192.168.1.2:50000」",
"import_from_other_device": "他のデバイスからインポート",
"select_folder_desc": "フォルダを選択\n(フォルダ内のすべてのzip/pkiをインポート)\n(パワー使用後)"
},
"download_info": {
"loading": "読み込み中",
"chapter": "チャプター",
"comment": "コメント",
"recommend": "おすすめ"
},
"download_list": {
"search_download": "ダウンロードを検索",
"multi_select_operation": "複数選択操作",
"download_list": "ダウンロードリスト",
"search": "検索",
"select_folder": "フォルダーを選択",
"download_already_in_delete_queue": "ダウンロードはすでに削除キューにあります",
"import": "インポート",
"export": "エクスポート",
"file": "ファイル",
"download_task": "ダウンロードタスク",
"pause_download": "ダウンロードを一時停止しますか?",
"start_download": "ダウンロードを開始しますか?",
"resume_failed": "失敗したタスクを再開",
"resume_failed_desc": "すべての失敗したダウンロードが再開されました",
"downloading": "ダウンロード中",
"paused": "一時停止",
"move_download": "ダウンロードを移動",
"select_download_to_move": "移動するダウンロードを選択してください",
"select_download_to_delete": "削除するダウンロードを選択してください",
"input_name": "==> 名前を入力 <==",
"empty_folder_will_be_deleted": "(空のフォルダは自動的に削除されます、次回は手動で入力する必要があります)",
"folder_name": "フォルダ名",
"please_input_folder_name": "フォルダ名を入力してください",
"delete_download": "ダウンロードを削除",
"delete_selected_download": "選択したダウンロードを削除しますか?",
"multi_select": "複数選択"
},
"download_only_import": {
"importing": "インポート中",
"import_success": "インポート成功",
"import_failed": "インポート失敗",
"click_import_file": "インポートファイルをクリック",
"importing_please_wait": "インポート中です、しばらくお待ちください"
},
"favourite_paper": {
"favourite": "お気に入り"
},
"forgot_password": {
"title": "パスワードの回復",
"username": "ユーザー名",
"not_set": "未設定",
"confirm": "確認",
"please_enter_username": "ユーザー名を入力してください",
"question_1": "質問1",
"question_2": "質問2",
"question_3": "質問3",
"answer_1": "回答1",
"answer_2": "回答2",
"answer_3": "回答3",
"please_enter_answer_1": "回答1を入力してください",
"please_enter_answer_2": "回答2を入力してください",
"please_enter_answer_3": "回答3を入力してください",
"use_answer_1_recover": "回答1を使用してパスワードを回復",
"use_answer_2_recover": "回答2を使用してパスワードを回復",
"use_answer_3_recover": "回答3を使用してパスワードを回復",
"please_enter_answer": "回答を入力してください",
"new_password_copied": "新しいパスワードがクリップボードにコピーされました",
"answer_incorrect": "回答が間違っています",
"password": "パスワード"
},
"game_download": {
"title": "ダウンロード",
"download_links_obtained": "ダウンロードリンクが取得されました、そのうちの1つを選択するだけです"
},
"game_info": {
"download": "ダウンロード",
"details": "詳細",
"comments": "コメント"
},
"games": {
"title": "ゲーム"
},
"import_from_off": {
"title": "インポート",
"import_success": "インポート成功",
"import_failed": "インポート失敗"
},
"modify_password": {
"title": "パスワードを変更",
"please_wait": "お待ちください",
"old_password": "古いパスワード",
"new_password": "新しいパスワード",
"repeat_new_password": "新しいパスワードを繰り返す",
"not_filled": "未入力",
"please_enter_old_password": "古いパスワードを入力してください",
"please_enter_new_password": "新しいパスワードを入力してください",
"please_repeat_new_password": "新しいパスワードを再度入力してください",
"new_password_mismatch": "新しいパスワードが一致しません",
"modify_success": "変更成功",
"failed": "失敗",
"confirm": "確認"
},
"network_settings": {
"title": "ネットワーク設定"
},
"pkz_reader": {
"reading_downloaded_comic": "ダウンロードした漫画を読んでいます"
},
"pro": {
"title": "パワーセンター",
"power_center": "パワーセンター",
"power_status": "パワーステータス",
"powered": "パワーオン",
"not_powered": "パワーオフ",
"pat_membership": "PATメンバーシップ",
"pat_status": "PATステータス",
"pat_normal": "PAT正常",
"pat_bind_hint": "現在のアカウントにバインドしてパワーを得るにはここをクリックしてください",
"pat_rebind_hint": "現在のアカウントに再バインドしてパワーを得るにはクリックしてください",
"pat_not_detected": "メンバーシップが検出されません、ダウンロードページに移動して参加してください",
"i_have_powered": "以前にパワーオンしました",
"i_just_powered": "ちょうどパワーオンしました",
"enter_code": "コードを入力",
"power_method": "パワー方法",
"wind_power": "風力発電",
"hydro_power": "水力発電",
"solar_power": "太陽光発電",
"nuclear_power": "原子力発電",
"choose_power_method": "パワー方法を選択",
"sign_in_exchange": "サインイン/交換",
"click_pat_to_change": "変更するには下のPATメンバーシップをクリックしてください",
"update_pat_status": "PATパワーステータスを更新",
"bind_to_account": "このアカウントにバインド",
"change_pat_key": "PATキーを変更",
"clear_pat_info": "PAT情報をクリア",
"click_to_bind": "クリックしてバインド",
"enter_auth_code": "認証コードを入力してください",
"please_wait": "お待ちください",
"key_recorded": "キー:記録済み",
"pat_account": "PATアカウント",
"bind_pika_account": "PIKAアカウントをバインド",
"bind_account_time": "アカウントのバインド時間",
"rebind_time": "再バインド可能時間",
"power_features": "パワー機能:マルチスレッドダウンロード/一括インポート/エクスポートダウンロード",
"power_guide": "「バージョン情報」ページに移動して、パワーガイドのメンテナンスアドレスを見つけてください\n\n 「以前にパワーオンしました」は対応するパワーステータスを同期できます\n 「ちょうどパワーオンしました」は神秘的なコードを交換します\n 「パワー方法」はネットワークが機能していないときに変更できます\n 「PATメンバーシップ」は独立したパワー方法です"
},
"rankings": {
"title": "ランキング",
"day": "日",
"week": "週",
"month": "月",
"knight": "ナイト",
"refresh": "更新",
"comics_count": "漫画"
},
"random_comics": {
"title": "ランダム漫画"
},
"register": {
"title": "登録",
"registering": "登録中",
"register_success": "登録成功",
"register_failed": "登録失敗",
"account_exists": "アカウントはすでに存在します",
"name_exists": "名前はすでに存在します",
"check_form": "フォームを確認してください、空のフィールドは許可されていません",
"account": "アカウント",
"password": "パスワード",
"nickname": "ニックネーム",
"gender": "性別",
"birthday": "誕生日",
"question_1": "質問1",
"answer_1": "回答1",
"question_2": "質問2",
"answer_2": "回答2",
"question_3": "質問3",
"answer_3": "回答3",
"not_set": "未設定",
"please_enter_account": "アカウントを入力してください",
"please_enter_password": "パスワードを入力してください",
"please_enter_nickname": "ニックネームを入力してください",
"please_enter_question_1": "質問1を入力してください",
"please_enter_answer_1": "回答1を入力してください",
"please_enter_question_2": "質問2を入力してください",
"please_enter_answer_2": "回答2を入力してください",
"please_enter_question_3": "質問3を入力してください",
"please_enter_answer_3": "回答3を入力してください",
"account_desc": "(小文字+数字/ログイン用)",
"password_desc": "(大文字と小文字+数字/ 8文字以上)",
"nickname_desc": "(日本語可/ 2-50文字)",
"choose_gender": "性別を選択してください",
"futa": "ふたなり",
"male": "男性",
"female": "女性",
"register_success_desc": "登録に成功しました、ログインに戻ってください",
"account_label": "アカウント",
"nickname_label": "ニックネーム"
},
"search": {
"title": "検索",
"search_hint": "検索",
"choose_category": "カテゴリを選択してください"
},
"search_author": {
"title": "作者で検索",
"search_hint": "作者で検索+",
"by_author": "作者:"
},
"space": {
"title": "マイページ",
"logout": "ログアウト",
"logout_confirm": "現在のアカウントからログアウトしますか?",
"my_favourites": "お気に入り",
"view_history": "閲覧履歴",
"my_downloads": "マイダウンロード"
},
"theme": {
"title": "テーマ設定",
"theme": "テーマ",
"dark_mode_different_theme": "ダークモードで異なるテーマを使用",
"dark_mode_theme": "テーマ(ダークモード)"
},
"view_logs": {
"title": "閲覧履歴",
"clear_all": "すべての閲覧履歴をクリアしますか?",
"clear_all_desc": "読書の進捗も削除されます!",
"clear_one": "この閲覧履歴をクリアしますか?",
"clear_one_desc": "読書の進捗も削除されます!",
"clear_selected": "選択した閲覧履歴をクリアしますか?",
"clear_selected_desc": "読書の進捗も削除されます!",
"categories": "カテゴリ"
},
"web_server": {
"title": "ダウンロード - Webサーバー",
"loading": "読み込み中",
"get_ip_failed": "IP取得失敗",
"getting_ip": "IP取得中",
"port": "ポート:8080",
"usage_instruction": "ブラウザで「http://device_ip:8080/」と入力して、ダウンロードした漫画にアクセスします",
"leave_notice": "このページを離れるとサーバーが閉じます"
}
},
"components": {
"comic_info_card": {
"categories": "カテゴリ",
"finished": "完結",
"viewed": "閲覧済み"
},
"comic_list": {
"shadow": "シャドウコミック"
},
"common": {
"display_mode": "表示モード",
"shadow_mode": "シャドウモード",
"shadow_list": "シャドウリスト",
"batch_download": "一括ダウンロード"
},
"image_reader": {
"already_at_the_end": "すでに最後に達しています",
"click_to_next_chapter": "クリックして次の章へ",
"reload_page": "ページを再読み込み",
"next_chapter": "次の章",
"end_reading": "読書を終了",
"reload_image": "画像を再読み込み",
"save_image_in_this_page": "このページの画像を保存",
"image_load_failed": "画像の読み込みに失敗しました"
}
}
}
================================================
FILE: lib/assets/translations/ko-KR.json
================================================
{
"language": {
"title": "언어",
"name": "한국어 - 대한민국"
},
"app": {
"categories": "카테고리",
"my": "내 정보",
"copied_to_clipboard": "클립보드에 복사되었습니다",
"not_supported_platform": "지원되지 않는 플랫폼",
"cancel": "취소",
"confirm": "확인",
"save_cancel": "저장이 취소되었습니다",
"save_success": "저장에 성공했습니다",
"save_failed": "저장에 실패했습니다",
"pro": "프로",
"pro_required": "이 기능을 사용하려면 프로로 업그레이드하세요",
"choose_folder": "파일을 저장할 폴더를 선택하세요",
"permission_denied": "권한이 거부되었습니다",
"loading": "로딩 중",
"error": "오류",
"pat": {
"success": "스폰서 로그인이 성공했습니다. 돌아가세요",
"title": "PAT 계정 교체"
},
"previous_page": "이전 페이지",
"next_page": "다음 페이지",
"page": "페이지",
"please_enter_page_number": "페이지 번호를 입력하세요:",
"select_all": "모두 선택",
"load_failed": "로딩에 실패했습니다",
"all": "모두",
"delete": "삭제",
"save_image": "이미지 저장",
"preview_image": "이미지 미리보기",
"please_select": "선택하세요",
"refresh": "새로고침",
"initializing": "초기화 중",
"like_failed": "좋아요에 실패했습니다",
"network_error": "네트워크 오류입니다. 네트워크를 확인하세요",
"no_permission": "권한이 없거나 경로를 사용할 수 없습니다",
"check_device_time": "장치 시간을 확인하세요",
"resource_not_available": "리소스를 사용할 수 없습니다",
"something_went_wrong": "문제가 발생했습니다",
"click_refresh": "클릭하여 새로고침",
"pull_down_refresh": "아래로 당겨서 새로고침",
"continue_reading": "계속 읽기",
"start_reading": "읽기 시작",
"image_crop": "이미지 자르기",
"download": "다운로드",
"download_failed": "다운로드에 실패했습니다",
"download_finished": "다운로드 완료",
"downloading": "다운로드 중",
"queue": "대기열",
"deleting": "삭제 중",
"please_select_comic": "만화를 선택하세요",
"please_choose": "선택하세요",
"last_viewed": "마지막으로 본",
"auto_punch": "자동 체크인",
"yes": "예",
"no": "아니오",
"confirm_download": "다운로드 확인",
"copy": "복사"
},
"net": {
"no_address": "주소 없음",
"address": "주소",
"address_sync": "주소 동기화",
"address_sync_from_server": "서버에서 최신 주소 가져오기",
"address_sync_reset": "주소를 기본값으로 재설정",
"address_sync_success": "주소 동기화에 성공했습니다",
"address_sync_failed": "주소 동기화에 실패했습니다",
"address_sync_reset_success": "주소 동기화 재설정에 성공했습니다",
"address_sync_reset_failed": "주소 동기화 재설정에 실패했습니다",
"choose_address": "주소 선택",
"image_address": "이미지 주소",
"use_api_load_image": "API를 사용하여 이미지 로드",
"ping_testing": "테스트 중",
"ping_failed": "실패했습니다"
},
"categories": {
"all": "모두",
"recommend": "추천",
"rankings": "랭킹",
"random": "랜덤",
"game": "게임"
},
"settings": {
"settings": "설정",
"interface": "인터페이스",
"network": "네트워크",
"seal": "봉인",
"interaction": "상호작용",
"reading": "읽기",
"download": "다운로드",
"auto_download_on_favorite": "즐겨찾기 시 자동 다운로드",
"disable_auto_download_on_mobile": "모바일 데이터에서는 자동 다운로드 안 함",
"auto_delete_download_on_unfavorite": "즐겨찾기 해제 시 자동 삭제",
"web_server": "웹 서버",
"web_server_subtitle": "로컬 네트워크의 장치가 브라우저를 통해 다운로드한 만화를 볼 수 있게 합니다",
"sync": "동기화",
"account": "계정",
"modify_password": "Modify password",
"ebook": "전자책",
"system": "시스템",
"clear_cache": "캐시 지우기",
"migrate": "이전",
"migrate_subtitle": "데이터 폴더를 메모리 카드로 변경",
"migrate_confirm": "이 기능은 프로그램을 다시 시작한 후에 저장됩니다. 확실합니까",
"app_orientation": {
"title": "앱 방향",
"choose": "앱 방향 선택",
"normal": "일반",
"landscape": "가로",
"portrait": "세로"
},
"will_pop_notice": "뒤로 키를 연속으로 두 번 눌러 앱을 종료합니다",
"android_secure_flag": "스크린샷 비활성화/작업 보기에서 표시 비활성화",
"android_display_mode": {
"title": "화면 새로고침 속도(Android)",
"dialog_title": "Android 화면 새로고침 속도 \n(절전 모드에서는 고주사율이 적용되지 않음)"
},
"authentication": "앱에 들어갈 때 인증 (시스템이 이미 비밀번호나 지문을 입력한 경우)",
"set_password": "애플리케이션 비밀번호 설정",
"auto_clean": {
"title": "자동 캐시 정리",
"one_month_ago": "한 달 전",
"one_week_ago": "일주일 전",
"one_day_ago": "하루 전",
"no_auto_clean": "자동 정리 안 함"
},
"categories_column_count": {
"title": "카테고리 열 수",
"choose": "카테고리 열 수 선택",
"auto": "자동"
},
"categories_sort": {
"title": "카테고리 정렬"
},
"chooser_root": {
"title": "폴더 선택기 루트 경로",
"hint": "폴더 선택기 루트 경로를 입력하세요",
"desc": "내보낼 때 디렉토리 선택의 기본 경로이며, 루트 경로이기도 합니다. 내보내기가 정상적으로 작동하지 않을 때 이 옵션을 설정해 볼 수 있습니다."
},
"content_failed_reload_action": {
"title": "콘텐츠 로드 실패 시 새로고침 방식",
"choose": "콘텐츠 로드 실패 시 새로고침 방식 선택",
"pull_down": "아래로 당기기",
"touch_loader": "화면 터치"
},
"copy_full_name": {
"title": "만화 이름 복사 시 템플릿 사용"
},
"copy_full_name_template": {
"title": "만화 이름 복사 템플릿",
"hint": "만화 이름 복사 템플릿을 입력하세요"
},
"copy_skip_confirm": {
"title": "긴 터치 복사 시 확인 안 함"
},
"download_and_export_path": {
"title": "다운로드와 동시에 파일 시스템으로 내보내기",
"confirm": "다운로드와 동시에 파일 시스템으로 내보내기",
"desc": "디렉토리를 선택하면, 파일 시스템이 쓰기 가능한 경우 다운로드와 동시에 자동으로 내보내집니다"
},
"download_cache_path": {
"title": "다른 프로그램의 캐시를 사용하여 다운로드 가속화",
"confirm": "다른 프로그램의 캐시를 사용하여 다운로드 가속화",
"desc": "디렉토리를 선택하면, 이 디렉토리는 다음 디렉토리에서 복사된 것이어야 사용할 수 있습니다. 다운로드 시 캐시 폴더로 우선 읽어집니다.",
"cancel_desc": "다른 소프트웨어의 다운로드 콘텐츠 가속화 기능을 취소하시겠습니까? 취소 후 다시 설정할 수 있습니다",
"import_view_log_from_off": {
"title": "다른 프로그램의 기록 가져오기",
"desc": "파일을 선택하면, 이 파일은 다음 경로에서 복사된 것이어야 사용할 수 있습니다.",
"choose_file_dialog_title": "가져올 파일 선택"
}
},
"download_thread_count": {
"title": "다운로드 스레드 수",
"choose": "다운로드 스레드 수 선택"
},
"ebook_scrolling": {
"title": "전자책 모드 스크롤 UI"
},
"ebook_scrolling_range": {
"title": "전자책 모드 스크롤 UI",
"desc": "스크롤 범위",
"screen_height": "화면 높이"
},
"ebook_scrolling_trigger": {
"title": "전자책 모드 스크롤 UI",
"desc": "트리거 거리",
"cm": "센티미터"
},
"export_path": {
"ios_desc": "파일 관리자에서 내보낸 콘텐츠를 찾을 수 있습니다",
"ios_desc2": "iOS 장치를 사용하고 있습니다:\n파일로 내보낸 콘텐츠는 시스템 내장 파일 관리자를 열어서 찾아보세요",
"export_path_desc": "내보내기 경로 (클릭하여 수정)",
"android_desc": "Android 장치를 사용하고 있습니다:\n내보내기가 실패하고 권한 부족 오류가 발생하면, Download 또는 Document 하위에 서브디렉토리를 만들어 내보내기를 시도해 보세요"
},
"export_rename": {
"title": "내보낼 때 이름 바꾸기"
},
"yes": "예",
"no": "아니오",
"full_screen_action": {
"title": "조작 방식",
"choose": "조작 방식 선택",
"touch_once": "화면 한 번 터치로 전체 화면",
"controller": "컨트롤러 사용으로 전체 화면",
"touch_double": "화면 두 번 터치로 전체 화면",
"touch_double_once_next": "화면 두 번 터치로 전체 화면 + 한 번 터치로 다음 페이지",
"three_area": "화면을 세 영역으로 나누기 (이전 페이지, 다음 페이지, 전체 화면)"
},
"full_screen_ui": {
"title": "전체 화면 UI",
"choose": "전체 화면 UI 선택",
"no": "사용 안 함",
"hidden_bottom": "가상 컨트롤러 제거",
"all": "전체 화면"
},
"auto_full_screen": {
"title": "리더 진입 시 자동 전체 화면"
},
"auto_full_screen_on_forward": {
"title": "앞으로 갈 때 자동 전체 화면"
},
"ignore_info_history": {
"title": "상세 페이지 기록 제외"
},
"icon_loading": {
"title": "UI 애니메이션 최소화"
},
"ignore_upgrade_confirm": {
"title": "업그레이드 팝업 닫기"
},
"hidden_fd_icon": {
"title": "개인 공간의 전원 아이콘 숨기기"
},
"hidden_search_persion": {
"title": "작가별 검색 기능 숨기기"
},
"hidden_viewed": {
"title": "읽은 만화 숨기기"
},
"hidden_sub_icon": {
"title": "구독 기능 숨기기"
},
"hide_online_favorite": {
"title": "온라인 즐겨찾기 숨기기",
"desc": "온라인 즐겨찾기 진입 및 즐겨찾기 버튼 숨기기"
},
"hidden_words": {
"title": "키워드로 숨기기",
"clear_all": "지우기 확인",
"clear_all_desc": "모든 키워드를 지우시겠습니까?",
"input_hint": "숨길 키워드를 입력하세요",
"no_words": "키워드 없음"
},
"image_address": {
"title": "이미지 주소",
"pinging": "핑 테스트 중",
"failed": "실패"
},
"image_filter": {
"title": "리더 이미지 필터",
"normal": "일반",
"gray": "회색",
"brown": "갈색",
"choose": "리더 이미지 필터 선택"
},
"import_notice": {
"android_desc": "Android 장치를 사용하고 있습니다:\n가져오기/내보내기가 안 되고 권한 부족 오류가 발생하면, Download 또는 Document 하위에 서브디렉토리를 만들어 가져오기를 시도해 보세요"
},
"keyboard_controller": {
"title": "리더 키보드 페이지 (PC만 해당)"
},
"list_layout": {
"choose": "레이아웃 선택",
"info_card": "정보",
"only_image": "표지",
"cover_and_title": "표지 + 제목"
},
"local_history_sync": {
"sync_to_local": "기록을 로컬에 동기화",
"not_set": "설정되지 않음",
"sync_success": "동기화 성공",
"sync_failed": "동기화 실패",
"auto_sync": "기록을 로컬에 자동 동기화",
"auto_sync_desc": "애플리케이션을 열 때마다 기록이 자동으로 백업됩니다",
"choose_dir": "디렉터리 선택",
"clear_path": "경로 지우기",
"clear_path_desc": "경로를 지우시겠습니까?"
},
"history_sync": "기록 동기화",
"local_favorite_sync_title": "로컬 즐겨찾기 동기화",
"use_local_favorite": "로컬 즐겨찾기 사용",
"use_local_favorite_desc": "즐겨찾기를 로컬에서 관리하고 폴더 분류를 지원합니다",
"local_favorite_sync": {
"auto_sync": "로컬 즐겨찾기 자동 동기화",
"auto_sync_desc": "WebDAV로 로컬 즐겨찾기를 자동 동기화",
"manual_sync": "로컬 즐겨찾기 수동 동기화",
"sync_success": "동기화 성공",
"sync_failed": "동기화 실패"
},
"no_animation": {
"title": "페이지 애니메이션 취소 (화면 터치, 볼륨 키, 키보드)"
},
"pager_action": {
"title": "목록 페이지 로딩 방법",
"choose": "목록 페이지 로딩 방법 선택",
"controller": "버튼 사용",
"stream": "스트림"
},
"proxy": {
"title": "프록시 서버",
"hint": "프록시 서버를 입력하세요",
"desc": " ( 예: socks5://127.0.0.1:1080/ ) ",
"no_proxy": "설정되지 않음"
},
"quality": {
"title": "탐색 시 이미지 품질",
"choose": "이미지 품질 선택",
"original": "원본",
"low": "낮음",
"medium": "보통",
"high": "높음"
},
"reader_background_color": {
"title": "리더 배경색",
"choose": "리더 배경색 선택",
"black": "검은색",
"gray": "회색",
"white": "흰색"
},
"reader_direction": {
"title": "리더 방향",
"choose": "리더 방향 선택",
"top_to_bottom": "위에서 아래로",
"left_to_right": "왼쪽에서 오른쪽으로",
"right_to_left": "오른쪽에서 왼쪽으로"
},
"reader_scroll_by_screen_percentage": {
"title": "거리별 페이지 넘김 길이",
"screen_size": "화면 크기"
},
"web_toon_scroll_mode": {
"title": "WebToon 페이지 넘김 모드",
"choose": "WebToon 페이지 넘김 모드 선택",
"image": "이미지",
"screen": "거리"
},
"reader_zoom": {
"out_title": "축소 배율 (최소 확대)",
"in_title": "확대 배율 (최대 확대)",
"double_tap_title": "더블탭 확대 배율"
},
"drag_region_lock": {
"title": "드래그 경계 잠금"
},
"gesture_speed": {
"title": "제스처 속도 배율"
},
"reader_slider_position": {
"title": "슬라이더 위치",
"choose": "슬라이더 위치 선택",
"bottom": "아래",
"right": "오른쪽",
"left": "왼쪽"
},
"reader_two_page_direction": {
"title": "두 페이지 리더 콘텐츠 배열",
"choose": "두 페이지 리더 콘텐츠 배열 선택",
"close_to": "가깝게",
"pull_away": "멀리",
"each_centered": "각각 중앙"
},
"reader_type": {
"title": "리더 모드",
"choose": "리더 모드 선택",
"web_toon": "웹툰 (기본)",
"web_toon_zoom": "웹툰 (더블 클릭으로 확대)",
"gallery": "갤러리",
"web_toon_free_zoom": "웹툰 (ListView 더블 클릭으로 확대)\n(이 모드는 진행률 표시줄이 무효)",
"two_page_gallery": "두 페이지 모드\n(실험적)",
"left_to_right": "왼쪽에서 오른쪽으로",
"right_to_left": "오른쪽에서 왼쪽으로",
"two_page_direction": "두 페이지 방향",
"two_page_direction_choose": "두 페이지 방향 선택"
},
"shadow_categories": {
"title": "봉인",
"search_hint": "검색"
},
"shadow_categories_mode": {
"title": "봉인 모드",
"black_list": "블랙 리스트",
"white_list": "화이트 리스트"
},
"startup_pic": {
"title": "시작 화면 설정",
"subtitle": "애플리케이션 시작 시 표시되는 이미지 설정",
"clear_title": "시작 화면 지우기",
"clear_subtitle": "애플리케이션 시작 시 표시되는 이미지 지우기",
"clear_success": "시작 화면이 지워졌습니다",
"update_success": "시작 화면이 업데이트되었습니다"
},
"show_comment_at_download": {
"title": "다운로드에서 댓글 표시"
},
"font": {
"title": "글꼴",
"hint": "글꼴을 입력하세요",
"input_hint": "글꼴 이름을 입력하고 영어 쉼표로 구분하세요. 예: \"굴림, 돋움\", 저장 후 변경되지 않으면 글꼴을 사용할 수 없거나 이름이 잘못되었음을 의미합니다. C:\\Windows\\Fonts를 참조하여 글꼴을 찾을 수 있습니다. flutter2 엔진 버전을 사용하는 경우 첫 번째 글꼴만 적용됩니다.",
"choose_hint": "배경 영역을 클릭할 때까지 여러 글꼴을 선택해야 합니다"
},
"theme": {
"origin": "원본",
"pink": "핑크",
"black": "검은색",
"dark": "다크",
"dusty_blue": "먼지 파란색",
"dark_black": "진한 검은색",
"choose_theme": "테마 선택",
"book": "책",
"enable_status_bar_color": "상태 표시줄 색상 활성화",
"enable_status_restart_hint": "비활성화된 경우 상태 표시줄 색상을 새로 고치려면 애플리케이션을 다시 시작해야 합니다"
},
"three_keep_right": {
"title": "세 영역 모드 페이지를 항상 오른쪽으로"
},
"time_zone": {
"title": "시간대"
},
"timeout_lock": {
"title": "자동 잠금",
"notice": "참고: 자동 잠금은 데스크톱에서 최소화 후 타임아웃만 지원하며, 모바일에서는 백그라운드 및 화면 잠금 후 타임아웃을 지원합니다. 비밀번호가 설정되지 않은 경우 자동 잠금이 무효입니다. Android와 데스크톱은 데스크톱만 잠그고 다운로드는 잠그지 않으며, iOS는 테스트되지 않았으므로 백그라운드 활동을 수동으로 활성화해야 합니다.",
"1_hour": "1시간",
"10_minutes": "10분",
"3_minutes": "3분",
"1_minute": "1분",
"10_seconds": "10초",
"1_second": "1초",
"no_lock": "잠금 안 함"
},
"using_right_click_pop": {
"title": "마우스 오른쪽 클릭으로 이전 페이지로 돌아가기"
},
"volume_controller": {
"title": "리더 볼륨 버튼 페이지 넘기기"
},
"volume_next_chapter": {
"title": "볼륨/키보드/컨트롤러 더블 클릭으로 다음 챕터"
},
"webdav": {
"title": "WebDav",
"not_set": "설정되지 않음",
"path": "WebDav 경로",
"path_hint": "WebDav 경로를 입력하세요",
"username": "WebDav 사용자명",
"username_hint": "WebDav 사용자명을 입력하세요",
"password": "WebDav 비밀번호",
"password_hint": "WebDav 비밀번호를 입력하세요",
"auto_sync_history_to_webdav": "WebDav에 기록 자동 동기화",
"sync_history_to_webdav": "기록을 WebDAV에 동기화",
"upload_history_to_webdav": "WebDAV의 기록 덮어쓰기",
"upload_history_to_webdav_desc": "여러 장치가 있는 경우 자동 동기화 기능에 유의하세요",
"sync_success": "동기화 성공",
"sync_failed": "동기화 실패"
}
},
"local_favorite": {
"title": "로컬 즐겨찾기",
"all_folders": "전체",
"new_folder": "새 폴더",
"select_mode": "선택",
"cancel_select_mode": "선택 취소",
"select_all": "전체 선택",
"delete_folder": "폴더 삭제",
"move_to_folder": "폴더로 이동",
"remove_selected": "선택 항목 제거",
"remove_selected_confirm": "선택한 만화를 로컬 즐겨찾기에서 제거할까요?",
"remove_selected_success": "제거됨",
"remove_selected_failed": "제거 실패",
"select_comics": "먼저 만화를 선택하세요",
"folder_limit_reached": "무료 버전은 폴더를 최대 3개까지 만들 수 있습니다. Pro로 업그레이드하면 무제한입니다",
"batch_download": "일괄 다운로드",
"select_folder": "폴더 선택",
"folder_name": "폴더 이름",
"delete_confirm": "폴더를 삭제하시겠습니까?",
"empty_folder": "아직 즐겨찾기가 없습니다",
"no_folders": "폴더가 없습니다. 먼저 폴더를 만들어주세요",
"remove_confirm_title": "즐겨찾기에서 제거",
"remove_confirm_content": "이 만화를 로컬 즐겨찾기에서 제거하시겠습니까?",
"remove_failed": "제거 실패",
"load_failed": "불러오기 실패",
"add_success": "로컬 즐겨찾기에 추가됨",
"add_failed": "추가 실패",
"create_folder_failed": "폴더 생성 실패",
"create_success": "생성됨",
"delete_success": "삭제됨",
"delete_failed": "삭제 실패",
"move_success": "이동됨",
"move_failed": "이동 실패",
"select_comics_to_download": "다운로드할 만화를 선택하세요",
"download_started": "다운로드 시작됨",
"download_failed": "다운로드 실패"
},
"screen": {
"about": {
"title": "정보",
"version": "소프트웨어 버전",
"check_update": "업데이트 확인",
"tips": "팁 : \n1. 상세 페이지의 작가/업로더/카테고리/태그는 클릭 가능합니다\n2. 상세 페이지의 작가/업로더/제목은 길게 눌러 복사할 수 있습니다\n3. 폭포수 흐름 대신 페이지네이션을 사용하면 빠르게 페이지를 넘길 수 있습니다\n4. 다운로드는 로컬에 캐시하는 것을 의미하며, 공유하려면 내보내야 합니다\n5. 다운로드는 길게 눌러 삭제할 수 있습니다",
"download_new_version": "채널에서 새 버전을 다운로드하십시오",
"no_new_version": "새 버전이 없습니다",
"download_release_version": "RELEASE 버전 다운로드",
"update_content": "업데이트 내용",
"go_to_release_repository": "RELEASE 저장소로 이동"
},
"account": {
"title": "계정",
"username": "사용자 이름",
"username_hint": "사용자 이름을 입력하세요",
"password": "비밀번호",
"password_hint": "비밀번호를 입력하세요",
"no_account_register": "계정이 없습니다, 등록하고 싶습니다",
"password_reset": "비밀번호 재설정",
"check_username_password_or_network": "사용자 이름과 비밀번호 또는 네트워크 환경을 확인하세요",
"check_device_time": "장치 시간을 확인하세요",
"username_or_password_error": "사용자 이름 또는 비밀번호 오류",
"login_failed": "로그인 실패",
"not_set": "설정되지 않음"
},
"app": {
"will_pop_notice": "뒤로 키를 연속으로 두 번 눌러 앱을 종료합니다"
},
"categories": {
"search_hint": "검색"
},
"clean": {
"title": "정리",
"cleaning": "정리 중",
"clean_network_cache": "네트워크 캐시 정리",
"clean_image_cache": "이미지 캐시 정리",
"clean_all_cache": "모든 캐시 정리",
"clean_success": "정리 성공",
"clean_failed": "정리 실패"
},
"close_app": {
"title": "팁",
"close_app": "앱을 닫고 다시 열어주세요"
},
"comic_collections": {
"no_resource": "여기에 리소스가 없습니다"
},
"comic_info": {
"chapter": "챕터",
"comment": "댓글",
"recommend": "추천"
},
"comics": {
"search_hint": "카테고리 검색",
"choose_category": "카테고리를 선택하세요"
},
"comic_subscribes": {
"update_reminder": "업데이트 알림",
"check_update": "업데이트 확인",
"cancel_all_update_reminder": "모든 업데이트 알림 취소"
},
"comment": {
"title": "댓글",
"hint_text": "댓글 내용을 입력하세요",
"success": "댓글 성공",
"i_have_something_to_say": "할 말이 있습니다",
"please_enter_comment": "댓글 내용을 입력하세요"
},
"desktop_authentication": {
"current_password": "현재 비밀번호",
"password_error": "비밀번호 오류",
"password_initialization": "비밀번호 초기화",
"password": "비밀번호",
"re_enter_password": "비밀번호 다시 입력",
"password_mismatch": "입력한 두 비밀번호가 다릅니다",
"set_password": "비밀번호 설정"
},
"download_confirm": {
"please_select_ep": "다운로드할 EP를 선택하세요",
"already_added_to_download_list": "이미 다운로드 목록에 추가되었습니다"
},
"download_export_group": {
"title": "일괄 내보내기",
"please_select_content": "내보낼 콘텐츠를 선택하세요",
"exporting": "내보내는 중",
"export_failed": "내보내기 실패",
"export_success": "내보내기 성공",
"export_to_pkz": "PKZ로 내보내기\n(암호화 모드, 웹 감지 방지, pikapika로 열 수 있음)",
"export_to_pki": "PKI로 내보내기\n(암호화 모드, 웹 감지 방지, pikapika로 가져올 수 있음)",
"export_to_zip": "ZIP으로 내보내기\n(암호화되지 않은 모드, pikapika로 가져오거나 볼 수 있음)",
"export_to_jpeg_zip": "ZIP+JPEG로 내보내기\n(다른 리더에서 직접 사용할 수 있으며, 다시 가져올 수 없음)",
"export_to_jpeg_folder": "폴더+JPEG로 내보내기",
"export_to_pdf": "PDF로 내보내기",
"export_to_epub": "EPUB로 내보내기",
"export_to_pdf_folder": "폴더로 내보내기, 각 챕터마다 PDF 하나씩",
"export_to_cbz": "cbz로 내보내기",
"after_power_use": "전원 사용 후",
"input_save_name": "저장할 이름을 입력하세요",
"export_confirm": "내보내기 확인",
"export_to_pkz_title": "선택한 만화를 PKZ로 내보내기",
"export_to_pki_title": "선택한 만화를 별도의 PKI로 내보내기",
"please_power_up": "먼저 전원을 켜주세요",
"export_to_zip_title": "선택한 만화를 ZIP으로 내보내기",
"export_to_jpeg_zip_title": "선택한 만화를 ZIP+JPEG로 내보내기",
"export_to_jpeg_zip_title_not_down_over": "선택한 만화를 ZIP+JPEG로 내보내기\n(다운로드가 성공하지 않아도 사용할 수 있음)",
"export_to_jpeg_folder_title": "선택한 만화를 폴더+JPEG로 내보내기",
"export_to_pdf_title": "선택한 만화를 PDF로 내보내기",
"export_to_epub_title": "선택한 만화를 EPUB로 내보내기",
"export_to_pdf_folder_title": "선택한 만화를 폴더로 내보내기, 각 챕터마다 PDF 하나씩",
"export_to_cbz_title": "선택한 만화를 cbz로 내보내기",
"exporting_please_wait": "내보내는 중, 잠시만 기다려주세요"
},
"download_export_to_file": {
"title": "내보내기",
"transfer_to_other_device": "다른 장치로 전송",
"input_save_name": "저장할 이름을 입력하세요",
"export_confirm": "내보내기 확인",
"export_to_pkz_title": "선택한 만화를 PKZ로 내보내기",
"export_to_pkz_desc": "xxx.pkz로 내보내기\n(암호화 모드, 웹 감지 방지, pikapika로 열 수 있음)",
"export_to_pki_title": "선택한 만화를 별도의 PKI로 내보내기",
"export_to_pki_desc": "xxx.pki로 내보내기\n(암호화 모드, 웹 감지 방지, pikapika로 가져올 수 있음)",
"export_to_zip_title": "선택한 만화를 ZIP으로 내보내기",
"export_to_zip_desc": "xxx.zip으로 내보내기\n(암호화되지 않은 모드, pikapika로 가져오거나 볼 수 있음)",
"export_to_jpeg_zip_title": "선택한 만화를 ZIP+JPEG로 내보내기",
"export_to_jpeg_zip_desc": "xxx.jpeg로 내보내기\n(다른 리더에서 직접 사용할 수 있으며, 다시 가져올 수 없음)",
"export_to_pdf_title": "선택한 만화를 PDF로 내보내기",
"export_to_pdf_desc": "xxx.pdf로 내보내기\n(다운로드가 성공하지 않아도 사용할 수 있으며, 실패한 이미지는 건너뜁니다)\n(사진 앨범에서 직접 열 수 있음)",
"export_to_pdf_folder_title": "선택한 만화를 폴더로 내보내기, 각 챕터마다 PDF 하나씩",
"export_to_pdf_folder_desc": "xxx.pdf로 내보내기\n(다운로드가 성공하지 않아도 사용할 수 있으며, 실패한 이미지는 건너뜁니다)\n(사진 앨범에서 직접 열 수 있음)",
"export_to_epub_title": "선택한 만화를 EPUB로 내보내기",
"export_to_epub_desc": "xxx.epub로 내보내기\n(리더에서 직접 열 수 있음)",
"export_to_jpeg_folder_title": "선택한 만화를 JPEGS.zip으로 내보내기",
"export_to_jpeg_folder_desc": "JPGS.zip으로 내보내기\n(다시 가져올 수 없음)",
"export_to_cbz_title": "선택한 만화를 cbk.zip으로 내보내기",
"export_to_cbz_desc": "xxx.cbz로 내보내기, 리더에서 직접 사용할 수 있음 (다시 가져올 수 없음)"
},
"download_export_to_socket": {
"title": "네트워크 내보내기",
"loading": "로딩 중",
"tips": "전송이 성공하기 전에 페이지를 나가지 마십시오. 한 번에 하나의 장치만 내보낼 수 있으며, 두 장치는 동일한 네트워크 세그먼트 또는 무한 LAN에 있어야 합니다. 다른 장치에서 IP:port를 입력하십시오. IP가 하나만 있는 경우 무한 LAN의 IP를 선택하십시오. 일반적으로 192.168로 시작합니다",
"get_ip_failed": "IP 가져오기 실패",
"getting_ip": "IP 가져오는 중",
"port": "포트"
},
"download_import": {
"title": "가져오기",
"open_file": "파일 열기",
"select_file": "가져올 파일 선택",
"import_success": "가져오기 성공",
"import_failed": "가져오기 실패",
"select_file_desc": "가져올 zip 파일 선택\n가져올 pki 파일 선택\n읽을 pkz 파일 선택",
"input_address": "내보내기 장치에서 제공한 주소를 입력하세요\n예: \"192.168.1.2:50000\"",
"import_from_other_device": "다른 장치에서 가져오기",
"select_folder_desc": "폴더 선택\n(폴더의 모든 zip/pki 가져오기)\n(전원 사용 후)"
},
"download_info": {
"loading": "로딩 중",
"chapter": "챕터",
"comment": "댓글",
"recommend": "추천"
},
"download_list": {
"search_download": "다운로드 검색",
"multi_select_operation": "다중 선택 작업",
"download_list": "다운로드 목록",
"search": "검색",
"select_folder": "폴더 선택",
"download_already_in_delete_queue": "다운로드가 이미 삭제 대기열에 있습니다",
"import": "가져오기",
"export": "내보내기",
"file": "파일",
"download_task": "다운로드 작업",
"pause_download": "다운로드를 일시 중지하시겠습니까?",
"start_download": "다운로드를 시작하시겠습니까?",
"resume_failed": "실패한 작업 다시 시작",
"resume_failed_desc": "모든 실패한 다운로드가 다시 시작되었습니다",
"downloading": "다운로드 중",
"paused": "일시 중지됨",
"move_download": "다운로드 이동",
"select_download_to_move": "이동할 다운로드를 선택하세요",
"select_download_to_delete": "삭제할 다운로드를 선택하세요",
"input_name": "==> 이름 입력 <==",
"empty_folder_will_be_deleted": "(빈 폴더는 자동으로 삭제되며, 다음에 수동으로 입력해야 합니다)",
"folder_name": "폴더 이름",
"please_input_folder_name": "폴더 이름을 입력하세요",
"delete_download": "다운로드 삭제",
"delete_selected_download": "선택한 다운로드를 삭제하시겠습니까?",
"multi_select": "다중 선택"
},
"download_only_import": {
"importing": "가져오는 중",
"import_success": "가져오기 성공",
"import_failed": "가져오기 실패",
"click_import_file": "가져올 파일 클릭",
"importing_please_wait": "가져오는 중, 잠시만 기다려주세요"
},
"favourite_paper": {
"favourite": "즐겨찾기"
},
"forgot_password": {
"title": "비밀번호 복구",
"username": "사용자 이름",
"not_set": "설정되지 않음",
"confirm": "확인",
"please_enter_username": "사용자 이름을 입력하세요",
"question_1": "질문 1",
"question_2": "질문 2",
"question_3": "질문 3",
"answer_1": "답변 1",
"answer_2": "답변 2",
"answer_3": "답변 3",
"please_enter_answer_1": "답변 1을 입력하세요",
"please_enter_answer_2": "답변 2를 입력하세요",
"please_enter_answer_3": "답변 3을 입력하세요",
"use_answer_1_recover": "답변 1을 사용하여 비밀번호 복구",
"use_answer_2_recover": "답변 2를 사용하여 비밀번호 복구",
"use_answer_3_recover": "답변 3을 사용하여 비밀번호 복구",
"please_enter_answer": "답변을 입력하세요",
"new_password_copied": "새 비밀번호가 클립보드에 복사되었습니다",
"answer_incorrect": "답변이 올바르지 않습니다",
"password": "비밀번호"
},
"game_download": {
"title": "다운로드",
"download_links_obtained": "다운로드 링크를 얻었습니다. 그 중 하나를 선택하면 됩니다"
},
"game_info": {
"download": "다운로드",
"details": "상세 정보",
"comments": "댓글"
},
"games": {
"title": "게임"
},
"import_from_off": {
"title": "가져오기",
"import_success": "가져오기 성공",
"import_failed": "가져오기 실패"
},
"modify_password": {
"title": "비밀번호 수정",
"please_wait": "잠시만 기다려주세요",
"old_password": "이전 비밀번호",
"new_password": "새 비밀번호",
"repeat_new_password": "새 비밀번호 반복",
"not_filled": "채워지지 않음",
"please_enter_old_password": "이전 비밀번호를 입력하세요",
"please_enter_new_password": "새 비밀번호를 입력하세요",
"please_repeat_new_password": "새 비밀번호를 다시 입력하세요",
"new_password_mismatch": "새 비밀번호가 일치하지 않습니다",
"modify_success": "수정 성공",
"failed": "실패",
"confirm": "확인"
},
"network_settings": {
"title": "네트워크 설정"
},
"pkz_reader": {
"reading_downloaded_comic": "다운로드한 만화를 읽고 있습니다"
},
"pro": {
"title": "파워 센터",
"power_center": "파워 센터",
"power_status": "파워 상태",
"powered": "전원 켜짐",
"not_powered": "전원 꺼짐",
"pat_membership": "PAT 멤버십",
"pat_status": "PAT 상태",
"pat_normal": "PAT 정상",
"pat_bind_hint": "전원을 위해 현재 계정에 바인딩하려면 여기를 클릭하세요",
"pat_rebind_hint": "전원을 위해 현재 계정에 다시 바인딩하려면 클릭하세요",
"pat_not_detected": "멤버십이 감지되지 않았습니다. 다운로드 페이지로 이동하여 가입하세요",
"i_have_powered": "이전에 전원을 켰습니다",
"i_just_powered": "방금 전원을 켰습니다",
"enter_code": "코드 입력",
"power_method": "전원 방식",
"wind_power": "풍력 발전",
"hydro_power": "수력 발전",
"solar_power": "태양광 발전",
"nuclear_power": "원자력 발전",
"choose_power_method": "전원 방식 선택",
"sign_in_exchange": "로그인/교환",
"click_pat_to_change": "변경하려면 아래의 PAT 멤버십을 클릭하세요",
"update_pat_status": "PAT 전원 상태 업데이트",
"bind_to_account": "이 계정에 바인딩",
"change_pat_key": "PAT 키 변경",
"clear_pat_info": "PAT 정보 지우기",
"click_to_bind": "바인딩하려면 클릭",
"enter_auth_code": "인증 코드를 입력하세요",
"please_wait": "잠시만 기다려주세요",
"key_recorded": "키: 기록됨",
"pat_account": "PAT 계정",
"bind_pika_account": "PIKA 계정 바인딩",
"bind_account_time": "계정 바인딩 시간",
"rebind_time": "재바인딩 가능 시간",
"power_features": "파워 기능: 다중 스레드 다운로드 / 일괄 가져오기/내보내기 다운로드",
"power_guide": "\"정보\" 페이지로 이동하여 파워 가이드를 위한 유지 관리 주소를 찾으십시오\n\n \"이전에 전원을 켰습니다\"는 해당 파워 상태를 동기화할 수 있습니다\n \"방금 전원을 켰습니다\"는 신비한 코드를 교환합니다\n \"전원 방식\"은 네트워크가 작동하지 않을 때 변경할 수 있습니다\n \"PAT 멤버십\"은 독립적인 전원 방식입니다"
},
"rankings": {
"title": "순위",
"day": "일",
"week": "주",
"month": "월",
"knight": "기사",
"refresh": "새로고침",
"comics_count": "만화"
},
"random_comics": {
"title": "랜덤 만화"
},
"register": {
"title": "등록",
"registering": "등록 중",
"register_success": "등록 성공",
"register_failed": "등록 실패",
"account_exists": "계정이 이미 존재합니다",
"name_exists": "이름이 이미 존재합니다",
"check_form": "양식을 확인하세요, 빈 필드는 허용되지 않습니다",
"account": "계정",
"password": "비밀번호",
"nickname": "닉네임",
"gender": "성별",
"birthday": "생일",
"question_1": "질문 1",
"answer_1": "답변 1",
"question_2": "질문 2",
"answer_2": "답변 2",
"question_3": "질문 3",
"answer_3": "답변 3",
"not_set": "설정되지 않음",
"please_enter_account": "계정을 입력하세요",
"please_enter_password": "비밀번호를 입력하세요",
"please_enter_nickname": "닉네임을 입력하세요",
"please_enter_question_1": "질문 1을 입력하세요",
"please_enter_answer_1": "답변 1을 입력하세요",
"please_enter_question_2": "질문 2를 입력하세요",
"please_enter_answer_2": "답변 2를 입력하세요",
"please_enter_question_3": "질문 3을 입력하세요",
"please_enter_answer_3": "답변 3을 입력하세요",
"account_desc": "(소문자 + 숫자 / 로그인용)",
"password_desc": "(대소문자 + 숫자 / 8자 이상)",
"nickname_desc": "(한글 허용 / 2-50자)",
"choose_gender": "성별을 선택하세요",
"futa": "후타",
"male": "남성",
"female": "여성",
"register_success_desc": "성공적으로 등록되었습니다. 로그인으로 돌아가세요",
"account_label": "계정",
"nickname_label": "닉네임"
},
"search": {
"title": "검색",
"search_hint": "검색",
"choose_category": "카테고리를 선택하세요"
},
"search_author": {
"title": "작가별 검색",
"search_hint": "작가별 검색 + ",
"by_author": "작가별: "
},
"space": {
"title": "내 정보",
"logout": "로그아웃",
"logout_confirm": "현재 계정에서 로그아웃하시겠습니까?",
"my_favourites": "내 즐겨찾기",
"view_history": "조회 기록",
"my_downloads": "내 다운로드"
},
"theme": {
"title": "테마 설정",
"theme": "테마",
"dark_mode_different_theme": "다크 모드에서 다른 테마 사용",
"dark_mode_theme": "테마 (다크 모드)"
},
"view_logs": {
"title": "조회 기록",
"clear_all": "모든 조회 기록을 지우시겠습니까?",
"clear_all_desc": "읽기 진행 상황도 삭제됩니다!",
"clear_one": "이 조회 기록을 지우시겠습니까?",
"clear_one_desc": "읽기 진행 상황도 삭제됩니다!",
"clear_selected": "선택한 조회 기록을 지우시겠습니까?",
"clear_selected_desc": "읽기 진행 상황도 삭제됩니다!",
"categories": "카테고리"
},
"web_server": {
"title": "다운로드 - 웹 서버",
"loading": "로딩 중",
"get_ip_failed": "IP 가져오기 실패",
"getting_ip": "IP 가져오는 중",
"port": "포트: 8080",
"usage_instruction": "브라우저에 \"http://device_ip:8080/\"를 입력하여 다운로드한 만화에 액세스",
"leave_notice": "이 페이지를 나가면 서버가 닫힙니다"
}
},
"components": {
"comic_info_card": {
"categories": "카테고리",
"finished": "완결",
"viewed": "조회함"
},
"comic_list": {
"shadow": "그림자 만화"
},
"common": {
"display_mode": "표시 모드",
"shadow_mode": "그림자 모드",
"shadow_list": "그림자 목록",
"batch_download": "일괄 다운로드"
},
"image_reader": {
"already_at_the_end": "이미 끝에 도달했습니다",
"click_to_next_chapter": "다음 챕터로 이동하려면 클릭",
"reload_page": "페이지 새로고침",
"next_chapter": "다음 챕터",
"end_reading": "읽기 종료",
"reload_image": "이미지 새로고침",
"save_image_in_this_page": "이 페이지의 이미지 저장",
"image_load_failed": "이미지 로드 실패"
}
}
}
================================================
FILE: lib/assets/translations/zh-CN.json
================================================
{
"language": {
"title": "语言",
"name": "简体中文 - 中国大陆"
},
"app": {
"categories": "分类",
"my": "我的",
"copied_to_clipboard": "已复制到剪切板",
"not_supported_platform": "暂不支持该平台",
"cancel": "取消",
"confirm": "确定",
"save_cancel": "保存取消",
"save_success": "保存成功",
"save_failed": "保存失败",
"pro": "发电",
"pro_required": "请先发电再使用",
"choose_folder": "选择一个文件夹, 将文件保存到这里",
"permission_denied": "申请权限被拒绝",
"loading": "加载中",
"error": "错误",
"pat": {
"success": "您的赞助登录成功, 请返回",
"title": "更换PAT账户"
},
"previous_page": "上一页",
"next_page": "下一页",
"page": "页",
"please_enter_page_number": "请输入页数:",
"select_all": "全选",
"load_failed": "加载失败",
"all": "全部",
"delete": "删除",
"save_image": "保存图片",
"preview_image": "预览图片",
"please_select": "请选择",
"refresh": "刷新",
"initializing": "初始化",
"like_failed": "点赞失败",
"network_error": "连接不上啦, 请检查网络",
"no_permission": "没有权限或路径不可用",
"check_device_time": "请检查设备时间",
"resource_not_available": "资源未审核或不可用",
"something_went_wrong": "啊哦, 被玩坏了",
"click_refresh": "点击刷新",
"pull_down_refresh": "下拉刷新",
"continue_reading": "继续阅读",
"start_reading": "开始阅读",
"image_crop": "图片裁剪",
"download": "下载",
"download_failed": "下载失败",
"download_finished": "下载完成",
"downloading": "下载中",
"queue": "队列中",
"deleting": "删除中",
"please_select_comic": "请选择漫画",
"please_choose": "请选择",
"last_viewed": "上次观看到",
"auto_punch": "自动打卡",
"yes": "是",
"no": "否",
"confirm_download": "确认下载",
"copy": "复制"
},
"net": {
"no_address": "不分流",
"address": "分流",
"address_sync": "分流同步",
"address_sync_from_server": "从服务器获取最新的分流地址",
"address_sync_reset": "重制分流为默认值",
"address_sync_success": "分流同步成功",
"address_sync_failed": "分流同步失败",
"address_sync_reset_success": "分流重制成功",
"address_sync_reset_failed": "分流重制失败",
"choose_address": "选择分流",
"image_address": "图片分流",
"use_api_load_image": "用API加载图片",
"ping_testing": "测速中",
"ping_failed": "失败"
},
"categories": {
"all": "全分类",
"recommend": "推荐",
"rankings": "排行榜",
"random": "随机本子",
"game": "游戏专区"
},
"settings": {
"settings": "设置",
"interface": "界面",
"network": "网络",
"seal": "封印",
"interaction": "交互",
"reading": "阅读",
"download": "下载",
"auto_download_on_favorite": "收藏时自动下载",
"disable_auto_download_on_mobile": "移动网络下收藏时不自动下载",
"auto_delete_download_on_unfavorite": "取消收藏时自动删除下载",
"web_server": "启动Web服务器",
"web_server_subtitle": "让局域网内的设备通过浏览器看下载的漫画",
"sync": "同步",
"history_sync": "历史记录同步",
"local_favorite_sync_title": "本地收藏夹同步",
"use_local_favorite": "使用本地收藏夹",
"use_local_favorite_desc": "在本地管理收藏,支持文件夹分类",
"account": "账户",
"modify_password": "修改密码",
"ebook": "电纸书",
"system": "系统",
"clear_cache": "清除缓存",
"migrate": "文件迁移",
"migrate_subtitle": "更换您的数据文件夹到内存卡",
"migrate_confirm": "此功能菜单保存后, 需要重启程序, 您确认吗",
"app_orientation": {
"title": "APP方向",
"choose": "请选择APP方向",
"normal": "正常",
"landscape": "横屏",
"portrait": "竖屏"
},
"will_pop_notice": "在首页连续按两下返回键才能退出APP",
"android_secure_flag": "禁止截图/禁止显示在任务视图",
"android_display_mode": {
"title": "屏幕刷新率(安卓)",
"dialog_title": "安卓屏幕刷新率 \n(省电模式下不会高刷)"
},
"authentication": "进入APP时验证身份(如果系统已经录入密码或指纹)",
"set_password": "设置应用程序密码",
"auto_clean": {
"title": "自动清理缓存",
"one_month_ago": "一个月前",
"one_week_ago": "一周前",
"one_day_ago": "一天前",
"no_auto_clean": "不自动清理"
},
"categories_column_count": {
"title": "首页分类展示列数",
"choose": "选择首页分类展示列数",
"auto": "自动"
},
"categories_sort": {
"title": "首页分类排序"
},
"chooser_root": {
"title": "文件夹选择器根路径",
"hint": "请输入文件夹选择器根路径",
"desc": "导出时选择目录的默认路径, 同时也是根路径, 不能正常导出时也可以尝试设置此选项。"
},
"content_failed_reload_action": {
"title": "页面加载失败刷新方式",
"choose": "选择页面加载失败刷新方式",
"pull_down": "下拉刷新",
"touch_loader": "点击屏幕刷新"
},
"copy_full_name": {
"title": "复制漫画名称时使用模版"
},
"copy_full_name_template": {
"title": "复制漫画名称模版",
"hint": "模版内容"
},
"copy_skip_confirm": {
"title": "长按复制不需要确认"
},
"download_and_export_path": {
"title": "下载的同时导出到文件系统",
"confirm": "下载的同时导出到文件系统",
"desc": "您即将选择一个目录, 如果文件系统可写, 下载的同时会为您自动导出一份"
},
"download_cache_path": {
"title": "使用其他程序的缓存下载加速",
"confirm": "使用其他程序的缓存下载加速",
"desc": "您即将选择一个目录, 这个目录拷贝自以下目录才能使用。下载时将会作为缓存文件夹优先读取。 ",
"cancel_desc": "您确定取消使用其他软件的下载内容加速的功能吗? 取消之后您可以再次点击设置",
"import_view_log_from_off": {
"title": "导入其他程序的历史记录",
"desc": "您即将选择一个文件, 这个文件拷贝自以下路径才能使用。",
"choose_file_dialog_title": "选择要导入的文件"
}
},
"download_thread_count": {
"title": "下载线程数",
"choose": "选择下载线程数"
},
"ebook_scrolling": {
"title": "电子书模式滚动UI"
},
"ebook_scrolling_range": {
"title": "电子书模式滚动UI",
"desc": "滚动幅度",
"screen_height": "屏幕高度"
},
"ebook_scrolling_trigger": {
"title": "电子书模式滚动UI",
"desc": "触发距离",
"cm": "厘米"
},
"export_path": {
"ios_desc": "随后可在文件管理中找到导出的内容",
"ios_desc2": "您正在使用iOS设备:\n导出到文件的内容请打开系统自带文件管理进行浏览",
"export_path_desc": "导出路径 (点击可修改)",
"android_desc": "您正在使用安卓设备:\n如果不能成功导出并且提示权限不足, 可以尝试在Download或Document下建立子目录进行导出"
},
"export_rename": {
"title": "导出时进行重命名"
},
"yes": "是",
"no": "否",
"full_screen_action": {
"title": "操控方式",
"choose": "选择操控方式",
"touch_once": "点击屏幕一次全屏",
"controller": "使用控制器全屏",
"touch_double": "双击屏幕全屏",
"touch_double_once_next": "双击屏幕全屏 + 单击屏幕下一页",
"three_area": "将屏幕划分成三个区域 (上一页, 下一页, 全屏)"
},
"full_screen_ui": {
"title": "全屏UI",
"choose": "选择全屏UI",
"no": "不使用",
"hidden_bottom": "去除虚拟控制器",
"all": "全屏"
},
"auto_full_screen": {
"title": "进入阅读器自动全屏"
},
"auto_full_screen_on_forward": {
"title": "前进时自动全屏"
},
"ignore_info_history": {
"title": "详情页不计入历史记录"
},
"icon_loading": {
"title": "尽量减少UI动画"
},
"ignore_upgrade_confirm": {
"title": "关闭升级弹窗"
},
"hidden_fd_icon": {
"title": "隐藏个人空间的发电图标"
},
"hidden_search_persion": {
"title": "隐藏按作者搜索功能"
},
"hidden_viewed": {
"title": "隐藏阅读过的漫画"
},
"hidden_sub_icon": {
"title": "隐藏订阅功能"
},
"hide_online_favorite": {
"title": "隐藏在线收藏",
"desc": "隐藏在线收藏入口与收藏按钮"
},
"hidden_words": {
"title": "根据关键词隐藏",
"clear_all": "确认清空",
"clear_all_desc": "确定要清空所有关键词吗?",
"input_hint": "输入要隐藏的关键词",
"no_words": "暂无关键词"
},
"image_address": {
"title": "图片分流",
"pinging": "测速中",
"failed": "失败"
},
"image_filter": {
"title": "阅读器图片滤镜",
"normal": "正常",
"gray": "灰度",
"brown": "棕褐色",
"choose": "选择阅读器图片滤镜"
},
"import_notice": {
"android_desc": "您正在使用安卓设备:\n如果不能导入导出并且提示权限不足, 可以尝试在Download或Document下建立子目录进行导入"
},
"keyboard_controller": {
"title": "阅读器键盘翻页(仅PC)"
},
"list_layout": {
"choose": "请选择布局",
"info_card": "详情",
"only_image": "封面",
"cover_and_title": "封面+标题"
},
"local_history_sync": {
"sync_to_local": "同步历史记录到本地",
"not_set": "未设置",
"sync_success": "同步成功",
"sync_failed": "同步失败",
"auto_sync": "自动同步历史记录到本地",
"auto_sync_desc": "开启后每次打开应用会自动备份历史记录",
"choose_dir": "选择目录",
"clear_path": "清除路径",
"clear_path_desc": "确定要清除路径吗?"
},
"local_favorite_sync": {
"auto_sync": "自动同步本地收藏夹",
"auto_sync_desc": "使用WebDAV自动同步本地收藏夹",
"manual_sync": "手动同步本地收藏夹",
"sync_success": "同步成功",
"sync_failed": "同步失败"
},
"no_animation": {
"title": "取消翻页动画(点按屏幕、音量键、键盘)"
},
"pager_action": {
"title": "列表页加载方式",
"choose": "选择列表页加载方式",
"controller": "使用按钮",
"stream": "瀑布流"
},
"proxy": {
"title": "代理服务器",
"hint": "请输入代理服务器",
"desc": " ( 例如 socks5://127.0.0.1:1080/ ) ",
"no_proxy": "未设置"
},
"quality": {
"title": "浏览时的图片质量",
"choose": "请选择图片质量",
"original": "原图",
"low": "低",
"medium": "中",
"high": "高"
},
"reader_background_color": {
"title": "阅读器背景色",
"choose": "选择阅读器背景色",
"black": "黑色",
"gray": "灰度",
"white": "白色"
},
"reader_direction": {
"title": "阅读器方向",
"choose": "选择翻页方向",
"top_to_bottom": "从上到下",
"left_to_right": "从左到右",
"right_to_left": "从右到左"
},
"reader_scroll_by_screen_percentage": {
"title": "按距离翻页长度",
"screen_size": "屏幕尺寸"
},
"web_toon_scroll_mode": {
"title": "WebToon 翻页模式",
"choose": "选择 WebToon 翻页模式",
"image": "图片",
"screen": "距离"
},
"reader_zoom": {
"out_title": "缩小倍数(最小缩放)",
"in_title": "放大倍数(最大缩放)",
"double_tap_title": "双击缩放倍数"
},
"drag_region_lock": {
"title": "锁定拖动边界"
},
"gesture_speed": {
"title": "手势速度倍率"
},
"reader_slider_position": {
"title": "滚动条的位置",
"choose": "选择滑动条位置",
"bottom": "下方",
"right": "右侧",
"left": "左侧"
},
"reader_two_page_direction": {
"title": "双页阅读器内容排列",
"choose": "选择双页阅读器内容排列",
"close_to": "靠近",
"pull_away": "远离",
"each_centered": "各自居中"
},
"reader_type": {
"title": "阅读器模式",
"choose": "选择阅读器模式",
"web_toon": "WebToon (默认)",
"web_toon_zoom": "WebToon (双击放大)",
"gallery": "相册",
"web_toon_free_zoom": "WebToon (ListView双击放大)\n(此模式进度条无效)",
"two_page_gallery": "双页模式\n(实验)",
"left_to_right": "从左到右",
"right_to_left": "从右到左",
"two_page_direction": "双页方向",
"two_page_direction_choose": "选择双页方向"
},
"shadow_categories": {
"title": "封印",
"search_hint": "搜索"
},
"shadow_categories_mode": {
"title": "封印模式",
"black_list": "黑名单",
"white_list": "白名单"
},
"startup_pic": {
"title": "设置启动图片",
"subtitle": "设置应用启动时显示的图片",
"clear_title": "清除启动图片",
"clear_subtitle": "清除应用启动时显示的图片",
"clear_success": "启动图片已清除",
"update_success": "启动图片已更新"
},
"show_comment_at_download": {
"title": "在下载显示评论区"
},
"font": {
"title": "字体",
"hint": "请输入字体",
"input_hint": "请输入字体的名称且用英文逗号分隔, 例如 \"宋体,黑体\", 如果您保存后没有发生变化, 说明字体无法使用或名称错误, 可以去参考C:\\Windows\\Fonts寻找您的字体。若您使用的是flutter2引擎的版本,只有第一个字体生效。",
"choose_hint": "需要您选择多个字体,直至您点击背景区域"
},
"theme": {
"origin": "原生",
"pink": "粉色",
"black": "酷黑",
"dark": "暗黑",
"dusty_blue": "灰蓝",
"dark_black": "纯黑",
"choose_theme": "选择主题",
"book": "书本",
"enable_status_bar_color": "启用状态栏颜色",
"enable_status_restart_hint": "关闭时需要重新启动应用程序刷新状态栏颜色"
},
"three_keep_right": {
"title": "三区域模式翻页始终为右侧下一页"
},
"time_zone": {
"title": "时区"
},
"timeout_lock": {
"title": "自动锁定",
"notice": "注意:自动锁定在桌面端仅支持最小化后超时,手机端支持后台以及锁屏后超时。如果没有设置密码,自动锁定无效。安卓以及桌面端只会锁定桌面,不会锁定下载,iOS未测试,需要手动开启后台活动。",
"1_hour": "一小时",
"10_minutes": "十分钟",
"3_minutes": "三分钟",
"1_minute": "一分钟",
"10_seconds": "十秒",
"1_second": "一秒",
"no_lock": "不锁定"
},
"using_right_click_pop": {
"title": "鼠标右键返回上一页"
},
"volume_controller": {
"title": "阅读器音量键翻页"
},
"volume_next_chapter": {
"title": "双击 音量/键盘/控制器 下一章节"
},
"webdav": {
"title": "WebDav",
"not_set": "未设置",
"path": "WebDav 路径",
"path_hint": "请输入WebDav 路径",
"username": "WebDav 用户名",
"username_hint": "请输入WebDav 用户名",
"password": "WebDav 密码",
"password_hint": "请输入WebDav 密码",
"auto_sync_history_to_webdav": "开启时自动同步浏览记录到WebDav",
"sync_history_to_webdav": "立即同步浏览记录到WebDAV",
"upload_history_to_webdav": "覆盖WebDAV中的浏览记录",
"upload_history_to_webdav_desc": "如有多台设备,请注意自动同步功能",
"sync_success": "同步成功",
"sync_failed": "同步失败"
}
},
"local_favorite": {
"title": "本地收藏夹",
"all_folders": "全部",
"new_folder": "新建文件夹",
"select_mode": "多选",
"cancel_select_mode": "退出多选",
"select_all": "全选",
"delete_folder": "删除文件夹",
"move_to_folder": "移动到文件夹",
"remove_selected": "移除选中收藏",
"remove_selected_confirm": "确认从本地收藏夹中移除选中的漫画?",
"remove_selected_success": "已移除",
"remove_selected_failed": "移除失败",
"select_comics": "请先选择漫画",
"folder_limit_reached": "免费版最多创建3个文件夹,升级Pro解锁无限制",
"batch_download": "批量下载",
"select_folder": "选择文件夹",
"folder_name": "文件夹名称",
"delete_confirm": "确认删除文件夹?",
"empty_folder": "暂无收藏",
"no_folders": "还没有文件夹,请先创建",
"remove_confirm_title": "取消收藏",
"remove_confirm_content": "确定要从本地收藏夹中移除这部漫画吗?",
"remove_failed": "取消收藏失败",
"load_failed": "加载失败",
"add_success": "已添加到本地收藏夹",
"add_failed": "添加失败",
"create_folder_failed": "创建文件夹失败",
"create_success": "创建成功",
"delete_success": "删除成功",
"delete_failed": "删除失败",
"move_success": "移动成功",
"move_failed": "移动失败",
"select_comics_to_download": "请选择要下载的漫画",
"download_started": "开始下载",
"download_failed": "下载失败"
},
"screen": {
"about": {
"title": "关于",
"version": "软件版本",
"check_update": "检查更新",
"tips": "提示 : \n1. 详情页的作者/上传者/分类/标签都可以点击\n2. 详情页的作者/上传者/标题长按可以复制\n3. 使用分页而不是瀑布流点击页码可以快速翻页\n4. 下载指的是缓存到本地, 需要导出才可以分享\n5. 下载长按可以删除",
"download_new_version": "请从获取渠道下载新版",
"no_new_version": "未检测到新版本",
"download_release_version": "下载RELEASE版",
"update_content": "更新内容",
"go_to_release_repository": "去RELEASE仓库"
},
"account": {
"title": "账户",
"username": "账号",
"username_hint": "请输入账号",
"password": "密码",
"password_hint": "请输入密码",
"no_account_register": "没有账号,我要注册",
"password_reset": "密码找回",
"check_username_password_or_network": "请检查账号密码或网络环境",
"check_device_time": "请检查设备时间",
"username_or_password_error": "账号或密码错误",
"login_failed": "登录失败",
"not_set": "未设置"
},
"app": {
"will_pop_notice": "再次返回将会退出应用程序"
},
"categories": {
"search_hint": "搜索"
},
"clean": {
"title": "清理",
"cleaning": "清理中",
"clean_network_cache": "清理网络缓存",
"clean_image_cache": "清理图片缓存",
"clean_all_cache": "清理全部缓存",
"clean_success": "清理成功",
"clean_failed": "清理失败"
},
"close_app": {
"title": "提示",
"close_app": "请关闭应用重新打开"
},
"comic_collections": {
"no_resource": "这里没有资源呀"
},
"comic_info": {
"chapter": "章节",
"comment": "评论",
"recommend": "推荐"
},
"comics": {
"search_hint": "搜索分类",
"choose_category": "请选择分类"
},
"comic_subscribes": {
"update_reminder": "更新提醒",
"check_update": "检查更新",
"cancel_all_update_reminder": "取消所有更新提醒"
},
"comment": {
"title": "评论",
"hint_text": "请输入评论内容",
"success": "评论成功",
"i_have_something_to_say": "我有话要讲",
"please_enter_comment": "请输入评论内容"
},
"desktop_authentication": {
"current_password": "当前密码",
"password_error": "密码错误",
"password_initialization": "密码初始化",
"password": "密码",
"re_enter_password": "再次输入密码",
"password_mismatch": "两次输入的密码不一致",
"set_password": "设置密码"
},
"download_confirm": {
"please_select_ep": "请选择下载的EP",
"already_added_to_download_list": "已经加入下载列表"
},
"download_export_group": {
"title": "批量导出",
"please_select_content": "请选择导出的内容",
"exporting": "正在导出",
"export_failed": "导出失败",
"export_success": "导出成功",
"export_to_pkz": "导出成一个PKZ\n(加密模式,防止网盘检测,能用pikapika打开观看)",
"export_to_pki": "每部漫画都打包一个PKI\n(加密模式,防止网盘检测,能用pikapika导入)",
"export_to_zip": "每部漫画都打包一个ZIP\n(不加密模式,能用pikapika导入或网页浏览器观看)",
"export_to_jpeg_zip": "每部漫画都打包一个ZIP+JPEG\n(能直接使用其他阅读器看,不可再导入)",
"export_to_jpeg_folder": "每部漫画都导出成文件夹+JPEG",
"export_to_pdf": "每部漫画都导出成PDF",
"export_to_epub": "每部漫画都导出成EPUB",
"export_to_pdf_folder": "每部漫画都导出到文件夹, 每个章节一个PDF",
"export_to_cbz": "每部漫画都导出成cbz",
"after_power_use": "发电后使用",
"input_save_name": "请输入保存后的名称",
"export_confirm": "导出确认",
"export_to_pkz_title": "将导出您所选的漫画为一个PKZ",
"export_to_pki_title": "将您所选的漫画分别导出成单独的PKI",
"please_power_up": "请先发电鸭",
"export_to_zip_title": "将您所选的漫画分别导出成ZIP",
"export_to_jpeg_zip_title": "将您所选的漫画分别导出成ZIP+JPEG",
"export_to_jpeg_zip_title_not_down_over": "将您所选的漫画分别导出成ZIP+JPEG\n(即便没有下载完成也可以使用)",
"export_to_jpeg_folder_title": "将您所选的漫画分别导出成文件夹+JPEG",
"export_to_pdf_title": "将您所选的漫画分别导出成PDF",
"export_to_epub_title": "将您所选的漫画分别导出成EPUB",
"export_to_pdf_folder_title": "将您所选的漫画分别导出到文件夹, 每个章节一个PDF",
"export_to_cbz_title": "将您所选的漫画分别导出成cbz",
"exporting_please_wait": "导出中, 请稍后"
},
"download_export_to_file": {
"title": "导出",
"transfer_to_other_device": "传输到其他设备",
"input_save_name": "请输入保存后的名称",
"export_confirm": "导出确认",
"export_to_pkz_title": "将您所选的漫画导出PKZ",
"export_to_pkz_desc": "导出到xxx.pkz\n(可直接打开观看的格式,不支持导入)\n(可以躲避网盘或者聊天软件的扫描)",
"export_to_pki_title": "将您所选的漫画导出PKI",
"export_to_pki_desc": "导出到xxx.pki\n(只支持导入, 不支持直接阅读)\n(可以躲避网盘或者聊天软件的扫描)\n(后期版本可能支持直接阅读)",
"export_to_zip_title": "将您所选的漫画导出HTML+ZIP",
"export_to_zip_desc": "导出到xxx.zip\n(可从其他设备导入 / 解压后可阅读)",
"export_to_jpeg_zip_title": "将您所选的漫画导出HTML+JPEG",
"export_to_jpeg_zip_desc": "导出到xxx.jpeg\n(可直接在相册中打开观看)",
"export_to_pdf_title": "将您所选的漫画导出PDF",
"export_to_pdf_desc": "导出到xxx.pdf\n(即使没有下载成功也可以使用、未成功下载的图片将会跳过)\n(可直接在相册中打开观看)",
"export_to_pdf_folder_title": "将您所选的漫画导出到文件夹, 每个章节一个PDF",
"export_to_pdf_folder_desc": "导出到xxx.pdf\n(即使没有下载成功也可以使用、未成功下载的图片将会跳过)\n(可直接在相册中打开观看)",
"export_to_epub_title": "将您所选的漫画导出EPUB",
"export_to_epub_desc": "导出到xxx.epub\n(可直接在阅读器中打开观看)",
"export_to_jpeg_folder_title": "将您所选的漫画导出JPEGS.zip",
"export_to_jpeg_folder_desc": "导出阅读器用JPGS.zip\n(不可再导入)",
"export_to_cbz_title": "将您所选的漫画导出cbk.zip",
"export_to_cbz_desc": "导出到xxx.cbz, 阅读器可以直接使用(不可再导入)"
},
"download_export_to_socket": {
"title": "网络导出",
"loading": "加载中",
"tips": "传输成功之前请不要退出页面, 一次只能导出到一个设备, 两台设备需要在同一网段或无限局域网中, 请另外一台设备输入 IP:端口 , 有一个IP时请选择无限局域网的IP, 通常是192.168开头",
"get_ip_failed": "获取IP失败",
"getting_ip": "正在获取IP",
"port": "端口号"
},
"download_import": {
"title": "导入",
"open_file": "打开文件",
"select_file": "选择要导入的文件",
"import_success": "导入成功",
"import_failed": "导入失败",
"select_file_desc": "选择zip文件进行导入\n选择pki文件进行导入\n选择pkz文件进行阅读",
"input_address": "请输入导出设备提供的地址\n例如 \"192.168.1.2:50000\"",
"import_from_other_device": "从其他设备导入",
"select_folder_desc": "选择文件夹\n(导入里面所有的zip/pki)\n(发电后使用)"
},
"download_info": {
"loading": "加载中",
"chapter": "章节",
"comment": "评论",
"recommend": "推荐"
},
"download_list": {
"search_download": "搜索下载",
"multi_select_operation": "多选操作",
"download_list": "下载列表",
"search": "搜索",
"select_folder": "选择文件夹",
"download_already_in_delete_queue": "该下载已经在删除队列中",
"import": "导入",
"export": "导出",
"file": "文件",
"download_task": "下载任务",
"pause_download": "暂停下载吗?",
"start_download": "启动下载吗?",
"resume_failed": "恢复失败任务",
"resume_failed_desc": "所有失败的下载已经恢复",
"downloading": "下载中",
"paused": "暂停中",
"move_download": "移动下载",
"select_download_to_move": "请选择要移动下载",
"select_download_to_delete": "请选择要删除下载",
"input_name": "==> 输入名称 <==",
"empty_folder_will_be_deleted": "(空文件夹将会自动删除,下次需要手动输入)",
"folder_name": "文件夹名称",
"please_input_folder_name": "请输入文件夹名称",
"delete_download": "删除下载",
"delete_selected_download": "删除选中的下载吗?",
"multi_select": "多选"
},
"download_only_import": {
"importing": "正在导入",
"import_success": "导入成功",
"import_failed": "导入失败",
"click_import_file": "点击导入文件",
"importing_please_wait": "导入中, 请稍后"
},
"favourite_paper": {
"favourite": "收藏"
},
"forgot_password": {
"title": "找回密码",
"username": "账号",
"not_set": "未设置",
"confirm": "确认",
"please_enter_username": "请输入账号",
"question_1": "问题1",
"question_2": "问题2",
"question_3": "问题3",
"answer_1": "回答1",
"answer_2": "回答2",
"answer_3": "回答3",
"please_enter_answer_1": "请输入回答1",
"please_enter_answer_2": "请输入回答2",
"please_enter_answer_3": "请输入回答3",
"use_answer_1_recover": "使用回答1找回密码",
"use_answer_2_recover": "使用回答2找回密码",
"use_answer_3_recover": "使用回答3找回密码",
"please_enter_answer": "请输入答案",
"new_password_copied": "新密码正在复制到剪切板",
"answer_incorrect": "答案不正确",
"password": "密码"
},
"game_download": {
"title": "下载",
"download_links_obtained": "获取到下载链接, 您只需要选择其中一个"
},
"game_info": {
"download": "下载",
"details": "详情",
"comments": "评论"
},
"games": {
"title": "游戏"
},
"import_from_off": {
"title": "导入",
"import_success": "导入成功",
"import_failed": "导入失败"
},
"modify_password": {
"title": "修改密码",
"please_wait": "请稍后",
"old_password": "旧密码",
"new_password": "新密码",
"repeat_new_password": "重复输入新密码",
"not_filled": "未填写",
"please_enter_old_password": "请输入旧密码",
"please_enter_new_password": "请输入新密码",
"please_repeat_new_password": "请重复输入新密码",
"new_password_mismatch": "新密码不匹配",
"modify_success": "修改成功",
"failed": "失败",
"confirm": "确认"
},
"network_settings": {
"title": "网络设置"
},
"pkz_reader": {
"reading_downloaded_comic": "您阅读的是下载漫画"
},
"pro": {
"title": "发电中心",
"power_center": "发电中心",
"power_status": "发电状态",
"powered": "发电中",
"not_powered": "未发电",
"pat_membership": "PAT入会",
"pat_status": "PAT状态",
"pat_normal": "PAT正常",
"pat_bind_hint": "请点击这里绑定到当前账号发电",
"pat_rebind_hint": "请点换绑到当前账号发电",
"pat_not_detected": "未检测到入会, 请到下载页入会",
"i_have_powered": "我曾经发过电",
"i_just_powered": "我刚才发了电",
"enter_code": "输入代码",
"power_method": "发电方式",
"wind_power": "风力发电",
"hydro_power": "水力发电",
"solar_power": "光伏发电",
"nuclear_power": "核能发电",
"choose_power_method": "选择发电方式",
"sign_in_exchange": "签到/兑换",
"click_pat_to_change": "点击下面的PAT会籍进行变更",
"update_pat_status": "更新PAT发电状态",
"bind_to_account": "绑定到此账号",
"change_pat_key": "更换PAT密钥",
"clear_pat_info": "清除PAT信息",
"click_to_bind": "点击绑定",
"enter_auth_code": "请输入授权代码",
"please_wait": "请稍后",
"key_recorded": "密钥 : 已录入",
"pat_account": "PAT账号",
"bind_pika_account": "绑定PIKA账号",
"bind_account_time": "绑定账号时间",
"rebind_time": "可以换绑时间",
"power_features": "发电小功能: 多线程下载 / 批量导入导出下载",
"power_guide": "去\"关于\"界面找到维护地址可获得发电指引\n\n \"我曾经发过电\"可同步相应发电状态\n \"我刚才发了电\"兑换神秘代码\n \"发电方式\"可以在网络不通时尝试更换\n \"PAT入会\"是独立的发电方式"
},
"rankings": {
"title": "排行榜",
"day": "天",
"week": "周",
"month": "月",
"knight": "骑",
"refresh": "刷新",
"comics_count": "本"
},
"random_comics": {
"title": "随机本子"
},
"register": {
"title": "注册",
"registering": "注册中",
"register_success": "注册成功",
"register_failed": "注册失败",
"account_exists": "账号已存在",
"name_exists": "昵称已存在",
"check_form": "请检查表单, 不允许留空",
"account": "账号",
"password": "密码",
"nickname": "昵称",
"gender": "性别",
"birthday": "生日",
"question_1": "问题1",
"answer_1": "回答1",
"question_2": "问题2",
"answer_2": "回答2",
"question_3": "问题3",
"answer_3": "回答3",
"not_set": "未设置",
"please_enter_account": "请输入账号",
"please_enter_password": "请输入密码",
"please_enter_nickname": "请输入昵称",
"please_enter_question_1": "请输入问题1",
"please_enter_answer_1": "请输入回答1",
"please_enter_question_2": "请输入问题2",
"please_enter_answer_2": "请输入回答2",
"please_enter_question_3": "请输入问题3",
"please_enter_answer_3": "请输入回答3",
"account_desc": "(小写字母+数字/登录使用)",
"password_desc": "(大小写字母+数字/8位或以上)",
"nickname_desc": "(可使用中文/2-50字)",
"choose_gender": "选择您的性别",
"futa": "扶她",
"male": "公",
"female": "母",
"register_success_desc": "您已经注册成功, 请返回登录",
"account_label": "账号",
"nickname_label": "昵称"
},
"search": {
"title": "搜索",
"search_hint": "搜索",
"choose_category": "请选择分类"
},
"search_author": {
"title": "按作者搜索",
"search_hint": "搜索 按作者 + ",
"by_author": "按作者: "
},
"space": {
"title": "我的",
"logout": "退出登录",
"logout_confirm": "您确认要退出当前账号吗?",
"my_favourites": "我的收藏",
"view_history": "浏览记录",
"my_downloads": "我的下载"
},
"theme": {
"title": "主题设置",
"theme": "主题",
"dark_mode_different_theme": "深色模式下使用不同的主题",
"dark_mode_theme": "主题 (深色模式)"
},
"view_logs": {
"title": "浏览记录",
"clear_all": "您要清除所有浏览记录吗? ",
"clear_all_desc": "将会同时删除浏览进度!",
"clear_one": "您要清除这条浏览记录吗? ",
"clear_one_desc": "将会同时删除浏览进度!",
"clear_selected": "您要清除选中的浏览记录吗? ",
"clear_selected_desc": "将会同时删除浏览进度!",
"categories": "分类"
},
"web_server": {
"title": "下载 - Web服务器",
"loading": "加载中",
"get_ip_failed": "获取IP失败",
"getting_ip": "正在获取IP",
"port": "端口号:8080",
"usage_instruction": "在浏览器中输入\"http://本设备ip:8080/\"访问下载的漫画",
"leave_notice": "离开页面后服务器将关闭"
}
},
"components": {
"comic_info_card": {
"categories": "分类",
"finished": "完结",
"viewed": "看过"
},
"comic_list": {
"shadow": "被封印的本子"
},
"common": {
"display_mode": "显示模式",
"shadow_mode": "封印模式",
"shadow_list": "封印列表",
"batch_download": "批量下载"
},
"image_reader": {
"already_at_the_end": "已经到头了",
"click_to_next_chapter": "再次点击跳转到下一章",
"reload_page": "重载页面",
"next_chapter": "下一章",
"end_reading": "结束阅读",
"reload_image": "重新加载图片",
"save_image_in_this_page": "保存本页的图片",
"image_load_failed": "图片加载失败"
}
}
}
================================================
FILE: lib/assets/translations/zh-TW.json
================================================
{
"language": {
"title": "語言",
"name": "繁體中文 - 中國台灣"
},
"app": {
"categories": "分類",
"my": "我的",
"copied_to_clipboard": "已複製到剪貼簿",
"not_supported_platform": "不支援此平台",
"cancel": "取消",
"confirm": "確定",
"save_cancel": "保存取消",
"save_success": "保存成功",
"save_failed": "保存失败",
"pro": "發電",
"pro_required": "請先發電再使用",
"choose_folder": "選擇一個文件夾, 將文件保存到這裡",
"permission_denied": "申請權限被拒絕",
"loading": "加载中",
"error": "错误",
"pat": {
"success": "您的贊助登錄成功, 請返回",
"title": "更換PAT賬戶"
},
"previous_page": "上一頁",
"next_page": "下一頁",
"page": "頁",
"please_enter_page_number": "請輸入頁數:",
"select_all": "全選",
"load_failed": "加載失敗",
"all": "全部",
"delete": "刪除",
"save_image": "保存圖片",
"preview_image": "預覽圖片",
"please_select": "請選擇",
"refresh": "刷新",
"initializing": "初始化",
"like_failed": "點讚失敗",
"network_error": "連接不上啦, 請檢查網路",
"no_permission": "沒有權限或路徑不可用",
"check_device_time": "請檢查設備時間",
"resource_not_available": "資源未審核或不可用",
"something_went_wrong": "啊哦, 被玩壞了",
"click_refresh": "點擊刷新",
"pull_down_refresh": "下拉刷新",
"continue_reading": "繼續閱讀",
"start_reading": "開始閱讀",
"image_crop": "圖片裁剪",
"download": "下載",
"download_failed": "下載失敗",
"download_finished": "下載完成",
"downloading": "下載中",
"queue": "隊列中",
"deleting": "刪除中",
"please_select_comic": "請選擇漫畫",
"please_choose": "請選擇",
"last_viewed": "上次觀看到",
"auto_punch": "自動打卡",
"yes": "是",
"no": "否",
"confirm_download": "確認下載",
"copy": "複製"
},
"net": {
"no_address": "不分流",
"address": "分流",
"address_sync": "分流同步",
"address_sync_from_server": "從伺服器獲取最新的分流地址",
"address_sync_reset": "重制分流為預設值",
"address_sync_success": "分流同步成功",
"address_sync_failed": "分流同步失敗",
"address_sync_reset_success": "分流重制成功",
"address_sync_reset_failed": "分流重制失敗",
"choose_address": "選擇分流",
"image_address": "圖片分流",
"use_api_load_image": "用API加載圖片",
"ping_testing": "測速中",
"ping_failed": "失敗"
},
"categories": {
"all": "全分類",
"recommend": "推薦",
"rankings": "排行榜",
"random": "隨機本子",
"game": "遊戲專區"
},
"settings": {
"settings": "設定",
"interface": "介面",
"network": "網路",
"seal": "封印",
"interaction": "交互",
"reading": "閱讀",
"download": "下載",
"auto_download_on_favorite": "收藏時自動下載",
"disable_auto_download_on_mobile": "行動網路下收藏時不自動下載",
"auto_delete_download_on_unfavorite": "取消收藏時自動刪除下載",
"web_server": "啟動Web伺服器",
"web_server_subtitle": "讓局域網內的設備通過瀏覽器看下載的漫畫",
"sync": "同步",
"account": "帳戶",
"modify_password": "修改密碼",
"ebook": "電子書",
"system": "系統",
"clear_cache": "清除快取",
"migrate": "文件遷移",
"migrate_subtitle": "更換您的資料文件夾到記憶卡",
"migrate_confirm": "此功能菜單保存後, 需要重啟程序, 您確認嗎",
"app_orientation": {
"title": "APP方向",
"choose": "請選擇APP方向",
"normal": "正常",
"landscape": "橫屏",
"portrait": "豎屏"
},
"will_pop_notice": "在首頁連續按兩下返回鍵才能退出APP",
"android_secure_flag": "禁止截圖/禁止顯示在任務視圖",
"android_display_mode": {
"title": "屏幕刷新率(安卓)",
"dialog_title": "安卓屏幕刷新率 \n(省電模式下不會高刷)"
},
"authentication": "進入APP時驗證身份(如果系統已經錄入密碼或指紋)",
"set_password": "設置應用程序密碼",
"auto_clean": {
"title": "自動清理快取",
"one_month_ago": "一個月前",
"one_week_ago": "一周前",
"one_day_ago": "一天前",
"no_auto_clean": "不自動清理"
},
"categories_column_count": {
"title": "首頁分類展示列數",
"choose": "選擇首頁分類展示列數",
"auto": "自動"
},
"categories_sort": {
"title": "首頁分類排序"
},
"chooser_root": {
"title": "文件夾選擇器根路徑",
"hint": "請輸入文件夾選擇器根路徑",
"desc": "導出時選擇目錄的默認路徑, 同時也是根路徑, 不能正常導出時也可以嘗試設置此選項。"
},
"content_failed_reload_action": {
"title": "頁面加載失敗刷新方式",
"choose": "選擇頁面加載失敗刷新方式",
"pull_down": "下拉刷新",
"touch_loader": "點擊屏幕刷新"
},
"copy_full_name": {
"title": "複製漫畫名稱時使用模版"
},
"copy_full_name_template": {
"title": "複製漫畫名稱模版",
"hint": "模版內容"
},
"copy_skip_confirm": {
"title": "長按複製不需要確認"
},
"download_and_export_path": {
"title": "下載的同時導出到文件系統",
"confirm": "下載的同時導出到文件系統",
"desc": "您即將選擇一個目錄, 如果文件系統可寫, 下載的同時會為您自動導出一份"
},
"download_cache_path": {
"title": "使用其他程序的緩存下載加速",
"confirm": "使用其他程序的緩存下載加速",
"desc": "您即將選擇一個目錄, 這個目錄拷貝自以下目錄才能使用。下載時將會作為緩存文件夾優先讀取。 ",
"cancel_desc": "您確定取消使用其他軟件的內容加速的功能嗎? 取消之後您可以再次點擊設置",
"import_view_log_from_off": {
"title": "導入其他程序的歷史記錄",
"desc": "您即將選擇一個文件, 這個文件拷貝自以下路徑才能使用。",
"choose_file_dialog_title": "選擇要導入的文件"
}
},
"download_thread_count": {
"title": "下載線程數",
"choose": "選擇下載線程數"
},
"ebook_scrolling": {
"title": "電子書模式滾動UI"
},
"ebook_scrolling_range": {
"title": "電子書模式滾動UI",
"desc": "滾動幅度",
"screen_height": "屏幕高度"
},
"ebook_scrolling_trigger": {
"title": "電子書模式滾動UI",
"desc": "觸發距離",
"cm": "厘米"
},
"export_path": {
"ios_desc": "隨後可在文件管理中找到導出的內容",
"ios_desc2": "您正在使用iOS設備:\n導出到文件的內容請打開系統自帶文件管理進行瀏覽",
"export_path_desc": "導出路徑 (點擊可修改)",
"android_desc": "您正在使用安卓設備:\n如果不能成功導出並且提示權限不足, 可以嘗試在Download或Document下建立子目錄進行導出"
},
"export_rename": {
"title": "導出時進行重命名"
},
"yes": "是",
"no": "否",
"full_screen_action": {
"title": "操控方式",
"choose": "選擇操控方式",
"touch_once": "點擊屏幕一次全屏",
"controller": "使用控制器全屏",
"touch_double": "雙擊屏幕全屏",
"touch_double_once_next": "雙擊屏幕全屏 + 單擊屏幕下一頁",
"three_area": "將屏幕劃分成三個區域 (上一頁, 下一頁, 全屏)"
},
"full_screen_ui": {
"title": "全屏UI",
"choose": "選擇全屏UI",
"no": "不使用",
"hidden_bottom": "去除虛擬控制器",
"all": "全屏"
},
"auto_full_screen": {
"title": "進入閱讀器自動全屏"
},
"auto_full_screen_on_forward": {
"title": "前進時自動全螢幕"
},
"ignore_info_history": {
"title": "詳情頁不計入歷史記錄"
},
"icon_loading": {
"title": "盡量減少UI動畫"
},
"ignore_upgrade_confirm": {
"title": "關閉升級彈窗"
},
"hidden_fd_icon": {
"title": "隱藏個人空間的發電圖標"
},
"hidden_search_persion": {
"title": "隱藏按作者搜索功能"
},
"hidden_viewed": {
"title": "隱藏閱讀過的漫畫"
},
"hidden_sub_icon": {
"title": "隱藏訂閱功能"
},
"hide_online_favorite": {
"title": "隱藏線上收藏",
"desc": "隱藏線上收藏入口與收藏按鈕"
},
"hidden_words": {
"title": "根據關鍵詞隱藏",
"clear_all": "確認清空",
"clear_all_desc": "確定要清空所有關鍵詞嗎?",
"input_hint": "輸入要隱藏的關鍵詞",
"no_words": "暫無關鍵詞"
},
"image_address": {
"title": "圖片分流",
"pinging": "測速中",
"failed": "失敗"
},
"image_filter": {
"title": "閱讀器圖片濾鏡",
"normal": "正常",
"gray": "灰度",
"brown": "棕褐色",
"choose": "選擇閱讀器圖片濾鏡"
},
"import_notice": {
"android_desc": "您正在使用安卓設備:\n如果不能導入導出並且提示權限不足, 可以嘗試在Download或Document下建立子目錄進行導入"
},
"keyboard_controller": {
"title": "閱讀器鍵盤翻頁(僅PC)"
},
"list_layout": {
"choose": "請選擇布局",
"info_card": "詳情",
"only_image": "封面",
"cover_and_title": "封面+標題"
},
"local_history_sync": {
"sync_to_local": "同步歷史記錄到本地",
"not_set": "未設置",
"sync_success": "同步成功",
"sync_failed": "同步失敗",
"auto_sync": "自動同步歷史記錄到本地",
"auto_sync_desc": "開啟後每次打開應用會自動備份歷史記錄",
"choose_dir": "選擇目錄",
"clear_path": "清除路徑",
"clear_path_desc": "確定要清除路徑嗎?"
},
"history_sync": "歷史記錄同步",
"local_favorite_sync_title": "本地收藏夾同步",
"use_local_favorite": "使用本地收藏夾",
"use_local_favorite_desc": "在本地管理收藏,支援資料夾分類",
"local_favorite_sync": {
"auto_sync": "自動同步本地收藏夾",
"auto_sync_desc": "使用WebDAV自動同步本地收藏夾",
"manual_sync": "手動同步本地收藏夾",
"sync_success": "同步成功",
"sync_failed": "同步失敗"
},
"no_animation": {
"title": "取消翻頁動畫(點按屏幕、音量鍵、鍵盤)"
},
"pager_action": {
"title": "列表頁加載方式",
"choose": "選擇列表頁加載方式",
"controller": "使用按鈕",
"stream": "瀑布流"
},
"proxy": {
"title": "代理伺服器",
"hint": "請輸入代理伺服器",
"desc": " ( 例如 socks5://127.0.0.1:1080/ ) ",
"no_proxy": "未設置"
},
"quality": {
"title": "瀏覽時的圖片質量",
"choose": "請選擇圖片質量",
"original": "原圖",
"low": "低",
"medium": "中",
"high": "高"
},
"reader_background_color": {
"title": "閱讀器背景色",
"choose": "選擇閱讀器背景色",
"black": "黑色",
"gray": "灰度",
"white": "白色"
},
"reader_direction": {
"title": "閱讀器方向",
"choose": "選擇翻頁方向",
"top_to_bottom": "從上到下",
"left_to_right": "從左到右",
"right_to_left": "從右到左"
},
"reader_scroll_by_screen_percentage": {
"title": "按距離翻頁長度",
"screen_size": "屏幕尺寸"
},
"web_toon_scroll_mode": {
"title": "WebToon 翻頁模式",
"choose": "選擇 WebToon 翻頁模式",
"image": "圖片",
"screen": "距離"
},
"reader_zoom": {
"out_title": "縮小倍數(最小縮放)",
"in_title": "放大倍數(最大縮放)",
"double_tap_title": "雙擊縮放倍數"
},
"drag_region_lock": {
"title": "鎖定拖動邊界"
},
"gesture_speed": {
"title": "手勢速度倍率"
},
"reader_slider_position": {
"title": "滾動條的位置",
"choose": "選擇滑動條位置",
"bottom": "下方",
"right": "右側",
"left": "左側"
},
"reader_two_page_direction": {
"title": "雙頁閱讀器內容排列",
"choose": "選擇雙頁閱讀器內容排列",
"close_to": "靠近",
"pull_away": "遠離",
"each_centered": "各自居中"
},
"reader_type": {
"title": "閱讀器模式",
"choose": "選擇閱讀器模式",
"web_toon": "WebToon (默認)",
"web_toon_zoom": "WebToon (雙擊放大)",
"gallery": "相冊",
"web_toon_free_zoom": "WebToon (ListView雙擊放大)\n(此模式進度條無效)",
"two_page_gallery": "雙頁模式\n(實驗)",
"left_to_right": "從左到右",
"right_to_left": "從右到左",
"two_page_direction": "雙頁方向",
"two_page_direction_choose": "選擇雙頁方向"
},
"shadow_categories": {
"title": "封印",
"search_hint": "搜索"
},
"shadow_categories_mode": {
"title": "封印模式",
"black_list": "黑名單",
"white_list": "白名單"
},
"startup_pic": {
"title": "設置啟動圖片",
"subtitle": "設置應用啟動時顯示的圖片",
"clear_title": "清除啟動圖片",
"clear_subtitle": "清除應用啟動時顯示的圖片",
"clear_success": "啟動圖片已清除",
"update_success": "啟動圖片已更新"
},
"show_comment_at_download": {
"title": "在下載顯示評論區"
},
"font": {
"title": "字體",
"hint": "請輸入字體",
"input_hint": "請輸入字體的名稱且用英文逗號分隔, 例如 \"宋體,黑體\", 如果您保存後沒有發生變化, 說明字體無法使用或名稱錯誤, 可以去參考C:\\Windows\\Fonts尋找您的字體。若您使用的是flutter2引擎的版本,只有第一個字體生效。",
"choose_hint": "需要您選擇多個字體,直至您點擊背景區域"
},
"theme": {
"origin": "原生",
"pink": "粉色",
"black": "酷黑",
"dark": "暗黑",
"dusty_blue": "灰蓝",
"dark_black": "纯黑",
"choose_theme": "選擇主題",
"book": "書本",
"enable_status_bar_color": "啟用狀態欄顏色",
"enable_status_restart_hint": "關閉時需要重新啟動應用程序刷新狀態欄顏色"
},
"three_keep_right": {
"title": "三區域模式翻頁始終為右側下一頁"
},
"time_zone": {
"title": "時區"
},
"timeout_lock": {
"title": "自動鎖定",
"notice": "注意:自動鎖定在桌面端僅支持最小化後超時,手機端支持後台以及鎖屏後超時。如果沒有設置密碼,自動鎖定無效。安卓以及桌面端只會鎖定桌面,不會鎖定下載,iOS未測試,需要手動開啟後台活動。",
"1_hour": "一小時",
"10_minutes": "十分鐘",
"3_minutes": "三分鐘",
"1_minute": "一分鐘",
"10_seconds": "十秒",
"1_second": "一秒",
"no_lock": "不鎖定"
},
"using_right_click_pop": {
"title": "鼠標右鍵返回上一頁"
},
"volume_controller": {
"title": "閱讀器音量鍵翻頁"
},
"volume_next_chapter": {
"title": "雙擊 音量/鍵盤/控制器 下一章節"
},
"webdav": {
"title": "WebDav",
"not_set": "未設置",
"path": "WebDav 路徑",
"path_hint": "請輸入WebDav 路徑",
"username": "WebDav 用戶名",
"username_hint": "請輸入WebDav 用戶名",
"password": "WebDav 密碼",
"password_hint": "請輸入WebDav 密碼",
"auto_sync_history_to_webdav": "開啟時自動同步瀏覽記錄到WebDav",
"sync_history_to_webdav": "立即同步瀏覽記錄到WebDAV",
"upload_history_to_webdav": "覆蓋WebDAV中的瀏覽記錄",
"upload_history_to_webdav_desc": "如有多台設備,請注意自動同步功能",
"sync_success": "同步成功",
"sync_failed": "同步失敗"
}
},
"local_favorite": {
"title": "本地收藏夾",
"all_folders": "全部",
"new_folder": "新建資料夾",
"select_mode": "多選",
"cancel_select_mode": "退出多選",
"select_all": "全選",
"delete_folder": "刪除資料夾",
"move_to_folder": "移動到資料夾",
"remove_selected": "移除選中收藏",
"remove_selected_confirm": "確認從本地收藏夾中移除選中的漫畫?",
"remove_selected_success": "已移除",
"remove_selected_failed": "移除失敗",
"select_comics": "請先選擇漫畫",
"folder_limit_reached": "免費版最多建立3個資料夾,升級Pro解鎖無限制",
"batch_download": "批次下載",
"select_folder": "選擇資料夾",
"folder_name": "資料夾名稱",
"delete_confirm": "確認刪除資料夾?",
"empty_folder": "暫無收藏",
"no_folders": "還沒有資料夾,請先建立",
"remove_confirm_title": "取消收藏",
"remove_confirm_content": "確定要從本地收藏夾中移除這部漫畫嗎?",
"remove_failed": "取消收藏失敗",
"load_failed": "載入失敗",
"add_success": "已新增到本地收藏夾",
"add_failed": "新增失敗",
"create_folder_failed": "建立資料夾失敗",
"create_success": "建立成功",
"delete_success": "刪除成功",
"delete_failed": "刪除失敗",
"move_success": "移動成功",
"move_failed": "移動失敗",
"select_comics_to_download": "請選擇要下載的漫畫",
"download_started": "開始下載",
"download_failed": "下載失敗"
},
"screen": {
"about": {
"title": "關於",
"version": "軟件版本",
"check_update": "檢查更新",
"tips": "提示 : \n1. 詳情頁的作者/上傳者/分類/標籤都可以點擊\n2. 詳情頁的作者/上傳者/標題長按可以複製\n3. 使用分頁而不是瀑布流點擊頁碼可以快速翻頁\n4. 下載指的是緩存到本地, 需要導出才可以分享\n5. 下載長按可以刪除",
"download_new_version": "請從獲取渠道下載新版",
"no_new_version": "未檢測到新版本",
"download_release_version": "下載RELEASE版",
"update_content": "更新內容",
"go_to_release_repository": "去RELEASE倉庫"
},
"account": {
"title": "賬戶",
"username": "賬號",
"username_hint": "請輸入賬號",
"password": "密碼",
"password_hint": "請輸入密碼",
"no_account_register": "沒有賬號,我要註冊",
"password_reset": "密碼找回",
"check_username_password_or_network": "請檢查賬號密碼或網絡環境",
"check_device_time": "請檢查設備時間",
"username_or_password_error": "賬號或密碼錯誤",
"login_failed": "登錄失敗",
"not_set": "未設置"
},
"app": {
"will_pop_notice": "再次返回將會退出應用程序"
},
"categories": {
"search_hint": "搜索"
},
"clean": {
"title": "清理",
"cleaning": "清理中",
"clean_network_cache": "清理网络缓存",
"clean_image_cache": "清理图片缓存",
"clean_all_cache": "清理全部缓存",
"clean_success": "清理成功",
"clean_failed": "清理失败"
},
"close_app": {
"title": "提示",
"close_app": "請關閉應用重新打開"
},
"comic_collections": {
"no_resource": "這裡沒有資源呀"
},
"comic_info": {
"chapter": "章节",
"comment": "评论",
"recommend": "推荐"
},
"comics": {
"search_hint": "搜索分类",
"choose_category": "请选择分类"
},
"comic_subscribes": {
"update_reminder": "更新提醒",
"check_update": "检查更新",
"cancel_all_update_reminder": "取消所有更新提醒"
},
"comment": {
"title": "評論",
"hint_text": "請輸入評論內容",
"success": "評論成功",
"i_have_something_to_say": "我有話要講",
"please_enter_comment": "請輸入評論內容"
},
"desktop_authentication": {
"current_password": "當前密碼",
"password_error": "密碼錯誤",
"password_initialization": "密碼初始化",
"password": "密碼",
"re_enter_password": "再次輸入密碼",
"password_mismatch": "兩次輸入的密碼不一致",
"set_password": "設置密碼"
},
"download_confirm": {
"please_select_ep": "請選擇下載的EP",
"already_added_to_download_list": "已經加入下載列表"
},
"download_export_group": {
"title": "批量導出",
"please_select_content": "請選擇導出的內容",
"exporting": "正在導出",
"export_failed": "導出失敗",
"export_success": "導出成功",
"export_to_pkz": "導出成一個PKZ\n(加密模式,防止網盤檢測,能用pikapika打開觀看)",
"export_to_pki": "每部漫畫都打包一個PKI\n(加密模式,防止網盤檢測,能用pikapika導入)",
"export_to_zip": "每部漫畫都打包一個ZIP\n(不加密模式,能用pikapika導入或網頁瀏覽器觀看)",
"export_to_jpeg_zip": "每部漫畫都打包一個ZIP+JPEG\n(能直接使用其他閱讀器看,不可再導入)",
"export_to_jpeg_folder": "每部漫畫都導出成文件夾+JPEG",
"export_to_pdf": "每部漫畫都導出成PDF",
"export_to_epub": "每部漫畫都導出成EPUB",
"export_to_pdf_folder": "每部漫畫都導出到文件夾, 每個章節一個PDF",
"export_to_cbz": "每部漫畫都導出成cbz",
"after_power_use": "發電後使用",
"input_save_name": "請輸入保存後的名称",
"export_confirm": "導出確認",
"export_to_pkz_title": "將導出您所選的漫畫為一個PKZ",
"export_to_pki_title": "將您所選的漫畫分別導出成單獨的PKI",
"please_power_up": "請先發電鴨",
"export_to_zip_title": "將您所選的漫畫分別導出成ZIP",
"export_to_jpeg_zip_title": "將您所選的漫畫分別導出成ZIP+JPEG",
"export_to_jpeg_zip_title_not_down_over": "將您所選的漫畫分別導出成ZIP+JPEG\n(即便沒有下載完成也可以使用)",
"export_to_jpeg_folder_title": "將您所選的漫畫分別導出成文件夾+JPEG",
"export_to_pdf_title": "將您所選的漫畫分別導出成PDF",
"export_to_epub_title": "將您所選的漫畫分別導出成EPUB",
"export_to_pdf_folder_title": "將您所選的漫畫分別導出到文件夾, 每個章節一個PDF",
"export_to_cbz_title": "將您所選的漫畫分別導出成cbz",
"exporting_please_wait": "導出中, 請稍後"
},
"download_export_to_file": {
"title": "導出",
"transfer_to_other_device": "傳輸到其他設備",
"input_save_name": "請輸入保存後的名称",
"export_confirm": "導出確認",
"export_to_pkz_title": "將您所選的漫畫導出PKZ",
"export_to_pkz_desc": "導出到xxx.pkz\n(可直接打開觀看,不支持導入)\n(可以躲避網盤或者聊天軟件的掃描)",
"export_to_pki_title": "將您所選的漫畫導出PKI",
"export_to_pki_desc": "導出到xxx.pki\n(只支持導入, 不支持直接閱讀)\n(可以躲避網盤或者聊天軟件的掃描)\n(後期版本可能支持直接閱讀)",
"export_to_zip_title": "將您所選的漫畫導出HTML+ZIP",
"export_to_zip_desc": "導出到xxx.zip\n(可從其他設備導入 / 解壓後可閱讀)",
"export_to_jpeg_zip_title": "將您所選的漫畫導出HTML+JPEG",
"export_to_jpeg_zip_desc": "導出到xxx.jpeg\n(可直接在相冊中打開觀看)",
"export_to_pdf_title": "將您所選的漫畫導出PDF",
"export_to_pdf_desc": "導出到xxx.pdf\n(即使沒有下載成功也可以使用、未成功下載的圖片將會跳過)\n(可直接在相冊中打開觀看)",
"export_to_pdf_folder_title": "將您所選的漫畫導出到文件夾, 每個章節一個PDF",
"export_to_pdf_folder_desc": "導出到xxx.pdf\n(即使沒有下載成功也可以使用、未成功下載的圖片將會跳過)\n(可直接在相冊中打開觀看)",
"export_to_epub_title": "將您所選的漫畫導出EPUB",
"export_to_epub_desc": "導出到xxx.epub, 閱讀器可以直接使用(不可再導入)",
"export_to_jpeg_folder_title": "將您所選的漫畫導出JPEGS.zip",
"export_to_jpeg_folder_desc": "導出閱讀器用JPGS.zip\n(不可再導入)",
"export_to_cbz_title": "將您所選的漫畫導出cbk.zip",
"export_to_cbz_desc": "導出到xxx.cbz, 閱讀器可以直接使用(不可再導入)"
},
"download_export_to_socket": {
"title": "網絡導出",
"loading": "加載中",
"tips": "傳輸成功之前請不要退出頁面, 一次只能導出到一個設備, 兩台設備需要在同一網段或無限局域網中, 請另外一台設備輸入 IP:端口 , 有一個IP時請選擇無限局域網的IP, 通常是192.168開頭",
"get_ip_failed": "獲取IP失敗",
"getting_ip": "正在獲取IP",
"port": "端口號"
},
"download_import": {
"title": "導入",
"open_file": "打開文件",
"select_file": "選擇要導入的文件",
"import_success": "導入成功",
"import_failed": "導入失敗",
"select_file_desc": "選擇zip文件進行導入\n選擇pki文件進行導入\n選擇pkz文件進行閱讀",
"input_address": "請輸入導出設備提供的地址\n例如 \"192.168.1.2:50000\"",
"import_from_other_device": "從其他設備導入",
"select_folder_desc": "選擇文件夾\n(導入裡面所有的zip/pki)\n(發電後使用)"
},
"download_info": {
"loading": "加載中",
"chapter": "章節",
"comment": "評論",
"recommend": "推薦"
},
"download_list": {
"search_download": "搜索下載",
"multi_select_operation": "多選操作",
"download_list": "下載列表",
"search": "搜索",
"select_folder": "選擇文件夾",
"download_already_in_delete_queue": "該下載已經在刪除隊列中",
"import": "導入",
"export": "導出",
"file": "文件",
"download_task": "下載任務",
"pause_download": "暫停下載嗎?",
"start_download": "啟動下載嗎?",
"resume_failed": "恢復失敗任務",
"resume_failed_desc": "所有失敗的下載已經恢復",
"downloading": "下載中",
"paused": "暫停中",
"move_download": "移動下載",
"select_download_to_move": "請選擇要移動的下載",
"select_download_to_delete": "請選擇要刪除的下載",
"input_name": "==> 輸入名稱 <==",
"empty_folder_will_be_deleted": "(空文件夾將會自動刪除,下次需要手動輸入)",
"folder_name": "文件夾名稱",
"please_input_folder_name": "請輸入文件夾名稱",
"delete_download": "刪除下載",
"delete_selected_download": "刪除選中的下載嗎?",
"multi_select": "多選"
},
"download_only_import": {
"importing": "正在導入",
"import_success": "導入成功",
"import_failed": "導入失敗",
"click_import_file": "點擊導入文件",
"importing_please_wait": "導入中, 請稍後"
},
"favourite_paper": {
"favourite": "收藏"
},
"forgot_password": {
"title": "找回密碼",
"username": "帳號",
"not_set": "未設置",
"confirm": "確認",
"please_enter_username": "請輸入帳號",
"question_1": "問題1",
"question_2": "問題2",
"question_3": "問題3",
"answer_1": "回答1",
"answer_2": "回答2",
"answer_3": "回答3",
"please_enter_answer_1": "請輸入回答1",
"please_enter_answer_2": "請輸入回答2",
"please_enter_answer_3": "請輸入回答3",
"use_answer_1_recover": "使用回答1找回密碼",
"use_answer_2_recover": "使用回答2找回密碼",
"use_answer_3_recover": "使用回答3找回密碼",
"please_enter_answer": "請輸入答案",
"new_password_copied": "新密碼正在複製到剪切板",
"answer_incorrect": "答案不正確",
"password": "密碼"
},
"game_download": {
"title": "下載",
"download_links_obtained": "獲取到下載鏈接, 您只需要選擇其中一個"
},
"game_info": {
"download": "下載",
"details": "詳情",
"comments": "評論"
},
"games": {
"title": "遊戲"
},
"import_from_off": {
"title": "導入",
"import_success": "導入成功",
"import_failed": "導入失敗"
},
"modify_password": {
"title": "修改密碼",
"please_wait": "請稍後",
"old_password": "舊密碼",
"new_password": "新密碼",
"repeat_new_password": "重複輸入新密碼",
"not_filled": "未填寫",
"please_enter_old_password": "請輸入舊密碼",
"please_enter_new_password": "請輸入新密碼",
"please_repeat_new_password": "請重複輸入新密碼",
"new_password_mismatch": "新密碼不匹配",
"modify_success": "修改成功",
"failed": "失敗",
"confirm": "確認"
},
"network_settings": {
"title": "網路設置"
},
"pkz_reader": {
"reading_downloaded_comic": "您閱讀的是下載漫畫"
},
"pro": {
"title": "發電中心",
"power_center": "發電中心",
"power_status": "發電狀態",
"powered": "發電中",
"not_powered": "未發電",
"pat_membership": "PAT入會",
"pat_status": "PAT狀態",
"pat_normal": "PAT正常",
"pat_bind_hint": "請點擊這裡綁定到當前賬號發電",
"pat_rebind_hint": "請點換綁到當前賬號發電",
"pat_not_detected": "未檢測到入會, 請到下載頁入會",
"i_have_powered": "我曾經發過電",
"i_just_powered": "我剛才發了電",
"enter_code": "輸入代碼",
"power_method": "發電方式",
"wind_power": "風力發電",
"hydro_power": "水力發電",
"solar_power": "光伏發電",
"nuclear_power": "核能發電",
"choose_power_method": "選擇發電方式",
"sign_in_exchange": "簽到/兌換",
"click_pat_to_change": "點擊下面的PAT會籍進行變更",
"update_pat_status": "更新PAT發電狀態",
"bind_to_account": "綁定到此賬號",
"change_pat_key": "更換PAT密鑰",
"clear_pat_info": "清除PAT信息",
"click_to_bind": "點擊綁定",
"enter_auth_code": "請輸入授權代碼",
"please_wait": "請稍後",
"key_recorded": "密鑰 : 已錄入",
"pat_account": "PAT賬號",
"bind_pika_account": "綁定PIKA賬號",
"bind_account_time": "綁定賬號時間",
"rebind_time": "可以換綁時間",
"power_features": "發電小功能: 多線程下載 / 批量導入導出下載",
"power_guide": "去\"關於\"界面找到維護地址可獲得發電指引\n\n \"我曾經發過電\"可同步相應發電狀態\n \"我剛才發了電\"兌換神秘代碼\n \"發電方式\"可以在網絡不通時嘗試更換\n \"PAT入會\"是獨立的發電方式"
},
"rankings": {
"title": "排行榜",
"day": "天",
"week": "周",
"month": "月",
"knight": "騎",
"refresh": "刷新",
"comics_count": "本"
},
"random_comics": {
"title": "隨機本子"
},
"register": {
"title": "註冊",
"registering": "註冊中",
"register_success": "註冊成功",
"register_failed": "註冊失敗",
"account_exists": "賬號已存在",
"name_exists": "暱稱已存在",
"check_form": "請檢查表單, 不允許留空",
"account": "賬號",
"password": "密碼",
"nickname": "暱稱",
"gender": "性別",
"birthday": "生日",
"question_1": "問題1",
"answer_1": "回答1",
"question_2": "問題2",
"answer_2": "回答2",
"question_3": "問題3",
"answer_3": "回答3",
"not_set": "未設置",
"please_enter_account": "請輸入賬號",
"please_enter_password": "請輸入密碼",
"please_enter_nickname": "請輸入暱稱",
"please_enter_question_1": "請輸入問題1",
"please_enter_answer_1": "請輸入回答1",
"please_enter_question_2": "請輸入問題2",
"please_enter_answer_2": "請輸入回答2",
"please_enter_question_3": "請輸入問題3",
"please_enter_answer_3": "請輸入回答3",
"account_desc": "(小寫字母+數字/登錄使用)",
"password_desc": "(大小寫字母+數字/8位或以上)",
"nickname_desc": "(可使用中文/2-50字)",
"choose_gender": "選擇您的性別",
"futa": "扶她",
"male": "公",
"female": "母",
"register_success_desc": "您已經註冊成功, 請返回登錄",
"account_label": "賬號",
"nickname_label": "暱稱"
},
"search": {
"title": "搜索",
"search_hint": "搜索",
"choose_category": "請選擇分類"
},
"search_author": {
"title": "按作者搜索",
"search_hint": "搜索 按作者 + ",
"by_author": "按作者: "
},
"space": {
"title": "我的",
"logout": "退出登錄",
"logout_confirm": "您確認要退出當前賬號嗎?",
"my_favourites": "我的收藏",
"view_history": "瀏覽記錄",
"my_downloads": "我的下載"
},
"theme": {
"title": "主題設置",
"theme": "主題",
"dark_mode_different_theme": "深色模式下使用不同的主題",
"dark_mode_theme": "主題 (深色模式)"
},
"view_logs": {
"title": "瀏覽記錄",
"clear_all": "您要清除所有瀏覽記錄嗎? ",
"clear_all_desc": "將會同時刪除瀏覽進度!",
"clear_one": "您要清除這條瀏覽記錄嗎? ",
"clear_one_desc": "將會同時刪除瀏覽進度!",
"clear_selected": "您要清除選中的瀏覽記錄嗎? ",
"clear_selected_desc": "將會同時刪除瀏覽進度!",
"categories": "分類"
},
"web_server": {
"title": "下載 - Web服務器",
"loading": "加載中",
"get_ip_failed": "獲取IP失敗",
"getting_ip": "正在獲取IP",
"port": "端口號:8080",
"usage_instruction": "在瀏覽器中輸入\"http://本設備ip:8080/\"訪問下載的漫畫",
"leave_notice": "離開頁面後服務器將關閉"
}
},
"components": {
"comic_info_card": {
"categories": "分類",
"finished": "完結",
"viewed": "看過"
},
"comic_list": {
"shadow": "被封印的本子"
},
"common": {
"display_mode": "顯示模式",
"shadow_mode": "封印模式",
"shadow_list": "封印列表",
"batch_download": "批量下載"
},
"image_reader": {
"already_at_the_end": "已經到頭了",
"click_to_next_chapter": "再次點擊跳轉到下一章",
"reload_page": "重載頁面",
"next_chapter": "下一章",
"end_reading": "結束閱讀",
"reload_image": "重新加載圖片",
"save_image_in_this_page": "保存本頁的圖片",
"image_load_failed": "圖片加載失敗"
}
}
}
================================================
FILE: lib/basic/Channels.dart
================================================
import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart';
// EventChannel
// 由于Flutter的EventChannel只能订阅一次, 且为了和golang的的通信, 这里实现了多次订阅的分发和平铺
// 根据eventName订阅和取消订阅
var _eventChannel = const EventChannel("flatEvent");
StreamSubscription? _eventChannelListen;
Map _eventMap = {};
void registerEvent(void Function(String args) eventHandler, String eventName) {
if (_eventMap.containsKey(eventHandler)) {
throw 'once register';
}
_eventMap[eventHandler] = eventName;
if (_eventMap.length == 1) {
_eventChannelListen =
_eventChannel.receiveBroadcastStream().listen(_onFlatEvent);
}
}
void unregisterEvent(void Function(String args) eventHandler) {
if (!_eventMap.containsKey(eventHandler)) {
throw 'no register';
}
_eventMap.remove(eventHandler);
if (_eventMap.isEmpty) {
_eventChannelListen?.cancel();
}
}
void _onFlatEvent(dynamic t) {
_FlatEvent e = _FlatEvent.fromJson(jsonDecode(t));
_eventMap.forEach((key, value) {
if (value == e.function) {
key(e.content);
}
});
}
class _FlatEvent {
late String function;
late String content;
_FlatEvent.fromJson(Map json) {
this.function = json["function"];
this.content = json["content"];
}
}
================================================
FILE: lib/basic/Common.dart
================================================
import 'dart:async';
import 'dart:io';
import 'package:pikapika/i18.dart';
import 'package:flutter/material.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:pikapika/screens/AccessKeyReplaceScreen.dart';
import 'package:uni_links/uni_links.dart';
import 'package:uri_to_file/uri_to_file.dart';
import '../screens/ComicInfoScreen.dart';
import '../screens/DownloadOnlyImportScreen.dart';
import '../screens/PkzArchiveScreen.dart';
import 'config/IconLoading.dart';
import 'config/TimeOffsetHour.dart';
/// 默认的图片尺寸
double coverWidth = 210;
double coverHeight = 315;
String categoryTitle(String? categoryTitle) {
return categoryTitle ?? tr('categories.all');
}
/// 显示一个toast
void defaultToast(BuildContext context, String title) {
showToast(
title,
context: context,
position: StyledToastPosition.center,
animation: StyledToastAnimation.scale,
reverseAnimation: StyledToastAnimation.fade,
duration: const Duration(seconds: 4),
animDuration: const Duration(seconds: 1),
curve: Curves.elasticOut,
reverseCurve: Curves.linear,
);
}
/// 显示一个确认框, 用户关闭弹窗以及选择否都会返回false, 仅当用户选择确定时返回true
Future confirmDialog(
BuildContext context, String title, String content) async {
return await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(title),
content: SingleChildScrollView(
child: ListBody(
children: [Text(content)],
),
),
actions: [
MaterialButton(
child: Text(tr('app.cancel')),
onPressed: () {
Navigator.of(context).pop(false);
},
),
MaterialButton(
child: Text(tr('app.confirm')),
onPressed: () {
Navigator.of(context).pop(true);
},
),
],
)) ??
false;
}
/// 显示一个消息提示框
Future alertDialog(BuildContext context, String title, String content) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(title),
content: SingleChildScrollView(
child: ListBody(
children: [
Text(content),
],
),
),
actions: [
MaterialButton(
child: Text(tr('app.confirm')),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
);
}
/// stream-filter的替代方法
List filteredList(List list, bool Function(T) filter) {
List result = [];
for (var element in list) {
if (filter(element)) {
result.add(element);
}
}
return result;
}
/// 创建一个单选对话框, 用户取消选择返回null, 否则返回所选内容
Future chooseListDialog(
BuildContext context, String title, List items,
{String? tips}) async {
return showDialog(
context: context,
builder: (BuildContext context) {
return SimpleDialog(
title: Text(title),
children: [
...items.map((e) => SimpleDialogOption(
onPressed: () {
Navigator.of(context).pop(e);
},
child: Text('$e'),
)),
...tips != null
? [
Container(
padding: const EdgeInsets.fromLTRB(15, 5, 15, 15),
child: Text(tips),
),
]
: [],
],
);
},
);
}
/// 创建一个单选对话框, 用户取消选择返回null, 否则返回所选内容(value)
Future chooseMapDialog(
BuildContext buildContext, Map values, String title) async {
return await showDialog(
context: buildContext,
builder: (BuildContext context) {
return SimpleDialog(
title: Text(title),
children: values.entries
.map((e) => SimpleDialogOption(
child: Text(e.key),
onPressed: () {
Navigator.of(context).pop(e.value);
},
))
.toList(),
);
},
);
}
/// 输入对话框1
var _controller =
TextEditingController.fromValue(const TextEditingValue(text: ''));
Future displayTextInputDialog(BuildContext context,
{String? title,
String src = "",
String? hint,
String? desc,
bool isPasswd = false}) {
_controller.text = src;
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: title == null ? null : Text(title),
content: SingleChildScrollView(
child: ListBody(
children: [
TextField(
controller: _controller,
decoration: InputDecoration(hintText: hint),
obscureText: isPasswd,
obscuringCharacter: '\u2022',
),
...(desc == null
? []
: [
Container(
padding: const EdgeInsets.only(top: 20, bottom: 10),
child: Text(
desc,
style: TextStyle(
fontSize: 12,
color: Theme.of(context)
.textTheme
.bodyText1
?.color
?.withOpacity(.5)),
),
)
]),
],
),
),
actions: [
MaterialButton(
child: Text(tr('app.cancel')),
onPressed: () {
Navigator.of(context).pop();
},
),
MaterialButton(
child: Text(tr('app.confirm')),
onPressed: () {
Navigator.of(context).pop(_controller.text);
},
),
],
);
},
);
}
/// 将字符串前面加0直至满足len位
String add0(int num, int len) {
var rsp = "$num";
while (rsp.length < len) {
rsp = "0$rsp";
}
return rsp;
}
/// 格式化时间 2012-34-56
String formatTimeToDate(String str) {
try {
var c = DateTime.parse(str).add(Duration(hours: currentTimeOffsetHour()));
return "${add0(c.year, 4)}-${add0(c.month, 2)}-${add0(c.day, 2)}";
} catch (e) {
return "-";
}
}
/// 格式化时间 2012-34-56 12:34:56
String formatTimeToDateTime(String str) {
try {
var c = DateTime.parse(str).add(Duration(hours: currentTimeOffsetHour()));
return "${add0(c.year, 4)}-${add0(c.month, 2)}-${add0(c.day, 2)} ${add0(c.hour, 2)}:${add0(c.minute, 2)}";
} catch (e) {
return "-";
}
}
/// 输入对话框2
final TextEditingController _textEditController =
TextEditingController(text: '');
Future inputString(BuildContext context, String title,
{String hint = "", String? defaultValue}) async {
if (defaultValue != null) {
_textEditController.text = defaultValue;
} else {
_textEditController.clear();
}
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Card(
child: SingleChildScrollView(
child: ListBody(
children: [
Text(title),
TextField(
controller: _textEditController,
decoration: InputDecoration(
labelText: hint,
),
),
],
),
),
),
actions: [
MaterialButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(tr('app.cancel')),
),
MaterialButton(
onPressed: () {
Navigator.pop(context, _textEditController.text);
},
child: Text(tr('app.confirm')),
),
],
);
},
);
}
StreamSubscription linkSubscript(BuildContext context) {
return linkStream.listen((uri) async {
if (uri == null) return;
var parsed = Uri.parse(uri);
if (RegExp(r"^pika://access_key/([0-9A-z:\-]+)/$").allMatches(uri).isNotEmpty) {
String accessKey = RegExp(r"^pika://access_key/([0-9A-z:\-]+)/$")
.allMatches(uri)
.first
.group(1)!;
Navigator.of(context).push(
mixRoute(
builder: (BuildContext context) => AccessKeyReplaceScreen(accessKey: accessKey),
),
);
} else if (RegExp(r"^pika://comic/([0-9A-z]+)/$").allMatches(uri).isNotEmpty) {
String comicId = RegExp(r"^pika://comic/([0-9A-z]+)/$")
.allMatches(uri)
.first
.group(1)!;
Navigator.of(context).push(
mixRoute(
builder: (BuildContext context) => ComicInfoScreen(comicId: comicId),
),
);
} else if (RegExp(r"^https?://pika/comic/([0-9A-z]+)/$").allMatches(uri).isNotEmpty) {
String comicId = RegExp(r"^https?://pika/comic/([0-9A-z]+)/$")
.allMatches(uri)
.first
.group(1)!;
Navigator.of(context).push(
mixRoute(
builder: (BuildContext context) => ComicInfoScreen(comicId: comicId),
),
);
} else if (RegExp(r"^.*\.pkz$").allMatches(parsed.path).isNotEmpty) {
File file = await toFile(uri);
Navigator.of(context).push(
mixRoute(
builder: (BuildContext context) =>
PkzArchiveScreen(pkzPath: file.path),
),
);
} else if (RegExp(r"^.*\.((pki)|(zip))$").allMatches(parsed.path).isNotEmpty) {
File file = await toFile(uri);
Navigator.of(context).push(
mixRoute(
builder: (BuildContext context) =>
DownloadOnlyImportScreen(path: file.path),
),
);
}
});
}
================================================
FILE: lib/basic/Cross.dart
================================================
/// 与平台交互的操作
import 'dart:io';
import 'package:clipboard/clipboard.dart';
import 'package:pikapika/i18.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:pikapika/basic/Common.dart';
import 'package:pikapika/basic/config/CopySkipConfirm.dart';
import 'package:pikapika/basic/config/Platform.dart';
import 'package:url_launcher/url_launcher.dart';
import 'Method.dart';
import 'config/ChooserRoot.dart';
/// 复制内容到剪切板
void copyToClipBoard(BuildContext context, String string) {
FlutterClipboard.copy(string);
defaultToast(
context,
tr('app.copied_to_clipboard'),
);
}
void copyToClipBoardTips(BuildContext context, String string) {
FlutterClipboard.copy(string);
defaultToast(context, tr('app.copied_to_clipboard') + " :\n$string");
}
/// 打开web页面
Future openUrl(String url) async {
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: false,
);
}
}
/// 保存图片
Future saveImage(String path, BuildContext context) async {
Future? future;
if (Platform.isIOS) {
future = method.iosSaveFileToImage(path);
} else if (Platform.isAndroid) {
future = _saveImageAndroid(path, context);
} else if (Platform.isWindows || Platform.isMacOS || Platform.isLinux) {
String? folder = await chooseFolder(context);
if (folder != null) {
future = method.convertImageToJPEG100(path, folder);
}
} else {
defaultToast(context, tr('app.not_supported_platform'));
return;
}
if (future == null) {
defaultToast(context, tr('app.save_cancel'));
return;
}
try {
await future;
defaultToast(context, tr('app.save_success'));
} catch (e, s) {
print("$e\n$s");
defaultToast(context, tr('app.save_failed'));
}
}
/// 保存图片且保持静默, 用于批量导出到相册
Future saveImageQuiet(String path, BuildContext context) async {
if (Platform.isIOS) {
return method.iosSaveFileToImage(path);
} else if (Platform.isAndroid) {
return _saveImageAndroid(path, context);
} else {
throw Exception("only mobile");
}
}
Future _saveImageAndroid(String path, BuildContext context) async {
late bool g;
if (androidVersion < 30) {
g = await Permission.storage.request().isGranted;
} else {
g = await Permission.manageExternalStorage.request().isGranted;
}
if (!g) {
return;
}
return method.androidSaveFileToImage(path);
}
/// 选择一个文件夹用于保存文件
Future chooseFolder(BuildContext context) async {
return FilePicker.platform.getDirectoryPath(
dialogTitle: tr('app.choose_folder'),
initialDirectory:
Directory.fromUri(Uri.file(await currentChooserRoot())).absolute.path,
);
}
/// 复制对话框
void confirmCopy(BuildContext context, String content) async {
if (copySkipConfirm()) {
copyToClipBoardTips(context, content);
} else {
if (await confirmDialog(context, tr('app.copy'), content)) {
copyToClipBoard(context, content);
}
}
}
================================================
FILE: lib/basic/Entities.dart
================================================
import 'dart:convert';
/// 图片
class RemoteImageInfo {
late String originalName;
late String path;
late String fileServer;
RemoteImageInfo.fromJson(Map json) {
this.originalName = json["originalName"];
this.path = json["path"];
this.fileServer = json["fileServer"];
}
Map toJson() {
final _data = {};
_data['originalName'] = originalName;
_data['path'] = path;
_data['fileServer'] = fileServer;
return _data;
}
}
/// 用户基本信息
class BasicUser {
late String id;
late String gender;
late String name;
late String title;
late bool verified;
late int exp;
late int level;
late List characters;
late RemoteImageInfo avatar;
late String? slogan;
BasicUser.fromJson(Map json) {
this.id = json["_id"];
this.gender = json["gender"];
this.name = json["name"];
this.title = json["title"];
this.verified = json["verified"];
this.exp = json["exp"];
this.level = json["level"];
this.characters = json["characters"] == null
? []
: List.of(json["characters"]).map((e) => "$e").toList();
this.avatar =
RemoteImageInfo.fromJson(Map.of(json["avatar"]));
this.slogan = json["slogan"];
}
}
/// 用户自己的信息
class UserProfile extends BasicUser {
late String birthday;
late String email;
late String createdAt;
late bool isPunched;
UserProfile.fromJson(Map json) : super.fromJson(json) {
this.birthday = json["birthday"];
this.email = json["email"];
this.createdAt = json["created_at"];
this.isPunched = json["isPunched"];
}
}
/// 分页
class Page {
late int total;
late int limit;
late int page;
late int pages;
Page.fromJson(Map json) {
this.total = json["total"];
this.limit = json["limit"];
this.page = json["page"];
this.pages = json["pages"];
}
Page.of(this.total, this.limit, this.page, this.pages);
}
/// 分类
class Category {
late String id;
late String title;
late String description;
late RemoteImageInfo thumb;
late bool isWeb;
late bool active;
late String link;
Category.fromJson(Map json) {
this.id = json["_id"];
this.title = json["title"];
this.description = json["description"];
this.thumb = RemoteImageInfo.fromJson(json["thumb"]);
this.isWeb = json["isWeb"];
this.active = json["active"];
this.link = json["link"];
}
}
/// 漫画分页
class ComicsPage extends Page {
late List docs;
ComicsPage.fromJson(Map json) : super.fromJson(json) {
this.docs = List.from(json["docs"])
.map((e) => Map.from(e))
.map((e) => ComicSimple.fromJson(e))
.toList();
}
}
/// 漫画基本信息
class ComicSimple {
late String id;
late String title;
late String author;
late int pagesCount;
late int epsCount;
late bool finished;
late List categories;
late RemoteImageInfo thumb;
late int likesCount;
ComicSimple.fromJson(Map json) {
this.id = json["_id"];
this.title = json["title"];
this.author = json["author"];
this.pagesCount = json["pagesCount"];
this.epsCount = json["epsCount"];
this.finished = json["finished"];
this.categories = List.from(json["categories"]);
this.thumb = RemoteImageInfo.fromJson(json["thumb"]);
this.likesCount = json["likesCount"];
}
}
/// 漫画详情
class ComicInfo extends ComicSimple {
late String description;
late String chineseTeam;
late List tags;
late String updatedAt;
late String createdAt;
late bool allowDownload;
late int viewsCount;
late bool isFavourite;
late bool isLiked;
late int commentsCount;
late Creator creator;
ComicInfo.fromJson(Map json) : super.fromJson(json) {
this.description = json["description"];
this.chineseTeam = json["chineseTeam"];
this.tags = List.from(json["tags"]);
this.updatedAt = (json["updated_at"]);
this.createdAt = (json["created_at"]);
this.allowDownload = json["allowDownload"];
this.viewsCount = json["viewsCount"];
this.isFavourite = json["isFavourite"];
this.isLiked = json["isLiked"];
this.commentsCount = json["commentsCount"];
this.creator = Creator.fromJson(Map.of(json["_creator"]));
}
}
/// 漫画创建人信息
class Creator extends BasicUser {
late String role;
late String character;
Creator.fromJson(Map json) : super.fromJson(json) {
this.role = json["role"];
this.character = json["character"];
}
}
/// 漫画章节
class Ep {
late String id;
late String title;
late int order;
late String updatedAt;
Ep.fromJson(Map json) {
this.id = json["_id"];
this.title = json["title"];
this.order = json["order"];
this.updatedAt = (json["updated_at"]);
}
}
/// 漫画章节分页
class EpPage extends Page {
late List docs;
EpPage.fromJson(Map json) : super.fromJson(json) {
this.docs = List.from(json["docs"])
.map((e) => Map.from(e))
.map((e) => Ep.fromJson(e))
.toList();
}
}
/// 漫画图片分页
class PicturePage extends Page {
late List docs;
PicturePage.fromJson(Map json) : super.fromJson(json) {
this.docs = List.from(json["docs"])
.map((e) => Map.from(e))
.map((e) => Picture.fromJson(e))
.toList();
}
}
/// 漫画图片信息
class Picture {
late String id;
late RemoteImageInfo media;
Picture.fromJson(Map json) {
this.id = json["_id"];
this.media = RemoteImageInfo.fromJson(json["media"]);
}
}
/// 显示图片数据
class RemoteImageData {
late int fileSize;
late String format;
late int width;
late int height;
late String finalPath;
RemoteImageData.forData(
this.fileSize,
this.format,
this.width,
this.height,
this.finalPath,
);
RemoteImageData.fromJson(Map json) {
this.fileSize = json["fileSize"];
this.format = json["format"];
this.width = json["width"];
this.height = json["height"];
this.finalPath = json["finalPath"];
}
}
/// 漫画评论分页
class CommentPage extends Page {
late List docs;
CommentPage.fromJson(Map json) : super.fromJson(json) {
this.docs = List.from(json["docs"])
.map((e) => Map.from(e))
.map((e) => Comment.fromJson(e))
.toList();
}
}
class CommentBase {
late String id;
late String content;
late CommentUser user;
late bool isTop;
late bool hide;
late String createdAt;
late int likesCount;
late int commentsCount;
late bool isLiked;
CommentBase.fromJson(Map json) {
this.id = json["_id"];
this.content = json["content"];
this.user = CommentUser.fromJson(Map.of(json["_user"]));
this.isTop = json["isTop"];
this.hide = json["hide"];
this.createdAt = json["created_at"];
this.likesCount = json["likesCount"];
this.commentsCount = json["commentsCount"];
this.isLiked = json["isLiked"];
}
}
/// 子评论
class ChildOfComment extends CommentBase {
late String parent;
ChildOfComment.fromJson(Map json) : super.fromJson(json) {
this.parent = json["_parent"];
}
}
/// 漫画评论详情
class Comment extends CommentBase {
late String comic;
Comment.fromJson(Map json) : super.fromJson(json) {
this.comic = json["_comic"];
}
}
/// 评论的用户信息
class CommentUser extends BasicUser {
late String role;
CommentUser.fromJson(Map json) : super.fromJson(json) {
this.role = json["role"];
}
}
/// 已下载图片的信息
class DownloadPicture {
late int rankInEp;
late String fileServer;
late String path;
late String localPath;
late int width;
late int height;
late String format;
late int fileSize;
DownloadPicture.fromJson(Map json) {
this.rankInEp = json["rankInEp"];
this.fileServer = json["fileServer"];
this.path = json["path"];
this.localPath = json["localPath"];
this.width = json["width"];
this.height = json["height"];
this.format = json["format"];
this.fileSize = json["fileSize"];
}
}
/// 浏览历史记录
class ViewLog {
late String id;
late String title;
late String author;
late int pagesCount;
late int epsCount;
late bool finished;
late String categories;
late String thumbOriginalName;
late String thumbFileServer;
late String thumbPath;
late String description;
late String chineseTeam;
late String tags;
late String lastViewTime;
late int lastViewEpOrder;
late String lastViewEpTitle;
late int lastViewPictureRank;
ViewLog.fromJson(Map json) {
this.id = json["id"];
this.title = json["title"];
this.author = json["author"];
this.pagesCount = json["pagesCount"];
this.epsCount = json["epsCount"];
this.finished = json["finished"];
this.categories = json["categories"];
this.thumbOriginalName = json["thumbOriginalName"];
this.thumbFileServer = json["thumbFileServer"];
this.thumbPath = json["thumbPath"];
this.description = json["description"];
this.chineseTeam = json["chineseTeam"];
this.tags = json["tags"];
this.lastViewTime = json["lastViewTime"];
this.lastViewEpOrder = json["lastViewEpOrder"];
this.lastViewEpTitle = json["lastViewEpTitle"];
this.lastViewPictureRank = json["lastViewPictureRank"];
}
}
/// 已下载漫画的信息
class DownloadComic {
late String id;
late String createdAt;
late String updatedAt;
late String title;
late String author;
late int pagesCount;
late int epsCount;
late bool finished;
late String categories;
late String thumbOriginalName;
late String thumbFileServer;
late String thumbPath;
late String thumbLocalPath;
late String description;
late String chineseTeam;
late String tags;
late int selectedEpCount;
late int selectedPictureCount;
late int downloadEpCount;
late int downloadPictureCount;
late bool downloadFinished;
late String downloadFinishedTime;
late bool downloadFailed;
late bool deleting;
void copy(DownloadComic other) {
this.id = other.id;
this.createdAt = other.createdAt;
this.updatedAt = other.updatedAt;
this.title = other.title;
this.author = other.author;
this.pagesCount = other.pagesCount;
this.epsCount = other.epsCount;
this.finished = other.finished;
this.categories = other.categories;
this.thumbOriginalName = other.thumbOriginalName;
this.thumbFileServer = other.thumbFileServer;
this.thumbPath = other.thumbPath;
this.description = other.description;
this.chineseTeam = other.chineseTeam;
this.tags = other.tags;
this.selectedEpCount = other.selectedEpCount;
this.selectedPictureCount = other.selectedPictureCount;
this.downloadEpCount = other.downloadEpCount;
this.downloadPictureCount = other.downloadPictureCount;
this.downloadFinished = other.downloadFinished;
this.downloadFinishedTime = other.downloadFinishedTime;
this.downloadFailed = other.downloadFailed;
this.thumbLocalPath = other.thumbLocalPath;
// this.deleting = other.deleting;
}
DownloadComic.fromJson(Map json) {
this.id = json["id"];
this.createdAt = (json["createdAt"]);
this.updatedAt = (json["updatedAt"]);
this.title = json["title"];
this.author = json["author"];
this.pagesCount = json["pagesCount"];
this.epsCount = json["epsCount"];
this.finished = json["finished"];
this.categories = json["categories"];
this.thumbOriginalName = json["thumbOriginalName"];
this.thumbFileServer = json["thumbFileServer"];
this.thumbPath = json["thumbPath"];
this.description = json["description"];
this.chineseTeam = json["chineseTeam"];
this.tags = json["tags"];
this.selectedEpCount = json["selectedEpCount"];
this.selectedPictureCount = json["selectedPictureCount"];
this.downloadEpCount = json["downloadEpCount"];
this.downloadPictureCount = json["downloadPictureCount"];
this.downloadFinished = json["downloadFinished"];
this.downloadFinishedTime = json["downloadFinishedTime"];
this.downloadFailed = json["downloadFailed"];
this.deleting = json["deleting"];
this.thumbLocalPath = json["thumbLocalPath"];
}
}
/// 已下载的章节信息
class DownloadEp {
late String comicId;
late String id;
late String updatedAt;
late int epOrder;
late String title;
late bool fetchedPictures;
late int selectedPictureCount;
late int downloadPictureCount;
late bool downloadFinish;
late String downloadFinishTime;
late bool downloadFailed;
DownloadEp.fromJson(Map json) {
this.comicId = json["comicId"];
this.id = json["id"];
this.epOrder = json["epOrder"];
this.title = json["title"];
this.fetchedPictures = json["fetchedPictures"];
this.selectedPictureCount = json["selectedPictureCount"];
this.downloadPictureCount = json["downloadPictureCount"];
this.downloadFinish = json["downloadFinish"];
this.downloadFinishTime = json["downloadFinishTime"];
this.downloadFailed = json["downloadFailed"];
}
}
/// 游戏的分页
class GamePage extends Page {
late List docs;
GamePage.fromJson(Map json) : super.fromJson(json) {
this.docs = List.of(json["docs"])
.map((e) => Map.of(e))
.map((e) => GameSimple.fromJson(e))
.toList();
}
}
/// 游戏的简要信息
class GameSimple {
late String id;
late String title;
late String version;
late RemoteImageInfo icon;
late String publisher;
late bool adult;
late bool suggest;
late int likesCount;
late bool android;
late bool ios;
GameSimple.fromJson(Map json) {
this.id = json["_id"];
this.title = json["title"];
this.version = json["version"];
this.icon = RemoteImageInfo.fromJson(json["icon"]);
this.publisher = json["publisher"];
this.adult = json["adult"];
this.suggest = json["suggest"];
this.likesCount = json["likesCount"];
this.android = json["android"];
this.ios = json["ios"];
}
}
/// 游戏详情
class GameInfo extends GameSimple {
late String description;
late String updateContent;
late String videoLink;
late List screenshots;
late int commentsCount;
late int downloadsCount;
late bool isLiked;
late List androidLinks;
late double androidSize;
late List iosLinks;
late double iosSize;
late String updatedAt;
late String createdAt;
GameInfo.fromJson(Map json) : super.fromJson(json) {
this.description = json["description"];
this.updateContent = json["updateContent"];
this.videoLink = json["videoLink"];
this.screenshots = List.of(json["screenshots"])
.map((e) => Map.of(e))
.map((e) => RemoteImageInfo.fromJson(e))
.toList();
this.commentsCount = json["commentsCount"];
this.downloadsCount = json["downloadsCount"];
this.isLiked = json["isLiked"];
this.androidLinks = List.of(json["androidLinks"]).map((e) => "$e").toList();
this.androidSize = double.parse(json["androidSize"].toString());
this.iosLinks = List.of(json["iosLinks"]).map((e) => "$e").toList();
this.iosSize = double.parse(json["iosSize"].toString());
this.updatedAt = json["updated_at"];
this.createdAt = json["created_at"];
}
}
/// 我的评论页面分页
class MyCommentsPage extends Page {
late List docs;
MyCommentsPage.fromJson(Map json) : super.fromJson(json) {
this.docs =
List.of(json["docs"]).map((e) => MyComment.fromJson(e)).toList();
}
}
/// 我的评论
class MyComment {
late String id;
late String content;
late bool hide;
late String createdAt;
late int likesCount;
late int commentsCount;
late bool isLiked;
late MyCommentComic comic;
MyComment.fromJson(Map json) {
this.id = json["_id"];
this.content = json["content"];
this.hide = json["hide"];
this.createdAt = json["created_at"];
this.likesCount = json["likesCount"];
this.commentsCount = json["commentsCount"];
this.isLiked = json["isLiked"];
this.comic = MyCommentComic.fromJson(json["_comic"]);
}
}
/// 我的评论漫画简要信息
class MyCommentComic {
late String id;
late String title;
MyCommentComic.fromJson(Map json) {
this.id = json["_id"];
this.title = json["title"];
}
}
/// 子评论分页
class CommentChildrenPage extends Page {
late List docs;
CommentChildrenPage.fromJson(Map json)
: super.fromJson(json) {
this.docs = [];
if (json["docs"] != null) {
docs.addAll(
List.of(json["docs"]).map((e) => CommentChild.fromJson(e)).toList());
}
}
}
/// 子评论
class CommentChild extends ChildOfComment {
late String comic;
CommentChild.fromJson(Map json) : super.fromJson(json) {
this.comic = json["_comic"];
}
}
/// 漫画评论分页
class GameCommentPage extends Page {
late List docs;
GameCommentPage.fromJson(Map json) : super.fromJson(json) {
this.docs = List.from(json["docs"])
.map((e) => Map.from(e))
.map((e) => GameComment.fromJson(e))
.toList();
}
}
/// 游戏评论
class GameComment extends CommentBase {
late String game;
GameComment.fromJson(Map json) : super.fromJson(json) {
this.game = json["_game"];
}
}
/// 子评论分页
class GameCommentChildrenPage extends Page {
late List docs;
GameCommentChildrenPage.fromJson(Map json)
: super.fromJson(json) {
this.docs = [];
if (json["docs"] != null) {
docs.addAll(List.of(json["docs"])
.map((e) => GameCommentChild.fromJson(e))
.toList());
}
}
}
/// 子评论
class GameCommentChild extends ChildOfComment {
late String game;
GameCommentChild.fromJson(Map json) : super.fromJson(json) {
this.game = json["_game"];
}
}
class Collection {
late String title;
late List comics;
Collection.fromJson(Map json) {
this.title = json["title"];
this.comics = List.from(json["comics"])
.map((e) => Map.from(e))
.map((e) => ComicSimple.fromJson(e))
.toList();
}
}
class PkzArchive {
PkzArchive({
required this.coverPath,
required this.authorAvatarPath,
required this.comics,
required this.comicCount,
required this.volumesCount,
required this.chapterCount,
required this.pictureCount,
});
late final String coverPath;
late final String authorAvatarPath;
late final List comics;
late final int comicCount;
late final int volumesCount;
late final int chapterCount;
late final int pictureCount;
PkzArchive.fromJson(Map json) {
coverPath = json['cover_path'];
authorAvatarPath = json['author_avatar_path'];
comics =
List.from(json['comics']).map((e) => PkzComic.fromJson(e)).toList();
comicCount = json['comic_count'];
volumesCount = json['volumes_count'];
chapterCount = json['chapter_count'];
pictureCount = json['picture_count'];
}
Map toJson() {
final _data = {};
_data['cover_path'] = coverPath;
_data['author_avatar_path'] = authorAvatarPath;
_data['comics'] = comics.map((e) => e.toJson()).toList();
_data['comic_count'] = comicCount;
_data['volumes_count'] = volumesCount;
_data['chapter_count'] = chapterCount;
_data['picture_count'] = pictureCount;
return _data;
}
}
class PkzComic {
PkzComic({
required this.id,
required this.title,
required this.categories,
required this.tags,
required this.updatedAt,
required this.createdAt,
required this.description,
required this.chineseTeam,
required this.finished,
required this.coverPath,
required this.authorAvatarPath,
required this.volumes,
required this.volumesCount,
required this.chapterCount,
required this.pictureCount,
required this.idx,
});
late final String id;
late final String title;
late final List categories;
late final List tags;
late final int updatedAt;
late final int createdAt;
late final String description;
late final String chineseTeam;
late final bool finished;
late final String coverPath;
late final String authorAvatarPath;
late final List volumes;
late final int volumesCount;
late final int chapterCount;
late final int pictureCount;
late final int idx;
late final String author;
late final String authorId;
PkzComic.fromJson(Map json) {
id = json['id'];
title = json['title'];
categories = List.castFrom(json['categories']);
tags = List.castFrom(json['tags']);
updatedAt = json['updated_at'];
createdAt = json['created_at'];
description = json['description'];
chineseTeam = json['chinese_team'];
finished = json['finished'];
coverPath = json['cover_path'];
authorAvatarPath = json['author_avatar_path'];
volumes =
List.from(json['volumes']).map((e) => PkzVolume.fromJson(e)).toList();
volumesCount = json['volumes_count'];
chapterCount = json['chapter_count'];
pictureCount = json['picture_count'];
idx = json['idx'];
author = json['author'];
authorId = json['author_id'];
}
Map toJson() {
final _data = {};
_data['id'] = id;
_data['title'] = title;
_data['categories'] = categories;
_data['tags'] = tags;
_data['updated_at'] = updatedAt;
_data['created_at'] = createdAt;
_data['description'] = description;
_data['chinese_team'] = chineseTeam;
_data['finished'] = finished;
_data['cover_path'] = coverPath;
_data['author_avatar_path'] = authorAvatarPath;
_data['volumes'] = volumes.map((e) => e.toJson()).toList();
_data['volumes_count'] = volumesCount;
_data['chapter_count'] = chapterCount;
_data['picture_count'] = pictureCount;
_data['idx'] = idx;
_data['author'] = author;
_data['author_id'] = authorId;
return _data;
}
}
class PkzVolume {
PkzVolume({
required this.id,
required this.title,
required this.updatedAt,
required this.createdAt,
required this.coverPath,
required this.chapters,
required this.chapterCount,
required this.pictureCount,
required this.idx,
});
late final String id;
late final String title;
late final int updatedAt;
late final int createdAt;
late final String coverPath;
late final List chapters;
late final int chapterCount;
late final int pictureCount;
late final int idx;
PkzVolume.fromJson(Map json) {
id = json['id'];
title = json['title'];
updatedAt = json['updated_at'];
createdAt = json['created_at'];
coverPath = json['cover_path'];
chapters =
List.from(json['chapters']).map((e) => PkzChapter.fromJson(e)).toList();
chapterCount = json['chapter_count'];
pictureCount = json['picture_count'];
idx = json['idx'];
}
Map toJson() {
final _data = {};
_data['id'] = id;
_data['title'] = title;
_data['updated_at'] = updatedAt;
_data['created_at'] = createdAt;
_data['cover_path'] = coverPath;
_data['chapters'] = chapters.map((e) => e.toJson()).toList();
_data['chapter_count'] = chapterCount;
_data['picture_count'] = pictureCount;
_data['idx'] = idx;
return _data;
}
}
class PkzChapter {
PkzChapter({
required this.id,
required this.title,
required this.updatedAt,
required this.createdAt,
required this.coverPath,
required this.pictures,
required this.pictureCount,
required this.idx,
});
late final String id;
late final String title;
late final int updatedAt;
late final int createdAt;
late final String coverPath;
late final List pictures;
late final int pictureCount;
late final int idx;
PkzChapter.fromJson(Map json) {
id = json['id'];
title = json['title'];
updatedAt = json['updated_at'];
createdAt = json['created_at'];
coverPath = json['cover_path'];
pictures =
List.from(json['pictures']).map((e) => PkzPicture.fromJson(e)).toList();
pictureCount = json['picture_count'];
idx = json['idx'];
}
Map toJson() {
final _data = {};
_data['id'] = id;
_data['title'] = title;
_data['updated_at'] = updatedAt;
_data['created_at'] = createdAt;
_data['cover_path'] = coverPath;
_data['pictures'] = pictures.map((e) => e.toJson()).toList();
_data['picture_count'] = pictureCount;
_data['idx'] = idx;
return _data;
}
}
class PkzPicture {
PkzPicture({
required this.id,
required this.title,
required this.width,
required this.height,
required this.format,
required this.picturePath,
required this.idx,
});
late final String id;
late final String title;
late final int width;
late final int height;
late final String format;
late final String picturePath;
late final int idx;
PkzPicture.fromJson(Map json) {
id = json['id'];
title = json['title'];
width = json['width'];
height = json['height'];
format = json['format'];
picturePath = json['picture_path'];
idx = json['idx'];
}
Map toJson() {
final _data = {};
_data['id'] = id;
_data['title'] = title;
_data['width'] = width;
_data['height'] = height;
_data['format'] = format;
_data['picture_path'] = picturePath;
_data['idx'] = idx;
return _data;
}
}
class Knight extends BasicUser {
late final String role;
late final String character;
late final int comicsUploaded;
Knight.fromJson(Map json) : super.fromJson(json) {
role = json['role'];
character = json['character'];
comicsUploaded = json['comicsUploaded'];
}
}
class PkzComicViewLog {
PkzComicViewLog({
required this.fileName,
required this.lastViewComicId,
required this.filePath,
required this.lastViewComicTitle,
required this.lastViewEpId,
required this.lastViewEpName,
required this.lastViewPictureRank,
required this.lastViewTime,
});
late final String fileName;
late final String lastViewComicId;
late final String filePath;
late final String lastViewComicTitle;
late final String lastViewEpId;
late final String lastViewEpName;
late final int lastViewPictureRank;
late final String lastViewTime;
PkzComicViewLog.fromJson(Map json) {
fileName = json['fileName'];
lastViewComicId = json['lastViewComicId'];
filePath = json['filePath'];
lastViewComicTitle = json['lastViewComicTitle'];
lastViewEpId = json['lastViewEpId'];
lastViewEpName = json['lastViewEpName'];
lastViewPictureRank = json['lastViewPictureRank'];
lastViewTime = json['lastViewTime'];
}
Map toJson() {
final _data = {};
_data['fileName'] = fileName;
_data['lastViewComicId'] = lastViewComicId;
_data['filePath'] = filePath;
_data['lastViewComicTitle'] = lastViewComicTitle;
_data['lastViewEpId'] = lastViewEpId;
_data['lastViewEpName'] = lastViewEpName;
_data['lastViewPictureRank'] = lastViewPictureRank;
_data['lastViewTime'] = lastViewTime;
return _data;
}
}
class ProInfoAll {
ProInfoAll({
required this.proInfoAf,
required this.proInfoPat,
});
late final ProInfoAf proInfoAf;
late final ProInfoPat proInfoPat;
ProInfoAll.fromJson(Map json) {
proInfoAf = ProInfoAf.fromJson(json['pro_info_af']);
proInfoPat = ProInfoPat.fromJson(json['pro_info_pat']);
}
Map toJson() {
final _data = {};
_data['pro_info_normal'] = proInfoAf.toJson();
_data['pro_info_pat'] = proInfoPat.toJson();
return _data;
}
}
class ProInfoAf {
ProInfoAf({
required this.isPro,
required this.expire,
});
late final bool isPro;
late final int expire;
ProInfoAf.fromJson(Map json) {
isPro = json['is_pro'];
expire = json['expire'];
}
Map toJson() {
final _data = {};
_data['is_pro'] = isPro;
_data['expire'] = expire;
return _data;
}
}
class ProInfoPat {
ProInfoPat({
required this.isPro,
required this.patId,
required this.bindUid,
required this.requestDelete,
required this.reBind,
required this.errorType,
required this.errorMsg,
required this.accessKey,
});
late final bool isPro;
late final String patId;
late final String bindUid;
late final int requestDelete;
late final int reBind;
late final int errorType;
late final String errorMsg;
late final String accessKey;
ProInfoPat.fromJson(Map json) {
isPro = json['is_pro'];
patId = json['pat_id'];
bindUid = json['bind_uid'];
requestDelete = json['request_delete'];
reBind = json['re_bind'];
errorType = json['error_type'];
errorMsg = json['error_msg'];
accessKey = json['access_key'];
}
Map toJson() {
final _data = {};
_data['is_pro'] = isPro;
_data['pat_id'] = patId;
_data['bind_uid'] = bindUid;
_data['request_delete'] = requestDelete;
_data['re_bind'] = reBind;
_data['error_type'] = errorType;
_data['error_msg'] = errorMsg;
_data['access_key'] = accessKey;
return _data;
}
}
class ForgotPasswordResult {
ForgotPasswordResult({
required this.question1,
required this.question2,
required this.question3,
});
late final String question1;
late final String question2;
late final String question3;
ForgotPasswordResult.fromJson(Map json) {
question1 = json['question1'];
question2 = json['question2'];
question3 = json['question3'];
}
Map toJson() {
final _data = {};
_data['question1'] = question1;
_data['question2'] = question2;
_data['question3'] = question3;
return _data;
}
}
class ResetPasswordResult {
ResetPasswordResult({
required this.password,
});
late final String password;
ResetPasswordResult.fromJson(Map json) {
password = json['password'];
}
Map toJson() {
final _data = {};
_data['password'] = password;
return _data;
}
}
/// 订阅
class ComicSubscribe {
late String id;
late String title;
late String author;
late int pagesCount;
late int epsCount;
late bool finished;
late String categories;
late String thumbOriginalName;
late String thumbFileServer;
late String thumbPath;
late String description;
late String chineseTeam;
late String tags;
late int likesCount;
late String subscribeTime;
late String updateSubscribeTime;
late int newEpCount;
ComicSubscribe.fromJson(Map json) {
print(json);
this.id = json["id"];
this.title = json["title"];
this.author = json["author"];
this.pagesCount = json["pagesCount"];
this.epsCount = json["epsCount"];
this.finished = json["finished"];
this.categories = json["categories"];
this.thumbOriginalName = json["thumbOriginalName"];
this.thumbFileServer = json["thumbFileServer"];
this.thumbPath = json["thumbPath"];
this.description = json["description"];
this.chineseTeam = json["chineseTeam"];
this.tags = json["tags"];
this.likesCount = json["likesCount"];
this.subscribeTime = json["subscribeTime"];
this.updateSubscribeTime = json["updateSubscribeTime"];
this.newEpCount = json["newEpCount"];
}
Map toSimpleJson() {
final _data = {};
_data['id'] = id;
_data['_id'] = id;
_data['title'] = title;
_data['author'] = author;
_data['pagesCount'] = pagesCount;
_data['epsCount'] = epsCount;
_data['finished'] = finished;
_data['categories'] = jsonDecode(categories);
_data['thumbOriginalName'] = thumbOriginalName;
_data['thumbFileServer'] = thumbFileServer;
_data['thumbPath'] = thumbPath;
_data['description'] = description;
_data['chineseTeam'] = chineseTeam;
_data['tags'] = tags;
_data['likesCount'] = likesCount;
_data['thumb'] = jsonDecode(jsonEncode(RemoteImageInfo.fromJson({
"originalName": thumbOriginalName,
"fileServer": thumbFileServer,
"path": thumbPath
})));
_data['subscribeTime'] = subscribeTime;
_data['updateSubscribeTime'] = updateSubscribeTime;
_data['newEpCount'] = newEpCount;
return _data;
}
}
/// 本地收藏夹文件夹
class LocalFavoriteFolder {
late String id;
late String name;
late int createdAt;
late int updatedAt;
late int deletedAt;
LocalFavoriteFolder.fromJson(Map json) {
this.id = json["id"];
this.name = json["name"];
this.createdAt = json["createdAt"];
this.updatedAt = json["updatedAt"];
this.deletedAt = json["deletedAt"];
}
Map toJson() {
final _data = {};
_data['id'] = id;
_data['name'] = name;
_data['createdAt'] = createdAt;
_data['updatedAt'] = updatedAt;
_data['deletedAt'] = deletedAt;
return _data;
}
}
/// 本地收藏夹漫画
class LocalFavoriteComic {
late String comicId;
late String folderId;
String? info;
late int createdAt;
late int updatedAt;
late int deletedAt;
LocalFavoriteComic.fromJson(Map json) {
this.comicId = json["comicId"];
this.folderId = json["folderId"];
this.info = json["info"];
this.createdAt = json["createdAt"];
this.updatedAt = json["updatedAt"];
this.deletedAt = json["deletedAt"];
}
Map toJson() {
final _data = {};
_data['comicId'] = comicId;
_data['folderId'] = folderId;
_data['info'] = info;
_data['createdAt'] = createdAt;
_data['updatedAt'] = updatedAt;
_data['deletedAt'] = deletedAt;
return _data;
}
}
================================================
FILE: lib/basic/Method.dart
================================================
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:pikapika/basic/Entities.dart';
/// 使用MethodChannel与平台通信
final method = Method._();
class Method {
/// 禁止其他页面构造此类
Method._();
/// channel
final MethodChannel _channel = const MethodChannel("method");
/// 平铺调用, 为了直接与golang进行通信
Future _flatInvoke(String method, dynamic params) {
return _channel.invokeMethod("flatInvoke", {
"method": method,
"params": params is String ? params : jsonEncode(params),
});
}
/// 读取配置文件
Future loadProperty(String propertyName, String defaultValue) async {
return await _flatInvoke("loadProperty", {
"name": propertyName,
"defaultValue": defaultValue,
});
}
/// 远程推荐链接(来自 pikapika-config)
Future