mirror of
https://github.com/ZhuJHua/moodiary.git
synced 2026-04-05 16:39:01 +08:00
Compare commits
297 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8ce69011c | ||
|
|
4d93fe259b | ||
|
|
466a664157 | ||
|
|
7885b68415 | ||
|
|
8ef72433eb | ||
|
|
073e483112 | ||
|
|
967f652d9a | ||
|
|
64ca18ef44 | ||
|
|
c1948f888e | ||
|
|
2b7f750b4c | ||
|
|
ef3f0270a6 | ||
|
|
8d9f380ec5 | ||
|
|
2e206a9335 | ||
|
|
f642530bca | ||
|
|
13e3dc1bb2 | ||
|
|
ce319374a2 | ||
|
|
eee3cc03d8 | ||
|
|
372678fa82 | ||
|
|
9b3757dea1 | ||
|
|
cc4cee941d | ||
|
|
3be9f90575 | ||
|
|
87a7af08ff | ||
|
|
cf97917117 | ||
|
|
487972451c | ||
|
|
2eb6ab7409 | ||
|
|
f106154fe4 | ||
|
|
9524193261 | ||
|
|
59346795ae | ||
|
|
96682cb593 | ||
|
|
06b52fce5d | ||
|
|
9edc55a6c8 | ||
|
|
d25231c413 | ||
|
|
6584cca855 | ||
|
|
12e4e808da | ||
|
|
3266d9f438 | ||
|
|
c39f5b30f8 | ||
|
|
d5e5b94607 | ||
|
|
ddb6d8f2db | ||
|
|
a7f7601408 | ||
|
|
5edaf2f6cf | ||
|
|
b274622006 | ||
|
|
6de1968ddf | ||
|
|
aeef1e511c | ||
|
|
9589dc9e54 | ||
|
|
4abb85ad42 | ||
|
|
f9f2056d04 | ||
|
|
182008a678 | ||
|
|
0b1a9bf4c8 | ||
|
|
cd51e8922b | ||
|
|
8c9fe08128 | ||
|
|
8dc18c92cd | ||
|
|
2a9900556e | ||
|
|
0e46a830af | ||
|
|
41709c8832 | ||
|
|
316fa1119f | ||
|
|
0df58eed05 | ||
|
|
7d936ac1c3 | ||
|
|
4a1c2609ab | ||
|
|
28dc3e1114 | ||
|
|
cd78b4d64d | ||
|
|
e32bb156fe | ||
|
|
ab8f40b98f | ||
|
|
235f632670 | ||
|
|
af3bf29139 | ||
|
|
1afe59ac70 | ||
|
|
406e042411 | ||
|
|
8d95476d04 | ||
|
|
83049f598e | ||
|
|
047a3ac576 | ||
|
|
fe2f29c939 | ||
|
|
c631636472 | ||
|
|
ca9c553df1 | ||
|
|
4ca93f15ca | ||
|
|
9906d8c1af | ||
|
|
3a00ffa04f | ||
|
|
5328649b67 | ||
|
|
b3b3f526b4 | ||
|
|
1f438e5c52 | ||
|
|
c4f5cf7d96 | ||
|
|
443de5d35a | ||
|
|
c424839453 | ||
|
|
6d9489076e | ||
|
|
cb43f50ea5 | ||
|
|
b6e116418b | ||
|
|
574e7090cc | ||
|
|
77b9bd5005 | ||
|
|
7c6f704895 | ||
|
|
7ed54ddf95 | ||
|
|
d992cc173d | ||
|
|
1671c3c770 | ||
|
|
89f9045e30 | ||
|
|
80ad276634 | ||
|
|
3fb5573a7c | ||
|
|
9b72ceaa6e | ||
|
|
8047c391b3 | ||
|
|
ea053f5a73 | ||
|
|
31560b783f | ||
|
|
d25d8c8269 | ||
|
|
fae6316f55 | ||
|
|
63ba3c2b68 | ||
|
|
827fd89ddc | ||
|
|
5bf5f36f9d | ||
|
|
84d1bb5802 | ||
|
|
ee1e240f6d | ||
|
|
5f5e6b90ed | ||
|
|
512cd622f7 | ||
|
|
5b9ca30c95 | ||
|
|
348fe883ab | ||
|
|
64a65f39b6 | ||
|
|
acca62a525 | ||
|
|
cd78ab72c4 | ||
|
|
9c20ee729c | ||
|
|
a2c92ef947 | ||
|
|
42fe3ab33b | ||
|
|
738d13d67d | ||
|
|
e7ea753e78 | ||
|
|
39e52878e1 | ||
|
|
744e7464e1 | ||
|
|
a6c91f2316 | ||
|
|
10e0da1861 | ||
|
|
ccf2ec85dd | ||
|
|
bcdbabc8d4 | ||
|
|
80cd02e0fe | ||
|
|
abbd48d600 | ||
|
|
f172e0791a | ||
|
|
e5578bdeae | ||
|
|
b9d694ca50 | ||
|
|
827c98d177 | ||
|
|
e9992128c7 | ||
|
|
12e5dbdaad | ||
|
|
cdf39298f9 | ||
|
|
fe6267bf29 | ||
|
|
e53c379502 | ||
|
|
b3d1b53fb1 | ||
|
|
1c374b7a84 | ||
|
|
7597ff5194 | ||
|
|
6ce64f8b46 | ||
|
|
545891fe55 | ||
|
|
610b983e12 | ||
|
|
905a398e7e | ||
|
|
6b1aa8c07d | ||
|
|
2176e96c2d | ||
|
|
c0fe3d31a3 | ||
|
|
75dfb05e6c | ||
|
|
9ba802a6ae | ||
|
|
0029932e85 | ||
|
|
09b979493c | ||
|
|
97dd44856c | ||
|
|
cebab37e0a | ||
|
|
3006aa2dda | ||
|
|
527767e1ab | ||
|
|
1f08c317b9 | ||
|
|
5dc836ecce | ||
|
|
5154db3269 | ||
|
|
b5be93fa56 | ||
|
|
cb1bb4b891 | ||
|
|
5ded722d5c | ||
|
|
6ae4b4a45f | ||
|
|
7acbc7854d | ||
|
|
1374ae8a64 | ||
|
|
4436162bd7 | ||
|
|
e3066748d4 | ||
|
|
f6fbdf8c4c | ||
|
|
7523cd0f6b | ||
|
|
a1ad810e0f | ||
|
|
e9498646e2 | ||
|
|
4e05adca5d | ||
|
|
ac23cdaeb1 | ||
|
|
74b8f4db3b | ||
|
|
9daf5dfe4b | ||
|
|
bfb5429f76 | ||
|
|
c3aac55752 | ||
|
|
86f3ecbfb9 | ||
|
|
13348fd880 | ||
|
|
77bfab6584 | ||
|
|
6649f04ae3 | ||
|
|
a1379eb474 | ||
|
|
28bffec383 | ||
|
|
9ee9e78974 | ||
|
|
e563afc43a | ||
|
|
c6bc93fdbd | ||
|
|
ac01624def | ||
|
|
4e662f9b96 | ||
|
|
9a5b85cc02 | ||
|
|
676ea4d763 | ||
|
|
fb77e91a33 | ||
|
|
1e220f67c3 | ||
|
|
5f62a228f0 | ||
|
|
be911fbd17 | ||
|
|
509d8f17e2 | ||
|
|
c6022db034 | ||
|
|
686bd4f41a | ||
|
|
042da7d659 | ||
|
|
00395a27ac | ||
|
|
93a4325aec | ||
|
|
0b5aa5f762 | ||
|
|
c9fd39561f | ||
|
|
ad32aa616a | ||
|
|
41e6113a0a | ||
|
|
5cba840f80 | ||
|
|
2478c9c932 | ||
|
|
67bf72284f | ||
|
|
022c4bb60d | ||
|
|
5fe6d66d48 | ||
|
|
3584cca5c9 | ||
|
|
58ca34bcf9 | ||
|
|
3c05149bed | ||
|
|
4e525f4d30 | ||
|
|
6ff78e4538 | ||
|
|
502df877c1 | ||
|
|
875edb6dba | ||
|
|
7a2fe21a21 | ||
|
|
c9d626ed3d | ||
|
|
0d0c95b78c | ||
|
|
aa40bdb9ab | ||
|
|
f22231ff33 | ||
|
|
feed024495 | ||
|
|
c94499ad43 | ||
|
|
c36a771405 | ||
|
|
c67b13ecd3 | ||
|
|
630849e189 | ||
|
|
2ce60b0a21 | ||
|
|
47a6eb8baa | ||
|
|
cd4e699878 | ||
|
|
b5978de312 | ||
|
|
bc5f9ee3b8 | ||
|
|
246b17ab68 | ||
|
|
d525ddaa70 | ||
|
|
0354e1af37 | ||
|
|
df1020b7ee | ||
|
|
ca0f81a09c | ||
|
|
7fee9ae8ae | ||
|
|
17a7ee7ed9 | ||
|
|
f7da792bdb | ||
|
|
1de5ae87ae | ||
|
|
f84f636529 | ||
|
|
3709b4fd57 | ||
|
|
6eba9a1a1e | ||
|
|
865234514e | ||
|
|
c4f5780dab | ||
|
|
b31c7415a9 | ||
|
|
581655b2dd | ||
|
|
3c5dea31ab | ||
|
|
e4c356560d | ||
|
|
e55358cfbf | ||
|
|
93d378637e | ||
|
|
589a87b30d | ||
|
|
51e87f9ae6 | ||
|
|
c0d3d60674 | ||
|
|
08df9bba04 | ||
|
|
1e4b75b414 | ||
|
|
137a1f3c98 | ||
|
|
59caeb3f28 | ||
|
|
042a715595 | ||
|
|
3a55579f33 | ||
|
|
7736c72780 | ||
|
|
cabb760599 | ||
|
|
86f337c0a2 | ||
|
|
784297f007 | ||
|
|
5af6d9080b | ||
|
|
074b2e0631 | ||
|
|
4f12267b3f | ||
|
|
9e1ffc49e3 | ||
|
|
b3dddaabda | ||
|
|
81657dbe69 | ||
|
|
76365ece09 | ||
|
|
671aa29b3c | ||
|
|
d285b74131 | ||
|
|
3b7c46c815 | ||
|
|
0222f7b352 | ||
|
|
c30b84f668 | ||
|
|
04c37d3465 | ||
|
|
b05c71a69c | ||
|
|
2cd0661ee9 | ||
|
|
ca40667068 | ||
|
|
7a5df7605e | ||
|
|
d6012c6499 | ||
|
|
be5814c6a0 | ||
|
|
3aab7784c6 | ||
|
|
df95b1e252 | ||
|
|
e103f3fd8b | ||
|
|
e951a59d9d | ||
|
|
b66ff57c07 | ||
|
|
8250c7a0bf | ||
|
|
822719bdeb | ||
|
|
f3e735b886 | ||
|
|
3e0f437a0e | ||
|
|
e3d27db92e | ||
|
|
25d0858a76 | ||
|
|
8365641f74 | ||
|
|
691ff9a65d | ||
|
|
793c248b2a | ||
|
|
123d1842dc | ||
|
|
b7906f0114 | ||
|
|
2b279f59af | ||
|
|
685bb4e2dd | ||
|
|
66de7b3daf |
49
.github/release-drafter.yml
vendored
Normal file
49
.github/release-drafter.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name-template: 'v$RESOLVED_VERSION'
|
||||
tag-template: 'v$RESOLVED_VERSION'
|
||||
|
||||
categories:
|
||||
- title: ✨ Features
|
||||
labels:
|
||||
- feat
|
||||
- title: 🐛 Bug Fixes
|
||||
labels:
|
||||
- fix
|
||||
- title: 🛠️ Chores
|
||||
labels:
|
||||
- chore
|
||||
- title: 📚 Documentation Updates
|
||||
labels:
|
||||
- docs
|
||||
- title: 🎨 Code Style Updates
|
||||
labels:
|
||||
- style
|
||||
- title: 🔨 Refactors
|
||||
labels:
|
||||
- refactor
|
||||
- title: ⚡ Performance Improvements
|
||||
labels:
|
||||
- perf
|
||||
- title: ✅ Tests
|
||||
labels:
|
||||
- test
|
||||
- title: 🏗️ Build System
|
||||
labels:
|
||||
- build
|
||||
- title: 🧹 CI/CD Changes
|
||||
labels:
|
||||
- ci
|
||||
- title: ⏪ Reverts
|
||||
labels:
|
||||
- revert
|
||||
- title: ❓ What is This
|
||||
labels:
|
||||
- '?'
|
||||
|
||||
change-template: '- $TITLE (#$NUMBER) by @$AUTHOR'
|
||||
template: |
|
||||
# 🔥 What's Changed
|
||||
|
||||
$CHANGES
|
||||
|
||||
---
|
||||
🔖 Compare Changes: [View Changes](https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION)
|
||||
33
.github/workflows/auto-merge.yml
vendored
Normal file
33
.github/workflows/auto-merge.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: Auto Merge
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- labeled
|
||||
- unlabeled
|
||||
- synchronize
|
||||
- opened
|
||||
- edited
|
||||
- ready_for_review
|
||||
- reopened
|
||||
- unlocked
|
||||
pull_request_review:
|
||||
types:
|
||||
- submitted
|
||||
check_suite:
|
||||
types:
|
||||
- completed
|
||||
status: { }
|
||||
jobs:
|
||||
automerge:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- id: automerge
|
||||
name: automerge
|
||||
uses: "pascalgn/automerge-action@v0.16.4"
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
MERGE_METHOD: "squash"
|
||||
MERGE_DELETE_BRANCH: "true"
|
||||
206
.github/workflows/build.yml
vendored
206
.github/workflows/build.yml
vendored
@@ -1,9 +1,6 @@
|
||||
name: Build & Release
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -13,7 +10,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set Up Java
|
||||
uses: actions/setup-java@v3
|
||||
@@ -21,10 +18,32 @@ jobs:
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
|
||||
- name: Install jq
|
||||
run: sudo apt-get install -y jq
|
||||
|
||||
- name: Read Flutter Version
|
||||
id: flutter_version
|
||||
run: |
|
||||
if [ -f .fvmrc ]; then
|
||||
FLUTTER_VERSION=$(cat .fvmrc | jq -r '.flutter')
|
||||
echo "Flutter version detected: $FLUTTER_VERSION"
|
||||
echo "flutter-version=$FLUTTER_VERSION" >> $GITHUB_ENV
|
||||
else
|
||||
echo ".fvmrc not found. Defaulting to latest Flutter version."
|
||||
echo "flutter-version=stable" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Set Up Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: '3.27.1'
|
||||
flutter-version: ${{ env.flutter-version }}
|
||||
|
||||
- name: Set Up Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
|
||||
- name: Install Dependencies
|
||||
run: flutter pub get
|
||||
@@ -42,137 +61,122 @@ jobs:
|
||||
run: flutter build apk --release --obfuscate --split-debug-info=splitMap
|
||||
|
||||
- name: Upload APK Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: android-apk
|
||||
path: build/app/outputs/flutter-apk/app-release.apk
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
name: Build Windows
|
||||
|
||||
# build-msix:
|
||||
# runs-on: windows-latest
|
||||
# name: Build MSIX
|
||||
# needs: build-apk
|
||||
#
|
||||
# steps:
|
||||
# - name: Checkout Repository
|
||||
# uses: actions/checkout@v3
|
||||
#
|
||||
# - name: Set Up Flutter
|
||||
# uses: subosito/flutter-action@v2
|
||||
# with:
|
||||
# flutter-version: '3.27.1'
|
||||
#
|
||||
# - name: Install Dependencies
|
||||
# run: flutter pub get
|
||||
#
|
||||
# - name: Build MSIX
|
||||
# run: flutter build windows --release
|
||||
#
|
||||
# - name: Upload MSIX Artifact
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: windows-msix
|
||||
# path: build/windows/runner/Release/*.msix
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# build-ios-macos:
|
||||
# runs-on: macos-latest
|
||||
# name: Build iOS & macOS
|
||||
# needs: build-apk
|
||||
#
|
||||
# steps:
|
||||
# - name: Checkout Repository
|
||||
# uses: actions/checkout@v3
|
||||
#
|
||||
# - name: Set Up Flutter
|
||||
# uses: subosito/flutter-action@v2
|
||||
# with:
|
||||
# flutter-version: '3.27.0-0.2.pre'
|
||||
#
|
||||
# - name: Install Dependencies
|
||||
# run: flutter pub get
|
||||
#
|
||||
# - name: Set Up Certificates and Profiles
|
||||
# run: |
|
||||
# echo "${{ secrets.CERTIFICATE }}" | base64 --decode > signing_certificate.p12
|
||||
# echo "${{ secrets.PROFILE }}" | base64 --decode > provisioning_profile.mobileprovision
|
||||
#
|
||||
# - name: Build iOS
|
||||
# run: flutter build ipa --release
|
||||
#
|
||||
# - name: Build macOS
|
||||
# run: flutter build macos --release
|
||||
#
|
||||
# - name: Upload iOS Artifact
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: ios-ipa
|
||||
# path: build/ios/ipa/*.ipa
|
||||
#
|
||||
# - name: Upload macOS Artifact
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: macos-app
|
||||
# path: build/macos/Build/Products/Release/*.app
|
||||
- name: Set Up Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "21"
|
||||
|
||||
- name: Read Flutter Version
|
||||
id: flutter_version
|
||||
run: |
|
||||
if (Test-Path .fvmrc) {
|
||||
$FLUTTER_VERSION = (Get-Content .fvmrc | ConvertFrom-Json).flutter
|
||||
echo "Flutter version detected: $FLUTTER_VERSION"
|
||||
echo "flutter-version=$FLUTTER_VERSION" >> $env:GITHUB_ENV
|
||||
} else {
|
||||
echo ".fvmrc not found. Defaulting to latest Flutter version."
|
||||
echo "flutter-version=stable" >> $env:GITHUB_ENV
|
||||
}
|
||||
|
||||
- name: Set Up Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: ${{ env.flutter-version }}
|
||||
|
||||
- name: Set Up Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
|
||||
- name: Install Dependencies
|
||||
run: flutter pub get
|
||||
|
||||
- name: Build Windows
|
||||
run: flutter build windows --release
|
||||
|
||||
- name: Create ZIP Archive
|
||||
run: |
|
||||
Compress-Archive -Path build\windows\x64\runner\Release\* -DestinationPath build\windows\moodiary-windows.zip
|
||||
|
||||
- name: Upload Windows Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-app
|
||||
path: build\windows\moodiary-windows.zip
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
name: Publish Release
|
||||
needs: [ build-apk ]
|
||||
needs: [ build-apk, build-windows ]
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# 下载构建产物
|
||||
- name: Download APK Artifact
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: android-apk
|
||||
path: artifacts/android
|
||||
|
||||
# - name: Download MSIX Artifact
|
||||
# uses: actions/download-artifact@v3
|
||||
# with:
|
||||
# name: windows-msix
|
||||
# path: artifacts/windows
|
||||
- name: Download Windows Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: windows-app
|
||||
path: artifacts/windows
|
||||
|
||||
# - name: Download iOS Artifact
|
||||
# uses: actions/download-artifact@v3
|
||||
# with:
|
||||
# name: ios-ipa
|
||||
# path: artifacts/ios
|
||||
#
|
||||
# - name: Download macOS Artifact
|
||||
# uses: actions/download-artifact@v3
|
||||
# with:
|
||||
# name: macos-app
|
||||
# path: artifacts/macos
|
||||
- name: Get Latest Tag
|
||||
id: latest_tag
|
||||
uses: actions-ecosystem/action-get-latest-tag@v1.6.0
|
||||
with:
|
||||
fetch-all-tags: true
|
||||
sort-tags: true
|
||||
|
||||
# 提取版本号
|
||||
- name: Extract Version
|
||||
id: extract_version
|
||||
- name: Extract Tag Version
|
||||
id: extract_tag_version
|
||||
run: |
|
||||
version=$(grep '^version: ' pubspec.yaml | cut -d ' ' -f 2 | tr -d '\r')
|
||||
tag="${{ steps.latest_tag.outputs.tag }}"
|
||||
version="${tag#v}"
|
||||
echo "VERSION=$version" >> $GITHUB_ENV
|
||||
|
||||
# 重命名构建产物
|
||||
- name: Rename Artifacts
|
||||
run: |
|
||||
mkdir -p renamed-artifacts
|
||||
mv artifacts/android/app-release.apk renamed-artifacts/moodiary-${{ env.VERSION }}-android-arm64.apk
|
||||
# mv artifacts/windows/*.msix renamed-artifacts/moodiary-${{ env.VERSION }}-windows-x64.msix
|
||||
# mv artifacts/ios/*.ipa renamed-artifacts/moodiary-${{ env.VERSION }}-ios.ipa
|
||||
# mv artifacts/macos/*.app renamed-artifacts/moodiary-${{ env.VERSION }}-macos.app
|
||||
mv artifacts/windows/moodiary-windows.zip renamed-artifacts/moodiary-${{ env.VERSION }}-windows-x64.zip
|
||||
|
||||
# 生成 Release Notes
|
||||
- name: Generate Release Notes
|
||||
id: release_notes
|
||||
uses: release-drafter/release-drafter@v5
|
||||
with:
|
||||
config-name: release-drafter.yml
|
||||
tag: v${{ env.VERSION }}
|
||||
publish: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# 发布 Release
|
||||
- name: Create Release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: renamed-artifacts/*
|
||||
tag: v${{ env.VERSION }}
|
||||
tag: v${{ env.VERSION }}
|
||||
name: v${{ env.VERSION }}
|
||||
body: ${{ steps.release_notes.outputs.body }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
28
.github/workflows/cargo-ci.yml
vendored
Normal file
28
.github/workflows/cargo-ci.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: Cargo CI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Run Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
|
||||
- name: Run cargo test
|
||||
working-directory: rust
|
||||
run: cargo test
|
||||
|
||||
- name: Fail on Errors
|
||||
if: failure()
|
||||
run: exit 1
|
||||
57
.github/workflows/cliff.yml
vendored
Normal file
57
.github/workflows/cliff.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
name: Git Cliff
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
types:
|
||||
- closed
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
changelog:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check if PR is merged
|
||||
run: |
|
||||
if [ "${{ github.event.pull_request.merged }}" == "true" ]; then
|
||||
echo "PR is merged, proceeding with changelog update."
|
||||
else
|
||||
echo "PR is not merged, skipping changelog update."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
- name: Generate changelog using Git Cliff
|
||||
uses: orhun/git-cliff-action@v4
|
||||
with:
|
||||
config: cliff.toml
|
||||
args: --verbose
|
||||
env:
|
||||
OUTPUT: CHANGELOG.md
|
||||
GITHUB_REPO: ${{ github.repository }}
|
||||
|
||||
- name: Commit and push changelog changes
|
||||
run: |
|
||||
git checkout -b changelog-update
|
||||
git config user.name 'github-actions[bot]'
|
||||
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
git add CHANGELOG.md
|
||||
git commit -m "Update changelog"
|
||||
git push https://${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git changelog-update
|
||||
|
||||
- name: Create Pull Request
|
||||
run: |
|
||||
gh pr create --base master --head changelog-update --title "Update changelog" --body "This PR updates the changelog based on recent changes." --label bot
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Auto Merge Pull Request
|
||||
run: |
|
||||
gh pr merge --merge --delete-branch "changelog-update"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
49
.github/workflows/flutter-ci.yml
vendored
Normal file
49
.github/workflows/flutter-ci.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: Flutter CI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
flutter-ci:
|
||||
name: Analyze and Run Tests
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install jq
|
||||
run: sudo apt-get install -y jq
|
||||
|
||||
- name: Read Flutter Version
|
||||
id: flutter_version
|
||||
run: |
|
||||
if [ -f .fvmrc ]; then
|
||||
FLUTTER_VERSION=$(cat .fvmrc | jq -r '.flutter')
|
||||
echo "Flutter version detected: $FLUTTER_VERSION"
|
||||
echo "flutter-version=$FLUTTER_VERSION" >> $GITHUB_ENV
|
||||
else
|
||||
echo ".fvmrc not found. Defaulting to latest Flutter version."
|
||||
echo "flutter-version=stable" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Set Up Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: ${{ env.flutter-version }}
|
||||
|
||||
- name: Install Dependencies
|
||||
run: flutter pub get
|
||||
|
||||
- name: Run Flutter Analyze
|
||||
run: flutter analyze
|
||||
|
||||
- name: Run Flutter Tests
|
||||
run: flutter test
|
||||
|
||||
- name: Fail on Errors
|
||||
if: failure()
|
||||
run: exit 1
|
||||
2
.github/workflows/issue.yml
vendored
2
.github/workflows/issue.yml
vendored
@@ -2,7 +2,7 @@ name: Issue Labeled
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
types: [ labeled ]
|
||||
|
||||
jobs:
|
||||
issue-labeled:
|
||||
|
||||
54
.github/workflows/label-pr.yml
vendored
Normal file
54
.github/workflows/label-pr.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
name: Label PR Based on Conventional Commits
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [ opened, synchronize, reopened ]
|
||||
|
||||
jobs:
|
||||
label-pr:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Analyze PR Title
|
||||
id: analyze_title
|
||||
run: |
|
||||
pr_title="${{ github.event.pull_request.title }}"
|
||||
label=""
|
||||
|
||||
# Match against Conventional Commits
|
||||
if [[ "$pr_title" == feat* ]]; then
|
||||
label="feat"
|
||||
elif [[ "$pr_title" == fix* ]]; then
|
||||
label="fix"
|
||||
elif [[ "$pr_title" == chore* ]]; then
|
||||
label="chore"
|
||||
elif [[ "$pr_title" == docs* ]]; then
|
||||
label="docs"
|
||||
elif [[ "$pr_title" == style* ]]; then
|
||||
label="style"
|
||||
elif [[ "$pr_title" == refactor* ]]; then
|
||||
label="refactor"
|
||||
elif [[ "$pr_title" == perf* ]]; then
|
||||
label="perf"
|
||||
elif [[ "$pr_title" == test* ]]; then
|
||||
label="test"
|
||||
elif [[ "$pr_title" == build* ]]; then
|
||||
label="build"
|
||||
elif [[ "$pr_title" == ci* ]]; then
|
||||
label="ci"
|
||||
elif [[ "$pr_title" == revert* ]]; then
|
||||
label="revert"
|
||||
else
|
||||
label="?"
|
||||
fi
|
||||
|
||||
echo "label=$label" >> $GITHUB_ENV
|
||||
|
||||
- name: Add Label to PR
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
labels: ${{ env.label }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
83
.github/workflows/main.yml
vendored
83
.github/workflows/main.yml
vendored
@@ -1,83 +0,0 @@
|
||||
name: "Build"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch: # 添加手动触发
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build & Release
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
#1 Checkout Repository
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
#2 Setup Java
|
||||
- name: Set Up Java
|
||||
uses: actions/setup-java@v3.12.0
|
||||
with:
|
||||
distribution: 'oracle'
|
||||
java-version: '17'
|
||||
|
||||
#3 Setup Flutter
|
||||
- name: Set Up Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: '3.27.0-0.1.pre'
|
||||
channel: 'beta'
|
||||
|
||||
#4 Install Dependencies
|
||||
- name: Install Dependencies
|
||||
run: flutter pub get
|
||||
|
||||
#5 Setup Keystore
|
||||
- name: Decode Keystore
|
||||
run: |
|
||||
echo "${{ secrets.ANDROID_KJS }}" | base64 --decode > android/app/key.jks
|
||||
|
||||
- name: Create local.properties
|
||||
run: |
|
||||
echo "storePassword=${{ secrets.ANDROID_STORE_PASSWORD }}" > android/local.properties
|
||||
echo "keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}" >> android/local.properties
|
||||
|
||||
#6 Building APK
|
||||
- name: Build APK
|
||||
run: flutter build apk --obfuscate --split-debug-info=splitMap
|
||||
|
||||
|
||||
#10 Extract Version
|
||||
- name: Extract version from pubspec.yaml
|
||||
id: extract_version
|
||||
run: |
|
||||
version=$(grep '^version: ' pubspec.yaml | cut -d ' ' -f 2 | tr -d '\r')
|
||||
echo "VERSION=$version" >> $GITHUB_ENV
|
||||
|
||||
#11 Check if Tag Exists
|
||||
- name: Check if Tag Exists
|
||||
id: check_tag
|
||||
run: |
|
||||
if git rev-parse "v${{ env.VERSION }}" >/dev/null 2>&1; then
|
||||
echo "TAG_EXISTS=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "TAG_EXISTS=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
#12 Modify Tag if it Exists
|
||||
- name: Modify Tag
|
||||
if: env.TAG_EXISTS == 'true'
|
||||
id: modify_tag
|
||||
run: |
|
||||
new_version="${{ env.VERSION }}-build-${{ github.run_number }}"
|
||||
echo "VERSION=$new_version" >> $GITHUB_ENV
|
||||
|
||||
#13 Create Release
|
||||
- name: Create Release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "build/app/outputs/flutter-apk/app-release.apk"
|
||||
tag: v${{ env.VERSION }}
|
||||
token: ${{ secrets.TOKEN }}
|
||||
54
.github/workflows/telegram-bot.yml
vendored
Normal file
54
.github/workflows/telegram-bot.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
name: Release Notification
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- released
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
notify-telegram:
|
||||
name: Notify Telegram
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Extract Release Info
|
||||
id: extract_release
|
||||
run: |
|
||||
response=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/ZhuJHua/moodiary/releases/latest")
|
||||
|
||||
# Parse the response to extract needed fields
|
||||
RELEASE_TAG=$(echo "$response" | jq -r '.tag_name')
|
||||
RELEASE_NAME=$(echo "$response" | jq -r '.name')
|
||||
RELEASE_NOTES=$(echo "$response" | jq -r '.body')
|
||||
RELEASE_URL=$(echo "$response" | jq -r '.html_url')
|
||||
|
||||
# Export as environment variables
|
||||
echo "RELEASE_TAG=$RELEASE_TAG" >> $GITHUB_ENV
|
||||
echo "RELEASE_NAME=$RELEASE_NAME" >> $GITHUB_ENV
|
||||
{
|
||||
echo "RELEASE_NOTES<<EOF"
|
||||
echo "$RELEASE_NOTES"
|
||||
echo "EOF"
|
||||
} >> $GITHUB_ENV
|
||||
echo "RELEASE_URL=$RELEASE_URL" >> $GITHUB_ENV
|
||||
|
||||
- name: Send Telegram Message
|
||||
uses: appleboy/telegram-action@master
|
||||
with:
|
||||
to: ${{ secrets.TELEGRAM_TO }}
|
||||
token: ${{ secrets.TELEGRAM_TOKEN }}
|
||||
format: html
|
||||
message: |
|
||||
🎉 A new release is live! 🎉
|
||||
|
||||
Version: ${{ env.RELEASE_TAG }}
|
||||
|
||||
Release Notes:
|
||||
${{ env.RELEASE_NOTES }}
|
||||
|
||||
🔗 View Release: ${{ env.RELEASE_URL }}
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -43,6 +43,7 @@ app.*.map.json
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
/ios/build
|
||||
|
||||
# FVM Version Cache
|
||||
.fvm/
|
||||
691
CHANGELOG.md
Normal file
691
CHANGELOG.md
Normal file
@@ -0,0 +1,691 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [unreleased]
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(zip)* Use rust to increase data export speed
|
||||
- *(widget)* Add utility functions to capture widget as image
|
||||
- Add code scanning to import support
|
||||
- Optimize image processing capabilities
|
||||
- Integrate Jieba for keyword extraction and search optimization
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(share)* Fix capture and share methods
|
||||
- Remove workspace
|
||||
- Qweather api error
|
||||
- Qweather api error
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Optimize the code structure
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Update sponsor list
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Fix build
|
||||
- *(ci)* Remove redundant dependency installation for Rust builder
|
||||
- Remove custom_lint to fix dart analyzer slow
|
||||
- Update rust test ci
|
||||
- Add test module to lib.rs
|
||||
|
||||
## [2.7.3] - 2025-03-02
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(telegram-bot)* Enhance release notification workflow
|
||||
- *(telegram-bot)* Enhance release notification workflow
|
||||
- *(llama)* Add LlamaUtil class and update dependencies
|
||||
- *(text)* Introduce AdaptiveText and EllipsisText components for improved text handling
|
||||
- *(about)* Replace Text with AnimatedText for dynamic app info display
|
||||
- *(cache)* Implement LRUCache and AsyncLRUCache for efficient data management
|
||||
- *(font)* Streamline font loading
|
||||
- *(font)* Add caching for font name and weight axis retrieval
|
||||
- *(diary)* Enhance text handling by trimming titles and removing line breaks from content
|
||||
- *(font)* Enhance font loading capabilities
|
||||
- *(font)* Clear cache when font style change
|
||||
- *(aes)* Add aes-gcm encryption algorithm
|
||||
- Add secure storage to store user key
|
||||
- Use the new route transition
|
||||
- Optimize image preview
|
||||
- Enhance image viewing experience with hero transitions and loading states
|
||||
- Improve image handling with enhanced hero transitions and dynamic sizing
|
||||
- Add WindowsBar and MoveTitle widgets for improved window management
|
||||
- Enhance UI and improve desktop experience (#179)
|
||||
- Add workflow_run trigger for Git Cliff completion
|
||||
- Update changelog workflow to check PR merge status before generating changelog
|
||||
- Add an abstract sync interface
|
||||
- Enhance diary card views with icons and improve page transitions
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(font)* Fix adding the font may cause the application crash
|
||||
- *(font)* Fix font is not loaded when startup
|
||||
- *(log)* Log did not work in release mode
|
||||
- Route error
|
||||
- Update application name and improve debug configuration
|
||||
- Update localization configuration to include synthetic package option
|
||||
- Update dependencies and remove unused localization imports
|
||||
- Ci (#177)
|
||||
- Correct syntax for workflow_run trigger in auto-merge.yml
|
||||
- Update diary_view to use Get.put for DiaryLogic instantiation
|
||||
|
||||
### 💼 Other
|
||||
|
||||
- *(*)* Upgrade dependencies
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Rename rust library from rust_lib_mood_diary to moodiary_rust
|
||||
- Remove video page routing and update video state initialization
|
||||
- Streamline theme management and dynamic color support
|
||||
- Remove Objectbox plugin references and update tile caching implementation
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(*)* Update telegram bot workflow
|
||||
- *(*)* Adjust the output format of outdated dependencies in the Telegram bot workflow
|
||||
- *(*)* Adjust the output format of outdated dependencies in the Telegram bot workflow
|
||||
- *(*)* Adjust the output format of outdated dependencies in the Telegram bot workflow
|
||||
- *(*)* Adjust the output format of outdated dependencies in the Telegram bot workflow
|
||||
- *(*)* Adjust the output format of outdated dependencies in the Telegram bot workflow
|
||||
- *(*)* Adjust the output format of outdated dependencies in the Telegram bot workflow
|
||||
- *(*)* Adjust the output format of outdated dependencies in the Telegram bot workflow
|
||||
- *(*)* Adjust the output format of outdated dependencies in the Telegram bot workflow
|
||||
- Update flutter_rust_bridge to version 2.7.1 and adjust generated files
|
||||
- Update imports and refresh package version to 3.0.0
|
||||
- Update readme
|
||||
- *(*)* Upgrade flutter and frb version
|
||||
- *(*)* Upgrade flutter version to 3.29.0
|
||||
- Add git-cliff to generate changelog
|
||||
- Add git-cliff to generate changelog
|
||||
- Add git-cliff to generate changelog
|
||||
- Add git-cliff to generate changelog
|
||||
- Add git-cliff to generate changelog
|
||||
- Upgrade actions/checkout to v4 across workflow files
|
||||
- Fix cliff ci
|
||||
- Update dependencies in pubspec.yaml to latest versions
|
||||
- Update NDK and plugin versions in build configuration
|
||||
- Update .gitignore
|
||||
- *(fix build error)* [skip ci]
|
||||
|
||||
## [2.7.2] - 2025-01-27
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(ui)* Adjust lock page and correct localization
|
||||
- *(markdown)* Add support for markdown diary
|
||||
- *(android)* Update NDK and Kotlin versions
|
||||
- *(dependencies)* Update SDK and package versions
|
||||
- *(readme)* Update Flutter and Dart version requirements
|
||||
- *(category)* Init support nested multi-level classification
|
||||
- *(*)* Add workflow to send release notifications to Telegram
|
||||
- *(ui)* Optimize home page ui
|
||||
- *(ui)* Optimize UI details
|
||||
- *(about)* Add easter eggs
|
||||
- *(media)* Optimize UI layout
|
||||
- *(markdown)* Add markdown preview support
|
||||
- *(lint)* Add more lint rules
|
||||
- *(about)* Enhance confetti effect and update duration
|
||||
- *(text)* Optimize ellipsis text rendering
|
||||
- *(ui)* Refine window buttons and UI components
|
||||
- *(ui)* Add simple window button support for windows
|
||||
- *(msix)* Add msix configuration for store publishing
|
||||
- *(msix)* Update msix configuration for store
|
||||
- *(msix)* Update msix config for store publishing
|
||||
- *(pubspec)* Add logo path for desktop
|
||||
- *(ui)* Enhance diary card text visibility and format
|
||||
- *(markdown)* Support markdown editing and embed rendering
|
||||
- *(home)* Add shadow option for the HomeFab component
|
||||
- *(ui)* Enhance image viewing and navigation
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(ui)* Improve desktop page switching performance
|
||||
- *(ui)* Add microsoft yahei ui as default font at windows
|
||||
- *(*)* Remove pull to refresh at desktop platform
|
||||
|
||||
### 💼 Other
|
||||
|
||||
- *(macos)* Update code signing and provisioning settings
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(*)* Organize the project structure and use absolute paths uniformly
|
||||
- *(*)* Optimize project structure
|
||||
- *(media)* Reconstruct the media library, with more animation and better performance
|
||||
|
||||
### 🎨 Styling
|
||||
|
||||
- Code clean
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(flutter)* Update flutter version to 3.27.2
|
||||
- Simplify telegram release notification
|
||||
- *(ci)* Enhance telegram notification with release details
|
||||
- Refine release notification workflow
|
||||
- Update Flutter version to 3.27.3
|
||||
- Update shared_preferences_android to 2.4.3
|
||||
- *(*)* Adjust msix_config settings in pubspec.yaml
|
||||
- *(*)* Bump version to 2.7.2+72
|
||||
|
||||
## [2.7.1] - 2025-01-18
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(l10n)* Add full localization support
|
||||
- *(edit)* Add audio file selection
|
||||
- *(l10n)* Add localization for diary operations and data sync
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(ci)* Add release drafter
|
||||
- *(*)* Fix ci
|
||||
- *(*)* Fix ci
|
||||
- *(*)* Fix ci
|
||||
- *(ci)* Fix ci (#107)
|
||||
- *(*)* Fix ci
|
||||
- *(*)* Fix ci
|
||||
- *(calendar)* Filter visible diaries
|
||||
|
||||
### 💼 Other
|
||||
|
||||
- *(action)* Fix workflow
|
||||
- *(android)* Upgrade AGP to 8.8.0
|
||||
- *(android)* Upgrade AGP to 8.8.0
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(*)* Update readme
|
||||
- *(*)* Optimize release note generation logic
|
||||
- *(*)* Add flutter analyze workflow and dynamic flutter version support
|
||||
- *(ci)* Adjust flutter analyze trigger
|
||||
- *(ci)* Install dependencies for rust builder project in flutter analyze workflow
|
||||
- *(workflow)* Update flutter analyze workflow
|
||||
- *(ci)* Add dependency installation step for rust builder
|
||||
- *(*)* Bump version to 2.7.1+71
|
||||
|
||||
## [2.7.0] - 2025-01-17
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(diary)* Init support for multi diary
|
||||
- *(private)* Add private mode
|
||||
- *(feedback)* Add new feedback
|
||||
- *(lock)* Automatically invoke biometrics on startup
|
||||
- *(edit)* Add multi image picker support
|
||||
- *(webdav)* Added more option for webdav
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(webdav)* Fix webdav error
|
||||
- *(logger)* Fix logger can't export
|
||||
- *(log)* Fix logger
|
||||
- *(ci)* Fix workflow error (#105)
|
||||
- *(ci)* Fix ci (#106)
|
||||
- *(ci)* Fix work flows
|
||||
- *(media_view)* Fix file time sorting bug in media library
|
||||
- *(sync)* Fix local sync exception
|
||||
- *(*)* Fix unexpected issue causing immediate lockup
|
||||
|
||||
### 💼 Other
|
||||
|
||||
- *(pub)* Update dependencies
|
||||
- *(pub)* Upgrade dependencies
|
||||
- *(pub)* Upgrade dependencies
|
||||
- *(pub)* Upgrade dependencies
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(ui)* Improve ui
|
||||
- *(ui)* Improve ui
|
||||
- *(*)* Use refreshed to replace getx &use in app webview
|
||||
- *(ui)* Improve ui
|
||||
- *(ui)* Improve ui
|
||||
- *(ui)* Limit the maximum height of media files in rich text to 300
|
||||
|
||||
### 🎨 Styling
|
||||
|
||||
- *(*)* Code clean up
|
||||
- *(*)* Code clean
|
||||
- *(*)* Code clean
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(*)* Update readme
|
||||
- *(*)* Update readme
|
||||
- *(*)* Update readme
|
||||
- *(*)* Update readme
|
||||
- *(*)* Release at 2.7.0
|
||||
|
||||
## [2.6.5] - 2025-01-02
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(category)* Init support nested multi-level classification
|
||||
- *(font)* Add support for custom font
|
||||
- *(ui)* Optimize image and video viewing
|
||||
- *(ui)* Optimize desktop operating experience
|
||||
- *(fvm)* Add fvm to manager flutter version
|
||||
- *(*)* Improve category manager
|
||||
- *(hitokoto)* Add hitokoto in title
|
||||
- *(ui)* Add marquee to fix long text
|
||||
- *(*)* Add dev mode
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(fix display error when local send)* Closes #80
|
||||
- *(android)* Fix release build error on android platform
|
||||
- *(logger)* Fix can't catch error log at release mode
|
||||
- *(webdav)* Fix webdav error when creating dir
|
||||
- *(ui)* Fix text painter did not match custom text scale
|
||||
- *(font)* Fix variable font misans vf
|
||||
- *(action)* Fix github action
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(*)* Add some notice when catching error
|
||||
- *(ui)* New bottom sheet ui & new theme color picker
|
||||
- *(home)* New ui for home page
|
||||
- *(ui)* Add animated switcher to fade
|
||||
- *(ui)* Remove useless widget & add try catch for hitokoto
|
||||
|
||||
### 🎨 Styling
|
||||
|
||||
- *(code)* Cleanup the code
|
||||
- *(*)* Code cleanup
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(*)* Update readme
|
||||
- *(*)* Update readme
|
||||
- *(*)* Fix isar build error
|
||||
- *(*)* Release at 2.6.5
|
||||
|
||||
## [2.6.4] - 2024-12-15
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(data)* Fix date merge error
|
||||
- *(data)* Fix data merge error to 2.6.3
|
||||
- *(diary)* Home page did not remove deleted diary
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(ui)* Improve ui
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(*)* Release at 2.6.4 as hotfix
|
||||
|
||||
## [2.6.3] - 2024-12-15
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(icon)* Add new icon for desktop
|
||||
- *(webdav)* Improve webdav behavior
|
||||
- *(*)* Add try catch
|
||||
- *(sync)* Add local sync at home page
|
||||
- *(webdav)* Improve webdav util
|
||||
- *(save_image)* Add save image to local
|
||||
- *(media)* Improve media library
|
||||
- *(media)* Improve media
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(layout)* Fix home page layout overflow
|
||||
- *(desktop)* Improve desktop experience
|
||||
- *(layout)* Fix layout
|
||||
- *(logic)* Fix did not jump to new category tabview when add category
|
||||
- *(webdav)* Local did not delete
|
||||
- *(android)* Fix splash screen not full
|
||||
- *(lab)* Key did not update after input
|
||||
- *(log)* Error log did not write into file
|
||||
- *(local_sync)* Category sync error
|
||||
- *(location)* Fix can't get location on macos
|
||||
- *(toast)* Remove flutter hook
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(*)* Remove hitokoto
|
||||
- *(calendar)* Better calendar view
|
||||
- *(l10n)* Refactor localization
|
||||
- *(ui)* Refactor ui
|
||||
- *(ui)* Refactor rich text adding media
|
||||
- *(ui)* Make record_sheet_view higher
|
||||
|
||||
### ⚡ Performance
|
||||
|
||||
- *(image)* Improve image performance
|
||||
- *(*)* Improve performance
|
||||
- *(*)* Use isolate to improve performance
|
||||
|
||||
### 🎨 Styling
|
||||
|
||||
- *(*)* Code clean
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(*)* Hotfix at 2.6.1
|
||||
- *(*)* Update readme
|
||||
- *(isar)* Gen code
|
||||
- *(*)* Release at 2.6.3
|
||||
|
||||
## [2.6.1] - 2024-12-11
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(data)* Fix data merge error
|
||||
- *(webdav)* Behavior when has no options
|
||||
- *(rust)* Frb version
|
||||
- *(*)* Can't start on some devices
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(*)* Remove font setting
|
||||
- *(diary_detail)* Remove squad
|
||||
|
||||
## [2.6.0] - 2024-12-10
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(server)* Init server support
|
||||
- *(kmp)* Add kmp search use rust
|
||||
- *(webdav)* Init webdav util
|
||||
- *(server)* Init server
|
||||
- *(*)* Add rich text and media editor
|
||||
- *(util)* Add keyboard listener
|
||||
- *(icon)* Use new app icon
|
||||
- *(webdav)* Support webdav sync
|
||||
- *(webdav)* Improve webdav support
|
||||
- *(edit)* Add auto select category
|
||||
- *(*)* Add data merge to 2.6.0
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(rust)* Fix string error in kmp
|
||||
- *(ui)* Fixed layout issues with three-button navigation mode
|
||||
- *(image_compress)* Fix can't compress heif image
|
||||
- *(local_send)* Fix can't find ip at ethernet mode
|
||||
|
||||
### 💼 Other
|
||||
|
||||
- *(pubspec)* Upgrade dependencies
|
||||
- *(rust)* Update dependencies
|
||||
- *(rust)* Generated rust builder
|
||||
- *(*)* Platform build option
|
||||
- *(pubsepc)* Remove unused dependencies
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(ui)* Improve ui
|
||||
- *(ui)* Improve ui
|
||||
- *(*)* Use the new flutter api to catch error
|
||||
|
||||
### ⚡ Performance
|
||||
|
||||
- *(*)* Improve perf at home page
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(git)* Add attributes
|
||||
- *(*)* Add workflows
|
||||
- *(release)* Prepare release version 2.6.0
|
||||
|
||||
## [2.4.9] - 2024-11-19
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(password)* Remove password error
|
||||
- *(windows)* Fix biometric auth error in windows
|
||||
- *(windows)* Fix get video thumbnail error in windows
|
||||
- *(home)* Fix pagination error
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(image)* Use rust to compress image
|
||||
- *(ui)* Add some animation
|
||||
- *(ui)* Improve layout for better user experience
|
||||
- *(ui)* Improve layout for better user experience
|
||||
- *(*)* Add category manager
|
||||
|
||||
### 🎨 Styling
|
||||
|
||||
- *(*)* Code clean
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(*)* Release 2.4.9
|
||||
|
||||
## [2.4.8] - 2024-11-12
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(*)* Fix many bugs
|
||||
|
||||
## [2.4.8-rc] - 2024-11-12
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(*)* Initial localization and LAN synchronization
|
||||
- *(macos)* Prepare for macos support
|
||||
- *(map)* Add map support for viewing and managing diary entry locations
|
||||
- *(local_send)* Add local send support
|
||||
- *(local_send)* More improve about local send
|
||||
- *(*)* Add more function in home page
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(search)* Add title search support
|
||||
- *(*)* Fix title bar in macos
|
||||
- *(local_send)* Fix modifying list in loop
|
||||
- *(map)* Fix map cache error
|
||||
|
||||
### 💼 Other
|
||||
|
||||
- *(android)* Remove unused dependencies
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(*)* Improve performance
|
||||
|
||||
### 🎨 Styling
|
||||
|
||||
- *(*)* Code clean
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(*)* Release 2.4.8
|
||||
|
||||
## [2.4.7] - 2024-10-27
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(edit)* Add automatic weather getting
|
||||
- *(page/map)* Map
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(edit)* Fix tooltip position error
|
||||
- *(edit)* Fix tooltip position
|
||||
- *(category)* Fix category not be able to deselect
|
||||
- *(file_util)* Fix share and data export error on windows
|
||||
|
||||
### ⚡ Performance
|
||||
|
||||
- *(page/setting)* Improve performance
|
||||
|
||||
### 🎨 Styling
|
||||
|
||||
- *(*)* Code clean
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(*)* Release 2.4.7
|
||||
|
||||
## [2.4.6] - 2024-10-18
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(update)* Add check update in app
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(location)* Fix location error
|
||||
- *(app)* Fix title display on some devices
|
||||
- *(file_util)* Fix data import and export
|
||||
|
||||
## [2.4.5] - 2024-10-17
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(video)* Add support for video player
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(*)* Landscape cannot be used on Android tablets
|
||||
- *(weather)* Weather cannot be obtained due to positioning problems
|
||||
|
||||
### 💼 Other
|
||||
|
||||
- *(android)* Update gradle version
|
||||
- *(*)* Update version
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(*)* Refactor directory structure
|
||||
- *(*)* Refactor for performance
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(*)* Code clean
|
||||
|
||||
## [2.4.4] - 2024-10-01
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(ask_question)* Add SQuAD task in diary
|
||||
- *(media_view)* Add media view in navigator bar
|
||||
- *(media_view)* Add image manager
|
||||
|
||||
### 💼 Other
|
||||
|
||||
- *(android)* Change the minSdk 26
|
||||
- *(pubspec)* Update dependencies
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(*)* Optimize the color scheme
|
||||
|
||||
### ⚡ Performance
|
||||
|
||||
- *(setting_view)* Cache the list reduces unnecessary rebuild
|
||||
|
||||
### 🎨 Styling
|
||||
|
||||
- *(*)* Code clean
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(lint)* Add lint rules
|
||||
- *(lfs)* Add lfs support
|
||||
|
||||
## [2.4.3] - 2024-09-23
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(calendar)* Add timeline view in calendar page
|
||||
- *(home)* Auto hidden navigation bar
|
||||
- *(calendar_view)* Add calendar view
|
||||
- *(About)* Add about page
|
||||
- *(Calendar)* Add expansion panel in calendar view
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(isar)* Fix error when importing data
|
||||
- *(home)* Fix scrolling error
|
||||
- *(record_sheet)* Can not start recording after stop recording
|
||||
- *(calendar)* Unnecessary build in calendar page
|
||||
- *(*)* Diary is not change after edit or delete
|
||||
|
||||
### 💼 Other
|
||||
|
||||
- *(pubspec)* Update dependencies
|
||||
- *(pubspec)* Update dependencies
|
||||
- *(pubspec)* Update dependencies
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(wave_form)* Make wave form componentized
|
||||
- *(*)* Make the code clear
|
||||
- *(*)* Extract the border radius settings
|
||||
- *(isar)* Add equal method in diary
|
||||
- *(isar)* Rename the method
|
||||
- *(pref)* Change the default color when start up
|
||||
- *(*)* Remove useless method
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(theme)* New theme color
|
||||
- *(*)* Code clean
|
||||
- *(intl)* More localization
|
||||
- *(intl)* More localization
|
||||
|
||||
## [2.4.2] - 2024-09-19
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(windows)* Prepare for windows platform
|
||||
- *(assistant)* Prepare for assistant page
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(diary_details)* Fix banner height
|
||||
- *(home)* Fix multi scroll in home page
|
||||
- *(permission_util)* Fix get location on android platform
|
||||
- *(diary_card)* Fix an unexpected jump after modify a diary
|
||||
|
||||
### 💼 Other
|
||||
|
||||
- *(pubspec)* Update dependencies
|
||||
- *(android)* Remove unused abiFilters
|
||||
- *(pubspec)* Update dependencies
|
||||
- *(*)* Remove unused dependencies
|
||||
- *(pubsepc)* Update dependencies
|
||||
- *(android)* Update agp version
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- *(*)* There are so many changes, I don't know what changes, so fuck it
|
||||
|
||||
### ⚡ Performance
|
||||
|
||||
- *(*)* Improve performance in some cases
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(intl)* More localization
|
||||
|
||||
## [2.4.1] - 2024-08-26
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(record_sheet)* Fix wave form width anomalies
|
||||
- *(notice_util)* Something wrong when catching bugs
|
||||
|
||||
### 💼 Other
|
||||
|
||||
- *(pubspec)* Update dependencies
|
||||
|
||||
### ⚡ Performance
|
||||
|
||||
- *(home)* Improve performance in home view
|
||||
|
||||
<!-- generated by git-cliff -->
|
||||
180
README.en.md
180
README.en.md
@@ -1,180 +0,0 @@
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="res/banner/dark_en.svg">
|
||||
<source media="(prefers-color-scheme: light)" srcset="res/banner/light_en.svg">
|
||||
<img alt="The preview for moodiary." src="res/banner/light_en.svg">
|
||||
</picture>
|
||||
|
||||
<p align="center"><a href="README.md">简体中文</a> | English</p>
|
||||
|
||||
<p align="center">QQ Group: 760014526</p>
|
||||
|
||||
<div align="center">
|
||||
<img src="https://img.shields.io/badge/Flutter-3.27.0-blue?style=for-the-badge">
|
||||
<img src="https://img.shields.io/github/repo-size/ZhuJHua/moodiary?style=for-the-badge&color=ff7070">
|
||||
<img src="https://img.shields.io/github/stars/ZhuJHua/moodiary?style=for-the-badge&color=965f8a">
|
||||
<img src="https://img.shields.io/github/v/release/ZhuJHua/moodiary?style=for-the-badge&color=4f5e7f">
|
||||
<img src="https://img.shields.io/github/license/ZhuJHua/moodiary?style=for-the-badge&color=4ac6b7">
|
||||
</div>
|
||||
|
||||
## ✨ Feature
|
||||
|
||||
- **Cross-platform support**:🌍 Compatible with Android, iOS\*, Windows\*, MacOS\*, Linux.
|
||||
- **Material Design**:🎨 The interface is intuitive and user-friendly, and follows the Material Design specifications.
|
||||
- **Rich text editing**:📝 Supports text editing in bold, italic, underline and other formats.
|
||||
- **Multimedia accessories**:📷 You can add pictures, audio, video or even draw a picture to your diary.
|
||||
- **Search and classification**:🔍 Easily manage your diary by full-text search and categorization.
|
||||
- **Custom theme**:🌈 Supports light and dark modes, as well as a variety of color schemes.
|
||||
- **Data security**:🔒 Keep your diary safe with a password, supports biometric unlocking.
|
||||
- **Export and share**:🧾 Support all data import/export, as well as single diary sharing.
|
||||
- **Backup and synchronization**:☁ Support for LAN synchronization and WebDav backup.
|
||||
- **Footprint Map** : 🗺️ See your footprints on a map. Every step of your life is worth documenting.
|
||||
- **Intelligent assistant**:💬 Supports access to third-party large models, provides Q&A, sentiment analysis and other functions.
|
||||
- **Local Natural Language Processing (NLP)**:🤖 A more secure intelligent assistant that lets your diary know you better.
|
||||
|
||||
(Note: Cross-platform capabilities are provided by Flutter, platforms with * may need to configure your own signatures)
|
||||
|
||||
## 🔧 Main Technology stack
|
||||
|
||||
- [Flutter](https://github.com/flutter/flutter) ( Cross-platform UI framework )
|
||||
- [Isar](https://github.com/isar/isar) ( High performance local database )
|
||||
- [GetX](https://github.com/jonataslaw/getx) ( State management framework )
|
||||
|
||||
## 📸 Application screenshot
|
||||
|
||||
> The application is constantly updated, and the interface may change slightly in the new version
|
||||
|
||||
### Mobile
|
||||
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="res/screenshot/mobile_dark.webp">
|
||||
<source media="(prefers-color-scheme: light)" srcset="res/screenshot/mobile_light.webp">
|
||||
<img alt="The mobile screenshot for moodiary." src="res/screenshot/mobile_light.webp">
|
||||
</picture>
|
||||
|
||||
### Desktop
|
||||
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="res/screenshot/desktop_dark.webp">
|
||||
<source media="(prefers-color-scheme: light)" srcset="res/screenshot/desktop_light.webp">
|
||||
<img alt="The desktop screenshot for moodiary." src="res/screenshot/desktop_light.webp">
|
||||
</picture>
|
||||
|
||||
## 🚀 Installation guide
|
||||
|
||||
### Third party SDK
|
||||
|
||||
Some capabilities need to apply for third-party SDKS, and the following service providers provide free versions, and the obtained keys are configured in the lab.
|
||||
|
||||
#### Weather service
|
||||
|
||||
- [QWeather](https://dev.qweather.com/docs/api/)
|
||||
|
||||
#### Map service
|
||||
|
||||
- [Tianditu](http://lbs.tianditu.gov.cn/server/MapService.html)
|
||||
|
||||
#### Intelligent assistant
|
||||
|
||||
- [Tencent Hunyuan](https://cloud.tencent.com/document/product/1729/97731)
|
||||
|
||||
### Direct mounting
|
||||
|
||||
Use it by downloading the compiled installation package in Release, or manually compiling it if you don't have the platform you need.
|
||||
|
||||
### Manual compilation
|
||||
|
||||
#### Environmental requirement
|
||||
|
||||
- Flutter SDK (>= 3.27.0)
|
||||
- Dart (>= 3.6.0)
|
||||
- Rust Toolchain (Latest)
|
||||
- Clang/LLVM (Latest)
|
||||
- Compatible ides (e.g. Android Studio, Visual Studio Code)
|
||||
|
||||
#### Installation procedure
|
||||
|
||||
> Note: When packaging, you need to modify the corresponding platform configuration file, such as Android platform build.gradle
|
||||
|
||||
1. **Clone Repo**:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/ZhuJHua/moodiary.git
|
||||
cd moodiary
|
||||
```
|
||||
|
||||
2. **Installation dependency**:
|
||||
|
||||
```bash
|
||||
flutter pub get
|
||||
```
|
||||
|
||||
3. **Running application**:
|
||||
|
||||
```bash
|
||||
flutter run
|
||||
```
|
||||
|
||||
4. **Package release**:
|
||||
|
||||
- Android: `flutter build apk`
|
||||
- iOS: `flutter build ipa`
|
||||
- Windows: `flutter build windows`
|
||||
- MacOS: `flutter build macos`
|
||||
|
||||
## 📝 More description
|
||||
|
||||
### Natural Language Processing (NLP)
|
||||
|
||||
> In the experimental stage
|
||||
|
||||
Today, more and more industry products are beginning to incorporate AI technology, which undoubtedly greatly improves our experience. However, for diary applications, it is not acceptable to hand over the data to a large model because it is not certain that the data will be used for training. Therefore, a better approach is to adopt a local model. Although local models may not be as powerful as large models due to size limitations, they can still provide necessary help to a certain extent.
|
||||
|
||||
Currently, I have the following tasks integrated into the source code:
|
||||
|
||||
#### SQuAD task based on Bert pre-trained model
|
||||
|
||||
I used MobileBert for the SQuAD task, which is a simple machine reading comprehension task. You can ask it questions and it will return the answers you need. The model files are in the `.tflite` format required by TensorFlow Lite, so you can add your own model files to the `assets/tflite` directory.
|
||||
|
||||
Thanks to the following open source projects:
|
||||
|
||||
- [Chinese MobileBERT](https://github.com/ymcui/Chinese-MobileBERT)
|
||||
- [Mobilebert](https://github.com/google-research/google-research/tree/master/mobilebert)
|
||||
- [ChineseSquad](https://github.com/junzeng-pluto/ChineseSquad)
|
||||
|
||||
## 🤝 Contribution guide
|
||||
|
||||
Contributions are welcome! Please follow these steps to contribute:
|
||||
|
||||
1. Fork this repository.
|
||||
2. Create a new branch(`git checkout -b feature-branch-name`)。
|
||||
3. Commit your changes(`git commit -am 'Add some feature'`)。
|
||||
4. Push to branch(`git push origin feature-branch-name`)。
|
||||
5. Create a Pull Request.
|
||||
|
||||
Please make sure that your code to follow [Flutter style guide](https://flutter.dev/docs/development/tools/formatting) and include the appropriate tests.
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the AGPL-3.0 LICENSE, see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## 💖 Thanks
|
||||
|
||||
- Thanks to the Flutter team for the excellent framework.
|
||||
- Special thanks to the open source community for their valuable contributions.
|
||||
|
||||
## 🥪 Sponsor
|
||||
|
||||
You can buy me a sandwich to keep me motivated to continue developing.
|
||||
|
||||
<img src="res/sponsor/wechat.jpg" style="width:300px" alt="Sponsor"/>
|
||||
|
||||
### List of sponsors
|
||||
|
||||
If you want to be on the list, you can leave me a message, in no particular order, and the list will be updated regularly.
|
||||
|
||||
| Sponsor | Price | Sponsor | Price |
|
||||
|---------------------------------------|----------|---------|--------|
|
||||
| [dsxksss](https://github.com/dsxksss) | 50 CNY | 十一 | 20 CNY |
|
||||
| 沭飏秋 | 10 CNY | 朱东杰 | 60 CNY |
|
||||
| 匿名 | 5 CNY | wu | 10 CNY |
|
||||
| 云烨 | 2.76 CNY | | |
|
||||
190
README.md
190
README.md
@@ -1,180 +1,188 @@
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="res/banner/dark_zh.svg">
|
||||
<source media="(prefers-color-scheme: light)" srcset="res/banner/light_zh.svg">
|
||||
<img alt="The preview for moodiary." src="res/banner/light_zh.svg">
|
||||
<source media="(prefers-color-scheme: dark)" srcset="res/banner/dark_en.svg">
|
||||
<source media="(prefers-color-scheme: light)" srcset="res/banner/light_en.svg">
|
||||
<img alt="The preview for moodiary." src="res/banner/light_en.svg">
|
||||
</picture>
|
||||
<p align="center"><a href="README.zh.md">简体中文</a> | English</p>
|
||||
|
||||
<p align="center">简体中文 | <a href="README.en.md">English</a></p>
|
||||
|
||||
<p align="center">QQ 交流群:760014526</p>
|
||||
<p align="center"><a href="https://answer.moodiary.net" target="_blank">Official forum</a>丨QQ Group: <a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=xGr0TNp_X1z3XEn09_iE_iGSLolQwl6Y&jump_from=webapi&authKey=ZmSb2oEd94FSXxBXRBq53hgTjjvcfmgkQrduB3uL12XtRylPmRlO2OdFz6R25tIo">760014526</a>丨Telegram: <a target="_blank" href="https://t.me/openmoodiary">openmoodiary</a></p>
|
||||
|
||||
<div align="center">
|
||||
<img src="https://img.shields.io/badge/Flutter-3.27.0-blue?style=for-the-badge">
|
||||
<img src="https://img.shields.io/badge/Flutter-3.29.2-blue?style=for-the-badge">
|
||||
<img src="https://img.shields.io/github/repo-size/ZhuJHua/moodiary?style=for-the-badge&color=ff7070">
|
||||
<img src="https://img.shields.io/github/stars/ZhuJHua/moodiary?style=for-the-badge&color=965f8a">
|
||||
<img src="https://img.shields.io/github/v/release/ZhuJHua/moodiary?style=for-the-badge&color=4f5e7f">
|
||||
<img src="https://img.shields.io/github/license/ZhuJHua/moodiary?style=for-the-badge&color=4ac6b7">
|
||||
</div>
|
||||
|
||||
## ✨ 功能特性
|
||||
|
||||
- **跨平台支持**:🌍 兼容 Android、iOS\*、Windows\*、MacOS\*、Linux。
|
||||
- **Material Design**:🎨 界面直观且用户友好,遵循 Material Design 设计规范。
|
||||
- **富文本编辑**:📝 支持加粗、斜体、下划线等多种格式的文本编辑。
|
||||
- **多媒体附件**:📷 可以为你的日记添加图片、音频、视频甚至画一张画。
|
||||
- **搜索和分类**:🔍 轻松通过全文搜索及分类管理你的日记。
|
||||
- **自定义主题**:🌈 支持浅色和深色模式,以及多种配色的主题。
|
||||
- **数据安全**:🔒 通过密码来保障你的日记安全,支持通过生物识别解锁。
|
||||
- **导出和分享**:🧾 支持所有数据的导入/导出,以及单篇日记的分享。
|
||||
- **备份与同步**:☁ 支持局域网同步,快速在设备间同步数据,以及 WebDav 备份。
|
||||
- **足迹地图**:🗺️ 在地图上查看你足迹,生活中的每一步都值得被记录。
|
||||
- **智能助手**:💬 支持接入第三方大模型,提供问答、情绪分析等功能。
|
||||
- **本地自然语言处理(NLP)**:🤖 更安全的智能助手,让你的日记更懂你。
|
||||
## ✨ Feature
|
||||
|
||||
(注:跨平台能力由 Flutter 提供,带 * 号的平台可能需要自行配置签名)
|
||||
- **Cross-platform support**: 🌍 Compatible with Android, iOS, Windows, MacOS, Linux\*.
|
||||
- **Material Design**: 🎨 The interface is intuitive and user-friendly, and follows the Material Design specifications.
|
||||
- **Multiple editors**: 📝 supports markdown, plain text, rich text and other forms of text editing.
|
||||
- **Multimedia accessories**: 📷 You can add pictures, audio, video or even draw a picture to your diary.
|
||||
- **Search and classification**: 🔍 Easily manage your diary by full-text search and categorization.
|
||||
- **Custom theme**: 🌈 Supports light and dark modes, as well as a variety of color schemes.
|
||||
- **Custom fonts**: ✍️ Supports importing different fonts, and supports variable fonts.
|
||||
- **Data security**: 🔒 Keep your diary safe with a password, supports biometric unlocking.
|
||||
- **Export and share**: 🧾 Support all data import/export, as well as single diary sharing.
|
||||
- **Backup and synchronization**: ☁ Support for LAN synchronization and WebDav backup.
|
||||
- **Trail Map**: 🗺️ See your footprints on a map. Every step of your life is worth documenting.
|
||||
- **Intelligent assistant**: 💬 Supports access to third-party large models, provides Q&A, sentiment analysis and other functions.
|
||||
- **Local Natural Language Processing (NLP)**: 🤖 A more secure intelligent assistant that lets your diary know you better.
|
||||
|
||||
## 🔧 主要技术栈
|
||||
(Note: Cross-platform capabilities are provided by Flutter, and platforms with * marks may require more testing)
|
||||
|
||||
- [Flutter](https://github.com/flutter/flutter)(跨平台 UI 框架)
|
||||
- [Isar](https://github.com/isar/isar)(高性能本地数据库)
|
||||
- [GetX](https://github.com/jonataslaw/getx)(状态管理框架)
|
||||
## 🔧 Main Technology stack
|
||||
|
||||
## 📸 应用截图
|
||||
- [Flutter](https://github.com/flutter/flutter) ( Cross-platform UI framework )
|
||||
- [Isar](https://github.com/isar/isar) ( High performance local database )
|
||||
- [GetX](https://github.com/jonataslaw/getx) ( State management framework )
|
||||
|
||||
> 应用持续更新中,新版本界面可能稍有变化
|
||||
## 📸 Application screenshot
|
||||
|
||||
### 移动端
|
||||
> The application is constantly updated, and the interface may change slightly in the new version
|
||||
|
||||
### Mobile
|
||||
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="res/screenshot/mobile_dark.webp">
|
||||
<source media="(prefers-color-scheme: light)" srcset="res/screenshot/mobile_light.webp">
|
||||
<img alt="The mobile screenshot for moodiary." src="res/screenshot/mobile_light.webp">
|
||||
<source media="(prefers-color-scheme: dark)" srcset="res/screenshot/mobile_dark_en.webp">
|
||||
<source media="(prefers-color-scheme: light)" srcset="res/screenshot/mobile_light_en.webp">
|
||||
<img alt="The mobile screenshot for moodiary." src="res/screenshot/mobile_light_en.webp">
|
||||
</picture>
|
||||
|
||||
### 桌面端
|
||||
### Desktop
|
||||
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="res/screenshot/desktop_dark.webp">
|
||||
<source media="(prefers-color-scheme: light)" srcset="res/screenshot/desktop_light.webp">
|
||||
<img alt="The desktop screenshot for moodiary." src="res/screenshot/desktop_light.webp">
|
||||
<source media="(prefers-color-scheme: dark)" srcset="res/screenshot/desktop_dark_en.webp">
|
||||
<source media="(prefers-color-scheme: light)" srcset="res/screenshot/desktop_light_en.webp">
|
||||
<img alt="The desktop screenshot for moodiary." src="res/screenshot/desktop_light_en.webp">
|
||||
</picture>
|
||||
|
||||
## 🚀 安装指南
|
||||
## 🚀 Installation guide
|
||||
|
||||
### 第三方 SDK
|
||||
### Third party SDK
|
||||
|
||||
某些能力需要自行申请第三方 SDK,下列服务商均提供免费的版本,获取到的 Key 在实验室中配置。
|
||||
Some capabilities need to apply for third-party SDKS, and the following service providers provide free versions, and the obtained keys are configured in the lab.
|
||||
|
||||
#### 天气服务
|
||||
#### Weather service
|
||||
|
||||
- [和风天气](https://dev.qweather.com/docs/api/)
|
||||
- [QWeather](https://dev.qweather.com/docs/api/)
|
||||
|
||||
#### 地图服务
|
||||
#### Map service
|
||||
|
||||
- [天地图](http://lbs.tianditu.gov.cn/server/MapService.html)
|
||||
- [Tianditu](http://lbs.tianditu.gov.cn/server/MapService.html)
|
||||
|
||||
#### 智能助手
|
||||
#### Intelligent assistant
|
||||
|
||||
- [腾讯混元大模型](https://cloud.tencent.com/document/product/1729/97731)
|
||||
- [Tencent Hunyuan](https://cloud.tencent.com/document/product/1729/97731)
|
||||
|
||||
### 直接安装
|
||||
### Direct install
|
||||
|
||||
通过下载 Release 中已编译好的安装包来使用,如果没有你所需要的平台,请使用手动编译。
|
||||
Use it by downloading the compiled installation package in Release, or manually compiling it if you don't have the platform you need.
|
||||
|
||||
### 手动编译
|
||||
### Manual compilation
|
||||
|
||||
#### 环境要求
|
||||
#### Environmental requirement
|
||||
|
||||
- Flutter SDK (>= 3.27.0)
|
||||
- Dart (>= 3.6.0)
|
||||
- Rust 工具链 (Latest)
|
||||
- Clang/LLVM (Latest)
|
||||
- 兼容的 IDE(如 Android Studio、Visual Studio Code)
|
||||
> I always use the latest Flutter version (if possible), using newer versions will bring more features and better performance improvements, never use older versions unless you want your code to become a piece of 💩
|
||||
|
||||
#### 安装步骤
|
||||
- Flutter SDK (>= 3.29.0 Stable) (It is recommended to use FVM to manage the Flutter version)
|
||||
- Dart (>= 3.7.0)
|
||||
- Rust Toolchain (Nightly)
|
||||
- Clang/LLVM
|
||||
- Compatible IDE (e.g. Android Studio, Visual Studio Code)
|
||||
|
||||
> 注意:当打包时,需要自己修改对应平台的配置文件,例如安卓平台的 build.gradle
|
||||
#### Installation procedure
|
||||
|
||||
1. **克隆仓库**:
|
||||
> Note: For security reasons, I did not include my signature in the code base, when you need to manually package, you need to modify the configuration file of the corresponding platform, such as build.gradle on the Android platform, and package after modifying the package name, thank you for your understanding.
|
||||
|
||||
1. **Clone Repo**:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/ZhuJHua/moodiary.git
|
||||
cd moodiary
|
||||
```
|
||||
|
||||
2. **安装依赖**:
|
||||
2. **Installation dependency**:
|
||||
|
||||
```bash
|
||||
flutter pub get
|
||||
```
|
||||
|
||||
3. **运行应用**:
|
||||
3. **Running application**:
|
||||
|
||||
```bash
|
||||
flutter run
|
||||
```
|
||||
|
||||
4. **打包发布**:
|
||||
4. **Package release**:
|
||||
|
||||
- Android: `flutter build apk`
|
||||
- iOS: `flutter build ipa`
|
||||
- Windows: `flutter build windows`
|
||||
- MacOS: `flutter build macos`
|
||||
|
||||
## 📝 更多说明
|
||||
## 📝 More description
|
||||
|
||||
### 自然语言处理(NLP)
|
||||
### Natural Language Processing (NLP)
|
||||
|
||||
> 处于实验阶段
|
||||
> In the experimental stage
|
||||
|
||||
如今,越来越多的行业产品开始融入 AI 技术,这无疑极大地提升了我们的使用体验。然而,对于日记应用来说,将数据交给大型模型处理并不可接受,因为无法确定这些数据是否会被用于训练。因此,更好的方法是采用本地模型。虽然由于体积限制,本地模型的能力可能不如大型模型强大,但在一定程度上仍能为我们提供必要的帮助。
|
||||
Today, more and more industry products are beginning to incorporate AI technology, which undoubtedly greatly improves our experience. However, for diary applications, it is not acceptable to hand over the data to a large model because it is not certain that the data will be used for training. Therefore, a better approach is to adopt a local model. Although local models may not be as powerful as large models due to size limitations, they can still provide necessary help to a certain extent.
|
||||
|
||||
目前,我在源码中集成了以下任务:
|
||||
Currently, I have the following tasks integrated into the source code:
|
||||
|
||||
#### 基于 Bert 预训练模型的 SQuAD 任务
|
||||
#### SQuAD task based on Bert pre-trained model
|
||||
|
||||
我采用了 MobileBert 来处理 SQuAD 任务,这是一个简单的机器阅读理解任务。你可以向它提出问题,它会返回你需要的答案。模型文件采用 TensorFlow Lite 所需的 `.tflite` 格式,所以你可以添加自己的模型文件到 `assets/tflite` 目录下。
|
||||
I used MobileBert for the SQuAD task, which is a simple machine reading comprehension task. You can ask it questions and it will return the answers you need. The model files are in the `.tflite` format required by TensorFlow Lite, so you can add your own model files to the `assets/tflite` directory.
|
||||
|
||||
感谢以下开源项目:
|
||||
Thanks to the following open source projects:
|
||||
|
||||
- [Chinese MobileBERT](https://github.com/ymcui/Chinese-MobileBERT)
|
||||
- [Mobilebert](https://github.com/google-research/google-research/tree/master/mobilebert)
|
||||
- [ChineseSquad](https://github.com/junzeng-pluto/ChineseSquad)
|
||||
|
||||
## 🤝 贡献指南
|
||||
## 🤝 Contribution guide
|
||||
|
||||
欢迎贡献!请按照以下步骤进行贡献:
|
||||
Contributions are welcome! Please follow these steps to contribute:
|
||||
|
||||
1. Fork 本仓库。
|
||||
2. 创建一个新分支(`git checkout -b feature-branch-name`)。
|
||||
3. 提交你的修改(`git commit -am 'Add some feature'`)。
|
||||
4. 推送到分支(`git push origin feature-branch-name`)。
|
||||
5. 创建一个 Pull Request。
|
||||
1. Fork this repository.
|
||||
2. Create a new branch(`git checkout -b feature-branch-name`)。
|
||||
3. Commit your changes(`git commit -am 'Add some feature'`)。
|
||||
4. Push to branch(`git push origin feature-branch-name`)。
|
||||
5. Create a Pull Request.
|
||||
|
||||
请确保你的代码遵循 [Flutter 风格指南](https://flutter.dev/docs/development/tools/formatting) 并包含适当的测试。
|
||||
Please make sure that your code to follow [Flutter style guide](https://flutter.dev/docs/development/tools/formatting) and include the appropriate tests.
|
||||
|
||||
## 📄 许可证
|
||||
## 📄 License
|
||||
|
||||
此项目基于 AGPL-3.0 许可证进行许可,详情请参阅 [LICENSE](LICENSE) 文件。
|
||||
This project is licensed under the AGPL-3.0 LICENSE, see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## 💖 鸣谢
|
||||
## 💖 Thanks
|
||||
|
||||
- 感谢 Flutter 团队提供出色的框架。
|
||||
- 特别感谢开源社区的宝贵贡献。
|
||||
- Thanks to the Flutter team for the excellent framework.
|
||||
- Special thanks to the open source community for their valuable contributions.
|
||||
|
||||
## 🥪 捐助
|
||||
## 🥪 Sponsor
|
||||
|
||||
可以给我买一个三明治,让我更有动力继续开发。
|
||||
You can buy me a sandwich to keep me motivated to continue developing.
|
||||
|
||||
<img src="res/sponsor/wechat.jpg" style="width:300px" alt="Sponsor"/>
|
||||
<img src="res/sponsor/wechat.jpg" style="width:300px" alt="Sponsor"/>
|
||||
|
||||
### 捐助者名单
|
||||
### List of sponsors
|
||||
|
||||
如果您想要出现在名单中,可以给我留言,排名不分先后,名单会定期更新。
|
||||
If you want to appear on the list, you can leave your Github username in the comment, in no particular order, and the list will be updated regularly.
|
||||
|
||||
| 捐助者 | 金额 | 捐助者 | 金额 |
|
||||
|---------------------------------------|----------|-----|--------|
|
||||
| [dsxksss](https://github.com/dsxksss) | 50 CNY | 十一 | 20 CNY |
|
||||
| 沭飏秋 | 10 CNY | 朱东杰 | 60 CNY |
|
||||
| 匿名 | 5 CNY | wu | 10 CNY |
|
||||
| 云烨 | 2.76 CNY | | |
|
||||
| Sponsor | Price | Sponsor | Price |
|
||||
|-----------------------------------| -------- | ------------------------------------------------ | ------ |
|
||||
| [dsxksss](https://github.com/dsxksss) | 50 CNY | 十* | 20 CNY |
|
||||
| 沭** | 10 CNY | 朱东杰 | 60 CNY |
|
||||
| *Person* | 5 CNY | wu* | 10 CNY |
|
||||
| 云* | 2.76 CNY | 不对味的雪碧 | 10 CNY |
|
||||
| w** | 6.6 CNY | [帕斯卡的芦苇](https://github.com/xiaoxianzi-99) | 10 CNY |
|
||||
| 不** | 20 CNY | 曾** | 20 CNY |
|
||||
| *Person* | 20 CNY | *Person* | 18.88 CNY |
|
||||
| Lucci | 9.9 CNY | *Person* | 5 CNY |
|
||||
| 宋** | 5 CNY | 翰** | 5 CNY |
|
||||
|
||||
189
README.zh.md
Normal file
189
README.zh.md
Normal file
@@ -0,0 +1,189 @@
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="res/banner/dark_zh.svg">
|
||||
<source media="(prefers-color-scheme: light)" srcset="res/banner/light_zh.svg">
|
||||
<img alt="The preview for moodiary." src="res/banner/light_zh.svg">
|
||||
</picture>
|
||||
<p align="center">简体中文 | <a href="README.md">English</a></p>
|
||||
|
||||
<p align="center"><a href="https://answer.moodiary.net" target="_blank">官方论坛</a>丨QQ群: <a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=xGr0TNp_X1z3XEn09_iE_iGSLolQwl6Y&jump_from=webapi&authKey=ZmSb2oEd94FSXxBXRBq53hgTjjvcfmgkQrduB3uL12XtRylPmRlO2OdFz6R25tIo">760014526</a>丨Telegram: <a target="_blank" href="https://t.me/openmoodiary">openmoodiary</a></p>
|
||||
|
||||
<div align="center">
|
||||
<img src="https://img.shields.io/badge/Flutter-3.29.2-blue?style=for-the-badge">
|
||||
<img src="https://img.shields.io/github/repo-size/ZhuJHua/moodiary?style=for-the-badge&color=ff7070">
|
||||
<img src="https://img.shields.io/github/stars/ZhuJHua/moodiary?style=for-the-badge&color=965f8a">
|
||||
<img src="https://img.shields.io/github/v/release/ZhuJHua/moodiary?style=for-the-badge&color=4f5e7f">
|
||||
<img src="https://img.shields.io/github/license/ZhuJHua/moodiary?style=for-the-badge&color=4ac6b7">
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
## ✨ 功能特性
|
||||
|
||||
- **跨平台支持**:🌍 兼容 Android、iOS、Windows、MacOS、Linux\*。
|
||||
- **Material Design**:🎨 界面直观且用户友好,遵循 Material Design 设计规范。
|
||||
- **多种编辑器**:📝 支持 Markdown 、纯文本、富文本等多种形式的文本编辑。
|
||||
- **多媒体附件**:📷 可以为你的日记添加图片、音频、视频甚至画一张画。
|
||||
- **搜索和分类**:🔍 轻松通过全文搜索及分类管理你的日记。
|
||||
- **自定义主题**:🌈 支持浅色和深色模式,以及多种配色的主题。
|
||||
- **自定义字体**:✍️ 支持导入不同的字体,并支持可变字体。
|
||||
- **数据安全**:🔒 通过密码来保障你的日记安全,支持通过生物识别解锁。
|
||||
- **导出和分享**:🧾 支持所有数据的导入/导出,以及单篇日记的分享。
|
||||
- **备份与同步**:☁ 支持局域网同步,快速在设备间同步数据,以及 WebDav 备份。
|
||||
- **足迹地图**:🗺️ 在地图上查看你足迹,生活中的每一步都值得被记录。
|
||||
- **智能助手**:💬 支持接入第三方大模型,提供问答、情绪分析等功能。
|
||||
- **本地自然语言处理(NLP)**:🤖 更安全的智能助手,让你的日记更懂你。
|
||||
|
||||
(注:跨平台能力由 Flutter 提供,带 * 号的平台可能需要更多测试)
|
||||
|
||||
## 🔧 主要技术栈
|
||||
|
||||
- [Flutter](https://github.com/flutter/flutter)(跨平台 UI 框架)
|
||||
- [Isar](https://github.com/isar/isar)(高性能本地数据库)
|
||||
- [GetX](https://github.com/jonataslaw/getx)(状态管理框架)
|
||||
|
||||
## 📸 应用截图
|
||||
|
||||
> 应用持续更新中,新版本界面可能稍有变化
|
||||
|
||||
### 移动端
|
||||
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="res/screenshot/mobile_dark_zh.webp">
|
||||
<source media="(prefers-color-scheme: light)" srcset="res/screenshot/mobile_light_zh.webp">
|
||||
<img alt="The mobile screenshot for moodiary." src="res/screenshot/mobile_light_zh.webp">
|
||||
</picture>
|
||||
|
||||
### 桌面端
|
||||
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="res/screenshot/desktop_dark_zh.webp">
|
||||
<source media="(prefers-color-scheme: light)" srcset="res/screenshot/desktop_light_zh.webp">
|
||||
<img alt="The desktop screenshot for moodiary." src="res/screenshot/desktop_light_zh.webp">
|
||||
</picture>
|
||||
|
||||
## 🚀 安装指南
|
||||
|
||||
### 第三方 SDK
|
||||
|
||||
某些能力需要自行申请第三方 SDK,下列服务商均提供免费的版本,获取到的 Key 在实验室中配置。
|
||||
|
||||
#### 天气服务
|
||||
|
||||
- [和风天气](https://dev.qweather.com/docs/api/)
|
||||
|
||||
#### 地图服务
|
||||
|
||||
- [天地图](http://lbs.tianditu.gov.cn/server/MapService.html)
|
||||
|
||||
#### 智能助手
|
||||
|
||||
- [腾讯混元大模型](https://cloud.tencent.com/document/product/1729/97731)
|
||||
|
||||
### 直接安装
|
||||
|
||||
通过下载 Release 中已编译好的安装包来使用,如果没有你所需要的平台,请使用手动编译。
|
||||
|
||||
### 手动编译
|
||||
|
||||
#### 环境要求
|
||||
|
||||
> 我总是会使用最新的 Flutter 版本(如果可能的话),使用新版本可以带来更多的功能和更好的性能提升,永远不要使用老版本除非你希望代码变成一坨 💩
|
||||
|
||||
- Flutter SDK (>= 3.29.0 Stable)(建议使用 fvm 来管理 flutter 版本)
|
||||
- Dart (>= 3.7.0)
|
||||
- Rust 工具链(Nightly)
|
||||
- Clang/LLVM
|
||||
- 兼容的 IDE(如 Android Studio、Visual Studio Code)
|
||||
|
||||
#### 安装步骤
|
||||
|
||||
> 注意:出于安全考虑,我并没有在代码库中包含我的签名,当您需要手动打包时,需要自己修改对应平台的配置文件,例如安卓平台的 build.gradle,修改包名后打包,感谢您的理解
|
||||
|
||||
1. **克隆仓库**:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/ZhuJHua/moodiary.git
|
||||
cd moodiary
|
||||
```
|
||||
|
||||
2. **安装依赖**:
|
||||
|
||||
```bash
|
||||
flutter pub get
|
||||
```
|
||||
|
||||
3. **运行应用**:
|
||||
|
||||
```bash
|
||||
flutter run
|
||||
```
|
||||
|
||||
4. **打包发布**:
|
||||
|
||||
- Android: `flutter build apk`
|
||||
- iOS: `flutter build ipa`
|
||||
- Windows: `flutter build windows`
|
||||
- MacOS: `flutter build macos`
|
||||
|
||||
## 📝 更多说明
|
||||
|
||||
### 自然语言处理(NLP)
|
||||
|
||||
> 处于实验阶段
|
||||
|
||||
如今,越来越多的行业产品开始融入 AI 技术,这无疑极大地提升了我们的使用体验。然而,对于日记应用来说,将数据交给大型模型处理并不可接受,因为无法确定这些数据是否会被用于训练。因此,更好的方法是采用本地模型。虽然由于体积限制,本地模型的能力可能不如大型模型强大,但在一定程度上仍能为我们提供必要的帮助。
|
||||
|
||||
目前,我在源码中集成了以下任务:
|
||||
|
||||
#### 基于 Bert 预训练模型的 SQuAD 任务
|
||||
|
||||
我采用了 MobileBert 来处理 SQuAD 任务,这是一个简单的机器阅读理解任务。你可以向它提出问题,它会返回你需要的答案。模型文件采用 TensorFlow Lite 所需的 `.tflite` 格式,所以你可以添加自己的模型文件到 `assets/tflite` 目录下。
|
||||
|
||||
感谢以下开源项目:
|
||||
|
||||
- [Chinese MobileBERT](https://github.com/ymcui/Chinese-MobileBERT)
|
||||
- [Mobilebert](https://github.com/google-research/google-research/tree/master/mobilebert)
|
||||
- [ChineseSquad](https://github.com/junzeng-pluto/ChineseSquad)
|
||||
|
||||
## 🤝 贡献指南
|
||||
|
||||
欢迎贡献!请按照以下步骤进行贡献:
|
||||
|
||||
1. Fork 本仓库。
|
||||
2. 创建一个新分支(`git checkout -b feature-branch-name`)。
|
||||
3. 提交你的修改(`git commit -am 'Add some feature'`)。
|
||||
4. 推送到分支(`git push origin feature-branch-name`)。
|
||||
5. 创建一个 Pull Request。
|
||||
|
||||
请确保你的代码遵循 [Flutter 风格指南](https://flutter.dev/docs/development/tools/formatting) 并包含适当的测试。
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
此项目基于 AGPL-3.0 许可证进行许可,详情请参阅 [LICENSE](LICENSE) 文件。
|
||||
|
||||
## 💖 鸣谢
|
||||
|
||||
- 感谢 Flutter 团队提供出色的框架。
|
||||
- 特别感谢开源社区的宝贵贡献。
|
||||
|
||||
## 🥪 捐助
|
||||
|
||||
可以给我买一个三明治,让我更有动力继续开发。
|
||||
|
||||
<img src="res/sponsor/wechat.jpg" style="width:300px" alt="Sponsor"/>
|
||||
|
||||
### 捐助者名单
|
||||
|
||||
如果您想要出现在名单中,可以在留言中留下您的 Github 用户名,排名不分先后,名单会定期更新。
|
||||
|
||||
| 捐助者 | 金额 | 捐助者 | 金额 |
|
||||
| ------------------------------------- | -------- | ------------------------------------------------ | --------- |
|
||||
| [dsxksss](https://github.com/dsxksss) | 50 CNY | 十* | 20 CNY |
|
||||
| 沭** | 10 CNY | 朱东杰 | 60 CNY |
|
||||
| *人* | 5 CNY | wu* | 10 CNY |
|
||||
| 云* | 2.76 CNY | 不对味的雪碧 | 10 CNY |
|
||||
| w** | 6.6 CNY | [帕斯卡的芦苇](https://github.com/xiaoxianzi-99) | 10 CNY |
|
||||
| 不** | 20 CNY | 曾** | 20 CNY |
|
||||
| *人* | 20 CNY | *人* | 18.88 CNY |
|
||||
| Lucci | 9.9 CNY | *人* | 5 CNY |
|
||||
| 宋** | 5 CNY | 翰** | 5 CNY |
|
||||
@@ -1,33 +1,24 @@
|
||||
# This file configures the analyzer, which statically analyzes Dart code to
|
||||
# check for errors, warnings, and lints.
|
||||
#
|
||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||
# invoked from the command line by running `flutter analyze`.
|
||||
|
||||
# The following line activates a set of recommended lints for Flutter apps,
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
# included above or to enable additional rules. A list of all available lints
|
||||
# and their documentation is published at https://dart.dev/lints.
|
||||
#
|
||||
# Instead of disabling a lint rule for the entire project in the
|
||||
# section below, it can also be suppressed for a single line of code
|
||||
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||
# producing the lint.
|
||||
rules:
|
||||
prefer_const_constructors: true
|
||||
prefer_const_literals_to_create_immutables: true
|
||||
prefer_const_declarations: true
|
||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||
prefer_final_in_for_each: true
|
||||
prefer_final_fields: true
|
||||
prefer_final_locals: true
|
||||
|
||||
analyzer:
|
||||
plugins:
|
||||
- custom_lint
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
exclude:
|
||||
- "**/*.g.dart"
|
||||
- "**/*.freezed.dart"
|
||||
- "**/*.gr.dart"
|
||||
- "**/*.mocks.dart"
|
||||
- "rust_builder/**"
|
||||
- "ios/**"
|
||||
- "android/**"
|
||||
- "windows/**"
|
||||
- "macos/**"
|
||||
errors:
|
||||
invalid_annotation_target: ignore
|
||||
|
||||
4
android/.gitignore
vendored
4
android/.gitignore
vendored
@@ -1,8 +1,10 @@
|
||||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/app/.cxx
|
||||
/.kotlin
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/gradlew.bats
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@ if (flutterVersionName == null) {
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "cn.yooss.mood_diary"
|
||||
compileSdk = 35
|
||||
ndkVersion = "27.1.12297006"
|
||||
namespace = "cn.yooss.moodiary"
|
||||
compileSdk = 36
|
||||
ndkVersion = "28.0.13004108"
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
@@ -51,10 +51,11 @@ android {
|
||||
// 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.
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
targetSdk = 36
|
||||
versionCode = flutterVersionCode.toInteger()
|
||||
versionName = flutterVersionName
|
||||
ndk {
|
||||
//noinspection ChromeOsAbiSupport
|
||||
abiFilters 'arm64-v8a'
|
||||
}
|
||||
}
|
||||
@@ -68,6 +69,9 @@ android {
|
||||
}
|
||||
debug {
|
||||
signingConfig = signingConfigs.config
|
||||
resValue "string", "app_name", "Moodiary Debug"
|
||||
applicationIdSuffix ".debug"
|
||||
versionNameSuffix "-debug"
|
||||
}
|
||||
profile {
|
||||
signingConfig = signingConfigs.config
|
||||
|
||||
@@ -33,9 +33,9 @@
|
||||
</queries>
|
||||
<application
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/launcher_icon"
|
||||
android:label="Moodiary"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:icon="@mipmap/launcher_icon"
|
||||
android:label="@string/app_name"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:usesCleartextTraffic="true">
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package cn.yooss.mood_diary
|
||||
|
||||
import com.github.gzuliyujiang.oaid.IGetter
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import java.lang.Exception
|
||||
|
||||
class HandleGetOAID(private var resultCallback: MethodChannel.Result) : IGetter {
|
||||
override fun onOAIDGetComplete(result: String) {
|
||||
resultCallback.success(result)
|
||||
}
|
||||
|
||||
override fun onOAIDGetError(error: Exception?) {
|
||||
resultCallback.success(null)
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
package cn.yooss.mood_diary
|
||||
package cn.yooss.moodiary
|
||||
|
||||
import android.os.Bundle
|
||||
import com.github.gzuliyujiang.oaid.DeviceID
|
||||
import com.github.gzuliyujiang.oaid.IGetter
|
||||
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
|
||||
|
||||
class MainActivity : FlutterFragmentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
|
||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||
super.configureFlutterEngine(flutterEngine)
|
||||
@@ -27,15 +25,24 @@ class MainActivity : FlutterFragmentActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun getOAID(resultCallback: MethodChannel.Result) {
|
||||
if (DeviceID.supportedOAID(application)) {
|
||||
DeviceID.getOAID(application, HandleGetOAID(resultCallback));
|
||||
DeviceID.getOAID(application, HandleGetOAID(resultCallback))
|
||||
} else {
|
||||
resultCallback.success(null)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class HandleGetOAID(private var resultCallback: MethodChannel.Result) : IGetter {
|
||||
override fun onOAIDGetComplete(result: String) {
|
||||
resultCallback.success(result)
|
||||
}
|
||||
|
||||
override fun onOAIDGetError(error: Exception?) {
|
||||
resultCallback.success(null)
|
||||
}
|
||||
}
|
||||
4
android/app/src/main/res/values/app_name.xml
Normal file
4
android/app/src/main/res/values/app_name.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Moodiary</string>
|
||||
</resources>
|
||||
@@ -22,8 +22,8 @@ subprojects {
|
||||
if (project.plugins.hasPlugin("com.android.application") ||
|
||||
project.plugins.hasPlugin("com.android.library")) {
|
||||
project.android {
|
||||
compileSdkVersion 35
|
||||
buildToolsVersion "35.0.0"
|
||||
compileSdkVersion 36
|
||||
buildToolsVersion "36.0.0"
|
||||
}
|
||||
}
|
||||
if (project.hasProperty("android")) {
|
||||
|
||||
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.9-all.zip
|
||||
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.11.1-all.zip
|
||||
|
||||
90
android/gradlew.bat
vendored
Executable file
90
android/gradlew.bat
vendored
Executable file
@@ -0,0 +1,90 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -25,8 +25,8 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version '8.7.3' apply false
|
||||
id "org.jetbrains.kotlin.android" version "2.0.21" apply false
|
||||
id "com.android.application" version '8.9.1' apply false
|
||||
id "org.jetbrains.kotlin.android" version "2.1.20" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
||||
19
build.yaml
Normal file
19
build.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
targets:
|
||||
$default:
|
||||
builders:
|
||||
json_serializable:
|
||||
options:
|
||||
any_map: false
|
||||
checked: false
|
||||
constructor: ""
|
||||
create_factory: true
|
||||
create_field_map: false
|
||||
create_json_keys: false
|
||||
create_per_field_to_json: false
|
||||
create_to_json: true
|
||||
disallow_unrecognized_keys: false
|
||||
explicit_to_json: false
|
||||
field_rename: none
|
||||
generic_argument_factories: false
|
||||
ignore_unannotated: false
|
||||
include_if_null: false
|
||||
88
cliff.toml
Normal file
88
cliff.toml
Normal file
@@ -0,0 +1,88 @@
|
||||
# git-cliff ~ default configuration file
|
||||
# https://git-cliff.org/docs/configuration
|
||||
#
|
||||
# Lines starting with "#" are comments.
|
||||
# Configuration options are organized into tables and keys.
|
||||
# See documentation for more information on available options.
|
||||
|
||||
[output]
|
||||
file = "CHANGELOG.md"
|
||||
|
||||
[changelog]
|
||||
# template for the changelog header
|
||||
header = """
|
||||
# Changelog\n
|
||||
All notable changes to this project will be documented in this file.\n
|
||||
"""
|
||||
# template for the changelog body
|
||||
# https://keats.github.io/tera/docs/#introduction
|
||||
body = """
|
||||
{% if version %}\
|
||||
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||
{% else %}\
|
||||
## [unreleased]
|
||||
{% endif %}\
|
||||
{% for group, commits in commits | group_by(attribute="group") %}
|
||||
### {{ group | striptags | trim | upper_first }}
|
||||
{% for commit in commits %}
|
||||
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
|
||||
{% if commit.breaking %}[**breaking**] {% endif %}\
|
||||
{{ commit.message | upper_first }}\
|
||||
{% endfor %}
|
||||
{% endfor %}\n
|
||||
"""
|
||||
# template for the changelog footer
|
||||
footer = """
|
||||
<!-- generated by git-cliff -->
|
||||
"""
|
||||
# remove the leading and trailing s
|
||||
trim = true
|
||||
# postprocessors
|
||||
postprocessors = [
|
||||
# { pattern = '<REPO>', replace = "https://github.com/orhun/git-cliff" }, # replace repository URL
|
||||
]
|
||||
# render body even when there are no releases to process
|
||||
# render_always = true
|
||||
# output file path
|
||||
# output = "test.md"
|
||||
|
||||
[git]
|
||||
# parse the commits based on https://www.conventionalcommits.org
|
||||
conventional_commits = true
|
||||
# filter out the commits that are not conventional
|
||||
filter_unconventional = true
|
||||
# process each line of a commit as an individual commit
|
||||
split_commits = false
|
||||
# regex for preprocessing the commit messages
|
||||
commit_preprocessors = [
|
||||
# Replace issue numbers
|
||||
#{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"},
|
||||
# Check spelling of the commit with https://github.com/crate-ci/typos
|
||||
# If the spelling is incorrect, it will be automatically fixed.
|
||||
#{ pattern = '.*', replace_command = 'typos --write-changes -' },
|
||||
]
|
||||
# regex for parsing and grouping commits
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "<!-- 0 -->🚀 Features" },
|
||||
{ message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" },
|
||||
{ message = "^doc", group = "<!-- 3 -->📚 Documentation" },
|
||||
{ message = "^perf", group = "<!-- 4 -->⚡ Performance" },
|
||||
{ message = "^refactor", group = "<!-- 2 -->🚜 Refactor" },
|
||||
{ message = "^style", group = "<!-- 5 -->🎨 Styling" },
|
||||
{ message = "^test", group = "<!-- 6 -->🧪 Testing" },
|
||||
{ message = "^chore\\(release\\): prepare for", skip = true },
|
||||
{ message = "^chore\\(deps.*\\)", skip = true },
|
||||
{ message = "^chore\\(pr\\)", skip = true },
|
||||
{ message = "^chore\\(pull\\)", skip = true },
|
||||
{ message = "^chore\\(readme\\)", skip = true },
|
||||
{ message = "^chore|^ci", group = "<!-- 7 -->⚙️ Miscellaneous Tasks" },
|
||||
{ body = ".*security", group = "<!-- 8 -->🛡️ Security" },
|
||||
{ message = "^revert", group = "<!-- 9 -->◀️ Revert" },
|
||||
{ message = ".*", group = "<!-- 10 -->💼 Other" },
|
||||
]
|
||||
# filter out the commits that are not matched by commit parsers
|
||||
filter_commits = false
|
||||
# sort the tags topologically
|
||||
topo_order = false
|
||||
# sort the commits inside sections by oldest/newest order
|
||||
sort_commits = "oldest"
|
||||
@@ -1,3 +1,4 @@
|
||||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
||||
- shared_preferences: true
|
||||
@@ -1,3 +1,4 @@
|
||||
rust_input: crate::api
|
||||
rust_root: rust/
|
||||
dart_output: lib/src/rust
|
||||
dart_output: lib/src/rust
|
||||
web: false
|
||||
@@ -1,5 +1,5 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
platform :ios, '18.2'
|
||||
platform :ios, '15.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
121
ios/Podfile.lock
121
ios/Podfile.lock
@@ -5,7 +5,6 @@ PODS:
|
||||
- Flutter
|
||||
- connectivity_plus (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- device_info_plus (0.0.1):
|
||||
- Flutter
|
||||
- DKImagePickerController/Core (4.3.9):
|
||||
@@ -62,14 +61,19 @@ PODS:
|
||||
- Flutter
|
||||
- flutter_native_splash (2.4.3):
|
||||
- Flutter
|
||||
- fluttertoast (0.0.2):
|
||||
- flutter_secure_storage_darwin (10.0.0):
|
||||
- Flutter
|
||||
- Toast
|
||||
- FlutterMacOS
|
||||
- fvp (0.31.2):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- mdk (~> 0.32.0)
|
||||
- gal (1.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- geolocator_apple (1.2.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- image_picker_ios (0.0.1):
|
||||
- Flutter
|
||||
- isar_flutter_libs (1.0.0):
|
||||
@@ -92,18 +96,14 @@ PODS:
|
||||
- Mantle (2.2.0):
|
||||
- Mantle/extobjc (= 2.2.0)
|
||||
- Mantle/extobjc (2.2.0)
|
||||
- media_kit_libs_ios_video (1.0.4):
|
||||
- mdk (0.32.0)
|
||||
- mobile_scanner (7.0.0):
|
||||
- Flutter
|
||||
- media_kit_native_event_loop (1.0.0):
|
||||
- Flutter
|
||||
- media_kit_video (0.0.1):
|
||||
- FlutterMacOS
|
||||
- moodiary_rust (0.0.1):
|
||||
- Flutter
|
||||
- network_info_plus (0.0.1):
|
||||
- Flutter
|
||||
- ObjectBox (4.0.1)
|
||||
- objectbox_flutter_libs (0.0.1):
|
||||
- Flutter
|
||||
- ObjectBox (= 4.0.1)
|
||||
- OrderedSet (6.0.3)
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
@@ -114,13 +114,7 @@ PODS:
|
||||
- Flutter
|
||||
- quill_native_bridge_ios (0.0.1):
|
||||
- Flutter
|
||||
- record_darwin (1.0.0):
|
||||
- Flutter
|
||||
- rive_common (0.0.1):
|
||||
- Flutter
|
||||
- rust_lib_mood_diary (0.0.1):
|
||||
- Flutter
|
||||
- screen_brightness_ios (0.1.0):
|
||||
- record_ios (1.0.0):
|
||||
- Flutter
|
||||
- SDWebImage (5.19.7):
|
||||
- SDWebImage/Core (= 5.19.7)
|
||||
@@ -159,21 +153,18 @@ PODS:
|
||||
- TensorFlowLiteSwift (= 2.12.0)
|
||||
- TensorFlowLiteSwift/CoreML (= 2.12.0)
|
||||
- TensorFlowLiteSwift/Metal (= 2.12.0)
|
||||
- Toast (4.1.1)
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
- video_player_avfoundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- volume_controller (0.0.1):
|
||||
- Flutter
|
||||
- wakelock_plus (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- app_links (from `.symlinks/plugins/app_links/ios`)
|
||||
- audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/ios`)
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`)
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- fc_native_video_thumbnail (from `.symlinks/plugins/fc_native_video_thumbnail/darwin`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
@@ -182,32 +173,27 @@ DEPENDENCIES:
|
||||
- flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
|
||||
- flutter_keyboard_visibility_temp_fork (from `.symlinks/plugins/flutter_keyboard_visibility_temp_fork/ios`)
|
||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
||||
- flutter_secure_storage_darwin (from `.symlinks/plugins/flutter_secure_storage_darwin/darwin`)
|
||||
- fvp (from `.symlinks/plugins/fvp/darwin`)
|
||||
- gal (from `.symlinks/plugins/gal/darwin`)
|
||||
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`)
|
||||
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`)
|
||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||
- isar_flutter_libs (from `.symlinks/plugins/isar_flutter_libs/ios`)
|
||||
- local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`)
|
||||
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
||||
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
|
||||
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
|
||||
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`)
|
||||
- moodiary_rust (from `.symlinks/plugins/moodiary_rust/ios`)
|
||||
- network_info_plus (from `.symlinks/plugins/network_info_plus/ios`)
|
||||
- objectbox_flutter_libs (from `.symlinks/plugins/objectbox_flutter_libs/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- quill_native_bridge_ios (from `.symlinks/plugins/quill_native_bridge_ios/ios`)
|
||||
- record_darwin (from `.symlinks/plugins/record_darwin/ios`)
|
||||
- rive_common (from `.symlinks/plugins/rive_common/ios`)
|
||||
- rust_lib_mood_diary (from `.symlinks/plugins/rust_lib_mood_diary/ios`)
|
||||
- screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
|
||||
- record_ios (from `.symlinks/plugins/record_ios/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||
- tflite_flutter (from `.symlinks/plugins/tflite_flutter/ios`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
|
||||
- volume_controller (from `.symlinks/plugins/volume_controller/ios`)
|
||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
@@ -216,14 +202,13 @@ SPEC REPOS:
|
||||
- DKPhotoGallery
|
||||
- libwebp
|
||||
- Mantle
|
||||
- ObjectBox
|
||||
- mdk
|
||||
- OrderedSet
|
||||
- SDWebImage
|
||||
- SDWebImageWebPCoder
|
||||
- SwiftyGif
|
||||
- TensorFlowLiteC
|
||||
- TensorFlowLiteSwift
|
||||
- Toast
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
app_links:
|
||||
@@ -231,7 +216,7 @@ EXTERNAL SOURCES:
|
||||
audioplayers_darwin:
|
||||
:path: ".symlinks/plugins/audioplayers_darwin/ios"
|
||||
connectivity_plus:
|
||||
:path: ".symlinks/plugins/connectivity_plus/darwin"
|
||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||
device_info_plus:
|
||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||
fc_native_video_thumbnail:
|
||||
@@ -248,28 +233,26 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/flutter_keyboard_visibility_temp_fork/ios"
|
||||
flutter_native_splash:
|
||||
:path: ".symlinks/plugins/flutter_native_splash/ios"
|
||||
fluttertoast:
|
||||
:path: ".symlinks/plugins/fluttertoast/ios"
|
||||
flutter_secure_storage_darwin:
|
||||
:path: ".symlinks/plugins/flutter_secure_storage_darwin/darwin"
|
||||
fvp:
|
||||
:path: ".symlinks/plugins/fvp/darwin"
|
||||
gal:
|
||||
:path: ".symlinks/plugins/gal/darwin"
|
||||
geolocator_apple:
|
||||
:path: ".symlinks/plugins/geolocator_apple/ios"
|
||||
:path: ".symlinks/plugins/geolocator_apple/darwin"
|
||||
image_picker_ios:
|
||||
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||
isar_flutter_libs:
|
||||
:path: ".symlinks/plugins/isar_flutter_libs/ios"
|
||||
local_auth_darwin:
|
||||
:path: ".symlinks/plugins/local_auth_darwin/darwin"
|
||||
media_kit_libs_ios_video:
|
||||
:path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
|
||||
media_kit_native_event_loop:
|
||||
:path: ".symlinks/plugins/media_kit_native_event_loop/ios"
|
||||
media_kit_video:
|
||||
:path: ".symlinks/plugins/media_kit_video/ios"
|
||||
mobile_scanner:
|
||||
:path: ".symlinks/plugins/mobile_scanner/darwin"
|
||||
moodiary_rust:
|
||||
:path: ".symlinks/plugins/moodiary_rust/ios"
|
||||
network_info_plus:
|
||||
:path: ".symlinks/plugins/network_info_plus/ios"
|
||||
objectbox_flutter_libs:
|
||||
:path: ".symlinks/plugins/objectbox_flutter_libs/ios"
|
||||
package_info_plus:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider_foundation:
|
||||
@@ -278,14 +261,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
quill_native_bridge_ios:
|
||||
:path: ".symlinks/plugins/quill_native_bridge_ios/ios"
|
||||
record_darwin:
|
||||
:path: ".symlinks/plugins/record_darwin/ios"
|
||||
rive_common:
|
||||
:path: ".symlinks/plugins/rive_common/ios"
|
||||
rust_lib_mood_diary:
|
||||
:path: ".symlinks/plugins/rust_lib_mood_diary/ios"
|
||||
screen_brightness_ios:
|
||||
:path: ".symlinks/plugins/screen_brightness_ios/ios"
|
||||
record_ios:
|
||||
:path: ".symlinks/plugins/record_ios/ios"
|
||||
share_plus:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences_foundation:
|
||||
@@ -298,48 +275,42 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
video_player_avfoundation:
|
||||
:path: ".symlinks/plugins/video_player_avfoundation/darwin"
|
||||
volume_controller:
|
||||
:path: ".symlinks/plugins/volume_controller/ios"
|
||||
wakelock_plus:
|
||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
app_links: 3da4c36b46cac3bf24eb897f1a6ce80bda109874
|
||||
app_links: 76b66b60cc809390ca1ad69bfd66b998d2387ac7
|
||||
audioplayers_darwin: ccf9c770ee768abb07e26d90af093f7bab1c12ab
|
||||
connectivity_plus: 2256d3e20624a7749ed21653aafe291a46446fee
|
||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||
fc_native_video_thumbnail: ea75aa9d0f7e7b58215d2ad99ac9dddafc038bc9
|
||||
file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517
|
||||
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
|
||||
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
|
||||
flutter_keyboard_visibility_temp_fork: 95b2d534bacf6ac62e7fcbe5c2a9e2c2a17ce06f
|
||||
flutter_native_splash: 6cad9122ea0fad137d23137dd14b937f3e90b145
|
||||
fluttertoast: 76fea30fcf04176325f6864c87306927bd7d2038
|
||||
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
|
||||
flutter_secure_storage_darwin: ce237a8775b39723566dc72571190a3769d70468
|
||||
fvp: 89275776efede62b7fde1762afa518974e6d6750
|
||||
gal: baecd024ebfd13c441269ca7404792a7152fde89
|
||||
geolocator_apple: 1560c3c875af2a412242c7a923e15d0d401966ff
|
||||
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
|
||||
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
|
||||
isar_flutter_libs: 9fc2cfb928c539e1b76c481ba5d143d556d94920
|
||||
libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009
|
||||
local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391
|
||||
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
|
||||
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
|
||||
media_kit_native_event_loop: 5fba1a849a6c87a34985f1e178a0de5bd444a0cf
|
||||
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
|
||||
mdk: a726c85fd49c002b83d586b278d452f387750889
|
||||
mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93
|
||||
moodiary_rust: e75b3fb63e53d3ba5cfed0edf0b6df5f98c4c5f1
|
||||
network_info_plus: cf61925ab5205dce05a4f0895989afdb6aade5fc
|
||||
ObjectBox: 0bc4bb75eea85f6af06b369148b334c2056bbc29
|
||||
objectbox_flutter_libs: 3af037f7cc35e687acca01f1f6da6cb6c2abc22b
|
||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||
quill_native_bridge_ios: f47af4b14e7757968486641656c5d23250cee521
|
||||
record_darwin: fb1f375f1d9603714f55b8708a903bbb91ffdb0a
|
||||
rive_common: dd421daaf9ae69f0125aa761dd96abd278399952
|
||||
rust_lib_mood_diary: ea9f784d50426d5994e53cecee71cd23d965542a
|
||||
screen_brightness_ios: 5ed898fa50fa82a26171c086ca5e28228f932576
|
||||
record_ios: fee1c924aa4879b882ebca2b4bce6011bcfc3d8b
|
||||
SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3
|
||||
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
|
||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||
@@ -349,12 +320,10 @@ SPEC CHECKSUMS:
|
||||
TensorFlowLiteC: 20785a69299185a379ba9852b6625f00afd7984a
|
||||
TensorFlowLiteSwift: 3a4928286e9e35bdd3e17970f48e53c80d25e793
|
||||
tflite_flutter: 64b192e11352fe36943ab6656e1d49207f1a5595
|
||||
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
|
||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
|
||||
volume_controller: ca1cde542ee70fad77d388f82e9616488110942b
|
||||
wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49
|
||||
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
||||
|
||||
PODFILE CHECKSUM: 9752b5340b4d3f9618318fcd530d907790e2a9f5
|
||||
PODFILE CHECKSUM: ed22e19af5eb4a72710862041c4be54584bcf797
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
10D3882531AED19DB670FEB7 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2698D5B078302CF0E4E6EE6 /* Pods_RunnerTests.framework */; };
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
306627225710E691EF0E0A35 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A1A8341695BDC0741989253 /* Pods_Runner.framework */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
7F6D40933C7341CBD11FBDD8 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51E3DDEC08B33FD4E6BEE95D /* Pods_RunnerTests.framework */; };
|
||||
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 */; };
|
||||
FE9916AC13415D97E045D776 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E85B5AB729F0B2360835644 /* Pods_Runner.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -42,29 +42,31 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
132767BCEC59ECA2C27AAF55 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
2A1A8341695BDC0741989253 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
18106D637ED786D29FE68004 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
51E3DDEC08B33FD4E6BEE95D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
481FF39ABA9170A968D00D47 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
7D210E37B46E2650FA945AB1 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
8E85B5AB729F0B2360835644 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D3787A842552CCA621630495 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
D73569CF22DB2A16EAE0220D /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
E231F0C855BB3DD103DA44E9 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
E7AEAE59248BEA6C8378B114 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
E913EDBE59656A0E8EB14DDA /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
9F8B7E7E836FBA71F1E2767D /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
A910B4CF2D4C960600C998E7 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
A910B4D02D4C960600C998E7 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
A910B4D12D4C961C00C998E7 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = "zh-Hans"; path = "zh-Hans.lproj/Main.storyboard"; sourceTree = "<group>"; };
|
||||
A910B4D22D4C961C00C998E7 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = "zh-Hans"; path = "zh-Hans.lproj/LaunchScreen.storyboard"; sourceTree = "<group>"; };
|
||||
D0CBE1B7A5C3D8E84DECC981 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
F2698D5B078302CF0E4E6EE6 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
FD54B3E6C9A9278793818CA8 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -72,7 +74,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
306627225710E691EF0E0A35 /* Pods_Runner.framework in Frameworks */,
|
||||
FE9916AC13415D97E045D776 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -80,22 +82,13 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7F6D40933C7341CBD11FBDD8 /* Pods_RunnerTests.framework in Frameworks */,
|
||||
10D3882531AED19DB670FEB7 /* Pods_RunnerTests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
32F89EBD1A567B14B95A803E /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2A1A8341695BDC0741989253 /* Pods_Runner.framework */,
|
||||
51E3DDEC08B33FD4E6BEE95D /* Pods_RunnerTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -107,12 +100,12 @@
|
||||
4358F1D645E2BE879D24A551 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D3787A842552CCA621630495 /* Pods-Runner.debug.xcconfig */,
|
||||
E913EDBE59656A0E8EB14DDA /* Pods-Runner.release.xcconfig */,
|
||||
7D210E37B46E2650FA945AB1 /* Pods-Runner.profile.xcconfig */,
|
||||
D73569CF22DB2A16EAE0220D /* Pods-RunnerTests.debug.xcconfig */,
|
||||
E7AEAE59248BEA6C8378B114 /* Pods-RunnerTests.release.xcconfig */,
|
||||
E231F0C855BB3DD103DA44E9 /* Pods-RunnerTests.profile.xcconfig */,
|
||||
D0CBE1B7A5C3D8E84DECC981 /* Pods-Runner.debug.xcconfig */,
|
||||
FD54B3E6C9A9278793818CA8 /* Pods-Runner.release.xcconfig */,
|
||||
132767BCEC59ECA2C27AAF55 /* Pods-Runner.profile.xcconfig */,
|
||||
9F8B7E7E836FBA71F1E2767D /* Pods-RunnerTests.debug.xcconfig */,
|
||||
18106D637ED786D29FE68004 /* Pods-RunnerTests.release.xcconfig */,
|
||||
481FF39ABA9170A968D00D47 /* Pods-RunnerTests.profile.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
@@ -136,7 +129,7 @@
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
4358F1D645E2BE879D24A551 /* Pods */,
|
||||
32F89EBD1A567B14B95A803E /* Frameworks */,
|
||||
B0AE19443A2FC97A6908AB80 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -164,6 +157,15 @@
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B0AE19443A2FC97A6908AB80 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8E85B5AB729F0B2360835644 /* Pods_Runner.framework */,
|
||||
F2698D5B078302CF0E4E6EE6 /* Pods_RunnerTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -171,7 +173,7 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
802002D8FFADD5D24C50A9FA /* [CP] Check Pods Manifest.lock */,
|
||||
1C96070FD74708494C91C45C /* [CP] Check Pods Manifest.lock */,
|
||||
331C807D294A63A400263BE5 /* Sources */,
|
||||
331C807F294A63A400263BE5 /* Resources */,
|
||||
CE18F12EDBB0BF2FD5BF0F0E /* Frameworks */,
|
||||
@@ -190,15 +192,15 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
3190980419AFCAD7AC11C68D /* [CP] Check Pods Manifest.lock */,
|
||||
6FA29CD45882489C42CB69A1 /* [CP] Check Pods Manifest.lock */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
DDBAC86E6B3F372170C284A0 /* [CP] Embed Pods Frameworks */,
|
||||
B482CF705AC6985E445540F2 /* [CP] Copy Pods Resources */,
|
||||
523FF08A9B798D86BA8B9DD9 /* Frameworks */,
|
||||
24F448645ED8BCE73BE4BB9F /* [CP] Embed Pods Frameworks */,
|
||||
E28A122442FA326B99260C5B /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -231,11 +233,11 @@
|
||||
};
|
||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
developmentRegion = "zh-Hans";
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
"zh-Hans",
|
||||
);
|
||||
mainGroup = 97C146E51CF9000F007C117D;
|
||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||
@@ -270,45 +272,7 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3190980419AFCAD7AC11C68D /* [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;
|
||||
};
|
||||
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";
|
||||
};
|
||||
802002D8FFADD5D24C50A9FA /* [CP] Check Pods Manifest.lock */ = {
|
||||
1C96070FD74708494C91C45C /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -330,6 +294,61 @@
|
||||
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;
|
||||
};
|
||||
24F448645ED8BCE73BE4BB9F /* [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;
|
||||
};
|
||||
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";
|
||||
};
|
||||
6FA29CD45882489C42CB69A1 /* [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;
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
@@ -345,7 +364,7 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
B482CF705AC6985E445540F2 /* [CP] Copy Pods Resources */ = {
|
||||
E28A122442FA326B99260C5B /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -362,23 +381,6 @@
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
DDBAC86E6B3F372170C284A0 /* [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;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -413,7 +415,8 @@
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C146FB1CF9000F007C117D /* Base */,
|
||||
A910B4CF2D4C960600C998E7 /* en */,
|
||||
A910B4D12D4C961C00C998E7 /* zh-Hans */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
@@ -421,7 +424,8 @@
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C147001CF9000F007C117D /* Base */,
|
||||
A910B4D02D4C960600C998E7 /* en */,
|
||||
A910B4D22D4C961C00C998E7 /* zh-Hans */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
@@ -434,6 +438,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
@@ -467,6 +472,7 @@
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
@@ -495,9 +501,10 @@
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 3XA29H789G;
|
||||
ENABLE_BITCODE = NO;
|
||||
FLUTTER_BUILD_MODE = release;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -505,16 +512,21 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "moodiary-dev";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "moodiary-ios";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
331C8088294A63A400263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D73569CF22DB2A16EAE0220D /* Pods-RunnerTests.debug.xcconfig */;
|
||||
baseConfigurationReference = 9F8B7E7E836FBA71F1E2767D /* Pods-RunnerTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
@@ -534,7 +546,7 @@
|
||||
};
|
||||
331C8089294A63A400263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = E7AEAE59248BEA6C8378B114 /* Pods-RunnerTests.release.xcconfig */;
|
||||
baseConfigurationReference = 18106D637ED786D29FE68004 /* Pods-RunnerTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
@@ -552,7 +564,7 @@
|
||||
};
|
||||
331C808A294A63A400263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = E231F0C855BB3DD103DA44E9 /* Pods-RunnerTests.profile.xcconfig */;
|
||||
baseConfigurationReference = 481FF39ABA9170A968D00D47 /* Pods-RunnerTests.profile.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
@@ -573,6 +585,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
@@ -631,6 +644,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
@@ -664,6 +678,8 @@
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "DISABLE_PUSH_NOTIFICATIONS=1";
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
@@ -673,7 +689,7 @@
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
@@ -694,9 +710,10 @@
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 3XA29H789G;
|
||||
ENABLE_BITCODE = NO;
|
||||
FLUTTER_BUILD_MODE = debug;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -704,10 +721,15 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "moodiary-dev";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "moodiary-ios";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
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;
|
||||
@@ -725,9 +747,10 @@
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 3XA29H789G;
|
||||
ENABLE_BITCODE = NO;
|
||||
FLUTTER_BUILD_MODE = release;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -735,9 +758,14 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "moodiary-dev";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "moodiary-ios";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
@@ -59,6 +59,8 @@
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
enableGPUValidationMode = "1"
|
||||
showGraphicsOverview = "Yes"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
|
||||
@@ -20,24 +20,38 @@
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppleMusicUsageDescription</key>
|
||||
<string>应用需要您的同意,才能访问媒体资料库</string>
|
||||
<key>NSBluetoothAlwaysUsageDescription</key>
|
||||
<string>应用需要您的同意,才能使用蓝牙</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>使用你的摄像头拍摄媒体</string>
|
||||
<string>应用需要您的同意,才能访问相机</string>
|
||||
<key>NSContactsUsageDescription</key>
|
||||
<string>应用需要您的同意,才能访问通讯录</string>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>使用你的面部数据解锁</string>
|
||||
<string>应用需要您的同意,才能使用人脸识别</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>应用需要您的同意,才能访问位置</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>访问你的位置信息</string>
|
||||
<string>应用需要您的同意,才能访问位置</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>使用你的麦克风来录制声音</string>
|
||||
<string>应用需要您的同意,才能使用麦克风</string>
|
||||
<key>NSMotionUsageDescription</key>
|
||||
<string>应用需要您的同意,才能访问运动与健身</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>访问你的媒体数据</string>
|
||||
<string>应用需要您的同意,才能访问照片</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>访问你的照片</string>
|
||||
<string>应用需要您的同意,才能访问照片</string>
|
||||
<key>NSSiriUsageDescription</key>
|
||||
<string>应用需要您的同意,才能访问Siri</string>
|
||||
<key>NSSpeechRecognitionUsageDescription</key>
|
||||
<string>应用需要您的同意,才能访问语音识别</string>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
@@ -49,8 +63,6 @@
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
@@ -61,5 +73,7 @@
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>keychain-access-groups</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
44
ios/Runner/zh-Hans.lproj/LaunchScreen.storyboard
Normal file
44
ios/Runner/zh-Hans.lproj/LaunchScreen.storyboard
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="LaunchBackground" translatesAutoresizingMaskIntoConstraints="NO" id="tWc-Dq-wcI"/>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"></imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="3T2-ad-Qdv"/>
|
||||
<constraint firstItem="tWc-Dq-wcI" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="RPx-PI-7Xg"/>
|
||||
<constraint firstItem="tWc-Dq-wcI" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="SdS-ul-q2q"/>
|
||||
<constraint firstAttribute="trailing" secondItem="tWc-Dq-wcI" secondAttribute="trailing" id="Swv-Gf-Rwn"/>
|
||||
<constraint firstAttribute="trailing" secondItem="YRO-k0-Ey4" secondAttribute="trailing" id="TQA-XW-tRk"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="duK-uY-Gun"/>
|
||||
<constraint firstItem="tWc-Dq-wcI" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="kV7-tw-vXt"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="xPn-NY-SIU"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="LaunchImage" width="1152" height="1152"/>
|
||||
<image name="LaunchBackground" width="1" height="1"/>
|
||||
</resources>
|
||||
</document>
|
||||
29
ios/Runner/zh-Hans.lproj/Main.storyboard
Normal file
29
ios/Runner/zh-Hans.lproj/Main.storyboard
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Flutter View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-26" y="-77"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -1,3 +1,4 @@
|
||||
arb-dir: lib/l10n
|
||||
template-arb-file: intl_zh.arb
|
||||
output-localization-file: app_localizations.dart
|
||||
output-localization-file: app_localizations.dart
|
||||
synthetic-package: false
|
||||
160
lib/api/api.dart
160
lib/api/api.dart
@@ -5,25 +5,28 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:mood_diary/common/models/geo.dart';
|
||||
import 'package:mood_diary/common/models/github.dart';
|
||||
import 'package:mood_diary/common/models/hitokoto.dart';
|
||||
import 'package:mood_diary/common/models/hunyuan.dart';
|
||||
import 'package:mood_diary/common/models/image.dart';
|
||||
import 'package:mood_diary/common/models/weather.dart';
|
||||
import 'package:mood_diary/utils/http_util.dart';
|
||||
import 'package:mood_diary/utils/notice_util.dart';
|
||||
import 'package:mood_diary/utils/signature_util.dart';
|
||||
import 'package:refreshed/refreshed.dart';
|
||||
|
||||
import '../utils/data/pref.dart';
|
||||
import 'package:moodiary/common/models/geo.dart';
|
||||
import 'package:moodiary/common/models/github.dart';
|
||||
import 'package:moodiary/common/models/hitokoto.dart';
|
||||
import 'package:moodiary/common/models/hunyuan.dart';
|
||||
import 'package:moodiary/common/models/image.dart';
|
||||
import 'package:moodiary/common/models/weather.dart';
|
||||
import 'package:moodiary/l10n/l10n.dart';
|
||||
import 'package:moodiary/persistence/pref.dart';
|
||||
import 'package:moodiary/utils/http_util.dart';
|
||||
import 'package:moodiary/utils/notice_util.dart';
|
||||
import 'package:moodiary/utils/signature_util.dart';
|
||||
|
||||
class Api {
|
||||
static Future<Stream<String>?> getHunYuan(
|
||||
String id, String key, List<Message> messages, int model) async {
|
||||
String id,
|
||||
String key,
|
||||
List<Message> messages,
|
||||
int model,
|
||||
) async {
|
||||
//获取时间戳
|
||||
var timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
var hunyuanModel = switch (model) {
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
final hunyuanModel = switch (model) {
|
||||
0 => 'hunyuan-lite',
|
||||
1 => 'hunyuan-standard',
|
||||
2 => 'hunyuan-pro',
|
||||
@@ -31,66 +34,82 @@ class Api {
|
||||
_ => 'hunyuan-lite',
|
||||
};
|
||||
//请求正文
|
||||
var body = {
|
||||
final body = {
|
||||
'Model': hunyuanModel,
|
||||
'Messages': messages.map((value) => value.toMap()).toList(),
|
||||
'Messages': messages.map((value) => value.toJson()).toList(),
|
||||
'Stream': true,
|
||||
};
|
||||
|
||||
//获取签名
|
||||
var authorization =
|
||||
SignatureUtil.generateSignature(id, key, timestamp, body);
|
||||
final authorization = SignatureUtil.generateSignature(
|
||||
id,
|
||||
key,
|
||||
timestamp,
|
||||
body,
|
||||
);
|
||||
//构造请求头
|
||||
var header = PublicHeader(
|
||||
'ChatCompletions', timestamp ~/ 1000, '2023-09-01', authorization);
|
||||
final header = PublicHeader(
|
||||
action: 'ChatCompletions',
|
||||
timestamp: timestamp ~/ 1000,
|
||||
version: '2023-09-01',
|
||||
authorization: authorization,
|
||||
);
|
||||
//发起请求
|
||||
return await HttpUtil().postStream('https://hunyuan.tencentcloudapi.com',
|
||||
header: header.toMap(), data: body);
|
||||
return await HttpUtil().postStream(
|
||||
'https://hunyuan.tencentcloudapi.com',
|
||||
header: header.toJson(),
|
||||
data: body,
|
||||
);
|
||||
}
|
||||
|
||||
static Future<Uint8List?> getImageData(String url) async {
|
||||
return (await HttpUtil().get(url, type: ResponseType.bytes)).data;
|
||||
}
|
||||
|
||||
static Future<List<String>?> updatePosition() async {
|
||||
static Future<List<String>?> updatePosition(BuildContext context) async {
|
||||
Position? position;
|
||||
var permission = await Geolocator.checkPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
permission = await Geolocator.requestPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
NoticeUtil.showToast('请开启定位权限');
|
||||
if (permission == LocationPermission.denied && context.mounted) {
|
||||
toast.info(message: context.l10n.noticeEnableLocation);
|
||||
return null;
|
||||
}
|
||||
if (permission == LocationPermission.deniedForever) {
|
||||
NoticeUtil.showToast('请前往设置开启定位权限');
|
||||
if (permission == LocationPermission.deniedForever && context.mounted) {
|
||||
toast.info(message: context.l10n.noticeEnableLocation2);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (await Geolocator.isLocationServiceEnabled()) {
|
||||
position = await Geolocator.getLastKnownPosition(
|
||||
forceAndroidLocationManager: true);
|
||||
forceAndroidLocationManager: true,
|
||||
);
|
||||
position ??= await Geolocator.getCurrentPosition(
|
||||
locationSettings: AndroidSettings(forceLocationManager: true));
|
||||
locationSettings: AndroidSettings(forceLocationManager: true),
|
||||
);
|
||||
}
|
||||
if (position != null) {
|
||||
var local = Localizations.localeOf(Get.context!);
|
||||
var parameters = {
|
||||
if (position != null && context.mounted) {
|
||||
final local = Localizations.localeOf(context);
|
||||
final parameters = {
|
||||
'location':
|
||||
'${double.parse(position.longitude.toStringAsFixed(2))},${double.parse(position.latitude.toStringAsFixed(2))}',
|
||||
'key': PrefUtil.getValue<String>('qweatherKey'),
|
||||
'lang': local
|
||||
'lang': local,
|
||||
};
|
||||
var res = await HttpUtil().get(
|
||||
'https://geoapi.qweather.com/v2/city/lookup',
|
||||
parameters: parameters);
|
||||
var geo =
|
||||
await compute(GeoResponse.fromJson, res.data as Map<String, dynamic>);
|
||||
final res = await HttpUtil().get(
|
||||
'https://${PrefUtil.getValue<String>('qweatherApiHost')}/geo/v2/city/lookup',
|
||||
parameters: parameters,
|
||||
);
|
||||
final geo = await compute(
|
||||
GeoResponse.fromJson,
|
||||
res.data as Map<String, dynamic>,
|
||||
);
|
||||
if (geo.location != null && geo.location!.isNotEmpty) {
|
||||
var city = geo.location!.first;
|
||||
final city = geo.location!.first;
|
||||
return [
|
||||
position.latitude.toString(),
|
||||
position.longitude.toString(),
|
||||
'${city.adm2} ${city.name}'
|
||||
'${city.adm2} ${city.name}',
|
||||
];
|
||||
} else {
|
||||
return null;
|
||||
@@ -100,52 +119,63 @@ class Api {
|
||||
}
|
||||
}
|
||||
|
||||
static Future<List<String>?> updateWeather({required LatLng position}) async {
|
||||
var local = Localizations.localeOf(Get.context!);
|
||||
var parameters = {
|
||||
static Future<List<String>?> updateWeather({
|
||||
required BuildContext context,
|
||||
required LatLng position,
|
||||
}) async {
|
||||
final local = Localizations.localeOf(context);
|
||||
final parameters = {
|
||||
'location':
|
||||
'${double.parse(position.longitude.toStringAsFixed(2))},${double.parse(position.latitude.toStringAsFixed(2))}',
|
||||
'key': PrefUtil.getValue<String>('qweatherKey'),
|
||||
'lang': local
|
||||
'lang': local,
|
||||
};
|
||||
var res = await HttpUtil().get('https://devapi.qweather.com/v7/weather/now',
|
||||
parameters: parameters);
|
||||
var weather = await compute(
|
||||
WeatherResponse.fromJson, res.data as Map<String, dynamic>);
|
||||
final res = await HttpUtil().get(
|
||||
'https://${PrefUtil.getValue<String>('qweatherApiHost')}/v7/weather/now',
|
||||
parameters: parameters,
|
||||
);
|
||||
final weather = await compute(
|
||||
WeatherResponse.fromJson,
|
||||
res.data as Map<String, dynamic>,
|
||||
);
|
||||
if (weather.now != null) {
|
||||
return [
|
||||
weather.now!.icon!,
|
||||
weather.now!.temp!,
|
||||
weather.now!.text!,
|
||||
];
|
||||
return [weather.now!.icon!, weather.now!.temp!, weather.now!.text!];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<GithubRelease?> getGithubRelease() async {
|
||||
var res = await HttpUtil()
|
||||
.get('https://api.github.com/repos/ZhuJHua/moodiary/releases/latest');
|
||||
final res = await HttpUtil().get(
|
||||
'https://api.github.com/repos/ZhuJHua/moodiary/releases/latest',
|
||||
);
|
||||
if (res.data != null) {
|
||||
var githubRelease = await compute(
|
||||
GithubRelease.fromJson, res.data as Map<String, dynamic>);
|
||||
final githubRelease = await compute(
|
||||
GithubRelease.fromJson,
|
||||
res.data as Map<String, dynamic>,
|
||||
);
|
||||
return githubRelease;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<List<String>?> updateHitokoto() async {
|
||||
var res = await HttpUtil().get('https://v1.hitokoto.cn');
|
||||
var hitokoto = await compute(
|
||||
HitokotoResponse.fromJson, res.data as Map<String, dynamic>);
|
||||
final res = await HttpUtil().get('https://v1.hitokoto.cn');
|
||||
final hitokoto = await compute(
|
||||
HitokotoResponse.fromJson,
|
||||
res.data as Map<String, dynamic>,
|
||||
);
|
||||
return [hitokoto.hitokoto!];
|
||||
}
|
||||
|
||||
static Future<List<String>?> updateImageUrl() async {
|
||||
var res = await HttpUtil()
|
||||
.get('https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1');
|
||||
BingImage bingImage =
|
||||
await compute(BingImage.fromJson, res.data as Map<String, dynamic>);
|
||||
final res = await HttpUtil().get(
|
||||
'https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1',
|
||||
);
|
||||
final BingImage bingImage = await compute(
|
||||
BingImage.fromJson,
|
||||
res.data as Map<String, dynamic>,
|
||||
);
|
||||
return ['https://cn.bing.com${bingImage.images?[0].url}'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,110 +1,45 @@
|
||||
class GeoResponse {
|
||||
String? code;
|
||||
List<Location>? location;
|
||||
Refer? refer;
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
GeoResponse({this.code, this.location, this.refer});
|
||||
part 'geo.freezed.dart';
|
||||
part 'geo.g.dart';
|
||||
|
||||
GeoResponse.fromJson(Map<String, dynamic> json) {
|
||||
code = json["code"];
|
||||
location = json["location"] == null
|
||||
? null
|
||||
: (json["location"] as List).map((e) => Location.fromJson(e)).toList();
|
||||
refer = json["refer"] == null ? null : Refer.fromJson(json["refer"]);
|
||||
}
|
||||
@freezed
|
||||
abstract class GeoResponse with _$GeoResponse {
|
||||
const factory GeoResponse({
|
||||
String? code,
|
||||
List<Location>? location,
|
||||
Refer? refer,
|
||||
}) = _GeoResponse;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["code"] = code;
|
||||
data["location"] = location?.map((e) => e.toJson()).toList();
|
||||
data["refer"] = refer?.toJson();
|
||||
return data;
|
||||
}
|
||||
factory GeoResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GeoResponseFromJson(json);
|
||||
}
|
||||
|
||||
class Refer {
|
||||
List<String>? sources;
|
||||
List<String>? license;
|
||||
@freezed
|
||||
abstract class Refer with _$Refer {
|
||||
const factory Refer({List<String>? sources, List<String>? license}) = _Refer;
|
||||
|
||||
Refer({this.sources, this.license});
|
||||
|
||||
Refer.fromJson(Map<String, dynamic> json) {
|
||||
sources =
|
||||
json["sources"] == null ? null : List<String>.from(json["sources"]);
|
||||
license =
|
||||
json["license"] == null ? null : List<String>.from(json["license"]);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["sources"] = sources;
|
||||
data["license"] = license;
|
||||
return data;
|
||||
}
|
||||
factory Refer.fromJson(Map<String, dynamic> json) => _$ReferFromJson(json);
|
||||
}
|
||||
|
||||
class Location {
|
||||
String? name;
|
||||
String? id;
|
||||
String? lat;
|
||||
String? lon;
|
||||
String? adm2;
|
||||
String? adm1;
|
||||
String? country;
|
||||
String? tz;
|
||||
String? utcOffset;
|
||||
String? isDst;
|
||||
String? type;
|
||||
String? rank;
|
||||
String? fxLink;
|
||||
@freezed
|
||||
abstract class Location with _$Location {
|
||||
const factory Location({
|
||||
String? name,
|
||||
String? id,
|
||||
String? lat,
|
||||
String? lon,
|
||||
String? adm2,
|
||||
String? adm1,
|
||||
String? country,
|
||||
String? tz,
|
||||
String? utcOffset,
|
||||
String? isDst,
|
||||
String? type,
|
||||
String? rank,
|
||||
String? fxLink,
|
||||
}) = _Location;
|
||||
|
||||
Location({
|
||||
this.name,
|
||||
this.id,
|
||||
this.lat,
|
||||
this.lon,
|
||||
this.adm2,
|
||||
this.adm1,
|
||||
this.country,
|
||||
this.tz,
|
||||
this.utcOffset,
|
||||
this.isDst,
|
||||
this.type,
|
||||
this.rank,
|
||||
this.fxLink,
|
||||
});
|
||||
|
||||
Location.fromJson(Map<String, dynamic> json) {
|
||||
name = json["name"];
|
||||
id = json["id"];
|
||||
lat = json["lat"];
|
||||
lon = json["lon"];
|
||||
adm2 = json["adm2"];
|
||||
adm1 = json["adm1"];
|
||||
country = json["country"];
|
||||
tz = json["tz"];
|
||||
utcOffset = json["utcOffset"];
|
||||
isDst = json["isDst"];
|
||||
type = json["type"];
|
||||
rank = json["rank"];
|
||||
fxLink = json["fxLink"];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["name"] = name;
|
||||
data["id"] = id;
|
||||
data["lat"] = lat;
|
||||
data["lon"] = lon;
|
||||
data["adm2"] = adm2;
|
||||
data["adm1"] = adm1;
|
||||
data["country"] = country;
|
||||
data["tz"] = tz;
|
||||
data["utcOffset"] = utcOffset;
|
||||
data["isDst"] = isDst;
|
||||
data["type"] = type;
|
||||
data["rank"] = rank;
|
||||
data["fxLink"] = fxLink;
|
||||
return data;
|
||||
}
|
||||
factory Location.fromJson(Map<String, dynamic> json) =>
|
||||
_$LocationFromJson(json);
|
||||
}
|
||||
|
||||
768
lib/common/models/geo.freezed.dart
Normal file
768
lib/common/models/geo.freezed.dart
Normal file
@@ -0,0 +1,768 @@
|
||||
// dart format width=80
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'geo.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$GeoResponse {
|
||||
|
||||
String? get code;
|
||||
|
||||
List<Location>? get location;
|
||||
|
||||
Refer? get refer;
|
||||
|
||||
/// Create a copy of GeoResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$GeoResponseCopyWith<GeoResponse> get copyWith =>
|
||||
_$GeoResponseCopyWithImpl<GeoResponse>(this as GeoResponse, _$identity);
|
||||
|
||||
/// Serializes this GeoResponse to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is GeoResponse &&
|
||||
(identical(other.code, code) || other.code == code) &&
|
||||
const DeepCollectionEquality().equals(other.location, location) &&
|
||||
(identical(other.refer, refer) || other.refer == refer));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType, code, const DeepCollectionEquality().hash(location), refer);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'GeoResponse(code: $code, location: $location, refer: $refer)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $GeoResponseCopyWith<$Res> {
|
||||
factory $GeoResponseCopyWith(GeoResponse value,
|
||||
$Res Function(GeoResponse) _then) = _$GeoResponseCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call({
|
||||
String? code, List<Location>? location, Refer? refer
|
||||
});
|
||||
|
||||
|
||||
$ReferCopyWith<$Res>? get refer;
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$GeoResponseCopyWithImpl<$Res>
|
||||
implements $GeoResponseCopyWith<$Res> {
|
||||
_$GeoResponseCopyWithImpl(this._self, this._then);
|
||||
|
||||
final GeoResponse _self;
|
||||
final $Res Function(GeoResponse) _then;
|
||||
|
||||
/// Create a copy of GeoResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call(
|
||||
{Object? code = freezed, Object? location = freezed, Object? refer = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
code: freezed == code
|
||||
? _self.code
|
||||
: code // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
location: freezed == location
|
||||
? _self.location
|
||||
: location // ignore: cast_nullable_to_non_nullable
|
||||
as List<Location>?,
|
||||
refer: freezed == refer
|
||||
? _self.refer
|
||||
: refer // ignore: cast_nullable_to_non_nullable
|
||||
as Refer?,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of GeoResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ReferCopyWith<$Res>? get refer {
|
||||
if (_self.refer == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ReferCopyWith<$Res>(_self.refer!, (value) {
|
||||
return _then(_self.copyWith(refer: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _GeoResponse implements GeoResponse {
|
||||
const _GeoResponse({this.code, final List<Location>? location, this.refer})
|
||||
: _location = location;
|
||||
|
||||
factory _GeoResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GeoResponseFromJson(json);
|
||||
|
||||
@override final String? code;
|
||||
final List<Location>? _location;
|
||||
|
||||
@override List<Location>? get location {
|
||||
final value = _location;
|
||||
if (value == null) return null;
|
||||
if (_location is EqualUnmodifiableListView) return _location;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
@override final Refer? refer;
|
||||
|
||||
/// Create a copy of GeoResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$GeoResponseCopyWith<_GeoResponse> get copyWith =>
|
||||
__$GeoResponseCopyWithImpl<_GeoResponse>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$GeoResponseToJson(this,);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _GeoResponse &&
|
||||
(identical(other.code, code) || other.code == code) &&
|
||||
const DeepCollectionEquality().equals(other._location, _location) &&
|
||||
(identical(other.refer, refer) || other.refer == refer));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType, code, const DeepCollectionEquality().hash(_location), refer);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'GeoResponse(code: $code, location: $location, refer: $refer)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$GeoResponseCopyWith<$Res>
|
||||
implements $GeoResponseCopyWith<$Res> {
|
||||
factory _$GeoResponseCopyWith(_GeoResponse value,
|
||||
$Res Function(_GeoResponse) _then) = __$GeoResponseCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
String? code, List<Location>? location, Refer? refer
|
||||
});
|
||||
|
||||
|
||||
@override $ReferCopyWith<$Res>? get refer;
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$GeoResponseCopyWithImpl<$Res>
|
||||
implements _$GeoResponseCopyWith<$Res> {
|
||||
__$GeoResponseCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _GeoResponse _self;
|
||||
final $Res Function(_GeoResponse) _then;
|
||||
|
||||
/// Create a copy of GeoResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$Res call(
|
||||
{Object? code = freezed, Object? location = freezed, Object? refer = freezed,}) {
|
||||
return _then(_GeoResponse(
|
||||
code: freezed == code
|
||||
? _self.code
|
||||
: code // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
location: freezed == location
|
||||
? _self._location
|
||||
: location // ignore: cast_nullable_to_non_nullable
|
||||
as List<Location>?,
|
||||
refer: freezed == refer
|
||||
? _self.refer
|
||||
: refer // ignore: cast_nullable_to_non_nullable
|
||||
as Refer?,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of GeoResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ReferCopyWith<$Res>? get refer {
|
||||
if (_self.refer == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ReferCopyWith<$Res>(_self.refer!, (value) {
|
||||
return _then(_self.copyWith(refer: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Refer {
|
||||
|
||||
List<String>? get sources;
|
||||
|
||||
List<String>? get license;
|
||||
|
||||
/// Create a copy of Refer
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ReferCopyWith<Refer> get copyWith =>
|
||||
_$ReferCopyWithImpl<Refer>(this as Refer, _$identity);
|
||||
|
||||
/// Serializes this Refer to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is Refer &&
|
||||
const DeepCollectionEquality().equals(other.sources, sources) &&
|
||||
const DeepCollectionEquality().equals(other.license, license));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType, const DeepCollectionEquality().hash(sources),
|
||||
const DeepCollectionEquality().hash(license));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Refer(sources: $sources, license: $license)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ReferCopyWith<$Res> {
|
||||
factory $ReferCopyWith(Refer value,
|
||||
$Res Function(Refer) _then) = _$ReferCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call({
|
||||
List<String>? sources, List<String>? license
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ReferCopyWithImpl<$Res>
|
||||
implements $ReferCopyWith<$Res> {
|
||||
_$ReferCopyWithImpl(this._self, this._then);
|
||||
|
||||
final Refer _self;
|
||||
final $Res Function(Refer) _then;
|
||||
|
||||
/// Create a copy of Refer
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? sources = freezed, Object? license = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
sources: freezed == sources
|
||||
? _self.sources
|
||||
: sources // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>?,
|
||||
license: freezed == license
|
||||
? _self.license
|
||||
: license // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _Refer implements Refer {
|
||||
const _Refer({final List<String>? sources, final List<String>? license})
|
||||
: _sources = sources,
|
||||
_license = license;
|
||||
|
||||
factory _Refer.fromJson(Map<String, dynamic> json) => _$ReferFromJson(json);
|
||||
|
||||
final List<String>? _sources;
|
||||
|
||||
@override List<String>? get sources {
|
||||
final value = _sources;
|
||||
if (value == null) return null;
|
||||
if (_sources is EqualUnmodifiableListView) return _sources;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
final List<String>? _license;
|
||||
|
||||
@override List<String>? get license {
|
||||
final value = _license;
|
||||
if (value == null) return null;
|
||||
if (_license is EqualUnmodifiableListView) return _license;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
|
||||
/// Create a copy of Refer
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ReferCopyWith<_Refer> get copyWith =>
|
||||
__$ReferCopyWithImpl<_Refer>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$ReferToJson(this,);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _Refer &&
|
||||
const DeepCollectionEquality().equals(other._sources, _sources) &&
|
||||
const DeepCollectionEquality().equals(other._license, _license));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType, const DeepCollectionEquality().hash(_sources),
|
||||
const DeepCollectionEquality().hash(_license));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Refer(sources: $sources, license: $license)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ReferCopyWith<$Res> implements $ReferCopyWith<$Res> {
|
||||
factory _$ReferCopyWith(_Refer value,
|
||||
$Res Function(_Refer) _then) = __$ReferCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
List<String>? sources, List<String>? license
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$ReferCopyWithImpl<$Res>
|
||||
implements _$ReferCopyWith<$Res> {
|
||||
__$ReferCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _Refer _self;
|
||||
final $Res Function(_Refer) _then;
|
||||
|
||||
/// Create a copy of Refer
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$Res call({Object? sources = freezed, Object? license = freezed,}) {
|
||||
return _then(_Refer(
|
||||
sources: freezed == sources
|
||||
? _self._sources
|
||||
: sources // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>?,
|
||||
license: freezed == license
|
||||
? _self._license
|
||||
: license // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Location {
|
||||
|
||||
String? get name;
|
||||
|
||||
String? get id;
|
||||
|
||||
String? get lat;
|
||||
|
||||
String? get lon;
|
||||
|
||||
String? get adm2;
|
||||
|
||||
String? get adm1;
|
||||
|
||||
String? get country;
|
||||
|
||||
String? get tz;
|
||||
|
||||
String? get utcOffset;
|
||||
|
||||
String? get isDst;
|
||||
|
||||
String? get type;
|
||||
|
||||
String? get rank;
|
||||
|
||||
String? get fxLink;
|
||||
|
||||
/// Create a copy of Location
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$LocationCopyWith<Location> get copyWith =>
|
||||
_$LocationCopyWithImpl<Location>(this as Location, _$identity);
|
||||
|
||||
/// Serializes this Location to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is Location &&
|
||||
(identical(other.name, name) || other.name == name) &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.lat, lat) || other.lat == lat) &&
|
||||
(identical(other.lon, lon) || other.lon == lon) &&
|
||||
(identical(other.adm2, adm2) || other.adm2 == adm2) &&
|
||||
(identical(other.adm1, adm1) || other.adm1 == adm1) &&
|
||||
(identical(other.country, country) || other.country == country) &&
|
||||
(identical(other.tz, tz) || other.tz == tz) &&
|
||||
(identical(other.utcOffset, utcOffset) ||
|
||||
other.utcOffset == utcOffset) &&
|
||||
(identical(other.isDst, isDst) || other.isDst == isDst) &&
|
||||
(identical(other.type, type) || other.type == type) &&
|
||||
(identical(other.rank, rank) || other.rank == rank) &&
|
||||
(identical(other.fxLink, fxLink) || other.fxLink == fxLink));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType,
|
||||
name,
|
||||
id,
|
||||
lat,
|
||||
lon,
|
||||
adm2,
|
||||
adm1,
|
||||
country,
|
||||
tz,
|
||||
utcOffset,
|
||||
isDst,
|
||||
type,
|
||||
rank,
|
||||
fxLink);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Location(name: $name, id: $id, lat: $lat, lon: $lon, adm2: $adm2, adm1: $adm1, country: $country, tz: $tz, utcOffset: $utcOffset, isDst: $isDst, type: $type, rank: $rank, fxLink: $fxLink)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $LocationCopyWith<$Res> {
|
||||
factory $LocationCopyWith(Location value,
|
||||
$Res Function(Location) _then) = _$LocationCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call({
|
||||
String? name, String? id, String? lat, String? lon, String? adm2, String? adm1, String? country, String? tz, String? utcOffset, String? isDst, String? type, String? rank, String? fxLink
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LocationCopyWithImpl<$Res>
|
||||
implements $LocationCopyWith<$Res> {
|
||||
_$LocationCopyWithImpl(this._self, this._then);
|
||||
|
||||
final Location _self;
|
||||
final $Res Function(Location) _then;
|
||||
|
||||
/// Create a copy of Location
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call(
|
||||
{Object? name = freezed, Object? id = freezed, Object? lat = freezed, Object? lon = freezed, Object? adm2 = freezed, Object? adm1 = freezed, Object? country = freezed, Object? tz = freezed, Object? utcOffset = freezed, Object? isDst = freezed, Object? type = freezed, Object? rank = freezed, Object? fxLink = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
name: freezed == name
|
||||
? _self.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
id: freezed == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
lat: freezed == lat
|
||||
? _self.lat
|
||||
: lat // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
lon: freezed == lon
|
||||
? _self.lon
|
||||
: lon // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
adm2: freezed == adm2
|
||||
? _self.adm2
|
||||
: adm2 // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
adm1: freezed == adm1
|
||||
? _self.adm1
|
||||
: adm1 // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
country: freezed == country
|
||||
? _self.country
|
||||
: country // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
tz: freezed == tz ? _self.tz : tz // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
utcOffset: freezed == utcOffset
|
||||
? _self.utcOffset
|
||||
: utcOffset // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
isDst: freezed == isDst
|
||||
? _self.isDst
|
||||
: isDst // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
type: freezed == type
|
||||
? _self.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
rank: freezed == rank
|
||||
? _self.rank
|
||||
: rank // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
fxLink: freezed == fxLink
|
||||
? _self.fxLink
|
||||
: fxLink // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _Location implements Location {
|
||||
const _Location(
|
||||
{this.name, this.id, this.lat, this.lon, this.adm2, this.adm1, this.country, this.tz, this.utcOffset, this.isDst, this.type, this.rank, this.fxLink});
|
||||
|
||||
factory _Location.fromJson(Map<String, dynamic> json) =>
|
||||
_$LocationFromJson(json);
|
||||
|
||||
@override final String? name;
|
||||
@override final String? id;
|
||||
@override final String? lat;
|
||||
@override final String? lon;
|
||||
@override final String? adm2;
|
||||
@override final String? adm1;
|
||||
@override final String? country;
|
||||
@override final String? tz;
|
||||
@override final String? utcOffset;
|
||||
@override final String? isDst;
|
||||
@override final String? type;
|
||||
@override final String? rank;
|
||||
@override final String? fxLink;
|
||||
|
||||
/// Create a copy of Location
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$LocationCopyWith<_Location> get copyWith =>
|
||||
__$LocationCopyWithImpl<_Location>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$LocationToJson(this,);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _Location &&
|
||||
(identical(other.name, name) || other.name == name) &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.lat, lat) || other.lat == lat) &&
|
||||
(identical(other.lon, lon) || other.lon == lon) &&
|
||||
(identical(other.adm2, adm2) || other.adm2 == adm2) &&
|
||||
(identical(other.adm1, adm1) || other.adm1 == adm1) &&
|
||||
(identical(other.country, country) || other.country == country) &&
|
||||
(identical(other.tz, tz) || other.tz == tz) &&
|
||||
(identical(other.utcOffset, utcOffset) ||
|
||||
other.utcOffset == utcOffset) &&
|
||||
(identical(other.isDst, isDst) || other.isDst == isDst) &&
|
||||
(identical(other.type, type) || other.type == type) &&
|
||||
(identical(other.rank, rank) || other.rank == rank) &&
|
||||
(identical(other.fxLink, fxLink) || other.fxLink == fxLink));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType,
|
||||
name,
|
||||
id,
|
||||
lat,
|
||||
lon,
|
||||
adm2,
|
||||
adm1,
|
||||
country,
|
||||
tz,
|
||||
utcOffset,
|
||||
isDst,
|
||||
type,
|
||||
rank,
|
||||
fxLink);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Location(name: $name, id: $id, lat: $lat, lon: $lon, adm2: $adm2, adm1: $adm1, country: $country, tz: $tz, utcOffset: $utcOffset, isDst: $isDst, type: $type, rank: $rank, fxLink: $fxLink)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$LocationCopyWith<$Res>
|
||||
implements $LocationCopyWith<$Res> {
|
||||
factory _$LocationCopyWith(_Location value,
|
||||
$Res Function(_Location) _then) = __$LocationCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
String? name, String? id, String? lat, String? lon, String? adm2, String? adm1, String? country, String? tz, String? utcOffset, String? isDst, String? type, String? rank, String? fxLink
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$LocationCopyWithImpl<$Res>
|
||||
implements _$LocationCopyWith<$Res> {
|
||||
__$LocationCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _Location _self;
|
||||
final $Res Function(_Location) _then;
|
||||
|
||||
/// Create a copy of Location
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$Res call(
|
||||
{Object? name = freezed, Object? id = freezed, Object? lat = freezed, Object? lon = freezed, Object? adm2 = freezed, Object? adm1 = freezed, Object? country = freezed, Object? tz = freezed, Object? utcOffset = freezed, Object? isDst = freezed, Object? type = freezed, Object? rank = freezed, Object? fxLink = freezed,}) {
|
||||
return _then(_Location(
|
||||
name: freezed == name
|
||||
? _self.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
id: freezed == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
lat: freezed == lat
|
||||
? _self.lat
|
||||
: lat // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
lon: freezed == lon
|
||||
? _self.lon
|
||||
: lon // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
adm2: freezed == adm2
|
||||
? _self.adm2
|
||||
: adm2 // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
adm1: freezed == adm1
|
||||
? _self.adm1
|
||||
: adm1 // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
country: freezed == country
|
||||
? _self.country
|
||||
: country // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
tz: freezed == tz ? _self.tz : tz // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
utcOffset: freezed == utcOffset
|
||||
? _self.utcOffset
|
||||
: utcOffset // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
isDst: freezed == isDst
|
||||
? _self.isDst
|
||||
: isDst // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
type: freezed == type
|
||||
? _self.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
rank: freezed == rank
|
||||
? _self.rank
|
||||
: rank // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
fxLink: freezed == fxLink
|
||||
? _self.fxLink
|
||||
: fxLink // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
70
lib/common/models/geo.g.dart
Normal file
70
lib/common/models/geo.g.dart
Normal file
@@ -0,0 +1,70 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'geo.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_GeoResponse _$GeoResponseFromJson(Map<String, dynamic> json) => _GeoResponse(
|
||||
code: json['code'] as String?,
|
||||
location:
|
||||
(json['location'] as List<dynamic>?)
|
||||
?.map((e) => Location.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
refer:
|
||||
json['refer'] == null
|
||||
? null
|
||||
: Refer.fromJson(json['refer'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$GeoResponseToJson(_GeoResponse instance) =>
|
||||
<String, dynamic>{
|
||||
if (instance.code case final value?) 'code': value,
|
||||
if (instance.location case final value?) 'location': value,
|
||||
if (instance.refer case final value?) 'refer': value,
|
||||
};
|
||||
|
||||
_Refer _$ReferFromJson(Map<String, dynamic> json) => _Refer(
|
||||
sources:
|
||||
(json['sources'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||
license:
|
||||
(json['license'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ReferToJson(_Refer instance) => <String, dynamic>{
|
||||
if (instance.sources case final value?) 'sources': value,
|
||||
if (instance.license case final value?) 'license': value,
|
||||
};
|
||||
|
||||
_Location _$LocationFromJson(Map<String, dynamic> json) => _Location(
|
||||
name: json['name'] as String?,
|
||||
id: json['id'] as String?,
|
||||
lat: json['lat'] as String?,
|
||||
lon: json['lon'] as String?,
|
||||
adm2: json['adm2'] as String?,
|
||||
adm1: json['adm1'] as String?,
|
||||
country: json['country'] as String?,
|
||||
tz: json['tz'] as String?,
|
||||
utcOffset: json['utcOffset'] as String?,
|
||||
isDst: json['isDst'] as String?,
|
||||
type: json['type'] as String?,
|
||||
rank: json['rank'] as String?,
|
||||
fxLink: json['fxLink'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$LocationToJson(_Location instance) => <String, dynamic>{
|
||||
if (instance.name case final value?) 'name': value,
|
||||
if (instance.id case final value?) 'id': value,
|
||||
if (instance.lat case final value?) 'lat': value,
|
||||
if (instance.lon case final value?) 'lon': value,
|
||||
if (instance.adm2 case final value?) 'adm2': value,
|
||||
if (instance.adm1 case final value?) 'adm1': value,
|
||||
if (instance.country case final value?) 'country': value,
|
||||
if (instance.tz case final value?) 'tz': value,
|
||||
if (instance.utcOffset case final value?) 'utcOffset': value,
|
||||
if (instance.isDst case final value?) 'isDst': value,
|
||||
if (instance.type case final value?) 'type': value,
|
||||
if (instance.rank case final value?) 'rank': value,
|
||||
if (instance.fxLink case final value?) 'fxLink': value,
|
||||
};
|
||||
@@ -1,336 +1,107 @@
|
||||
class GithubRelease {
|
||||
String? url;
|
||||
String? assetsUrl;
|
||||
String? uploadUrl;
|
||||
String? htmlUrl;
|
||||
int? id;
|
||||
Author? author;
|
||||
String? nodeId;
|
||||
String? tagName;
|
||||
String? targetCommitish;
|
||||
String? name;
|
||||
bool? draft;
|
||||
bool? prerelease;
|
||||
String? createdAt;
|
||||
String? publishedAt;
|
||||
List<Assets>? assets;
|
||||
String? tarballUrl;
|
||||
String? zipballUrl;
|
||||
String? body;
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
GithubRelease(
|
||||
{this.url,
|
||||
this.assetsUrl,
|
||||
this.uploadUrl,
|
||||
this.htmlUrl,
|
||||
this.id,
|
||||
this.author,
|
||||
this.nodeId,
|
||||
this.tagName,
|
||||
this.targetCommitish,
|
||||
this.name,
|
||||
this.draft,
|
||||
this.prerelease,
|
||||
this.createdAt,
|
||||
this.publishedAt,
|
||||
this.assets,
|
||||
this.tarballUrl,
|
||||
this.zipballUrl,
|
||||
this.body});
|
||||
part 'github.freezed.dart';
|
||||
part 'github.g.dart';
|
||||
|
||||
GithubRelease.fromJson(Map<String, dynamic> json) {
|
||||
url = json["url"];
|
||||
assetsUrl = json["assets_url"];
|
||||
uploadUrl = json["upload_url"];
|
||||
htmlUrl = json["html_url"];
|
||||
id = json["id"];
|
||||
author = json["author"] == null ? null : Author.fromJson(json["author"]);
|
||||
nodeId = json["node_id"];
|
||||
tagName = json["tag_name"];
|
||||
targetCommitish = json["target_commitish"];
|
||||
name = json["name"];
|
||||
draft = json["draft"];
|
||||
prerelease = json["prerelease"];
|
||||
createdAt = json["created_at"];
|
||||
publishedAt = json["published_at"];
|
||||
assets = json["assets"] == null
|
||||
? null
|
||||
: (json["assets"] as List).map((e) => Assets.fromJson(e)).toList();
|
||||
tarballUrl = json["tarball_url"];
|
||||
zipballUrl = json["zipball_url"];
|
||||
body = json["body"];
|
||||
}
|
||||
@freezed
|
||||
abstract class GithubRelease with _$GithubRelease {
|
||||
const factory GithubRelease({
|
||||
String? url,
|
||||
@JsonKey(name: 'assets_url') String? assetsUrl,
|
||||
@JsonKey(name: 'upload_url') String? uploadUrl,
|
||||
@JsonKey(name: 'html_url') String? htmlUrl,
|
||||
int? id,
|
||||
Author? author,
|
||||
@JsonKey(name: 'node_id') String? nodeId,
|
||||
@JsonKey(name: 'tag_name') String? tagName,
|
||||
@JsonKey(name: 'target_commitish') String? targetCommitish,
|
||||
String? name,
|
||||
bool? draft,
|
||||
bool? prerelease,
|
||||
@JsonKey(name: 'created_at') String? createdAt,
|
||||
@JsonKey(name: 'published_at') String? publishedAt,
|
||||
List<Assets>? assets,
|
||||
@JsonKey(name: 'tarball_url') String? tarballUrl,
|
||||
@JsonKey(name: 'zipball_url') String? zipballUrl,
|
||||
String? body,
|
||||
}) = _GithubRelease;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["url"] = url;
|
||||
data["assets_url"] = assetsUrl;
|
||||
data["upload_url"] = uploadUrl;
|
||||
data["html_url"] = htmlUrl;
|
||||
data["id"] = id;
|
||||
if (author != null) {
|
||||
data["author"] = author?.toJson();
|
||||
}
|
||||
data["node_id"] = nodeId;
|
||||
data["tag_name"] = tagName;
|
||||
data["target_commitish"] = targetCommitish;
|
||||
data["name"] = name;
|
||||
data["draft"] = draft;
|
||||
data["prerelease"] = prerelease;
|
||||
data["created_at"] = createdAt;
|
||||
data["published_at"] = publishedAt;
|
||||
if (assets != null) {
|
||||
data["assets"] = assets?.map((e) => e.toJson()).toList();
|
||||
}
|
||||
data["tarball_url"] = tarballUrl;
|
||||
data["zipball_url"] = zipballUrl;
|
||||
data["body"] = body;
|
||||
return data;
|
||||
}
|
||||
factory GithubRelease.fromJson(Map<String, dynamic> json) =>
|
||||
_$GithubReleaseFromJson(json);
|
||||
}
|
||||
|
||||
class Assets {
|
||||
String? url;
|
||||
int? id;
|
||||
String? nodeId;
|
||||
String? name;
|
||||
dynamic label;
|
||||
Uploader? uploader;
|
||||
String? contentType;
|
||||
String? state;
|
||||
int? size;
|
||||
int? downloadCount;
|
||||
String? createdAt;
|
||||
String? updatedAt;
|
||||
String? browserDownloadUrl;
|
||||
@freezed
|
||||
abstract class Assets with _$Assets {
|
||||
const factory Assets({
|
||||
String? url,
|
||||
int? id,
|
||||
@JsonKey(name: 'node_id') String? nodeId,
|
||||
String? name,
|
||||
dynamic label,
|
||||
Uploader? uploader,
|
||||
@JsonKey(name: 'content_type') String? contentType,
|
||||
String? state,
|
||||
int? size,
|
||||
@JsonKey(name: 'download_count') int? downloadCount,
|
||||
@JsonKey(name: 'created_at') String? createdAt,
|
||||
@JsonKey(name: 'updated_at') String? updatedAt,
|
||||
@JsonKey(name: 'browser_download_url') String? browserDownloadUrl,
|
||||
}) = _Assets;
|
||||
|
||||
Assets(
|
||||
{this.url,
|
||||
this.id,
|
||||
this.nodeId,
|
||||
this.name,
|
||||
this.label,
|
||||
this.uploader,
|
||||
this.contentType,
|
||||
this.state,
|
||||
this.size,
|
||||
this.downloadCount,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.browserDownloadUrl});
|
||||
|
||||
Assets.fromJson(Map<String, dynamic> json) {
|
||||
url = json["url"];
|
||||
id = json["id"];
|
||||
nodeId = json["node_id"];
|
||||
name = json["name"];
|
||||
label = json["label"];
|
||||
uploader =
|
||||
json["uploader"] == null ? null : Uploader.fromJson(json["uploader"]);
|
||||
contentType = json["content_type"];
|
||||
state = json["state"];
|
||||
size = json["size"];
|
||||
downloadCount = json["download_count"];
|
||||
createdAt = json["created_at"];
|
||||
updatedAt = json["updated_at"];
|
||||
browserDownloadUrl = json["browser_download_url"];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["url"] = url;
|
||||
data["id"] = id;
|
||||
data["node_id"] = nodeId;
|
||||
data["name"] = name;
|
||||
data["label"] = label;
|
||||
if (uploader != null) {
|
||||
data["uploader"] = uploader?.toJson();
|
||||
}
|
||||
data["content_type"] = contentType;
|
||||
data["state"] = state;
|
||||
data["size"] = size;
|
||||
data["download_count"] = downloadCount;
|
||||
data["created_at"] = createdAt;
|
||||
data["updated_at"] = updatedAt;
|
||||
data["browser_download_url"] = browserDownloadUrl;
|
||||
return data;
|
||||
}
|
||||
factory Assets.fromJson(Map<String, dynamic> json) => _$AssetsFromJson(json);
|
||||
}
|
||||
|
||||
class Uploader {
|
||||
String? login;
|
||||
int? id;
|
||||
String? nodeId;
|
||||
String? avatarUrl;
|
||||
String? gravatarId;
|
||||
String? url;
|
||||
String? htmlUrl;
|
||||
String? followersUrl;
|
||||
String? followingUrl;
|
||||
String? gistsUrl;
|
||||
String? starredUrl;
|
||||
String? subscriptionsUrl;
|
||||
String? organizationsUrl;
|
||||
String? reposUrl;
|
||||
String? eventsUrl;
|
||||
String? receivedEventsUrl;
|
||||
String? type;
|
||||
String? userViewType;
|
||||
bool? siteAdmin;
|
||||
@freezed
|
||||
abstract class Uploader with _$Uploader {
|
||||
const factory Uploader({
|
||||
String? login,
|
||||
int? id,
|
||||
@JsonKey(name: 'node_id') String? nodeId,
|
||||
@JsonKey(name: 'avatar_url') String? avatarUrl,
|
||||
@JsonKey(name: 'gravatar_id') String? gravatarId,
|
||||
String? url,
|
||||
@JsonKey(name: 'html_url') String? htmlUrl,
|
||||
@JsonKey(name: 'followers_url') String? followersUrl,
|
||||
@JsonKey(name: 'following_url') String? followingUrl,
|
||||
@JsonKey(name: 'gists_url') String? gistsUrl,
|
||||
@JsonKey(name: 'starred_url') String? starredUrl,
|
||||
@JsonKey(name: 'subscriptions_url') String? subscriptionsUrl,
|
||||
@JsonKey(name: 'organizations_url') String? organizationsUrl,
|
||||
@JsonKey(name: 'repos_url') String? reposUrl,
|
||||
@JsonKey(name: 'events_url') String? eventsUrl,
|
||||
@JsonKey(name: 'received_events_url') String? receivedEventsUrl,
|
||||
String? type,
|
||||
@JsonKey(name: 'user_view_type') String? userViewType,
|
||||
@JsonKey(name: 'site_admin') bool? siteAdmin,
|
||||
}) = _Uploader;
|
||||
|
||||
Uploader(
|
||||
{this.login,
|
||||
this.id,
|
||||
this.nodeId,
|
||||
this.avatarUrl,
|
||||
this.gravatarId,
|
||||
this.url,
|
||||
this.htmlUrl,
|
||||
this.followersUrl,
|
||||
this.followingUrl,
|
||||
this.gistsUrl,
|
||||
this.starredUrl,
|
||||
this.subscriptionsUrl,
|
||||
this.organizationsUrl,
|
||||
this.reposUrl,
|
||||
this.eventsUrl,
|
||||
this.receivedEventsUrl,
|
||||
this.type,
|
||||
this.userViewType,
|
||||
this.siteAdmin});
|
||||
|
||||
Uploader.fromJson(Map<String, dynamic> json) {
|
||||
login = json["login"];
|
||||
id = json["id"];
|
||||
nodeId = json["node_id"];
|
||||
avatarUrl = json["avatar_url"];
|
||||
gravatarId = json["gravatar_id"];
|
||||
url = json["url"];
|
||||
htmlUrl = json["html_url"];
|
||||
followersUrl = json["followers_url"];
|
||||
followingUrl = json["following_url"];
|
||||
gistsUrl = json["gists_url"];
|
||||
starredUrl = json["starred_url"];
|
||||
subscriptionsUrl = json["subscriptions_url"];
|
||||
organizationsUrl = json["organizations_url"];
|
||||
reposUrl = json["repos_url"];
|
||||
eventsUrl = json["events_url"];
|
||||
receivedEventsUrl = json["received_events_url"];
|
||||
type = json["type"];
|
||||
userViewType = json["user_view_type"];
|
||||
siteAdmin = json["site_admin"];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["login"] = login;
|
||||
data["id"] = id;
|
||||
data["node_id"] = nodeId;
|
||||
data["avatar_url"] = avatarUrl;
|
||||
data["gravatar_id"] = gravatarId;
|
||||
data["url"] = url;
|
||||
data["html_url"] = htmlUrl;
|
||||
data["followers_url"] = followersUrl;
|
||||
data["following_url"] = followingUrl;
|
||||
data["gists_url"] = gistsUrl;
|
||||
data["starred_url"] = starredUrl;
|
||||
data["subscriptions_url"] = subscriptionsUrl;
|
||||
data["organizations_url"] = organizationsUrl;
|
||||
data["repos_url"] = reposUrl;
|
||||
data["events_url"] = eventsUrl;
|
||||
data["received_events_url"] = receivedEventsUrl;
|
||||
data["type"] = type;
|
||||
data["user_view_type"] = userViewType;
|
||||
data["site_admin"] = siteAdmin;
|
||||
return data;
|
||||
}
|
||||
factory Uploader.fromJson(Map<String, dynamic> json) =>
|
||||
_$UploaderFromJson(json);
|
||||
}
|
||||
|
||||
class Author {
|
||||
String? login;
|
||||
int? id;
|
||||
String? nodeId;
|
||||
String? avatarUrl;
|
||||
String? gravatarId;
|
||||
String? url;
|
||||
String? htmlUrl;
|
||||
String? followersUrl;
|
||||
String? followingUrl;
|
||||
String? gistsUrl;
|
||||
String? starredUrl;
|
||||
String? subscriptionsUrl;
|
||||
String? organizationsUrl;
|
||||
String? reposUrl;
|
||||
String? eventsUrl;
|
||||
String? receivedEventsUrl;
|
||||
String? type;
|
||||
String? userViewType;
|
||||
bool? siteAdmin;
|
||||
@freezed
|
||||
abstract class Author with _$Author {
|
||||
const factory Author({
|
||||
String? login,
|
||||
int? id,
|
||||
@JsonKey(name: 'node_id') String? nodeId,
|
||||
@JsonKey(name: 'avatar_url') String? avatarUrl,
|
||||
@JsonKey(name: 'gravatar_id') String? gravatarId,
|
||||
String? url,
|
||||
@JsonKey(name: 'html_url') String? htmlUrl,
|
||||
@JsonKey(name: 'followers_url') String? followersUrl,
|
||||
@JsonKey(name: 'following_url') String? followingUrl,
|
||||
@JsonKey(name: 'gists_url') String? gistsUrl,
|
||||
@JsonKey(name: 'starred_url') String? starredUrl,
|
||||
@JsonKey(name: 'subscriptions_url') String? subscriptionsUrl,
|
||||
@JsonKey(name: 'organizations_url') String? organizationsUrl,
|
||||
@JsonKey(name: 'repos_url') String? reposUrl,
|
||||
@JsonKey(name: 'events_url') String? eventsUrl,
|
||||
@JsonKey(name: 'received_events_url') String? receivedEventsUrl,
|
||||
String? type,
|
||||
@JsonKey(name: 'user_view_type') String? userViewType,
|
||||
@JsonKey(name: 'site_admin') bool? siteAdmin,
|
||||
}) = _Author;
|
||||
|
||||
Author(
|
||||
{this.login,
|
||||
this.id,
|
||||
this.nodeId,
|
||||
this.avatarUrl,
|
||||
this.gravatarId,
|
||||
this.url,
|
||||
this.htmlUrl,
|
||||
this.followersUrl,
|
||||
this.followingUrl,
|
||||
this.gistsUrl,
|
||||
this.starredUrl,
|
||||
this.subscriptionsUrl,
|
||||
this.organizationsUrl,
|
||||
this.reposUrl,
|
||||
this.eventsUrl,
|
||||
this.receivedEventsUrl,
|
||||
this.type,
|
||||
this.userViewType,
|
||||
this.siteAdmin});
|
||||
|
||||
Author.fromJson(Map<String, dynamic> json) {
|
||||
login = json["login"];
|
||||
id = json["id"];
|
||||
nodeId = json["node_id"];
|
||||
avatarUrl = json["avatar_url"];
|
||||
gravatarId = json["gravatar_id"];
|
||||
url = json["url"];
|
||||
htmlUrl = json["html_url"];
|
||||
followersUrl = json["followers_url"];
|
||||
followingUrl = json["following_url"];
|
||||
gistsUrl = json["gists_url"];
|
||||
starredUrl = json["starred_url"];
|
||||
subscriptionsUrl = json["subscriptions_url"];
|
||||
organizationsUrl = json["organizations_url"];
|
||||
reposUrl = json["repos_url"];
|
||||
eventsUrl = json["events_url"];
|
||||
receivedEventsUrl = json["received_events_url"];
|
||||
type = json["type"];
|
||||
userViewType = json["user_view_type"];
|
||||
siteAdmin = json["site_admin"];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["login"] = login;
|
||||
data["id"] = id;
|
||||
data["node_id"] = nodeId;
|
||||
data["avatar_url"] = avatarUrl;
|
||||
data["gravatar_id"] = gravatarId;
|
||||
data["url"] = url;
|
||||
data["html_url"] = htmlUrl;
|
||||
data["followers_url"] = followersUrl;
|
||||
data["following_url"] = followingUrl;
|
||||
data["gists_url"] = gistsUrl;
|
||||
data["starred_url"] = starredUrl;
|
||||
data["subscriptions_url"] = subscriptionsUrl;
|
||||
data["organizations_url"] = organizationsUrl;
|
||||
data["repos_url"] = reposUrl;
|
||||
data["events_url"] = eventsUrl;
|
||||
data["received_events_url"] = receivedEventsUrl;
|
||||
data["type"] = type;
|
||||
data["user_view_type"] = userViewType;
|
||||
data["site_admin"] = siteAdmin;
|
||||
return data;
|
||||
}
|
||||
factory Author.fromJson(Map<String, dynamic> json) => _$AuthorFromJson(json);
|
||||
}
|
||||
|
||||
1997
lib/common/models/github.freezed.dart
Normal file
1997
lib/common/models/github.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
183
lib/common/models/github.g.dart
Normal file
183
lib/common/models/github.g.dart
Normal file
@@ -0,0 +1,183 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'github.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_GithubRelease _$GithubReleaseFromJson(Map<String, dynamic> json) =>
|
||||
_GithubRelease(
|
||||
url: json['url'] as String?,
|
||||
assetsUrl: json['assets_url'] as String?,
|
||||
uploadUrl: json['upload_url'] as String?,
|
||||
htmlUrl: json['html_url'] as String?,
|
||||
id: (json['id'] as num?)?.toInt(),
|
||||
author:
|
||||
json['author'] == null
|
||||
? null
|
||||
: Author.fromJson(json['author'] as Map<String, dynamic>),
|
||||
nodeId: json['node_id'] as String?,
|
||||
tagName: json['tag_name'] as String?,
|
||||
targetCommitish: json['target_commitish'] as String?,
|
||||
name: json['name'] as String?,
|
||||
draft: json['draft'] as bool?,
|
||||
prerelease: json['prerelease'] as bool?,
|
||||
createdAt: json['created_at'] as String?,
|
||||
publishedAt: json['published_at'] as String?,
|
||||
assets:
|
||||
(json['assets'] as List<dynamic>?)
|
||||
?.map((e) => Assets.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
tarballUrl: json['tarball_url'] as String?,
|
||||
zipballUrl: json['zipball_url'] as String?,
|
||||
body: json['body'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$GithubReleaseToJson(_GithubRelease instance) =>
|
||||
<String, dynamic>{
|
||||
if (instance.url case final value?) 'url': value,
|
||||
if (instance.assetsUrl case final value?) 'assets_url': value,
|
||||
if (instance.uploadUrl case final value?) 'upload_url': value,
|
||||
if (instance.htmlUrl case final value?) 'html_url': value,
|
||||
if (instance.id case final value?) 'id': value,
|
||||
if (instance.author case final value?) 'author': value,
|
||||
if (instance.nodeId case final value?) 'node_id': value,
|
||||
if (instance.tagName case final value?) 'tag_name': value,
|
||||
if (instance.targetCommitish case final value?) 'target_commitish': value,
|
||||
if (instance.name case final value?) 'name': value,
|
||||
if (instance.draft case final value?) 'draft': value,
|
||||
if (instance.prerelease case final value?) 'prerelease': value,
|
||||
if (instance.createdAt case final value?) 'created_at': value,
|
||||
if (instance.publishedAt case final value?) 'published_at': value,
|
||||
if (instance.assets case final value?) 'assets': value,
|
||||
if (instance.tarballUrl case final value?) 'tarball_url': value,
|
||||
if (instance.zipballUrl case final value?) 'zipball_url': value,
|
||||
if (instance.body case final value?) 'body': value,
|
||||
};
|
||||
|
||||
_Assets _$AssetsFromJson(Map<String, dynamic> json) => _Assets(
|
||||
url: json['url'] as String?,
|
||||
id: (json['id'] as num?)?.toInt(),
|
||||
nodeId: json['node_id'] as String?,
|
||||
name: json['name'] as String?,
|
||||
label: json['label'],
|
||||
uploader:
|
||||
json['uploader'] == null
|
||||
? null
|
||||
: Uploader.fromJson(json['uploader'] as Map<String, dynamic>),
|
||||
contentType: json['content_type'] as String?,
|
||||
state: json['state'] as String?,
|
||||
size: (json['size'] as num?)?.toInt(),
|
||||
downloadCount: (json['download_count'] as num?)?.toInt(),
|
||||
createdAt: json['created_at'] as String?,
|
||||
updatedAt: json['updated_at'] as String?,
|
||||
browserDownloadUrl: json['browser_download_url'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AssetsToJson(_Assets instance) => <String, dynamic>{
|
||||
if (instance.url case final value?) 'url': value,
|
||||
if (instance.id case final value?) 'id': value,
|
||||
if (instance.nodeId case final value?) 'node_id': value,
|
||||
if (instance.name case final value?) 'name': value,
|
||||
if (instance.label case final value?) 'label': value,
|
||||
if (instance.uploader case final value?) 'uploader': value,
|
||||
if (instance.contentType case final value?) 'content_type': value,
|
||||
if (instance.state case final value?) 'state': value,
|
||||
if (instance.size case final value?) 'size': value,
|
||||
if (instance.downloadCount case final value?) 'download_count': value,
|
||||
if (instance.createdAt case final value?) 'created_at': value,
|
||||
if (instance.updatedAt case final value?) 'updated_at': value,
|
||||
if (instance.browserDownloadUrl case final value?)
|
||||
'browser_download_url': value,
|
||||
};
|
||||
|
||||
_Uploader _$UploaderFromJson(Map<String, dynamic> json) => _Uploader(
|
||||
login: json['login'] as String?,
|
||||
id: (json['id'] as num?)?.toInt(),
|
||||
nodeId: json['node_id'] as String?,
|
||||
avatarUrl: json['avatar_url'] as String?,
|
||||
gravatarId: json['gravatar_id'] as String?,
|
||||
url: json['url'] as String?,
|
||||
htmlUrl: json['html_url'] as String?,
|
||||
followersUrl: json['followers_url'] as String?,
|
||||
followingUrl: json['following_url'] as String?,
|
||||
gistsUrl: json['gists_url'] as String?,
|
||||
starredUrl: json['starred_url'] as String?,
|
||||
subscriptionsUrl: json['subscriptions_url'] as String?,
|
||||
organizationsUrl: json['organizations_url'] as String?,
|
||||
reposUrl: json['repos_url'] as String?,
|
||||
eventsUrl: json['events_url'] as String?,
|
||||
receivedEventsUrl: json['received_events_url'] as String?,
|
||||
type: json['type'] as String?,
|
||||
userViewType: json['user_view_type'] as String?,
|
||||
siteAdmin: json['site_admin'] as bool?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$UploaderToJson(_Uploader instance) => <String, dynamic>{
|
||||
if (instance.login case final value?) 'login': value,
|
||||
if (instance.id case final value?) 'id': value,
|
||||
if (instance.nodeId case final value?) 'node_id': value,
|
||||
if (instance.avatarUrl case final value?) 'avatar_url': value,
|
||||
if (instance.gravatarId case final value?) 'gravatar_id': value,
|
||||
if (instance.url case final value?) 'url': value,
|
||||
if (instance.htmlUrl case final value?) 'html_url': value,
|
||||
if (instance.followersUrl case final value?) 'followers_url': value,
|
||||
if (instance.followingUrl case final value?) 'following_url': value,
|
||||
if (instance.gistsUrl case final value?) 'gists_url': value,
|
||||
if (instance.starredUrl case final value?) 'starred_url': value,
|
||||
if (instance.subscriptionsUrl case final value?) 'subscriptions_url': value,
|
||||
if (instance.organizationsUrl case final value?) 'organizations_url': value,
|
||||
if (instance.reposUrl case final value?) 'repos_url': value,
|
||||
if (instance.eventsUrl case final value?) 'events_url': value,
|
||||
if (instance.receivedEventsUrl case final value?)
|
||||
'received_events_url': value,
|
||||
if (instance.type case final value?) 'type': value,
|
||||
if (instance.userViewType case final value?) 'user_view_type': value,
|
||||
if (instance.siteAdmin case final value?) 'site_admin': value,
|
||||
};
|
||||
|
||||
_Author _$AuthorFromJson(Map<String, dynamic> json) => _Author(
|
||||
login: json['login'] as String?,
|
||||
id: (json['id'] as num?)?.toInt(),
|
||||
nodeId: json['node_id'] as String?,
|
||||
avatarUrl: json['avatar_url'] as String?,
|
||||
gravatarId: json['gravatar_id'] as String?,
|
||||
url: json['url'] as String?,
|
||||
htmlUrl: json['html_url'] as String?,
|
||||
followersUrl: json['followers_url'] as String?,
|
||||
followingUrl: json['following_url'] as String?,
|
||||
gistsUrl: json['gists_url'] as String?,
|
||||
starredUrl: json['starred_url'] as String?,
|
||||
subscriptionsUrl: json['subscriptions_url'] as String?,
|
||||
organizationsUrl: json['organizations_url'] as String?,
|
||||
reposUrl: json['repos_url'] as String?,
|
||||
eventsUrl: json['events_url'] as String?,
|
||||
receivedEventsUrl: json['received_events_url'] as String?,
|
||||
type: json['type'] as String?,
|
||||
userViewType: json['user_view_type'] as String?,
|
||||
siteAdmin: json['site_admin'] as bool?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AuthorToJson(_Author instance) => <String, dynamic>{
|
||||
if (instance.login case final value?) 'login': value,
|
||||
if (instance.id case final value?) 'id': value,
|
||||
if (instance.nodeId case final value?) 'node_id': value,
|
||||
if (instance.avatarUrl case final value?) 'avatar_url': value,
|
||||
if (instance.gravatarId case final value?) 'gravatar_id': value,
|
||||
if (instance.url case final value?) 'url': value,
|
||||
if (instance.htmlUrl case final value?) 'html_url': value,
|
||||
if (instance.followersUrl case final value?) 'followers_url': value,
|
||||
if (instance.followingUrl case final value?) 'following_url': value,
|
||||
if (instance.gistsUrl case final value?) 'gists_url': value,
|
||||
if (instance.starredUrl case final value?) 'starred_url': value,
|
||||
if (instance.subscriptionsUrl case final value?) 'subscriptions_url': value,
|
||||
if (instance.organizationsUrl case final value?) 'organizations_url': value,
|
||||
if (instance.reposUrl case final value?) 'repos_url': value,
|
||||
if (instance.eventsUrl case final value?) 'events_url': value,
|
||||
if (instance.receivedEventsUrl case final value?)
|
||||
'received_events_url': value,
|
||||
if (instance.type case final value?) 'type': value,
|
||||
if (instance.userViewType case final value?) 'user_view_type': value,
|
||||
if (instance.siteAdmin case final value?) 'site_admin': value,
|
||||
};
|
||||
@@ -1,60 +1,25 @@
|
||||
class HitokotoResponse {
|
||||
int? id;
|
||||
String? uuid;
|
||||
String? hitokoto;
|
||||
String? type;
|
||||
String? from;
|
||||
String? fromWho;
|
||||
String? creator;
|
||||
int? creatorUid;
|
||||
int? reviewer;
|
||||
String? commitFrom;
|
||||
String? createdAt;
|
||||
int? length;
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
HitokotoResponse(
|
||||
{this.id,
|
||||
this.uuid,
|
||||
this.hitokoto,
|
||||
this.type,
|
||||
this.from,
|
||||
this.fromWho,
|
||||
this.creator,
|
||||
this.creatorUid,
|
||||
this.reviewer,
|
||||
this.commitFrom,
|
||||
this.createdAt,
|
||||
this.length});
|
||||
part 'hitokoto.freezed.dart';
|
||||
part 'hitokoto.g.dart';
|
||||
|
||||
HitokotoResponse.fromJson(Map<String, dynamic> json) {
|
||||
id = json["id"];
|
||||
uuid = json["uuid"];
|
||||
hitokoto = json["hitokoto"];
|
||||
type = json["type"];
|
||||
from = json["from"];
|
||||
fromWho = json["from_who"];
|
||||
creator = json["creator"];
|
||||
creatorUid = json["creator_uid"];
|
||||
reviewer = json["reviewer"];
|
||||
commitFrom = json["commit_from"];
|
||||
createdAt = json["created_at"];
|
||||
length = json["length"];
|
||||
}
|
||||
@freezed
|
||||
abstract class HitokotoResponse with _$HitokotoResponse {
|
||||
const factory HitokotoResponse({
|
||||
int? id,
|
||||
String? uuid,
|
||||
String? hitokoto,
|
||||
String? type,
|
||||
String? from,
|
||||
@JsonKey(name: 'from_who') String? fromWho,
|
||||
String? creator,
|
||||
@JsonKey(name: 'creator_uid') int? creatorUid,
|
||||
int? reviewer,
|
||||
@JsonKey(name: 'commit_from') String? commitFrom,
|
||||
@JsonKey(name: 'created_at') String? createdAt,
|
||||
int? length,
|
||||
}) = _HitokotoResponse;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["id"] = id;
|
||||
data["uuid"] = uuid;
|
||||
data["hitokoto"] = hitokoto;
|
||||
data["type"] = type;
|
||||
data["from"] = from;
|
||||
data["from_who"] = fromWho;
|
||||
data["creator"] = creator;
|
||||
data["creator_uid"] = creatorUid;
|
||||
data["reviewer"] = reviewer;
|
||||
data["commit_from"] = commitFrom;
|
||||
data["created_at"] = createdAt;
|
||||
data["length"] = length;
|
||||
return data;
|
||||
}
|
||||
factory HitokotoResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$HitokotoResponseFromJson(json);
|
||||
}
|
||||
|
||||
370
lib/common/models/hitokoto.freezed.dart
Normal file
370
lib/common/models/hitokoto.freezed.dart
Normal file
@@ -0,0 +1,370 @@
|
||||
// dart format width=80
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'hitokoto.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$HitokotoResponse {
|
||||
|
||||
int? get id;
|
||||
|
||||
String? get uuid;
|
||||
|
||||
String? get hitokoto;
|
||||
|
||||
String? get type;
|
||||
|
||||
String? get from;
|
||||
|
||||
@JsonKey(name: 'from_who') String? get fromWho;
|
||||
|
||||
String? get creator;
|
||||
|
||||
@JsonKey(name: 'creator_uid') int? get creatorUid;
|
||||
|
||||
int? get reviewer;
|
||||
|
||||
@JsonKey(name: 'commit_from') String? get commitFrom;
|
||||
|
||||
@JsonKey(name: 'created_at') String? get createdAt;
|
||||
|
||||
int? get length;
|
||||
|
||||
/// Create a copy of HitokotoResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$HitokotoResponseCopyWith<HitokotoResponse> get copyWith =>
|
||||
_$HitokotoResponseCopyWithImpl<HitokotoResponse>(
|
||||
this as HitokotoResponse, _$identity);
|
||||
|
||||
/// Serializes this HitokotoResponse to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is HitokotoResponse &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.uuid, uuid) || other.uuid == uuid) &&
|
||||
(identical(other.hitokoto, hitokoto) ||
|
||||
other.hitokoto == hitokoto) &&
|
||||
(identical(other.type, type) || other.type == type) &&
|
||||
(identical(other.from, from) || other.from == from) &&
|
||||
(identical(other.fromWho, fromWho) || other.fromWho == fromWho) &&
|
||||
(identical(other.creator, creator) || other.creator == creator) &&
|
||||
(identical(other.creatorUid, creatorUid) ||
|
||||
other.creatorUid == creatorUid) &&
|
||||
(identical(other.reviewer, reviewer) ||
|
||||
other.reviewer == reviewer) &&
|
||||
(identical(other.commitFrom, commitFrom) ||
|
||||
other.commitFrom == commitFrom) &&
|
||||
(identical(other.createdAt, createdAt) ||
|
||||
other.createdAt == createdAt) &&
|
||||
(identical(other.length, length) || other.length == length));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType,
|
||||
id,
|
||||
uuid,
|
||||
hitokoto,
|
||||
type,
|
||||
from,
|
||||
fromWho,
|
||||
creator,
|
||||
creatorUid,
|
||||
reviewer,
|
||||
commitFrom,
|
||||
createdAt,
|
||||
length);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'HitokotoResponse(id: $id, uuid: $uuid, hitokoto: $hitokoto, type: $type, from: $from, fromWho: $fromWho, creator: $creator, creatorUid: $creatorUid, reviewer: $reviewer, commitFrom: $commitFrom, createdAt: $createdAt, length: $length)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $HitokotoResponseCopyWith<$Res> {
|
||||
factory $HitokotoResponseCopyWith(HitokotoResponse value,
|
||||
$Res Function(HitokotoResponse) _then) = _$HitokotoResponseCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call({
|
||||
int? id, String? uuid, String? hitokoto, String? type, String? from, @JsonKey(
|
||||
name: 'from_who') String? fromWho, String? creator, @JsonKey(
|
||||
name: 'creator_uid') int? creatorUid, int? reviewer, @JsonKey(
|
||||
name: 'commit_from') String? commitFrom, @JsonKey(
|
||||
name: 'created_at') String? createdAt, int? length
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$HitokotoResponseCopyWithImpl<$Res>
|
||||
implements $HitokotoResponseCopyWith<$Res> {
|
||||
_$HitokotoResponseCopyWithImpl(this._self, this._then);
|
||||
|
||||
final HitokotoResponse _self;
|
||||
final $Res Function(HitokotoResponse) _then;
|
||||
|
||||
/// Create a copy of HitokotoResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call(
|
||||
{Object? id = freezed, Object? uuid = freezed, Object? hitokoto = freezed, Object? type = freezed, Object? from = freezed, Object? fromWho = freezed, Object? creator = freezed, Object? creatorUid = freezed, Object? reviewer = freezed, Object? commitFrom = freezed, Object? createdAt = freezed, Object? length = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
id: freezed == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
uuid: freezed == uuid
|
||||
? _self.uuid
|
||||
: uuid // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
hitokoto: freezed == hitokoto
|
||||
? _self.hitokoto
|
||||
: hitokoto // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
type: freezed == type
|
||||
? _self.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
from: freezed == from
|
||||
? _self.from
|
||||
: from // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
fromWho: freezed == fromWho
|
||||
? _self.fromWho
|
||||
: fromWho // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
creator: freezed == creator
|
||||
? _self.creator
|
||||
: creator // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
creatorUid: freezed == creatorUid
|
||||
? _self.creatorUid
|
||||
: creatorUid // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
reviewer: freezed == reviewer
|
||||
? _self.reviewer
|
||||
: reviewer // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
commitFrom: freezed == commitFrom
|
||||
? _self.commitFrom
|
||||
: commitFrom // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
createdAt: freezed == createdAt
|
||||
? _self.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
length: freezed == length
|
||||
? _self.length
|
||||
: length // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _HitokotoResponse implements HitokotoResponse {
|
||||
const _HitokotoResponse(
|
||||
{this.id, this.uuid, this.hitokoto, this.type, this.from, @JsonKey(
|
||||
name: 'from_who') this.fromWho, this.creator, @JsonKey(
|
||||
name: 'creator_uid') this.creatorUid, this.reviewer, @JsonKey(
|
||||
name: 'commit_from') this.commitFrom, @JsonKey(
|
||||
name: 'created_at') this.createdAt, this.length});
|
||||
|
||||
factory _HitokotoResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$HitokotoResponseFromJson(json);
|
||||
|
||||
@override final int? id;
|
||||
@override final String? uuid;
|
||||
@override final String? hitokoto;
|
||||
@override final String? type;
|
||||
@override final String? from;
|
||||
@override
|
||||
@JsonKey(name: 'from_who')
|
||||
final String? fromWho;
|
||||
@override final String? creator;
|
||||
@override
|
||||
@JsonKey(name: 'creator_uid')
|
||||
final int? creatorUid;
|
||||
@override final int? reviewer;
|
||||
@override
|
||||
@JsonKey(name: 'commit_from')
|
||||
final String? commitFrom;
|
||||
@override
|
||||
@JsonKey(name: 'created_at')
|
||||
final String? createdAt;
|
||||
@override final int? length;
|
||||
|
||||
/// Create a copy of HitokotoResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$HitokotoResponseCopyWith<_HitokotoResponse> get copyWith =>
|
||||
__$HitokotoResponseCopyWithImpl<_HitokotoResponse>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$HitokotoResponseToJson(this,);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _HitokotoResponse &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.uuid, uuid) || other.uuid == uuid) &&
|
||||
(identical(other.hitokoto, hitokoto) ||
|
||||
other.hitokoto == hitokoto) &&
|
||||
(identical(other.type, type) || other.type == type) &&
|
||||
(identical(other.from, from) || other.from == from) &&
|
||||
(identical(other.fromWho, fromWho) || other.fromWho == fromWho) &&
|
||||
(identical(other.creator, creator) || other.creator == creator) &&
|
||||
(identical(other.creatorUid, creatorUid) ||
|
||||
other.creatorUid == creatorUid) &&
|
||||
(identical(other.reviewer, reviewer) ||
|
||||
other.reviewer == reviewer) &&
|
||||
(identical(other.commitFrom, commitFrom) ||
|
||||
other.commitFrom == commitFrom) &&
|
||||
(identical(other.createdAt, createdAt) ||
|
||||
other.createdAt == createdAt) &&
|
||||
(identical(other.length, length) || other.length == length));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType,
|
||||
id,
|
||||
uuid,
|
||||
hitokoto,
|
||||
type,
|
||||
from,
|
||||
fromWho,
|
||||
creator,
|
||||
creatorUid,
|
||||
reviewer,
|
||||
commitFrom,
|
||||
createdAt,
|
||||
length);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'HitokotoResponse(id: $id, uuid: $uuid, hitokoto: $hitokoto, type: $type, from: $from, fromWho: $fromWho, creator: $creator, creatorUid: $creatorUid, reviewer: $reviewer, commitFrom: $commitFrom, createdAt: $createdAt, length: $length)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$HitokotoResponseCopyWith<$Res>
|
||||
implements $HitokotoResponseCopyWith<$Res> {
|
||||
factory _$HitokotoResponseCopyWith(_HitokotoResponse value,
|
||||
$Res Function(_HitokotoResponse) _then) = __$HitokotoResponseCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
int? id, String? uuid, String? hitokoto, String? type, String? from, @JsonKey(
|
||||
name: 'from_who') String? fromWho, String? creator, @JsonKey(
|
||||
name: 'creator_uid') int? creatorUid, int? reviewer, @JsonKey(
|
||||
name: 'commit_from') String? commitFrom, @JsonKey(
|
||||
name: 'created_at') String? createdAt, int? length
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$HitokotoResponseCopyWithImpl<$Res>
|
||||
implements _$HitokotoResponseCopyWith<$Res> {
|
||||
__$HitokotoResponseCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _HitokotoResponse _self;
|
||||
final $Res Function(_HitokotoResponse) _then;
|
||||
|
||||
/// Create a copy of HitokotoResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$Res call(
|
||||
{Object? id = freezed, Object? uuid = freezed, Object? hitokoto = freezed, Object? type = freezed, Object? from = freezed, Object? fromWho = freezed, Object? creator = freezed, Object? creatorUid = freezed, Object? reviewer = freezed, Object? commitFrom = freezed, Object? createdAt = freezed, Object? length = freezed,}) {
|
||||
return _then(_HitokotoResponse(
|
||||
id: freezed == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
uuid: freezed == uuid
|
||||
? _self.uuid
|
||||
: uuid // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
hitokoto: freezed == hitokoto
|
||||
? _self.hitokoto
|
||||
: hitokoto // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
type: freezed == type
|
||||
? _self.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
from: freezed == from
|
||||
? _self.from
|
||||
: from // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
fromWho: freezed == fromWho
|
||||
? _self.fromWho
|
||||
: fromWho // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
creator: freezed == creator
|
||||
? _self.creator
|
||||
: creator // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
creatorUid: freezed == creatorUid
|
||||
? _self.creatorUid
|
||||
: creatorUid // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
reviewer: freezed == reviewer
|
||||
? _self.reviewer
|
||||
: reviewer // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
commitFrom: freezed == commitFrom
|
||||
? _self.commitFrom
|
||||
: commitFrom // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
createdAt: freezed == createdAt
|
||||
? _self.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
length: freezed == length
|
||||
? _self.length
|
||||
: length // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
39
lib/common/models/hitokoto.g.dart
Normal file
39
lib/common/models/hitokoto.g.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'hitokoto.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_HitokotoResponse _$HitokotoResponseFromJson(Map<String, dynamic> json) =>
|
||||
_HitokotoResponse(
|
||||
id: (json['id'] as num?)?.toInt(),
|
||||
uuid: json['uuid'] as String?,
|
||||
hitokoto: json['hitokoto'] as String?,
|
||||
type: json['type'] as String?,
|
||||
from: json['from'] as String?,
|
||||
fromWho: json['from_who'] as String?,
|
||||
creator: json['creator'] as String?,
|
||||
creatorUid: (json['creator_uid'] as num?)?.toInt(),
|
||||
reviewer: (json['reviewer'] as num?)?.toInt(),
|
||||
commitFrom: json['commit_from'] as String?,
|
||||
createdAt: json['created_at'] as String?,
|
||||
length: (json['length'] as num?)?.toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$HitokotoResponseToJson(_HitokotoResponse instance) =>
|
||||
<String, dynamic>{
|
||||
if (instance.id case final value?) 'id': value,
|
||||
if (instance.uuid case final value?) 'uuid': value,
|
||||
if (instance.hitokoto case final value?) 'hitokoto': value,
|
||||
if (instance.type case final value?) 'type': value,
|
||||
if (instance.from case final value?) 'from': value,
|
||||
if (instance.fromWho case final value?) 'from_who': value,
|
||||
if (instance.creator case final value?) 'creator': value,
|
||||
if (instance.creatorUid case final value?) 'creator_uid': value,
|
||||
if (instance.reviewer case final value?) 'reviewer': value,
|
||||
if (instance.commitFrom case final value?) 'commit_from': value,
|
||||
if (instance.createdAt case final value?) 'created_at': value,
|
||||
if (instance.length case final value?) 'length': value,
|
||||
};
|
||||
@@ -1,136 +1,74 @@
|
||||
class PublicHeader {
|
||||
String? action;
|
||||
int? timestamp;
|
||||
String? version;
|
||||
String? authorization;
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'X-TC-Action': action,
|
||||
'X-TC-Timestamp': timestamp,
|
||||
'X-TC-Version': version,
|
||||
'Authorization': authorization,
|
||||
};
|
||||
}
|
||||
part 'hunyuan.freezed.dart';
|
||||
part 'hunyuan.g.dart';
|
||||
|
||||
PublicHeader.fromMap(Map<String, dynamic> map) {
|
||||
action = map['X-TC-Action'];
|
||||
timestamp = map['X-TC-Timestamp'];
|
||||
version = map['X-TC-Version'];
|
||||
authorization = map['Authorization'];
|
||||
}
|
||||
@freezed
|
||||
abstract class PublicHeader with _$PublicHeader {
|
||||
const factory PublicHeader({
|
||||
@JsonKey(name: 'X-TC-Action') String? action,
|
||||
@JsonKey(name: 'X-TC-Timestamp') int? timestamp,
|
||||
@JsonKey(name: 'X-TC-Version') String? version,
|
||||
@JsonKey(name: 'Authorization') String? authorization,
|
||||
}) = _PublicHeader;
|
||||
|
||||
PublicHeader(this.action, this.timestamp, this.version, this.authorization);
|
||||
factory PublicHeader.fromJson(Map<String, dynamic> json) =>
|
||||
_$PublicHeaderFromJson(json);
|
||||
}
|
||||
|
||||
class Message {
|
||||
late String role;
|
||||
late String content;
|
||||
@freezed
|
||||
abstract class Message with _$Message {
|
||||
const factory Message({
|
||||
@JsonKey(name: 'Role') required String role,
|
||||
@JsonKey(name: 'Content') required String content,
|
||||
}) = _Message;
|
||||
|
||||
Message(this.role, this.content);
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {'Role': role, 'Content': content};
|
||||
}
|
||||
|
||||
Message.fromMap(Map<String, dynamic> map) {
|
||||
role = map['Role'];
|
||||
content = map['Content'];
|
||||
}
|
||||
factory Message.fromJson(Map<String, dynamic> json) =>
|
||||
_$MessageFromJson(json);
|
||||
}
|
||||
|
||||
class HunyuanResponse {
|
||||
String? note;
|
||||
List<Choices>? choices;
|
||||
int? created;
|
||||
String? id;
|
||||
Usage? usage;
|
||||
@freezed
|
||||
abstract class HunyuanResponse with _$HunyuanResponse {
|
||||
const factory HunyuanResponse({
|
||||
@JsonKey(name: 'Note') String? note,
|
||||
@JsonKey(name: 'Choices') List<Choices>? choices,
|
||||
@JsonKey(name: 'Created') int? created,
|
||||
@JsonKey(name: 'Id') String? id,
|
||||
@JsonKey(name: 'Usage') Usage? usage,
|
||||
}) = _HunyuanResponse;
|
||||
|
||||
HunyuanResponse({this.note, this.choices, this.created, this.id, this.usage});
|
||||
|
||||
HunyuanResponse.fromJson(Map<String, dynamic> json) {
|
||||
note = json["Note"];
|
||||
choices = json["Choices"] == null
|
||||
? null
|
||||
: (json["Choices"] as List).map((e) => Choices.fromJson(e)).toList();
|
||||
created = json["Created"];
|
||||
id = json["Id"];
|
||||
usage = json["Usage"] == null ? null : Usage.fromJson(json["Usage"]);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["Note"] = note;
|
||||
if (choices != null) {
|
||||
data["Choices"] = choices?.map((e) => e.toJson()).toList();
|
||||
}
|
||||
data["Created"] = created;
|
||||
data["Id"] = id;
|
||||
if (usage != null) {
|
||||
data["Usage"] = usage?.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
factory HunyuanResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$HunyuanResponseFromJson(json);
|
||||
}
|
||||
|
||||
class Usage {
|
||||
int? promptTokens;
|
||||
int? completionTokens;
|
||||
int? totalTokens;
|
||||
@freezed
|
||||
abstract class Usage with _$Usage {
|
||||
const factory Usage({
|
||||
@JsonKey(name: 'PromptTokens') int? promptTokens,
|
||||
@JsonKey(name: 'CompletionTokens') int? completionTokens,
|
||||
@JsonKey(name: 'TotalTokens') int? totalTokens,
|
||||
}) = _Usage;
|
||||
|
||||
Usage({this.promptTokens, this.completionTokens, this.totalTokens});
|
||||
|
||||
Usage.fromJson(Map<String, dynamic> json) {
|
||||
promptTokens = json["PromptTokens"];
|
||||
completionTokens = json["CompletionTokens"];
|
||||
totalTokens = json["TotalTokens"];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["PromptTokens"] = promptTokens;
|
||||
data["CompletionTokens"] = completionTokens;
|
||||
data["TotalTokens"] = totalTokens;
|
||||
return data;
|
||||
}
|
||||
factory Usage.fromJson(Map<String, dynamic> json) => _$UsageFromJson(json);
|
||||
}
|
||||
|
||||
class Choices {
|
||||
String? finishReason;
|
||||
Delta? delta;
|
||||
@freezed
|
||||
abstract class Choices with _$Choices {
|
||||
const factory Choices({
|
||||
@JsonKey(name: 'FinishReason') String? finishReason,
|
||||
@JsonKey(name: 'Delta') Delta? delta,
|
||||
}) = _Choices;
|
||||
|
||||
Choices({this.finishReason, this.delta});
|
||||
|
||||
Choices.fromJson(Map<String, dynamic> json) {
|
||||
finishReason = json["FinishReason"];
|
||||
delta = json["Delta"] == null ? null : Delta.fromJson(json["Delta"]);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["FinishReason"] = finishReason;
|
||||
if (delta != null) {
|
||||
data["Delta"] = delta?.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
factory Choices.fromJson(Map<String, dynamic> json) =>
|
||||
_$ChoicesFromJson(json);
|
||||
}
|
||||
|
||||
class Delta {
|
||||
String? role;
|
||||
String? content;
|
||||
@freezed
|
||||
abstract class Delta with _$Delta {
|
||||
const factory Delta({
|
||||
@JsonKey(name: 'Role') String? role,
|
||||
@JsonKey(name: 'Content') String? content,
|
||||
}) = _Delta;
|
||||
|
||||
Delta({this.role, this.content});
|
||||
|
||||
Delta.fromJson(Map<String, dynamic> json) {
|
||||
role = json["Role"];
|
||||
content = json["Content"];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["Role"] = role;
|
||||
data["Content"] = content;
|
||||
return data;
|
||||
}
|
||||
factory Delta.fromJson(Map<String, dynamic> json) => _$DeltaFromJson(json);
|
||||
}
|
||||
|
||||
1250
lib/common/models/hunyuan.freezed.dart
Normal file
1250
lib/common/models/hunyuan.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
88
lib/common/models/hunyuan.g.dart
Normal file
88
lib/common/models/hunyuan.g.dart
Normal file
@@ -0,0 +1,88 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'hunyuan.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_PublicHeader _$PublicHeaderFromJson(Map<String, dynamic> json) =>
|
||||
_PublicHeader(
|
||||
action: json['X-TC-Action'] as String?,
|
||||
timestamp: (json['X-TC-Timestamp'] as num?)?.toInt(),
|
||||
version: json['X-TC-Version'] as String?,
|
||||
authorization: json['Authorization'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$PublicHeaderToJson(_PublicHeader instance) =>
|
||||
<String, dynamic>{
|
||||
if (instance.action case final value?) 'X-TC-Action': value,
|
||||
if (instance.timestamp case final value?) 'X-TC-Timestamp': value,
|
||||
if (instance.version case final value?) 'X-TC-Version': value,
|
||||
if (instance.authorization case final value?) 'Authorization': value,
|
||||
};
|
||||
|
||||
_Message _$MessageFromJson(Map<String, dynamic> json) =>
|
||||
_Message(role: json['Role'] as String, content: json['Content'] as String);
|
||||
|
||||
Map<String, dynamic> _$MessageToJson(_Message instance) => <String, dynamic>{
|
||||
'Role': instance.role,
|
||||
'Content': instance.content,
|
||||
};
|
||||
|
||||
_HunyuanResponse _$HunyuanResponseFromJson(Map<String, dynamic> json) =>
|
||||
_HunyuanResponse(
|
||||
note: json['Note'] as String?,
|
||||
choices:
|
||||
(json['Choices'] as List<dynamic>?)
|
||||
?.map((e) => Choices.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
created: (json['Created'] as num?)?.toInt(),
|
||||
id: json['Id'] as String?,
|
||||
usage:
|
||||
json['Usage'] == null
|
||||
? null
|
||||
: Usage.fromJson(json['Usage'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$HunyuanResponseToJson(_HunyuanResponse instance) =>
|
||||
<String, dynamic>{
|
||||
if (instance.note case final value?) 'Note': value,
|
||||
if (instance.choices case final value?) 'Choices': value,
|
||||
if (instance.created case final value?) 'Created': value,
|
||||
if (instance.id case final value?) 'Id': value,
|
||||
if (instance.usage case final value?) 'Usage': value,
|
||||
};
|
||||
|
||||
_Usage _$UsageFromJson(Map<String, dynamic> json) => _Usage(
|
||||
promptTokens: (json['PromptTokens'] as num?)?.toInt(),
|
||||
completionTokens: (json['CompletionTokens'] as num?)?.toInt(),
|
||||
totalTokens: (json['TotalTokens'] as num?)?.toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$UsageToJson(_Usage instance) => <String, dynamic>{
|
||||
if (instance.promptTokens case final value?) 'PromptTokens': value,
|
||||
if (instance.completionTokens case final value?) 'CompletionTokens': value,
|
||||
if (instance.totalTokens case final value?) 'TotalTokens': value,
|
||||
};
|
||||
|
||||
_Choices _$ChoicesFromJson(Map<String, dynamic> json) => _Choices(
|
||||
finishReason: json['FinishReason'] as String?,
|
||||
delta:
|
||||
json['Delta'] == null
|
||||
? null
|
||||
: Delta.fromJson(json['Delta'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ChoicesToJson(_Choices instance) => <String, dynamic>{
|
||||
if (instance.finishReason case final value?) 'FinishReason': value,
|
||||
if (instance.delta case final value?) 'Delta': value,
|
||||
};
|
||||
|
||||
_Delta _$DeltaFromJson(Map<String, dynamic> json) =>
|
||||
_Delta(role: json['Role'] as String?, content: json['Content'] as String?);
|
||||
|
||||
Map<String, dynamic> _$DeltaToJson(_Delta instance) => <String, dynamic>{
|
||||
if (instance.role case final value?) 'Role': value,
|
||||
if (instance.content case final value?) 'Content': value,
|
||||
};
|
||||
@@ -1,128 +1,50 @@
|
||||
class BingImage {
|
||||
List<Images>? images;
|
||||
Tooltips? tooltips;
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
BingImage({this.images, this.tooltips});
|
||||
part 'image.freezed.dart';
|
||||
part 'image.g.dart';
|
||||
|
||||
BingImage.fromJson(Map<String, dynamic> json) {
|
||||
images = json["images"] == null
|
||||
? null
|
||||
: (json["images"] as List).map((e) => Images.fromJson(e)).toList();
|
||||
tooltips =
|
||||
json["tooltips"] == null ? null : Tooltips.fromJson(json["tooltips"]);
|
||||
}
|
||||
@freezed
|
||||
abstract class BingImage with _$BingImage {
|
||||
const factory BingImage({List<Images>? images, Tooltips? tooltips}) =
|
||||
_BingImage;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
if (images != null) {
|
||||
data["images"] = images?.map((e) => e.toJson()).toList();
|
||||
}
|
||||
if (tooltips != null) {
|
||||
data["tooltips"] = tooltips?.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
factory BingImage.fromJson(Map<String, dynamic> json) =>
|
||||
_$BingImageFromJson(json);
|
||||
}
|
||||
|
||||
class Tooltips {
|
||||
String? loading;
|
||||
String? previous;
|
||||
String? next;
|
||||
String? walle;
|
||||
String? walls;
|
||||
@freezed
|
||||
abstract class Tooltips with _$Tooltips {
|
||||
const factory Tooltips({
|
||||
String? loading,
|
||||
String? previous,
|
||||
String? next,
|
||||
String? walle,
|
||||
String? walls,
|
||||
}) = _Tooltips;
|
||||
|
||||
Tooltips({this.loading, this.previous, this.next, this.walle, this.walls});
|
||||
|
||||
Tooltips.fromJson(Map<String, dynamic> json) {
|
||||
loading = json["loading"];
|
||||
previous = json["previous"];
|
||||
next = json["next"];
|
||||
walle = json["walle"];
|
||||
walls = json["walls"];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["loading"] = loading;
|
||||
data["previous"] = previous;
|
||||
data["next"] = next;
|
||||
data["walle"] = walle;
|
||||
data["walls"] = walls;
|
||||
return data;
|
||||
}
|
||||
factory Tooltips.fromJson(Map<String, dynamic> json) =>
|
||||
_$TooltipsFromJson(json);
|
||||
}
|
||||
|
||||
class Images {
|
||||
String? startdate;
|
||||
String? fullstartdate;
|
||||
String? enddate;
|
||||
String? url;
|
||||
String? urlbase;
|
||||
String? copyright;
|
||||
String? copyrightlink;
|
||||
String? title;
|
||||
String? quiz;
|
||||
bool? wp;
|
||||
String? hsh;
|
||||
int? drk;
|
||||
int? top;
|
||||
int? bot;
|
||||
List<dynamic>? hs;
|
||||
@freezed
|
||||
abstract class Images with _$Images {
|
||||
const factory Images({
|
||||
String? startdate,
|
||||
String? fullstartdate,
|
||||
String? enddate,
|
||||
String? url,
|
||||
String? urlbase,
|
||||
String? copyright,
|
||||
String? copyrightlink,
|
||||
String? title,
|
||||
String? quiz,
|
||||
bool? wp,
|
||||
String? hsh,
|
||||
int? drk,
|
||||
int? top,
|
||||
int? bot,
|
||||
List<dynamic>? hs,
|
||||
}) = _Images;
|
||||
|
||||
Images(
|
||||
{this.startdate,
|
||||
this.fullstartdate,
|
||||
this.enddate,
|
||||
this.url,
|
||||
this.urlbase,
|
||||
this.copyright,
|
||||
this.copyrightlink,
|
||||
this.title,
|
||||
this.quiz,
|
||||
this.wp,
|
||||
this.hsh,
|
||||
this.drk,
|
||||
this.top,
|
||||
this.bot,
|
||||
this.hs});
|
||||
|
||||
Images.fromJson(Map<String, dynamic> json) {
|
||||
startdate = json["startdate"];
|
||||
fullstartdate = json["fullstartdate"];
|
||||
enddate = json["enddate"];
|
||||
url = json["url"];
|
||||
urlbase = json["urlbase"];
|
||||
copyright = json["copyright"];
|
||||
copyrightlink = json["copyrightlink"];
|
||||
title = json["title"];
|
||||
quiz = json["quiz"];
|
||||
wp = json["wp"];
|
||||
hsh = json["hsh"];
|
||||
drk = json["drk"];
|
||||
top = json["top"];
|
||||
bot = json["bot"];
|
||||
hs = json["hs"] ?? [];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["startdate"] = startdate;
|
||||
data["fullstartdate"] = fullstartdate;
|
||||
data["enddate"] = enddate;
|
||||
data["url"] = url;
|
||||
data["urlbase"] = urlbase;
|
||||
data["copyright"] = copyright;
|
||||
data["copyrightlink"] = copyrightlink;
|
||||
data["title"] = title;
|
||||
data["quiz"] = quiz;
|
||||
data["wp"] = wp;
|
||||
data["hsh"] = hsh;
|
||||
data["drk"] = drk;
|
||||
data["top"] = top;
|
||||
data["bot"] = bot;
|
||||
if (hs != null) {
|
||||
data["hs"] = hs;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
factory Images.fromJson(Map<String, dynamic> json) => _$ImagesFromJson(json);
|
||||
}
|
||||
|
||||
825
lib/common/models/image.freezed.dart
Normal file
825
lib/common/models/image.freezed.dart
Normal file
@@ -0,0 +1,825 @@
|
||||
// dart format width=80
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'image.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$BingImage {
|
||||
|
||||
List<Images>? get images;
|
||||
|
||||
Tooltips? get tooltips;
|
||||
|
||||
/// Create a copy of BingImage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$BingImageCopyWith<BingImage> get copyWith =>
|
||||
_$BingImageCopyWithImpl<BingImage>(this as BingImage, _$identity);
|
||||
|
||||
/// Serializes this BingImage to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is BingImage &&
|
||||
const DeepCollectionEquality().equals(other.images, images) &&
|
||||
(identical(other.tooltips, tooltips) ||
|
||||
other.tooltips == tooltips));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType, const DeepCollectionEquality().hash(images), tooltips);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'BingImage(images: $images, tooltips: $tooltips)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $BingImageCopyWith<$Res> {
|
||||
factory $BingImageCopyWith(BingImage value,
|
||||
$Res Function(BingImage) _then) = _$BingImageCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call({
|
||||
List<Images>? images, Tooltips? tooltips
|
||||
});
|
||||
|
||||
|
||||
$TooltipsCopyWith<$Res>? get tooltips;
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$BingImageCopyWithImpl<$Res>
|
||||
implements $BingImageCopyWith<$Res> {
|
||||
_$BingImageCopyWithImpl(this._self, this._then);
|
||||
|
||||
final BingImage _self;
|
||||
final $Res Function(BingImage) _then;
|
||||
|
||||
/// Create a copy of BingImage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? images = freezed, Object? tooltips = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
images: freezed == images
|
||||
? _self.images
|
||||
: images // ignore: cast_nullable_to_non_nullable
|
||||
as List<Images>?,
|
||||
tooltips: freezed == tooltips
|
||||
? _self.tooltips
|
||||
: tooltips // ignore: cast_nullable_to_non_nullable
|
||||
as Tooltips?,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of BingImage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$TooltipsCopyWith<$Res>? get tooltips {
|
||||
if (_self.tooltips == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $TooltipsCopyWith<$Res>(_self.tooltips!, (value) {
|
||||
return _then(_self.copyWith(tooltips: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _BingImage implements BingImage {
|
||||
const _BingImage({final List<Images>? images, this.tooltips})
|
||||
: _images = images;
|
||||
|
||||
factory _BingImage.fromJson(Map<String, dynamic> json) =>
|
||||
_$BingImageFromJson(json);
|
||||
|
||||
final List<Images>? _images;
|
||||
|
||||
@override List<Images>? get images {
|
||||
final value = _images;
|
||||
if (value == null) return null;
|
||||
if (_images is EqualUnmodifiableListView) return _images;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
@override final Tooltips? tooltips;
|
||||
|
||||
/// Create a copy of BingImage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$BingImageCopyWith<_BingImage> get copyWith =>
|
||||
__$BingImageCopyWithImpl<_BingImage>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$BingImageToJson(this,);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _BingImage &&
|
||||
const DeepCollectionEquality().equals(other._images, _images) &&
|
||||
(identical(other.tooltips, tooltips) ||
|
||||
other.tooltips == tooltips));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType, const DeepCollectionEquality().hash(_images), tooltips);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'BingImage(images: $images, tooltips: $tooltips)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$BingImageCopyWith<$Res>
|
||||
implements $BingImageCopyWith<$Res> {
|
||||
factory _$BingImageCopyWith(_BingImage value,
|
||||
$Res Function(_BingImage) _then) = __$BingImageCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
List<Images>? images, Tooltips? tooltips
|
||||
});
|
||||
|
||||
|
||||
@override $TooltipsCopyWith<$Res>? get tooltips;
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$BingImageCopyWithImpl<$Res>
|
||||
implements _$BingImageCopyWith<$Res> {
|
||||
__$BingImageCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _BingImage _self;
|
||||
final $Res Function(_BingImage) _then;
|
||||
|
||||
/// Create a copy of BingImage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$Res call({Object? images = freezed, Object? tooltips = freezed,}) {
|
||||
return _then(_BingImage(
|
||||
images: freezed == images
|
||||
? _self._images
|
||||
: images // ignore: cast_nullable_to_non_nullable
|
||||
as List<Images>?,
|
||||
tooltips: freezed == tooltips
|
||||
? _self.tooltips
|
||||
: tooltips // ignore: cast_nullable_to_non_nullable
|
||||
as Tooltips?,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of BingImage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$TooltipsCopyWith<$Res>? get tooltips {
|
||||
if (_self.tooltips == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $TooltipsCopyWith<$Res>(_self.tooltips!, (value) {
|
||||
return _then(_self.copyWith(tooltips: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Tooltips {
|
||||
|
||||
String? get loading;
|
||||
|
||||
String? get previous;
|
||||
|
||||
String? get next;
|
||||
|
||||
String? get walle;
|
||||
|
||||
String? get walls;
|
||||
|
||||
/// Create a copy of Tooltips
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$TooltipsCopyWith<Tooltips> get copyWith =>
|
||||
_$TooltipsCopyWithImpl<Tooltips>(this as Tooltips, _$identity);
|
||||
|
||||
/// Serializes this Tooltips to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is Tooltips &&
|
||||
(identical(other.loading, loading) || other.loading == loading) &&
|
||||
(identical(other.previous, previous) ||
|
||||
other.previous == previous) &&
|
||||
(identical(other.next, next) || other.next == next) &&
|
||||
(identical(other.walle, walle) || other.walle == walle) &&
|
||||
(identical(other.walls, walls) || other.walls == walls));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, loading, previous, next, walle, walls);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Tooltips(loading: $loading, previous: $previous, next: $next, walle: $walle, walls: $walls)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $TooltipsCopyWith<$Res> {
|
||||
factory $TooltipsCopyWith(Tooltips value,
|
||||
$Res Function(Tooltips) _then) = _$TooltipsCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call({
|
||||
String? loading, String? previous, String? next, String? walle, String? walls
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$TooltipsCopyWithImpl<$Res>
|
||||
implements $TooltipsCopyWith<$Res> {
|
||||
_$TooltipsCopyWithImpl(this._self, this._then);
|
||||
|
||||
final Tooltips _self;
|
||||
final $Res Function(Tooltips) _then;
|
||||
|
||||
/// Create a copy of Tooltips
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call(
|
||||
{Object? loading = freezed, Object? previous = freezed, Object? next = freezed, Object? walle = freezed, Object? walls = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
loading: freezed == loading
|
||||
? _self.loading
|
||||
: loading // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
previous: freezed == previous
|
||||
? _self.previous
|
||||
: previous // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
next: freezed == next
|
||||
? _self.next
|
||||
: next // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
walle: freezed == walle
|
||||
? _self.walle
|
||||
: walle // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
walls: freezed == walls
|
||||
? _self.walls
|
||||
: walls // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _Tooltips implements Tooltips {
|
||||
const _Tooltips(
|
||||
{this.loading, this.previous, this.next, this.walle, this.walls});
|
||||
|
||||
factory _Tooltips.fromJson(Map<String, dynamic> json) =>
|
||||
_$TooltipsFromJson(json);
|
||||
|
||||
@override final String? loading;
|
||||
@override final String? previous;
|
||||
@override final String? next;
|
||||
@override final String? walle;
|
||||
@override final String? walls;
|
||||
|
||||
/// Create a copy of Tooltips
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$TooltipsCopyWith<_Tooltips> get copyWith =>
|
||||
__$TooltipsCopyWithImpl<_Tooltips>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$TooltipsToJson(this,);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _Tooltips &&
|
||||
(identical(other.loading, loading) || other.loading == loading) &&
|
||||
(identical(other.previous, previous) ||
|
||||
other.previous == previous) &&
|
||||
(identical(other.next, next) || other.next == next) &&
|
||||
(identical(other.walle, walle) || other.walle == walle) &&
|
||||
(identical(other.walls, walls) || other.walls == walls));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, loading, previous, next, walle, walls);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Tooltips(loading: $loading, previous: $previous, next: $next, walle: $walle, walls: $walls)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$TooltipsCopyWith<$Res>
|
||||
implements $TooltipsCopyWith<$Res> {
|
||||
factory _$TooltipsCopyWith(_Tooltips value,
|
||||
$Res Function(_Tooltips) _then) = __$TooltipsCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
String? loading, String? previous, String? next, String? walle, String? walls
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$TooltipsCopyWithImpl<$Res>
|
||||
implements _$TooltipsCopyWith<$Res> {
|
||||
__$TooltipsCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _Tooltips _self;
|
||||
final $Res Function(_Tooltips) _then;
|
||||
|
||||
/// Create a copy of Tooltips
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$Res call(
|
||||
{Object? loading = freezed, Object? previous = freezed, Object? next = freezed, Object? walle = freezed, Object? walls = freezed,}) {
|
||||
return _then(_Tooltips(
|
||||
loading: freezed == loading
|
||||
? _self.loading
|
||||
: loading // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
previous: freezed == previous
|
||||
? _self.previous
|
||||
: previous // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
next: freezed == next
|
||||
? _self.next
|
||||
: next // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
walle: freezed == walle
|
||||
? _self.walle
|
||||
: walle // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
walls: freezed == walls
|
||||
? _self.walls
|
||||
: walls // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Images {
|
||||
|
||||
String? get startdate;
|
||||
|
||||
String? get fullstartdate;
|
||||
|
||||
String? get enddate;
|
||||
|
||||
String? get url;
|
||||
|
||||
String? get urlbase;
|
||||
|
||||
String? get copyright;
|
||||
|
||||
String? get copyrightlink;
|
||||
|
||||
String? get title;
|
||||
|
||||
String? get quiz;
|
||||
|
||||
bool? get wp;
|
||||
|
||||
String? get hsh;
|
||||
|
||||
int? get drk;
|
||||
|
||||
int? get top;
|
||||
|
||||
int? get bot;
|
||||
|
||||
List<dynamic>? get hs;
|
||||
|
||||
/// Create a copy of Images
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ImagesCopyWith<Images> get copyWith =>
|
||||
_$ImagesCopyWithImpl<Images>(this as Images, _$identity);
|
||||
|
||||
/// Serializes this Images to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is Images &&
|
||||
(identical(other.startdate, startdate) ||
|
||||
other.startdate == startdate) &&
|
||||
(identical(other.fullstartdate, fullstartdate) ||
|
||||
other.fullstartdate == fullstartdate) &&
|
||||
(identical(other.enddate, enddate) || other.enddate == enddate) &&
|
||||
(identical(other.url, url) || other.url == url) &&
|
||||
(identical(other.urlbase, urlbase) || other.urlbase == urlbase) &&
|
||||
(identical(other.copyright, copyright) ||
|
||||
other.copyright == copyright) &&
|
||||
(identical(other.copyrightlink, copyrightlink) ||
|
||||
other.copyrightlink == copyrightlink) &&
|
||||
(identical(other.title, title) || other.title == title) &&
|
||||
(identical(other.quiz, quiz) || other.quiz == quiz) &&
|
||||
(identical(other.wp, wp) || other.wp == wp) &&
|
||||
(identical(other.hsh, hsh) || other.hsh == hsh) &&
|
||||
(identical(other.drk, drk) || other.drk == drk) &&
|
||||
(identical(other.top, top) || other.top == top) &&
|
||||
(identical(other.bot, bot) || other.bot == bot) &&
|
||||
const DeepCollectionEquality().equals(other.hs, hs));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType,
|
||||
startdate,
|
||||
fullstartdate,
|
||||
enddate,
|
||||
url,
|
||||
urlbase,
|
||||
copyright,
|
||||
copyrightlink,
|
||||
title,
|
||||
quiz,
|
||||
wp,
|
||||
hsh,
|
||||
drk,
|
||||
top,
|
||||
bot,
|
||||
const DeepCollectionEquality().hash(hs));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Images(startdate: $startdate, fullstartdate: $fullstartdate, enddate: $enddate, url: $url, urlbase: $urlbase, copyright: $copyright, copyrightlink: $copyrightlink, title: $title, quiz: $quiz, wp: $wp, hsh: $hsh, drk: $drk, top: $top, bot: $bot, hs: $hs)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ImagesCopyWith<$Res> {
|
||||
factory $ImagesCopyWith(Images value,
|
||||
$Res Function(Images) _then) = _$ImagesCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call({
|
||||
String? startdate, String? fullstartdate, String? enddate, String? url, String? urlbase, String? copyright, String? copyrightlink, String? title, String? quiz, bool? wp, String? hsh, int? drk, int? top, int? bot, List<
|
||||
dynamic>? hs
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ImagesCopyWithImpl<$Res>
|
||||
implements $ImagesCopyWith<$Res> {
|
||||
_$ImagesCopyWithImpl(this._self, this._then);
|
||||
|
||||
final Images _self;
|
||||
final $Res Function(Images) _then;
|
||||
|
||||
/// Create a copy of Images
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call(
|
||||
{Object? startdate = freezed, Object? fullstartdate = freezed, Object? enddate = freezed, Object? url = freezed, Object? urlbase = freezed, Object? copyright = freezed, Object? copyrightlink = freezed, Object? title = freezed, Object? quiz = freezed, Object? wp = freezed, Object? hsh = freezed, Object? drk = freezed, Object? top = freezed, Object? bot = freezed, Object? hs = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
startdate: freezed == startdate
|
||||
? _self.startdate
|
||||
: startdate // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
fullstartdate: freezed == fullstartdate
|
||||
? _self.fullstartdate
|
||||
: fullstartdate // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
enddate: freezed == enddate
|
||||
? _self.enddate
|
||||
: enddate // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
url: freezed == url
|
||||
? _self.url
|
||||
: url // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
urlbase: freezed == urlbase
|
||||
? _self.urlbase
|
||||
: urlbase // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
copyright: freezed == copyright
|
||||
? _self.copyright
|
||||
: copyright // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
copyrightlink: freezed == copyrightlink
|
||||
? _self.copyrightlink
|
||||
: copyrightlink // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
title: freezed == title
|
||||
? _self.title
|
||||
: title // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
quiz: freezed == quiz
|
||||
? _self.quiz
|
||||
: quiz // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
wp: freezed == wp ? _self.wp : wp // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
hsh: freezed == hsh
|
||||
? _self.hsh
|
||||
: hsh // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
drk: freezed == drk
|
||||
? _self.drk
|
||||
: drk // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
top: freezed == top
|
||||
? _self.top
|
||||
: top // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
bot: freezed == bot
|
||||
? _self.bot
|
||||
: bot // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
hs: freezed == hs ? _self.hs : hs // ignore: cast_nullable_to_non_nullable
|
||||
as List<dynamic>?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _Images implements Images {
|
||||
const _Images(
|
||||
{this.startdate, this.fullstartdate, this.enddate, this.url, this.urlbase, this.copyright, this.copyrightlink, this.title, this.quiz, this.wp, this.hsh, this.drk, this.top, this.bot, final List<
|
||||
dynamic>? hs}) : _hs = hs;
|
||||
|
||||
factory _Images.fromJson(Map<String, dynamic> json) => _$ImagesFromJson(json);
|
||||
|
||||
@override final String? startdate;
|
||||
@override final String? fullstartdate;
|
||||
@override final String? enddate;
|
||||
@override final String? url;
|
||||
@override final String? urlbase;
|
||||
@override final String? copyright;
|
||||
@override final String? copyrightlink;
|
||||
@override final String? title;
|
||||
@override final String? quiz;
|
||||
@override final bool? wp;
|
||||
@override final String? hsh;
|
||||
@override final int? drk;
|
||||
@override final int? top;
|
||||
@override final int? bot;
|
||||
final List<dynamic>? _hs;
|
||||
|
||||
@override List<dynamic>? get hs {
|
||||
final value = _hs;
|
||||
if (value == null) return null;
|
||||
if (_hs is EqualUnmodifiableListView) return _hs;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
|
||||
/// Create a copy of Images
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ImagesCopyWith<_Images> get copyWith =>
|
||||
__$ImagesCopyWithImpl<_Images>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$ImagesToJson(this,);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _Images &&
|
||||
(identical(other.startdate, startdate) ||
|
||||
other.startdate == startdate) &&
|
||||
(identical(other.fullstartdate, fullstartdate) ||
|
||||
other.fullstartdate == fullstartdate) &&
|
||||
(identical(other.enddate, enddate) || other.enddate == enddate) &&
|
||||
(identical(other.url, url) || other.url == url) &&
|
||||
(identical(other.urlbase, urlbase) || other.urlbase == urlbase) &&
|
||||
(identical(other.copyright, copyright) ||
|
||||
other.copyright == copyright) &&
|
||||
(identical(other.copyrightlink, copyrightlink) ||
|
||||
other.copyrightlink == copyrightlink) &&
|
||||
(identical(other.title, title) || other.title == title) &&
|
||||
(identical(other.quiz, quiz) || other.quiz == quiz) &&
|
||||
(identical(other.wp, wp) || other.wp == wp) &&
|
||||
(identical(other.hsh, hsh) || other.hsh == hsh) &&
|
||||
(identical(other.drk, drk) || other.drk == drk) &&
|
||||
(identical(other.top, top) || other.top == top) &&
|
||||
(identical(other.bot, bot) || other.bot == bot) &&
|
||||
const DeepCollectionEquality().equals(other._hs, _hs));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType,
|
||||
startdate,
|
||||
fullstartdate,
|
||||
enddate,
|
||||
url,
|
||||
urlbase,
|
||||
copyright,
|
||||
copyrightlink,
|
||||
title,
|
||||
quiz,
|
||||
wp,
|
||||
hsh,
|
||||
drk,
|
||||
top,
|
||||
bot,
|
||||
const DeepCollectionEquality().hash(_hs));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Images(startdate: $startdate, fullstartdate: $fullstartdate, enddate: $enddate, url: $url, urlbase: $urlbase, copyright: $copyright, copyrightlink: $copyrightlink, title: $title, quiz: $quiz, wp: $wp, hsh: $hsh, drk: $drk, top: $top, bot: $bot, hs: $hs)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ImagesCopyWith<$Res> implements $ImagesCopyWith<$Res> {
|
||||
factory _$ImagesCopyWith(_Images value,
|
||||
$Res Function(_Images) _then) = __$ImagesCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
String? startdate, String? fullstartdate, String? enddate, String? url, String? urlbase, String? copyright, String? copyrightlink, String? title, String? quiz, bool? wp, String? hsh, int? drk, int? top, int? bot, List<
|
||||
dynamic>? hs
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$ImagesCopyWithImpl<$Res>
|
||||
implements _$ImagesCopyWith<$Res> {
|
||||
__$ImagesCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _Images _self;
|
||||
final $Res Function(_Images) _then;
|
||||
|
||||
/// Create a copy of Images
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$Res call(
|
||||
{Object? startdate = freezed, Object? fullstartdate = freezed, Object? enddate = freezed, Object? url = freezed, Object? urlbase = freezed, Object? copyright = freezed, Object? copyrightlink = freezed, Object? title = freezed, Object? quiz = freezed, Object? wp = freezed, Object? hsh = freezed, Object? drk = freezed, Object? top = freezed, Object? bot = freezed, Object? hs = freezed,}) {
|
||||
return _then(_Images(
|
||||
startdate: freezed == startdate
|
||||
? _self.startdate
|
||||
: startdate // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
fullstartdate: freezed == fullstartdate
|
||||
? _self.fullstartdate
|
||||
: fullstartdate // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
enddate: freezed == enddate
|
||||
? _self.enddate
|
||||
: enddate // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
url: freezed == url
|
||||
? _self.url
|
||||
: url // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
urlbase: freezed == urlbase
|
||||
? _self.urlbase
|
||||
: urlbase // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
copyright: freezed == copyright
|
||||
? _self.copyright
|
||||
: copyright // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
copyrightlink: freezed == copyrightlink
|
||||
? _self.copyrightlink
|
||||
: copyrightlink // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
title: freezed == title
|
||||
? _self.title
|
||||
: title // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
quiz: freezed == quiz
|
||||
? _self.quiz
|
||||
: quiz // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
wp: freezed == wp ? _self.wp : wp // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
hsh: freezed == hsh
|
||||
? _self.hsh
|
||||
: hsh // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
drk: freezed == drk
|
||||
? _self.drk
|
||||
: drk // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
top: freezed == top
|
||||
? _self.top
|
||||
: top // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
bot: freezed == bot
|
||||
? _self.bot
|
||||
: bot // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
hs: freezed == hs
|
||||
? _self._hs
|
||||
: hs // ignore: cast_nullable_to_non_nullable
|
||||
as List<dynamic>?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
76
lib/common/models/image.g.dart
Normal file
76
lib/common/models/image.g.dart
Normal file
@@ -0,0 +1,76 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'image.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_BingImage _$BingImageFromJson(Map<String, dynamic> json) => _BingImage(
|
||||
images:
|
||||
(json['images'] as List<dynamic>?)
|
||||
?.map((e) => Images.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
tooltips:
|
||||
json['tooltips'] == null
|
||||
? null
|
||||
: Tooltips.fromJson(json['tooltips'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$BingImageToJson(_BingImage instance) =>
|
||||
<String, dynamic>{
|
||||
if (instance.images case final value?) 'images': value,
|
||||
if (instance.tooltips case final value?) 'tooltips': value,
|
||||
};
|
||||
|
||||
_Tooltips _$TooltipsFromJson(Map<String, dynamic> json) => _Tooltips(
|
||||
loading: json['loading'] as String?,
|
||||
previous: json['previous'] as String?,
|
||||
next: json['next'] as String?,
|
||||
walle: json['walle'] as String?,
|
||||
walls: json['walls'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$TooltipsToJson(_Tooltips instance) => <String, dynamic>{
|
||||
if (instance.loading case final value?) 'loading': value,
|
||||
if (instance.previous case final value?) 'previous': value,
|
||||
if (instance.next case final value?) 'next': value,
|
||||
if (instance.walle case final value?) 'walle': value,
|
||||
if (instance.walls case final value?) 'walls': value,
|
||||
};
|
||||
|
||||
_Images _$ImagesFromJson(Map<String, dynamic> json) => _Images(
|
||||
startdate: json['startdate'] as String?,
|
||||
fullstartdate: json['fullstartdate'] as String?,
|
||||
enddate: json['enddate'] as String?,
|
||||
url: json['url'] as String?,
|
||||
urlbase: json['urlbase'] as String?,
|
||||
copyright: json['copyright'] as String?,
|
||||
copyrightlink: json['copyrightlink'] as String?,
|
||||
title: json['title'] as String?,
|
||||
quiz: json['quiz'] as String?,
|
||||
wp: json['wp'] as bool?,
|
||||
hsh: json['hsh'] as String?,
|
||||
drk: (json['drk'] as num?)?.toInt(),
|
||||
top: (json['top'] as num?)?.toInt(),
|
||||
bot: (json['bot'] as num?)?.toInt(),
|
||||
hs: json['hs'] as List<dynamic>?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ImagesToJson(_Images instance) => <String, dynamic>{
|
||||
if (instance.startdate case final value?) 'startdate': value,
|
||||
if (instance.fullstartdate case final value?) 'fullstartdate': value,
|
||||
if (instance.enddate case final value?) 'enddate': value,
|
||||
if (instance.url case final value?) 'url': value,
|
||||
if (instance.urlbase case final value?) 'urlbase': value,
|
||||
if (instance.copyright case final value?) 'copyright': value,
|
||||
if (instance.copyrightlink case final value?) 'copyrightlink': value,
|
||||
if (instance.title case final value?) 'title': value,
|
||||
if (instance.quiz case final value?) 'quiz': value,
|
||||
if (instance.wp case final value?) 'wp': value,
|
||||
if (instance.hsh case final value?) 'hsh': value,
|
||||
if (instance.drk case final value?) 'drk': value,
|
||||
if (instance.top case final value?) 'top': value,
|
||||
if (instance.bot case final value?) 'bot': value,
|
||||
if (instance.hs case final value?) 'hs': value,
|
||||
};
|
||||
@@ -17,11 +17,7 @@ class Category {
|
||||
Category();
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'categoryName': categoryName,
|
||||
'parentId': parentId,
|
||||
};
|
||||
return {'id': id, 'categoryName': categoryName, 'parentId': parentId};
|
||||
}
|
||||
|
||||
factory Category.fromJson(Map<String, dynamic> json) {
|
||||
|
||||
@@ -20,16 +20,19 @@ const CategorySchema = IsarGeneratedSchema(
|
||||
idName: 'id',
|
||||
embedded: false,
|
||||
properties: [
|
||||
IsarPropertySchema(
|
||||
name: 'id',
|
||||
type: IsarType.string,
|
||||
),
|
||||
IsarPropertySchema(
|
||||
name: 'categoryName',
|
||||
type: IsarType.string,
|
||||
IsarPropertySchema(name: 'id', type: IsarType.string),
|
||||
IsarPropertySchema(name: 'categoryName', type: IsarType.string),
|
||||
IsarPropertySchema(name: 'parentId', type: IsarType.string),
|
||||
IsarPropertySchema(name: 'level', type: IsarType.string),
|
||||
],
|
||||
indexes: [
|
||||
IsarIndexSchema(
|
||||
name: 'level',
|
||||
properties: ["level"],
|
||||
unique: false,
|
||||
hash: false,
|
||||
),
|
||||
],
|
||||
indexes: [],
|
||||
),
|
||||
converter: IsarObjectConverter<String, Category>(
|
||||
serialize: serializeCategory,
|
||||
@@ -43,6 +46,15 @@ const CategorySchema = IsarGeneratedSchema(
|
||||
int serializeCategory(IsarWriter writer, Category object) {
|
||||
IsarCore.writeString(writer, 1, object.id);
|
||||
IsarCore.writeString(writer, 2, object.categoryName);
|
||||
{
|
||||
final value = object.parentId;
|
||||
if (value == null) {
|
||||
IsarCore.writeNull(writer, 3);
|
||||
} else {
|
||||
IsarCore.writeString(writer, 3, value);
|
||||
}
|
||||
}
|
||||
IsarCore.writeString(writer, 4, object.level);
|
||||
return Isar.fastHash(object.id);
|
||||
}
|
||||
|
||||
@@ -51,6 +63,7 @@ Category deserializeCategory(IsarReader reader) {
|
||||
final object = Category();
|
||||
object.id = IsarCore.readString(reader, 1) ?? '';
|
||||
object.categoryName = IsarCore.readString(reader, 2) ?? '';
|
||||
object.parentId = IsarCore.readString(reader, 3);
|
||||
return object;
|
||||
}
|
||||
|
||||
@@ -61,6 +74,10 @@ dynamic deserializeCategoryProp(IsarReader reader, int property) {
|
||||
return IsarCore.readString(reader, 1) ?? '';
|
||||
case 2:
|
||||
return IsarCore.readString(reader, 2) ?? '';
|
||||
case 3:
|
||||
return IsarCore.readString(reader, 3);
|
||||
case 4:
|
||||
return IsarCore.readString(reader, 4) ?? '';
|
||||
default:
|
||||
throw ArgumentError('Unknown property: $property');
|
||||
}
|
||||
@@ -70,6 +87,8 @@ sealed class _CategoryUpdate {
|
||||
bool call({
|
||||
required String id,
|
||||
String? categoryName,
|
||||
String? parentId,
|
||||
String? level,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -82,12 +101,17 @@ class _CategoryUpdateImpl implements _CategoryUpdate {
|
||||
bool call({
|
||||
required String id,
|
||||
Object? categoryName = ignore,
|
||||
Object? parentId = ignore,
|
||||
Object? level = ignore,
|
||||
}) {
|
||||
return collection.updateProperties([
|
||||
id
|
||||
], {
|
||||
if (categoryName != ignore) 2: categoryName as String?,
|
||||
}) >
|
||||
return collection.updateProperties(
|
||||
[id],
|
||||
{
|
||||
if (categoryName != ignore) 2: categoryName as String?,
|
||||
if (parentId != ignore) 3: parentId as String?,
|
||||
if (level != ignore) 4: level as String?,
|
||||
},
|
||||
) >
|
||||
0;
|
||||
}
|
||||
}
|
||||
@@ -96,6 +120,8 @@ sealed class _CategoryUpdateAll {
|
||||
int call({
|
||||
required List<String> id,
|
||||
String? categoryName,
|
||||
String? parentId,
|
||||
String? level,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -108,9 +134,13 @@ class _CategoryUpdateAllImpl implements _CategoryUpdateAll {
|
||||
int call({
|
||||
required List<String> id,
|
||||
Object? categoryName = ignore,
|
||||
Object? parentId = ignore,
|
||||
Object? level = ignore,
|
||||
}) {
|
||||
return collection.updateProperties(id, {
|
||||
if (categoryName != ignore) 2: categoryName as String?,
|
||||
if (parentId != ignore) 3: parentId as String?,
|
||||
if (level != ignore) 4: level as String?,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -122,9 +152,7 @@ extension CategoryUpdate on IsarCollection<String, Category> {
|
||||
}
|
||||
|
||||
sealed class _CategoryQueryUpdate {
|
||||
int call({
|
||||
String? categoryName,
|
||||
});
|
||||
int call({String? categoryName, String? parentId, String? level});
|
||||
}
|
||||
|
||||
class _CategoryQueryUpdateImpl implements _CategoryQueryUpdate {
|
||||
@@ -136,9 +164,13 @@ class _CategoryQueryUpdateImpl implements _CategoryQueryUpdate {
|
||||
@override
|
||||
int call({
|
||||
Object? categoryName = ignore,
|
||||
Object? parentId = ignore,
|
||||
Object? level = ignore,
|
||||
}) {
|
||||
return query.updateProperties(limit: limit, {
|
||||
if (categoryName != ignore) 2: categoryName as String?,
|
||||
if (parentId != ignore) 3: parentId as String?,
|
||||
if (level != ignore) 4: level as String?,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -159,11 +191,15 @@ class _CategoryQueryBuilderUpdateImpl implements _CategoryQueryUpdate {
|
||||
@override
|
||||
int call({
|
||||
Object? categoryName = ignore,
|
||||
Object? parentId = ignore,
|
||||
Object? level = ignore,
|
||||
}) {
|
||||
final q = query.build();
|
||||
try {
|
||||
return q.updateProperties(limit: limit, {
|
||||
if (categoryName != ignore) 2: categoryName as String?,
|
||||
if (parentId != ignore) 3: parentId as String?,
|
||||
if (level != ignore) 4: level as String?,
|
||||
});
|
||||
} finally {
|
||||
q.close();
|
||||
@@ -187,11 +223,7 @@ extension CategoryQueryFilter
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EqualCondition(
|
||||
property: 1,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
EqualCondition(property: 1, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -212,10 +244,7 @@ extension CategoryQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition>
|
||||
idGreaterThanOrEqualTo(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
idGreaterThanOrEqualTo(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterOrEqualCondition(
|
||||
@@ -233,11 +262,7 @@ extension CategoryQueryFilter
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessCondition(
|
||||
property: 1,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
LessCondition(property: 1, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -305,8 +330,9 @@ extension CategoryQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> idContains(
|
||||
String value,
|
||||
{bool caseSensitive = true}) {
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
ContainsCondition(
|
||||
@@ -319,8 +345,9 @@ extension CategoryQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> idMatches(
|
||||
String pattern,
|
||||
{bool caseSensitive = true}) {
|
||||
String pattern, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
MatchesCondition(
|
||||
@@ -335,10 +362,7 @@ extension CategoryQueryFilter
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> idIsEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const EqualCondition(
|
||||
property: 1,
|
||||
value: '',
|
||||
),
|
||||
const EqualCondition(property: 1, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -346,10 +370,7 @@ extension CategoryQueryFilter
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> idIsNotEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const GreaterCondition(
|
||||
property: 1,
|
||||
value: '',
|
||||
),
|
||||
const GreaterCondition(property: 1, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -360,20 +381,13 @@ extension CategoryQueryFilter
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EqualCondition(
|
||||
property: 2,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
EqualCondition(property: 2, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition>
|
||||
categoryNameGreaterThan(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
categoryNameGreaterThan(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterCondition(
|
||||
@@ -386,10 +400,7 @@ extension CategoryQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition>
|
||||
categoryNameGreaterThanOrEqualTo(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
categoryNameGreaterThanOrEqualTo(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterOrEqualCondition(
|
||||
@@ -407,20 +418,13 @@ extension CategoryQueryFilter
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessCondition(
|
||||
property: 2,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
LessCondition(property: 2, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition>
|
||||
categoryNameLessThanOrEqualTo(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
categoryNameLessThanOrEqualTo(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessOrEqualCondition(
|
||||
@@ -450,10 +454,7 @@ extension CategoryQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition>
|
||||
categoryNameStartsWith(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
categoryNameStartsWith(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
StartsWithCondition(
|
||||
@@ -481,8 +482,9 @@ extension CategoryQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> categoryNameContains(
|
||||
String value,
|
||||
{bool caseSensitive = true}) {
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
ContainsCondition(
|
||||
@@ -495,8 +497,9 @@ extension CategoryQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> categoryNameMatches(
|
||||
String pattern,
|
||||
{bool caseSensitive = true}) {
|
||||
String pattern, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
MatchesCondition(
|
||||
@@ -509,116 +512,509 @@ extension CategoryQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition>
|
||||
categoryNameIsEmpty() {
|
||||
categoryNameIsEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const EqualCondition(
|
||||
property: 2,
|
||||
value: '',
|
||||
const EqualCondition(property: 2, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition>
|
||||
categoryNameIsNotEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const GreaterCondition(property: 2, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> parentIdIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const IsNullCondition(property: 3));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> parentIdIsNotNull() {
|
||||
return QueryBuilder.apply(not(), (query) {
|
||||
return query.addFilterCondition(const IsNullCondition(property: 3));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> parentIdEqualTo(
|
||||
String? value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EqualCondition(property: 3, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> parentIdGreaterThan(
|
||||
String? value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterCondition(
|
||||
property: 3,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition>
|
||||
categoryNameIsNotEmpty() {
|
||||
parentIdGreaterThanOrEqualTo(String? value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const GreaterCondition(
|
||||
property: 2,
|
||||
value: '',
|
||||
GreaterOrEqualCondition(
|
||||
property: 3,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> parentIdLessThan(
|
||||
String? value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessCondition(property: 3, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition>
|
||||
parentIdLessThanOrEqualTo(String? value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessOrEqualCondition(
|
||||
property: 3,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> parentIdBetween(
|
||||
String? lower,
|
||||
String? upper, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
BetweenCondition(
|
||||
property: 3,
|
||||
lower: lower,
|
||||
upper: upper,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> parentIdStartsWith(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
StartsWithCondition(
|
||||
property: 3,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> parentIdEndsWith(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EndsWithCondition(
|
||||
property: 3,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> parentIdContains(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
ContainsCondition(
|
||||
property: 3,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> parentIdMatches(
|
||||
String pattern, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
MatchesCondition(
|
||||
property: 3,
|
||||
wildcard: pattern,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> parentIdIsEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const EqualCondition(property: 3, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> parentIdIsNotEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const GreaterCondition(property: 3, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> levelEqualTo(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EqualCondition(property: 4, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> levelGreaterThan(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterCondition(
|
||||
property: 4,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition>
|
||||
levelGreaterThanOrEqualTo(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterOrEqualCondition(
|
||||
property: 4,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> levelLessThan(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessCondition(property: 4, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition>
|
||||
levelLessThanOrEqualTo(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessOrEqualCondition(
|
||||
property: 4,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> levelBetween(
|
||||
String lower,
|
||||
String upper, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
BetweenCondition(
|
||||
property: 4,
|
||||
lower: lower,
|
||||
upper: upper,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> levelStartsWith(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
StartsWithCondition(
|
||||
property: 4,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> levelEndsWith(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EndsWithCondition(
|
||||
property: 4,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> levelContains(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
ContainsCondition(
|
||||
property: 4,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> levelMatches(
|
||||
String pattern, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
MatchesCondition(
|
||||
property: 4,
|
||||
wildcard: pattern,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> levelIsEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const EqualCondition(property: 4, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> levelIsNotEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const GreaterCondition(property: 4, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension CategoryQueryObject
|
||||
on QueryBuilder<Category, Category, QFilterCondition> {}
|
||||
|
||||
extension CategoryQuerySortBy on QueryBuilder<Category, Category, QSortBy> {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortById(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortById({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(
|
||||
1,
|
||||
caseSensitive: caseSensitive,
|
||||
);
|
||||
return query.addSortBy(1, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByIdDesc(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByIdDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(
|
||||
1,
|
||||
sort: Sort.desc,
|
||||
caseSensitive: caseSensitive,
|
||||
);
|
||||
return query.addSortBy(1, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByCategoryName(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByCategoryName({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(
|
||||
2,
|
||||
caseSensitive: caseSensitive,
|
||||
);
|
||||
return query.addSortBy(2, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByCategoryNameDesc(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByCategoryNameDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(
|
||||
2,
|
||||
sort: Sort.desc,
|
||||
caseSensitive: caseSensitive,
|
||||
);
|
||||
return query.addSortBy(2, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByParentId({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(3, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByParentIdDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(3, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByLevel({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(4, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByLevelDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(4, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension CategoryQuerySortThenBy
|
||||
on QueryBuilder<Category, Category, QSortThenBy> {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenById(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenById({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(1, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByIdDesc(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByIdDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(1, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByCategoryName(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByCategoryName({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(2, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByCategoryNameDesc(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByCategoryNameDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(2, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByParentId({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(3, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByParentIdDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(3, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByLevel({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(4, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByLevelDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(4, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension CategoryQueryWhereDistinct
|
||||
on QueryBuilder<Category, Category, QDistinct> {
|
||||
QueryBuilder<Category, Category, QAfterDistinct> distinctByCategoryName(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<Category, Category, QAfterDistinct> distinctByCategoryName({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(2, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterDistinct> distinctByParentId({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(3, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterDistinct> distinctByLevel({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(4, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension CategoryQueryProperty1
|
||||
@@ -634,6 +1030,18 @@ extension CategoryQueryProperty1
|
||||
return query.addProperty(2);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, String?, QAfterProperty> parentIdProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addProperty(3);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, String, QAfterProperty> levelProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addProperty(4);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension CategoryQueryProperty2<R>
|
||||
@@ -649,6 +1057,18 @@ extension CategoryQueryProperty2<R>
|
||||
return query.addProperty(2);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, (R, String?), QAfterProperty> parentIdProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addProperty(3);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, (R, String), QAfterProperty> levelProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addProperty(4);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension CategoryQueryProperty3<R1, R2>
|
||||
@@ -664,4 +1084,16 @@ extension CategoryQueryProperty3<R1, R2>
|
||||
return query.addProperty(2);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, (R1, R2, String?), QOperations> parentIdProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addProperty(3);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, (R1, R2, String), QOperations> levelProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addProperty(4);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,12 @@ class Diary {
|
||||
// 位置信息
|
||||
List<String> position = [];
|
||||
|
||||
// 关键词
|
||||
List<String> keywords = [];
|
||||
|
||||
// 分词
|
||||
List<String> tokenizer = [];
|
||||
|
||||
// 类型,富文本还是纯文本,不会为空,延迟加载
|
||||
late String type;
|
||||
|
||||
@@ -97,6 +103,8 @@ class Diary {
|
||||
const ListEquality().equals(videoName, other.videoName) &&
|
||||
const ListEquality().equals(tags, other.tags) &&
|
||||
const ListEquality().equals(position, other.position) &&
|
||||
const ListEquality().equals(keywords, other.keywords) &&
|
||||
const ListEquality().equals(tokenizer, other.tokenizer) &&
|
||||
type == other.type &&
|
||||
imageColor == other.imageColor &&
|
||||
aspect == other.aspect;
|
||||
@@ -118,6 +126,8 @@ class Diary {
|
||||
const ListEquality().hash(videoName) ^
|
||||
const ListEquality().hash(tags) ^
|
||||
const ListEquality().hash(position) ^
|
||||
const ListEquality().hash(keywords) ^
|
||||
const ListEquality().hash(tokenizer) ^
|
||||
type.hashCode ^
|
||||
imageColor.hashCode ^
|
||||
aspect.hashCode;
|
||||
@@ -135,7 +145,8 @@ class Diary {
|
||||
..contentText = contentText
|
||||
..time = DateTime.fromMillisecondsSinceEpoch(time.millisecondsSinceEpoch)
|
||||
..lastModified = DateTime.fromMillisecondsSinceEpoch(
|
||||
lastModified.millisecondsSinceEpoch)
|
||||
lastModified.millisecondsSinceEpoch,
|
||||
)
|
||||
..show = show
|
||||
..mood = mood
|
||||
..weather = List<String>.from(weather)
|
||||
@@ -144,6 +155,8 @@ class Diary {
|
||||
..videoName = List<String>.from(videoName)
|
||||
..tags = List<String>.from(tags)
|
||||
..position = List<String>.from(position)
|
||||
..keywords = List<String>.from(keywords)
|
||||
..tokenizer = List<String>.from(tokenizer)
|
||||
..type = type
|
||||
..imageColor = imageColor
|
||||
..aspect = aspect;
|
||||
@@ -167,6 +180,8 @@ class Diary {
|
||||
'videoName': videoName,
|
||||
'tags': tags,
|
||||
'position': position,
|
||||
'keywords': keywords,
|
||||
'tokenizer': tokenizer,
|
||||
'type': type,
|
||||
'imageColor': imageColor,
|
||||
'aspect': aspect,
|
||||
@@ -190,6 +205,8 @@ class Diary {
|
||||
..videoName = List<String>.from(json['videoName'] as List)
|
||||
..tags = List<String>.from(json['tags'] as List)
|
||||
..position = List<String>.from(json['position'] as List)
|
||||
..keywords = List<String>.from(json['keywords'] as List)
|
||||
..tokenizer = List<String>.from(json['tokenizer'] as List)
|
||||
..type = json['type'] as String
|
||||
..imageColor = json['imageColor'] as int?
|
||||
..aspect = (json['aspect'] as num?)?.toDouble();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
34
lib/common/models/isar/font.dart
Normal file
34
lib/common/models/isar/font.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
||||
part 'font.g.dart';
|
||||
|
||||
@collection
|
||||
class Font {
|
||||
@Id()
|
||||
int get id => fastHash(fontFamily);
|
||||
|
||||
final String fontFileName;
|
||||
|
||||
String get fontFamily => basenameWithoutExtension(fontFileName);
|
||||
|
||||
String get fontType => extension(fontFileName);
|
||||
|
||||
final Map<String, dynamic> fontWghtAxisMap;
|
||||
|
||||
Font({required this.fontFileName, required this.fontWghtAxisMap});
|
||||
}
|
||||
|
||||
int fastHash(String string) {
|
||||
var hash = 0xcbf29ce484222325;
|
||||
|
||||
var i = 0;
|
||||
while (i < string.length) {
|
||||
final codeUnit = string.codeUnitAt(i++);
|
||||
hash ^= codeUnit >> 8;
|
||||
hash *= 0x100000001b3;
|
||||
hash ^= codeUnit & 0xFF;
|
||||
hash *= 0x100000001b3;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
1033
lib/common/models/isar/font.g.dart
Normal file
1033
lib/common/models/isar/font.g.dart
Normal file
File diff suppressed because it is too large
Load Diff
@@ -20,22 +20,10 @@ const SyncRecordSchema = IsarGeneratedSchema(
|
||||
idName: 'isarId',
|
||||
embedded: false,
|
||||
properties: [
|
||||
IsarPropertySchema(
|
||||
name: 'syncId',
|
||||
type: IsarType.string,
|
||||
),
|
||||
IsarPropertySchema(
|
||||
name: 'diaryId',
|
||||
type: IsarType.string,
|
||||
),
|
||||
IsarPropertySchema(
|
||||
name: 'diaryJson',
|
||||
type: IsarType.string,
|
||||
),
|
||||
IsarPropertySchema(
|
||||
name: 'time',
|
||||
type: IsarType.dateTime,
|
||||
),
|
||||
IsarPropertySchema(name: 'syncId', type: IsarType.string),
|
||||
IsarPropertySchema(name: 'diaryId', type: IsarType.string),
|
||||
IsarPropertySchema(name: 'diaryJson', type: IsarType.string),
|
||||
IsarPropertySchema(name: 'time', type: IsarType.dateTime),
|
||||
IsarPropertySchema(
|
||||
name: 'syncType',
|
||||
type: IsarType.byte,
|
||||
@@ -104,8 +92,10 @@ dynamic deserializeSyncRecordProp(IsarReader reader, int property) {
|
||||
if (value == -9223372036854775808) {
|
||||
return DateTime.fromMillisecondsSinceEpoch(0, isUtc: true).toLocal();
|
||||
} else {
|
||||
return DateTime.fromMicrosecondsSinceEpoch(value, isUtc: true)
|
||||
.toLocal();
|
||||
return DateTime.fromMicrosecondsSinceEpoch(
|
||||
value,
|
||||
isUtc: true,
|
||||
).toLocal();
|
||||
}
|
||||
}
|
||||
case 5:
|
||||
@@ -149,15 +139,16 @@ class _SyncRecordUpdateImpl implements _SyncRecordUpdate {
|
||||
Object? time = ignore,
|
||||
Object? syncType = ignore,
|
||||
}) {
|
||||
return collection.updateProperties([
|
||||
isarId
|
||||
], {
|
||||
if (syncId != ignore) 1: syncId as String?,
|
||||
if (diaryId != ignore) 2: diaryId as String?,
|
||||
if (diaryJson != ignore) 3: diaryJson as String?,
|
||||
if (time != ignore) 4: time as DateTime?,
|
||||
if (syncType != ignore) 5: syncType as SyncType?,
|
||||
}) >
|
||||
return collection.updateProperties(
|
||||
[isarId],
|
||||
{
|
||||
if (syncId != ignore) 1: syncId as String?,
|
||||
if (diaryId != ignore) 2: diaryId as String?,
|
||||
if (diaryJson != ignore) 3: diaryJson as String?,
|
||||
if (time != ignore) 4: time as DateTime?,
|
||||
if (syncType != ignore) 5: syncType as SyncType?,
|
||||
},
|
||||
) >
|
||||
0;
|
||||
}
|
||||
}
|
||||
@@ -297,11 +288,7 @@ extension SyncRecordQueryFilter
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EqualCondition(
|
||||
property: 1,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
EqualCondition(property: 1, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -322,10 +309,7 @@ extension SyncRecordQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
syncIdGreaterThanOrEqualTo(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
syncIdGreaterThanOrEqualTo(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterOrEqualCondition(
|
||||
@@ -343,20 +327,13 @@ extension SyncRecordQueryFilter
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessCondition(
|
||||
property: 1,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
LessCondition(property: 1, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
syncIdLessThanOrEqualTo(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
syncIdLessThanOrEqualTo(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessOrEqualCondition(
|
||||
@@ -416,8 +393,9 @@ extension SyncRecordQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition> syncIdContains(
|
||||
String value,
|
||||
{bool caseSensitive = true}) {
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
ContainsCondition(
|
||||
@@ -430,8 +408,9 @@ extension SyncRecordQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition> syncIdMatches(
|
||||
String pattern,
|
||||
{bool caseSensitive = true}) {
|
||||
String pattern, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
MatchesCondition(
|
||||
@@ -446,22 +425,16 @@ extension SyncRecordQueryFilter
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition> syncIdIsEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const EqualCondition(
|
||||
property: 1,
|
||||
value: '',
|
||||
),
|
||||
const EqualCondition(property: 1, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
syncIdIsNotEmpty() {
|
||||
syncIdIsNotEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const GreaterCondition(
|
||||
property: 1,
|
||||
value: '',
|
||||
),
|
||||
const GreaterCondition(property: 1, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -472,20 +445,13 @@ extension SyncRecordQueryFilter
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EqualCondition(
|
||||
property: 2,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
EqualCondition(property: 2, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
diaryIdGreaterThan(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
diaryIdGreaterThan(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterCondition(
|
||||
@@ -498,10 +464,7 @@ extension SyncRecordQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
diaryIdGreaterThanOrEqualTo(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
diaryIdGreaterThanOrEqualTo(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterOrEqualCondition(
|
||||
@@ -519,20 +482,13 @@ extension SyncRecordQueryFilter
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessCondition(
|
||||
property: 2,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
LessCondition(property: 2, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
diaryIdLessThanOrEqualTo(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
diaryIdLessThanOrEqualTo(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessOrEqualCondition(
|
||||
@@ -592,8 +548,9 @@ extension SyncRecordQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition> diaryIdContains(
|
||||
String value,
|
||||
{bool caseSensitive = true}) {
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
ContainsCondition(
|
||||
@@ -606,8 +563,9 @@ extension SyncRecordQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition> diaryIdMatches(
|
||||
String pattern,
|
||||
{bool caseSensitive = true}) {
|
||||
String pattern, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
MatchesCondition(
|
||||
@@ -622,22 +580,16 @@ extension SyncRecordQueryFilter
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition> diaryIdIsEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const EqualCondition(
|
||||
property: 2,
|
||||
value: '',
|
||||
),
|
||||
const EqualCondition(property: 2, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
diaryIdIsNotEmpty() {
|
||||
diaryIdIsNotEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const GreaterCondition(
|
||||
property: 2,
|
||||
value: '',
|
||||
),
|
||||
const GreaterCondition(property: 2, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -648,20 +600,13 @@ extension SyncRecordQueryFilter
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EqualCondition(
|
||||
property: 3,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
EqualCondition(property: 3, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
diaryJsonGreaterThan(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
diaryJsonGreaterThan(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterCondition(
|
||||
@@ -674,10 +619,7 @@ extension SyncRecordQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
diaryJsonGreaterThanOrEqualTo(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
diaryJsonGreaterThanOrEqualTo(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterOrEqualCondition(
|
||||
@@ -695,20 +637,13 @@ extension SyncRecordQueryFilter
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessCondition(
|
||||
property: 3,
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
),
|
||||
LessCondition(property: 3, value: value, caseSensitive: caseSensitive),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
diaryJsonLessThanOrEqualTo(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
diaryJsonLessThanOrEqualTo(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessOrEqualCondition(
|
||||
@@ -738,10 +673,7 @@ extension SyncRecordQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
diaryJsonStartsWith(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
diaryJsonStartsWith(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
StartsWithCondition(
|
||||
@@ -769,8 +701,9 @@ extension SyncRecordQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition> diaryJsonContains(
|
||||
String value,
|
||||
{bool caseSensitive = true}) {
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
ContainsCondition(
|
||||
@@ -783,8 +716,9 @@ extension SyncRecordQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition> diaryJsonMatches(
|
||||
String pattern,
|
||||
{bool caseSensitive = true}) {
|
||||
String pattern, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
MatchesCondition(
|
||||
@@ -797,25 +731,19 @@ extension SyncRecordQueryFilter
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
diaryJsonIsEmpty() {
|
||||
diaryJsonIsEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const EqualCondition(
|
||||
property: 3,
|
||||
value: '',
|
||||
),
|
||||
const EqualCondition(property: 3, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
diaryJsonIsNotEmpty() {
|
||||
diaryJsonIsNotEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
const GreaterCondition(
|
||||
property: 3,
|
||||
value: '',
|
||||
),
|
||||
const GreaterCondition(property: 3, value: ''),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -825,10 +753,7 @@ extension SyncRecordQueryFilter
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EqualCondition(
|
||||
property: 4,
|
||||
value: value,
|
||||
),
|
||||
EqualCondition(property: 4, value: value),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -838,24 +763,16 @@ extension SyncRecordQueryFilter
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterCondition(
|
||||
property: 4,
|
||||
value: value,
|
||||
),
|
||||
GreaterCondition(property: 4, value: value),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
timeGreaterThanOrEqualTo(
|
||||
DateTime value,
|
||||
) {
|
||||
timeGreaterThanOrEqualTo(DateTime value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterOrEqualCondition(
|
||||
property: 4,
|
||||
value: value,
|
||||
),
|
||||
GreaterOrEqualCondition(property: 4, value: value),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -864,25 +781,15 @@ extension SyncRecordQueryFilter
|
||||
DateTime value,
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessCondition(
|
||||
property: 4,
|
||||
value: value,
|
||||
),
|
||||
);
|
||||
return query.addFilterCondition(LessCondition(property: 4, value: value));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
timeLessThanOrEqualTo(
|
||||
DateTime value,
|
||||
) {
|
||||
timeLessThanOrEqualTo(DateTime value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessOrEqualCondition(
|
||||
property: 4,
|
||||
value: value,
|
||||
),
|
||||
LessOrEqualCondition(property: 4, value: value),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -893,11 +800,7 @@ extension SyncRecordQueryFilter
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
BetweenCondition(
|
||||
property: 4,
|
||||
lower: lower,
|
||||
upper: upper,
|
||||
),
|
||||
BetweenCondition(property: 4, lower: lower, upper: upper),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -907,38 +810,25 @@ extension SyncRecordQueryFilter
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EqualCondition(
|
||||
property: 5,
|
||||
value: value.index,
|
||||
),
|
||||
EqualCondition(property: 5, value: value.index),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
syncTypeGreaterThan(
|
||||
SyncType value,
|
||||
) {
|
||||
syncTypeGreaterThan(SyncType value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterCondition(
|
||||
property: 5,
|
||||
value: value.index,
|
||||
),
|
||||
GreaterCondition(property: 5, value: value.index),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
syncTypeGreaterThanOrEqualTo(
|
||||
SyncType value,
|
||||
) {
|
||||
syncTypeGreaterThanOrEqualTo(SyncType value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterOrEqualCondition(
|
||||
property: 5,
|
||||
value: value.index,
|
||||
),
|
||||
GreaterOrEqualCondition(property: 5, value: value.index),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -948,24 +838,16 @@ extension SyncRecordQueryFilter
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessCondition(
|
||||
property: 5,
|
||||
value: value.index,
|
||||
),
|
||||
LessCondition(property: 5, value: value.index),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
syncTypeLessThanOrEqualTo(
|
||||
SyncType value,
|
||||
) {
|
||||
syncTypeLessThanOrEqualTo(SyncType value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessOrEqualCondition(
|
||||
property: 5,
|
||||
value: value.index,
|
||||
),
|
||||
LessOrEqualCondition(property: 5, value: value.index),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -976,11 +858,7 @@ extension SyncRecordQueryFilter
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
BetweenCondition(
|
||||
property: 5,
|
||||
lower: lower.index,
|
||||
upper: upper.index,
|
||||
),
|
||||
BetweenCondition(property: 5, lower: lower.index, upper: upper.index),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -990,10 +868,7 @@ extension SyncRecordQueryFilter
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EqualCondition(
|
||||
property: 0,
|
||||
value: value,
|
||||
),
|
||||
EqualCondition(property: 0, value: value),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1003,24 +878,16 @@ extension SyncRecordQueryFilter
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterCondition(
|
||||
property: 0,
|
||||
value: value,
|
||||
),
|
||||
GreaterCondition(property: 0, value: value),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
isarIdGreaterThanOrEqualTo(
|
||||
int value,
|
||||
) {
|
||||
isarIdGreaterThanOrEqualTo(int value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterOrEqualCondition(
|
||||
property: 0,
|
||||
value: value,
|
||||
),
|
||||
GreaterOrEqualCondition(property: 0, value: value),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1029,25 +896,15 @@ extension SyncRecordQueryFilter
|
||||
int value,
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessCondition(
|
||||
property: 0,
|
||||
value: value,
|
||||
),
|
||||
);
|
||||
return query.addFilterCondition(LessCondition(property: 0, value: value));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterFilterCondition>
|
||||
isarIdLessThanOrEqualTo(
|
||||
int value,
|
||||
) {
|
||||
isarIdLessThanOrEqualTo(int value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessOrEqualCondition(
|
||||
property: 0,
|
||||
value: value,
|
||||
),
|
||||
LessOrEqualCondition(property: 0, value: value),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1058,11 +915,7 @@ extension SyncRecordQueryFilter
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
BetweenCondition(
|
||||
property: 0,
|
||||
lower: lower,
|
||||
upper: upper,
|
||||
),
|
||||
BetweenCondition(property: 0, lower: lower, upper: upper),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1073,66 +926,51 @@ extension SyncRecordQueryObject
|
||||
|
||||
extension SyncRecordQuerySortBy
|
||||
on QueryBuilder<SyncRecord, SyncRecord, QSortBy> {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> sortBySyncId(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> sortBySyncId({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(
|
||||
1,
|
||||
caseSensitive: caseSensitive,
|
||||
);
|
||||
return query.addSortBy(1, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> sortBySyncIdDesc(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> sortBySyncIdDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(
|
||||
1,
|
||||
sort: Sort.desc,
|
||||
caseSensitive: caseSensitive,
|
||||
);
|
||||
return query.addSortBy(1, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> sortByDiaryId(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> sortByDiaryId({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(
|
||||
2,
|
||||
caseSensitive: caseSensitive,
|
||||
);
|
||||
return query.addSortBy(2, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> sortByDiaryIdDesc(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> sortByDiaryIdDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(
|
||||
2,
|
||||
sort: Sort.desc,
|
||||
caseSensitive: caseSensitive,
|
||||
);
|
||||
return query.addSortBy(2, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> sortByDiaryJson(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> sortByDiaryJson({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(
|
||||
3,
|
||||
caseSensitive: caseSensitive,
|
||||
);
|
||||
return query.addSortBy(3, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> sortByDiaryJsonDesc(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> sortByDiaryJsonDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(
|
||||
3,
|
||||
sort: Sort.desc,
|
||||
caseSensitive: caseSensitive,
|
||||
);
|
||||
return query.addSortBy(3, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1175,43 +1013,49 @@ extension SyncRecordQuerySortBy
|
||||
|
||||
extension SyncRecordQuerySortThenBy
|
||||
on QueryBuilder<SyncRecord, SyncRecord, QSortThenBy> {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> thenBySyncId(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> thenBySyncId({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(1, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> thenBySyncIdDesc(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> thenBySyncIdDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(1, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> thenByDiaryId(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> thenByDiaryId({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(2, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> thenByDiaryIdDesc(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> thenByDiaryIdDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(2, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> thenByDiaryJson(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> thenByDiaryJson({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(3, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> thenByDiaryJsonDesc(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterSortBy> thenByDiaryJsonDesc({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(3, sort: Sort.desc, caseSensitive: caseSensitive);
|
||||
});
|
||||
@@ -1256,22 +1100,25 @@ extension SyncRecordQuerySortThenBy
|
||||
|
||||
extension SyncRecordQueryWhereDistinct
|
||||
on QueryBuilder<SyncRecord, SyncRecord, QDistinct> {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterDistinct> distinctBySyncId(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterDistinct> distinctBySyncId({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(1, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterDistinct> distinctByDiaryId(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterDistinct> distinctByDiaryId({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(2, caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterDistinct> distinctByDiaryJson(
|
||||
{bool caseSensitive = true}) {
|
||||
QueryBuilder<SyncRecord, SyncRecord, QAfterDistinct> distinctByDiaryJson({
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(3, caseSensitive: caseSensitive);
|
||||
});
|
||||
|
||||
@@ -16,31 +16,34 @@ class ShiplyResponse {
|
||||
int? updateStrategy;
|
||||
int? updateTime;
|
||||
|
||||
ShiplyResponse(
|
||||
{this.apkBasicInfo,
|
||||
this.clientInfo,
|
||||
this.extra,
|
||||
this.grayType,
|
||||
this.newFeature,
|
||||
this.popInterval,
|
||||
this.popTimes,
|
||||
this.publishTime,
|
||||
this.receiveMoment,
|
||||
this.remindType,
|
||||
this.status,
|
||||
this.tacticsId,
|
||||
this.title,
|
||||
this.undisturbedDuration,
|
||||
this.updateStrategy,
|
||||
this.updateTime});
|
||||
ShiplyResponse({
|
||||
this.apkBasicInfo,
|
||||
this.clientInfo,
|
||||
this.extra,
|
||||
this.grayType,
|
||||
this.newFeature,
|
||||
this.popInterval,
|
||||
this.popTimes,
|
||||
this.publishTime,
|
||||
this.receiveMoment,
|
||||
this.remindType,
|
||||
this.status,
|
||||
this.tacticsId,
|
||||
this.title,
|
||||
this.undisturbedDuration,
|
||||
this.updateStrategy,
|
||||
this.updateTime,
|
||||
});
|
||||
|
||||
ShiplyResponse.fromJson(Map<String, dynamic> json) {
|
||||
apkBasicInfo = json["apkBasicInfo"] == null
|
||||
? null
|
||||
: ApkBasicInfo.fromJson(json["apkBasicInfo"]);
|
||||
clientInfo = json["clientInfo"] == null
|
||||
? null
|
||||
: ClientInfo.fromJson(json["clientInfo"]);
|
||||
apkBasicInfo =
|
||||
json["apkBasicInfo"] == null
|
||||
? null
|
||||
: ApkBasicInfo.fromJson(json["apkBasicInfo"]);
|
||||
clientInfo =
|
||||
json["clientInfo"] == null
|
||||
? null
|
||||
: ClientInfo.fromJson(json["clientInfo"]);
|
||||
extra = json["extra"] == null ? null : Extra.fromJson(json["extra"]);
|
||||
grayType = json["grayType"];
|
||||
newFeature = json["newFeature"];
|
||||
@@ -129,15 +132,16 @@ class ApkBasicInfo {
|
||||
int? versionCode;
|
||||
String? version;
|
||||
|
||||
ApkBasicInfo(
|
||||
{this.md5,
|
||||
this.pkgSize,
|
||||
this.buildNo,
|
||||
this.bundleId,
|
||||
this.downloadUrl,
|
||||
this.pkgName,
|
||||
this.versionCode,
|
||||
this.version});
|
||||
ApkBasicInfo({
|
||||
this.md5,
|
||||
this.pkgSize,
|
||||
this.buildNo,
|
||||
this.bundleId,
|
||||
this.downloadUrl,
|
||||
this.pkgName,
|
||||
this.versionCode,
|
||||
this.version,
|
||||
});
|
||||
|
||||
ApkBasicInfo.fromJson(Map<String, dynamic> json) {
|
||||
md5 = json["md5"];
|
||||
|
||||
8
lib/common/models/sync/sync.dart
Normal file
8
lib/common/models/sync/sync.dart
Normal file
@@ -0,0 +1,8 @@
|
||||
import 'package:moodiary/common/values/sync_status.dart';
|
||||
|
||||
class SyncResult<T> {
|
||||
final SyncStatus status;
|
||||
T? data;
|
||||
|
||||
SyncResult({required this.status, this.data});
|
||||
}
|
||||
@@ -24,7 +24,7 @@ class SquadExample {
|
||||
String toString() => _repr();
|
||||
|
||||
String _repr() {
|
||||
var s = StringBuffer();
|
||||
final s = StringBuffer();
|
||||
s.write('qas_id: ${_printableText(qasId)}, ');
|
||||
s.write('question_text: ${_printableText(questionText)}, ');
|
||||
s.write('doc_tokens: [${docTokens.join(' ')}]');
|
||||
@@ -104,9 +104,12 @@ class RawResult {
|
||||
});
|
||||
|
||||
List<int> getAnswerIndices() {
|
||||
int startIndex =
|
||||
startLogits.indexOf(startLogits.reduce((a, b) => a > b ? a : b));
|
||||
int endIndex = endLogits.indexOf(endLogits.reduce((a, b) => a > b ? a : b));
|
||||
final int startIndex = startLogits.indexOf(
|
||||
startLogits.reduce((a, b) => a > b ? a : b),
|
||||
);
|
||||
final int endIndex = endLogits.indexOf(
|
||||
endLogits.reduce((a, b) => a > b ? a : b),
|
||||
);
|
||||
return [startIndex, endIndex];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,130 +1,48 @@
|
||||
class WeatherResponse {
|
||||
String? code;
|
||||
String? updateTime;
|
||||
String? fxLink;
|
||||
Now? now;
|
||||
Refer? refer;
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
WeatherResponse(
|
||||
{this.code, this.updateTime, this.fxLink, this.now, this.refer});
|
||||
part 'weather.freezed.dart';
|
||||
part 'weather.g.dart';
|
||||
|
||||
WeatherResponse.fromJson(Map<String, dynamic> json) {
|
||||
code = json["code"];
|
||||
updateTime = json["updateTime"];
|
||||
fxLink = json["fxLink"];
|
||||
now = json["now"] == null ? null : Now.fromJson(json["now"]);
|
||||
refer = json["refer"] == null ? null : Refer.fromJson(json["refer"]);
|
||||
}
|
||||
@freezed
|
||||
abstract class WeatherResponse with _$WeatherResponse {
|
||||
const factory WeatherResponse({
|
||||
String? code,
|
||||
String? updateTime,
|
||||
String? fxLink,
|
||||
Now? now,
|
||||
Refer? refer,
|
||||
}) = _WeatherResponse;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["code"] = code;
|
||||
data["updateTime"] = updateTime;
|
||||
data["fxLink"] = fxLink;
|
||||
if (now != null) {
|
||||
data["now"] = now?.toJson();
|
||||
}
|
||||
if (refer != null) {
|
||||
data["refer"] = refer?.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
factory WeatherResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$WeatherResponseFromJson(json);
|
||||
}
|
||||
|
||||
class Refer {
|
||||
List<String>? sources;
|
||||
List<String>? license;
|
||||
@freezed
|
||||
abstract class Refer with _$Refer {
|
||||
const factory Refer({List<String>? sources, List<String>? license}) = _Refer;
|
||||
|
||||
Refer({this.sources, this.license});
|
||||
|
||||
Refer.fromJson(Map<String, dynamic> json) {
|
||||
sources =
|
||||
json["sources"] == null ? null : List<String>.from(json["sources"]);
|
||||
license =
|
||||
json["license"] == null ? null : List<String>.from(json["license"]);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
if (sources != null) {
|
||||
data["sources"] = sources;
|
||||
}
|
||||
if (license != null) {
|
||||
data["license"] = license;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
factory Refer.fromJson(Map<String, dynamic> json) => _$ReferFromJson(json);
|
||||
}
|
||||
|
||||
class Now {
|
||||
String? obsTime;
|
||||
String? temp;
|
||||
String? feelsLike;
|
||||
String? icon;
|
||||
String? text;
|
||||
String? wind360;
|
||||
String? windDir;
|
||||
String? windScale;
|
||||
String? windSpeed;
|
||||
String? humidity;
|
||||
String? precip;
|
||||
String? pressure;
|
||||
String? vis;
|
||||
String? cloud;
|
||||
String? dew;
|
||||
@freezed
|
||||
abstract class Now with _$Now {
|
||||
const factory Now({
|
||||
String? obsTime,
|
||||
String? temp,
|
||||
String? feelsLike,
|
||||
String? icon,
|
||||
String? text,
|
||||
String? wind360,
|
||||
String? windDir,
|
||||
String? windScale,
|
||||
String? windSpeed,
|
||||
String? humidity,
|
||||
String? precip,
|
||||
String? pressure,
|
||||
String? vis,
|
||||
String? cloud,
|
||||
String? dew,
|
||||
}) = _Now;
|
||||
|
||||
Now(
|
||||
{this.obsTime,
|
||||
this.temp,
|
||||
this.feelsLike,
|
||||
this.icon,
|
||||
this.text,
|
||||
this.wind360,
|
||||
this.windDir,
|
||||
this.windScale,
|
||||
this.windSpeed,
|
||||
this.humidity,
|
||||
this.precip,
|
||||
this.pressure,
|
||||
this.vis,
|
||||
this.cloud,
|
||||
this.dew});
|
||||
|
||||
Now.fromJson(Map<String, dynamic> json) {
|
||||
obsTime = json["obsTime"];
|
||||
temp = json["temp"];
|
||||
feelsLike = json["feelsLike"];
|
||||
icon = json["icon"];
|
||||
text = json["text"];
|
||||
wind360 = json["wind360"];
|
||||
windDir = json["windDir"];
|
||||
windScale = json["windScale"];
|
||||
windSpeed = json["windSpeed"];
|
||||
humidity = json["humidity"];
|
||||
precip = json["precip"];
|
||||
pressure = json["pressure"];
|
||||
vis = json["vis"];
|
||||
cloud = json["cloud"];
|
||||
dew = json["dew"];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["obsTime"] = obsTime;
|
||||
data["temp"] = temp;
|
||||
data["feelsLike"] = feelsLike;
|
||||
data["icon"] = icon;
|
||||
data["text"] = text;
|
||||
data["wind360"] = wind360;
|
||||
data["windDir"] = windDir;
|
||||
data["windScale"] = windScale;
|
||||
data["windSpeed"] = windSpeed;
|
||||
data["humidity"] = humidity;
|
||||
data["precip"] = precip;
|
||||
data["pressure"] = pressure;
|
||||
data["vis"] = vis;
|
||||
data["cloud"] = cloud;
|
||||
data["dew"] = dew;
|
||||
return data;
|
||||
}
|
||||
factory Now.fromJson(Map<String, dynamic> json) => _$NowFromJson(json);
|
||||
}
|
||||
|
||||
861
lib/common/models/weather.freezed.dart
Normal file
861
lib/common/models/weather.freezed.dart
Normal file
@@ -0,0 +1,861 @@
|
||||
// dart format width=80
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'weather.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$WeatherResponse {
|
||||
|
||||
String? get code;
|
||||
|
||||
String? get updateTime;
|
||||
|
||||
String? get fxLink;
|
||||
|
||||
Now? get now;
|
||||
|
||||
Refer? get refer;
|
||||
|
||||
/// Create a copy of WeatherResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$WeatherResponseCopyWith<WeatherResponse> get copyWith =>
|
||||
_$WeatherResponseCopyWithImpl<WeatherResponse>(
|
||||
this as WeatherResponse, _$identity);
|
||||
|
||||
/// Serializes this WeatherResponse to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is WeatherResponse &&
|
||||
(identical(other.code, code) || other.code == code) &&
|
||||
(identical(other.updateTime, updateTime) ||
|
||||
other.updateTime == updateTime) &&
|
||||
(identical(other.fxLink, fxLink) || other.fxLink == fxLink) &&
|
||||
(identical(other.now, now) || other.now == now) &&
|
||||
(identical(other.refer, refer) || other.refer == refer));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, code, updateTime, fxLink, now, refer);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'WeatherResponse(code: $code, updateTime: $updateTime, fxLink: $fxLink, now: $now, refer: $refer)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $WeatherResponseCopyWith<$Res> {
|
||||
factory $WeatherResponseCopyWith(WeatherResponse value,
|
||||
$Res Function(WeatherResponse) _then) = _$WeatherResponseCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call({
|
||||
String? code, String? updateTime, String? fxLink, Now? now, Refer? refer
|
||||
});
|
||||
|
||||
|
||||
$NowCopyWith<$Res>? get now;
|
||||
|
||||
$ReferCopyWith<$Res>? get refer;
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$WeatherResponseCopyWithImpl<$Res>
|
||||
implements $WeatherResponseCopyWith<$Res> {
|
||||
_$WeatherResponseCopyWithImpl(this._self, this._then);
|
||||
|
||||
final WeatherResponse _self;
|
||||
final $Res Function(WeatherResponse) _then;
|
||||
|
||||
/// Create a copy of WeatherResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call(
|
||||
{Object? code = freezed, Object? updateTime = freezed, Object? fxLink = freezed, Object? now = freezed, Object? refer = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
code: freezed == code
|
||||
? _self.code
|
||||
: code // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
updateTime: freezed == updateTime
|
||||
? _self.updateTime
|
||||
: updateTime // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
fxLink: freezed == fxLink
|
||||
? _self.fxLink
|
||||
: fxLink // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
now: freezed == now
|
||||
? _self.now
|
||||
: now // ignore: cast_nullable_to_non_nullable
|
||||
as Now?,
|
||||
refer: freezed == refer
|
||||
? _self.refer
|
||||
: refer // ignore: cast_nullable_to_non_nullable
|
||||
as Refer?,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of WeatherResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$NowCopyWith<$Res>? get now {
|
||||
if (_self.now == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $NowCopyWith<$Res>(_self.now!, (value) {
|
||||
return _then(_self.copyWith(now: value));
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of WeatherResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ReferCopyWith<$Res>? get refer {
|
||||
if (_self.refer == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ReferCopyWith<$Res>(_self.refer!, (value) {
|
||||
return _then(_self.copyWith(refer: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _WeatherResponse implements WeatherResponse {
|
||||
const _WeatherResponse(
|
||||
{this.code, this.updateTime, this.fxLink, this.now, this.refer});
|
||||
|
||||
factory _WeatherResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$WeatherResponseFromJson(json);
|
||||
|
||||
@override final String? code;
|
||||
@override final String? updateTime;
|
||||
@override final String? fxLink;
|
||||
@override final Now? now;
|
||||
@override final Refer? refer;
|
||||
|
||||
/// Create a copy of WeatherResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$WeatherResponseCopyWith<_WeatherResponse> get copyWith =>
|
||||
__$WeatherResponseCopyWithImpl<_WeatherResponse>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$WeatherResponseToJson(this,);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _WeatherResponse &&
|
||||
(identical(other.code, code) || other.code == code) &&
|
||||
(identical(other.updateTime, updateTime) ||
|
||||
other.updateTime == updateTime) &&
|
||||
(identical(other.fxLink, fxLink) || other.fxLink == fxLink) &&
|
||||
(identical(other.now, now) || other.now == now) &&
|
||||
(identical(other.refer, refer) || other.refer == refer));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, code, updateTime, fxLink, now, refer);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'WeatherResponse(code: $code, updateTime: $updateTime, fxLink: $fxLink, now: $now, refer: $refer)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$WeatherResponseCopyWith<$Res>
|
||||
implements $WeatherResponseCopyWith<$Res> {
|
||||
factory _$WeatherResponseCopyWith(_WeatherResponse value,
|
||||
$Res Function(_WeatherResponse) _then) = __$WeatherResponseCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
String? code, String? updateTime, String? fxLink, Now? now, Refer? refer
|
||||
});
|
||||
|
||||
|
||||
@override $NowCopyWith<$Res>? get now;
|
||||
|
||||
@override $ReferCopyWith<$Res>? get refer;
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$WeatherResponseCopyWithImpl<$Res>
|
||||
implements _$WeatherResponseCopyWith<$Res> {
|
||||
__$WeatherResponseCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _WeatherResponse _self;
|
||||
final $Res Function(_WeatherResponse) _then;
|
||||
|
||||
/// Create a copy of WeatherResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$Res call(
|
||||
{Object? code = freezed, Object? updateTime = freezed, Object? fxLink = freezed, Object? now = freezed, Object? refer = freezed,}) {
|
||||
return _then(_WeatherResponse(
|
||||
code: freezed == code
|
||||
? _self.code
|
||||
: code // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
updateTime: freezed == updateTime
|
||||
? _self.updateTime
|
||||
: updateTime // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
fxLink: freezed == fxLink
|
||||
? _self.fxLink
|
||||
: fxLink // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
now: freezed == now
|
||||
? _self.now
|
||||
: now // ignore: cast_nullable_to_non_nullable
|
||||
as Now?,
|
||||
refer: freezed == refer
|
||||
? _self.refer
|
||||
: refer // ignore: cast_nullable_to_non_nullable
|
||||
as Refer?,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of WeatherResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$NowCopyWith<$Res>? get now {
|
||||
if (_self.now == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $NowCopyWith<$Res>(_self.now!, (value) {
|
||||
return _then(_self.copyWith(now: value));
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of WeatherResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ReferCopyWith<$Res>? get refer {
|
||||
if (_self.refer == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ReferCopyWith<$Res>(_self.refer!, (value) {
|
||||
return _then(_self.copyWith(refer: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Refer {
|
||||
|
||||
List<String>? get sources;
|
||||
|
||||
List<String>? get license;
|
||||
|
||||
/// Create a copy of Refer
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ReferCopyWith<Refer> get copyWith =>
|
||||
_$ReferCopyWithImpl<Refer>(this as Refer, _$identity);
|
||||
|
||||
/// Serializes this Refer to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is Refer &&
|
||||
const DeepCollectionEquality().equals(other.sources, sources) &&
|
||||
const DeepCollectionEquality().equals(other.license, license));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType, const DeepCollectionEquality().hash(sources),
|
||||
const DeepCollectionEquality().hash(license));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Refer(sources: $sources, license: $license)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ReferCopyWith<$Res> {
|
||||
factory $ReferCopyWith(Refer value,
|
||||
$Res Function(Refer) _then) = _$ReferCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call({
|
||||
List<String>? sources, List<String>? license
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ReferCopyWithImpl<$Res>
|
||||
implements $ReferCopyWith<$Res> {
|
||||
_$ReferCopyWithImpl(this._self, this._then);
|
||||
|
||||
final Refer _self;
|
||||
final $Res Function(Refer) _then;
|
||||
|
||||
/// Create a copy of Refer
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? sources = freezed, Object? license = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
sources: freezed == sources
|
||||
? _self.sources
|
||||
: sources // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>?,
|
||||
license: freezed == license
|
||||
? _self.license
|
||||
: license // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _Refer implements Refer {
|
||||
const _Refer({final List<String>? sources, final List<String>? license})
|
||||
: _sources = sources,
|
||||
_license = license;
|
||||
|
||||
factory _Refer.fromJson(Map<String, dynamic> json) => _$ReferFromJson(json);
|
||||
|
||||
final List<String>? _sources;
|
||||
|
||||
@override List<String>? get sources {
|
||||
final value = _sources;
|
||||
if (value == null) return null;
|
||||
if (_sources is EqualUnmodifiableListView) return _sources;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
final List<String>? _license;
|
||||
|
||||
@override List<String>? get license {
|
||||
final value = _license;
|
||||
if (value == null) return null;
|
||||
if (_license is EqualUnmodifiableListView) return _license;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
|
||||
/// Create a copy of Refer
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ReferCopyWith<_Refer> get copyWith =>
|
||||
__$ReferCopyWithImpl<_Refer>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$ReferToJson(this,);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _Refer &&
|
||||
const DeepCollectionEquality().equals(other._sources, _sources) &&
|
||||
const DeepCollectionEquality().equals(other._license, _license));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType, const DeepCollectionEquality().hash(_sources),
|
||||
const DeepCollectionEquality().hash(_license));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Refer(sources: $sources, license: $license)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ReferCopyWith<$Res> implements $ReferCopyWith<$Res> {
|
||||
factory _$ReferCopyWith(_Refer value,
|
||||
$Res Function(_Refer) _then) = __$ReferCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
List<String>? sources, List<String>? license
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$ReferCopyWithImpl<$Res>
|
||||
implements _$ReferCopyWith<$Res> {
|
||||
__$ReferCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _Refer _self;
|
||||
final $Res Function(_Refer) _then;
|
||||
|
||||
/// Create a copy of Refer
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$Res call({Object? sources = freezed, Object? license = freezed,}) {
|
||||
return _then(_Refer(
|
||||
sources: freezed == sources
|
||||
? _self._sources
|
||||
: sources // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>?,
|
||||
license: freezed == license
|
||||
? _self._license
|
||||
: license // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Now {
|
||||
|
||||
String? get obsTime;
|
||||
|
||||
String? get temp;
|
||||
|
||||
String? get feelsLike;
|
||||
|
||||
String? get icon;
|
||||
|
||||
String? get text;
|
||||
|
||||
String? get wind360;
|
||||
|
||||
String? get windDir;
|
||||
|
||||
String? get windScale;
|
||||
|
||||
String? get windSpeed;
|
||||
|
||||
String? get humidity;
|
||||
|
||||
String? get precip;
|
||||
|
||||
String? get pressure;
|
||||
|
||||
String? get vis;
|
||||
|
||||
String? get cloud;
|
||||
|
||||
String? get dew;
|
||||
|
||||
/// Create a copy of Now
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$NowCopyWith<Now> get copyWith =>
|
||||
_$NowCopyWithImpl<Now>(this as Now, _$identity);
|
||||
|
||||
/// Serializes this Now to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is Now &&
|
||||
(identical(other.obsTime, obsTime) || other.obsTime == obsTime) &&
|
||||
(identical(other.temp, temp) || other.temp == temp) &&
|
||||
(identical(other.feelsLike, feelsLike) ||
|
||||
other.feelsLike == feelsLike) &&
|
||||
(identical(other.icon, icon) || other.icon == icon) &&
|
||||
(identical(other.text, text) || other.text == text) &&
|
||||
(identical(other.wind360, wind360) || other.wind360 == wind360) &&
|
||||
(identical(other.windDir, windDir) || other.windDir == windDir) &&
|
||||
(identical(other.windScale, windScale) ||
|
||||
other.windScale == windScale) &&
|
||||
(identical(other.windSpeed, windSpeed) ||
|
||||
other.windSpeed == windSpeed) &&
|
||||
(identical(other.humidity, humidity) ||
|
||||
other.humidity == humidity) &&
|
||||
(identical(other.precip, precip) || other.precip == precip) &&
|
||||
(identical(other.pressure, pressure) ||
|
||||
other.pressure == pressure) &&
|
||||
(identical(other.vis, vis) || other.vis == vis) &&
|
||||
(identical(other.cloud, cloud) || other.cloud == cloud) &&
|
||||
(identical(other.dew, dew) || other.dew == dew));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType,
|
||||
obsTime,
|
||||
temp,
|
||||
feelsLike,
|
||||
icon,
|
||||
text,
|
||||
wind360,
|
||||
windDir,
|
||||
windScale,
|
||||
windSpeed,
|
||||
humidity,
|
||||
precip,
|
||||
pressure,
|
||||
vis,
|
||||
cloud,
|
||||
dew);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Now(obsTime: $obsTime, temp: $temp, feelsLike: $feelsLike, icon: $icon, text: $text, wind360: $wind360, windDir: $windDir, windScale: $windScale, windSpeed: $windSpeed, humidity: $humidity, precip: $precip, pressure: $pressure, vis: $vis, cloud: $cloud, dew: $dew)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $NowCopyWith<$Res> {
|
||||
factory $NowCopyWith(Now value, $Res Function(Now) _then) = _$NowCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call({
|
||||
String? obsTime, String? temp, String? feelsLike, String? icon, String? text, String? wind360, String? windDir, String? windScale, String? windSpeed, String? humidity, String? precip, String? pressure, String? vis, String? cloud, String? dew
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$NowCopyWithImpl<$Res>
|
||||
implements $NowCopyWith<$Res> {
|
||||
_$NowCopyWithImpl(this._self, this._then);
|
||||
|
||||
final Now _self;
|
||||
final $Res Function(Now) _then;
|
||||
|
||||
/// Create a copy of Now
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call(
|
||||
{Object? obsTime = freezed, Object? temp = freezed, Object? feelsLike = freezed, Object? icon = freezed, Object? text = freezed, Object? wind360 = freezed, Object? windDir = freezed, Object? windScale = freezed, Object? windSpeed = freezed, Object? humidity = freezed, Object? precip = freezed, Object? pressure = freezed, Object? vis = freezed, Object? cloud = freezed, Object? dew = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
obsTime: freezed == obsTime
|
||||
? _self.obsTime
|
||||
: obsTime // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
temp: freezed == temp
|
||||
? _self.temp
|
||||
: temp // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
feelsLike: freezed == feelsLike
|
||||
? _self.feelsLike
|
||||
: feelsLike // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
icon: freezed == icon
|
||||
? _self.icon
|
||||
: icon // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
text: freezed == text
|
||||
? _self.text
|
||||
: text // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
wind360: freezed == wind360
|
||||
? _self.wind360
|
||||
: wind360 // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
windDir: freezed == windDir
|
||||
? _self.windDir
|
||||
: windDir // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
windScale: freezed == windScale
|
||||
? _self.windScale
|
||||
: windScale // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
windSpeed: freezed == windSpeed
|
||||
? _self.windSpeed
|
||||
: windSpeed // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
humidity: freezed == humidity
|
||||
? _self.humidity
|
||||
: humidity // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
precip: freezed == precip
|
||||
? _self.precip
|
||||
: precip // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
pressure: freezed == pressure
|
||||
? _self.pressure
|
||||
: pressure // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
vis: freezed == vis
|
||||
? _self.vis
|
||||
: vis // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
cloud: freezed == cloud
|
||||
? _self.cloud
|
||||
: cloud // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
dew: freezed == dew
|
||||
? _self.dew
|
||||
: dew // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _Now implements Now {
|
||||
const _Now(
|
||||
{this.obsTime, this.temp, this.feelsLike, this.icon, this.text, this.wind360, this.windDir, this.windScale, this.windSpeed, this.humidity, this.precip, this.pressure, this.vis, this.cloud, this.dew});
|
||||
|
||||
factory _Now.fromJson(Map<String, dynamic> json) => _$NowFromJson(json);
|
||||
|
||||
@override final String? obsTime;
|
||||
@override final String? temp;
|
||||
@override final String? feelsLike;
|
||||
@override final String? icon;
|
||||
@override final String? text;
|
||||
@override final String? wind360;
|
||||
@override final String? windDir;
|
||||
@override final String? windScale;
|
||||
@override final String? windSpeed;
|
||||
@override final String? humidity;
|
||||
@override final String? precip;
|
||||
@override final String? pressure;
|
||||
@override final String? vis;
|
||||
@override final String? cloud;
|
||||
@override final String? dew;
|
||||
|
||||
/// Create a copy of Now
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$NowCopyWith<_Now> get copyWith =>
|
||||
__$NowCopyWithImpl<_Now>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$NowToJson(this,);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _Now &&
|
||||
(identical(other.obsTime, obsTime) || other.obsTime == obsTime) &&
|
||||
(identical(other.temp, temp) || other.temp == temp) &&
|
||||
(identical(other.feelsLike, feelsLike) ||
|
||||
other.feelsLike == feelsLike) &&
|
||||
(identical(other.icon, icon) || other.icon == icon) &&
|
||||
(identical(other.text, text) || other.text == text) &&
|
||||
(identical(other.wind360, wind360) || other.wind360 == wind360) &&
|
||||
(identical(other.windDir, windDir) || other.windDir == windDir) &&
|
||||
(identical(other.windScale, windScale) ||
|
||||
other.windScale == windScale) &&
|
||||
(identical(other.windSpeed, windSpeed) ||
|
||||
other.windSpeed == windSpeed) &&
|
||||
(identical(other.humidity, humidity) ||
|
||||
other.humidity == humidity) &&
|
||||
(identical(other.precip, precip) || other.precip == precip) &&
|
||||
(identical(other.pressure, pressure) ||
|
||||
other.pressure == pressure) &&
|
||||
(identical(other.vis, vis) || other.vis == vis) &&
|
||||
(identical(other.cloud, cloud) || other.cloud == cloud) &&
|
||||
(identical(other.dew, dew) || other.dew == dew));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(
|
||||
runtimeType,
|
||||
obsTime,
|
||||
temp,
|
||||
feelsLike,
|
||||
icon,
|
||||
text,
|
||||
wind360,
|
||||
windDir,
|
||||
windScale,
|
||||
windSpeed,
|
||||
humidity,
|
||||
precip,
|
||||
pressure,
|
||||
vis,
|
||||
cloud,
|
||||
dew);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Now(obsTime: $obsTime, temp: $temp, feelsLike: $feelsLike, icon: $icon, text: $text, wind360: $wind360, windDir: $windDir, windScale: $windScale, windSpeed: $windSpeed, humidity: $humidity, precip: $precip, pressure: $pressure, vis: $vis, cloud: $cloud, dew: $dew)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$NowCopyWith<$Res> implements $NowCopyWith<$Res> {
|
||||
factory _$NowCopyWith(_Now value,
|
||||
$Res Function(_Now) _then) = __$NowCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
String? obsTime, String? temp, String? feelsLike, String? icon, String? text, String? wind360, String? windDir, String? windScale, String? windSpeed, String? humidity, String? precip, String? pressure, String? vis, String? cloud, String? dew
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$NowCopyWithImpl<$Res>
|
||||
implements _$NowCopyWith<$Res> {
|
||||
__$NowCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _Now _self;
|
||||
final $Res Function(_Now) _then;
|
||||
|
||||
/// Create a copy of Now
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$Res call(
|
||||
{Object? obsTime = freezed, Object? temp = freezed, Object? feelsLike = freezed, Object? icon = freezed, Object? text = freezed, Object? wind360 = freezed, Object? windDir = freezed, Object? windScale = freezed, Object? windSpeed = freezed, Object? humidity = freezed, Object? precip = freezed, Object? pressure = freezed, Object? vis = freezed, Object? cloud = freezed, Object? dew = freezed,}) {
|
||||
return _then(_Now(
|
||||
obsTime: freezed == obsTime
|
||||
? _self.obsTime
|
||||
: obsTime // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
temp: freezed == temp
|
||||
? _self.temp
|
||||
: temp // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
feelsLike: freezed == feelsLike
|
||||
? _self.feelsLike
|
||||
: feelsLike // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
icon: freezed == icon
|
||||
? _self.icon
|
||||
: icon // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
text: freezed == text
|
||||
? _self.text
|
||||
: text // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
wind360: freezed == wind360
|
||||
? _self.wind360
|
||||
: wind360 // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
windDir: freezed == windDir
|
||||
? _self.windDir
|
||||
: windDir // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
windScale: freezed == windScale
|
||||
? _self.windScale
|
||||
: windScale // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
windSpeed: freezed == windSpeed
|
||||
? _self.windSpeed
|
||||
: windSpeed // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
humidity: freezed == humidity
|
||||
? _self.humidity
|
||||
: humidity // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
precip: freezed == precip
|
||||
? _self.precip
|
||||
: precip // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
pressure: freezed == pressure
|
||||
? _self.pressure
|
||||
: pressure // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
vis: freezed == vis
|
||||
? _self.vis
|
||||
: vis // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
cloud: freezed == cloud
|
||||
? _self.cloud
|
||||
: cloud // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
dew: freezed == dew
|
||||
? _self.dew
|
||||
: dew // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
79
lib/common/models/weather.g.dart
Normal file
79
lib/common/models/weather.g.dart
Normal file
@@ -0,0 +1,79 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'weather.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_WeatherResponse _$WeatherResponseFromJson(Map<String, dynamic> json) =>
|
||||
_WeatherResponse(
|
||||
code: json['code'] as String?,
|
||||
updateTime: json['updateTime'] as String?,
|
||||
fxLink: json['fxLink'] as String?,
|
||||
now:
|
||||
json['now'] == null
|
||||
? null
|
||||
: Now.fromJson(json['now'] as Map<String, dynamic>),
|
||||
refer:
|
||||
json['refer'] == null
|
||||
? null
|
||||
: Refer.fromJson(json['refer'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$WeatherResponseToJson(_WeatherResponse instance) =>
|
||||
<String, dynamic>{
|
||||
if (instance.code case final value?) 'code': value,
|
||||
if (instance.updateTime case final value?) 'updateTime': value,
|
||||
if (instance.fxLink case final value?) 'fxLink': value,
|
||||
if (instance.now case final value?) 'now': value,
|
||||
if (instance.refer case final value?) 'refer': value,
|
||||
};
|
||||
|
||||
_Refer _$ReferFromJson(Map<String, dynamic> json) => _Refer(
|
||||
sources:
|
||||
(json['sources'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||
license:
|
||||
(json['license'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ReferToJson(_Refer instance) => <String, dynamic>{
|
||||
if (instance.sources case final value?) 'sources': value,
|
||||
if (instance.license case final value?) 'license': value,
|
||||
};
|
||||
|
||||
_Now _$NowFromJson(Map<String, dynamic> json) => _Now(
|
||||
obsTime: json['obsTime'] as String?,
|
||||
temp: json['temp'] as String?,
|
||||
feelsLike: json['feelsLike'] as String?,
|
||||
icon: json['icon'] as String?,
|
||||
text: json['text'] as String?,
|
||||
wind360: json['wind360'] as String?,
|
||||
windDir: json['windDir'] as String?,
|
||||
windScale: json['windScale'] as String?,
|
||||
windSpeed: json['windSpeed'] as String?,
|
||||
humidity: json['humidity'] as String?,
|
||||
precip: json['precip'] as String?,
|
||||
pressure: json['pressure'] as String?,
|
||||
vis: json['vis'] as String?,
|
||||
cloud: json['cloud'] as String?,
|
||||
dew: json['dew'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$NowToJson(_Now instance) => <String, dynamic>{
|
||||
if (instance.obsTime case final value?) 'obsTime': value,
|
||||
if (instance.temp case final value?) 'temp': value,
|
||||
if (instance.feelsLike case final value?) 'feelsLike': value,
|
||||
if (instance.icon case final value?) 'icon': value,
|
||||
if (instance.text case final value?) 'text': value,
|
||||
if (instance.wind360 case final value?) 'wind360': value,
|
||||
if (instance.windDir case final value?) 'windDir': value,
|
||||
if (instance.windScale case final value?) 'windScale': value,
|
||||
if (instance.windSpeed case final value?) 'windSpeed': value,
|
||||
if (instance.humidity case final value?) 'humidity': value,
|
||||
if (instance.precip case final value?) 'precip': value,
|
||||
if (instance.pressure case final value?) 'pressure': value,
|
||||
if (instance.vis case final value?) 'vis': value,
|
||||
if (instance.cloud case final value?) 'cloud': value,
|
||||
if (instance.dew case final value?) 'dew': value,
|
||||
};
|
||||
@@ -1,10 +1,13 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class AppBorderRadius {
|
||||
static const BorderRadius smallBorderRadius =
|
||||
BorderRadius.all(Radius.circular(8.0));
|
||||
static const BorderRadius mediumBorderRadius =
|
||||
BorderRadius.all(Radius.circular(12.0));
|
||||
static const BorderRadius largeBorderRadius =
|
||||
BorderRadius.all(Radius.circular(16.0));
|
||||
static const BorderRadius smallBorderRadius = BorderRadius.all(
|
||||
Radius.circular(8.0),
|
||||
);
|
||||
static const BorderRadius mediumBorderRadius = BorderRadius.all(
|
||||
Radius.circular(12.0),
|
||||
);
|
||||
static const BorderRadius largeBorderRadius = BorderRadius.all(
|
||||
Radius.circular(16.0),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../main.dart';
|
||||
import 'package:moodiary/l10n/l10n.dart';
|
||||
|
||||
enum AppColorType {
|
||||
common(0),
|
||||
@@ -35,21 +34,33 @@ class AppColor {
|
||||
// PANTONE 2008 Blue Iris
|
||||
static Color answerColor = const Color(0xFF5A5B9F);
|
||||
|
||||
static String colorName(index) {
|
||||
static String colorName(index, BuildContext context) {
|
||||
return switch (index) {
|
||||
0 => l10n.colorNameBaiCaoShuang,
|
||||
1 => l10n.colorNameQunQin,
|
||||
2 => l10n.colorNameQinDai,
|
||||
3 => l10n.colorNameShuiZhuHua,
|
||||
4 => l10n.colorNameJiHe,
|
||||
5 => l10n.colorNameXiangYe,
|
||||
9990 => l10n.specialColorNameMochaMousse,
|
||||
_ => l10n.colorNameSystem
|
||||
0 => context.l10n.colorNameBaiCaoShuang,
|
||||
1 => context.l10n.colorNameQunQin,
|
||||
2 => context.l10n.colorNameQinDai,
|
||||
3 => context.l10n.colorNameShuiZhuHua,
|
||||
4 => context.l10n.colorNameJiHe,
|
||||
5 => context.l10n.colorNameXiangYe,
|
||||
9990 => context.l10n.specialColorNameMochaMousse,
|
||||
_ => context.l10n.colorNameSystem,
|
||||
};
|
||||
}
|
||||
|
||||
static List<Color> emoColorList = [
|
||||
const Color(0xFFFA4659),
|
||||
const Color(0xFF2EB872)
|
||||
const Color(0xFF2EB872),
|
||||
];
|
||||
}
|
||||
|
||||
class ShareCardColor {
|
||||
static List<Color> cardColorList = [
|
||||
const Color(0xFFF8F3D4),
|
||||
const Color(0xFFF5F5F5),
|
||||
const Color(0xFFFFFFFF),
|
||||
const Color(0xFF393e46),
|
||||
const Color(0xFF252A34),
|
||||
const Color(0xFF212121),
|
||||
const Color(0xFF000000),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
enum DiaryType {
|
||||
text('text'),
|
||||
markdown('markdown'),
|
||||
@@ -6,4 +9,21 @@ enum DiaryType {
|
||||
final String value;
|
||||
|
||||
const DiaryType(this.value);
|
||||
|
||||
static DiaryType fromValue(String value) {
|
||||
return DiaryType.values.firstWhere((e) => e.value == value);
|
||||
}
|
||||
}
|
||||
|
||||
extension DiaryTypeIcon on DiaryType {
|
||||
IconData get icon {
|
||||
switch (this) {
|
||||
case DiaryType.text:
|
||||
return FontAwesomeIcons.font;
|
||||
case DiaryType.markdown:
|
||||
return FontAwesomeIcons.markdown;
|
||||
case DiaryType.richText:
|
||||
return FontAwesomeIcons.feather;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,6 +419,6 @@ class WeatherIcon {
|
||||
"2425": const IconData(62147, fontFamily: 'qweather'),
|
||||
"2426": const IconData(62148, fontFamily: 'qweather'),
|
||||
"9998": const IconData(61898, fontFamily: 'qweather'),
|
||||
"9999": const IconData(61899, fontFamily: 'qweather')
|
||||
"9999": const IconData(61899, fontFamily: 'qweather'),
|
||||
};
|
||||
}
|
||||
|
||||
25
lib/common/values/language.dart
Normal file
25
lib/common/values/language.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:moodiary/l10n/l10n.dart';
|
||||
|
||||
enum Language {
|
||||
system('system'),
|
||||
chinese('zh'),
|
||||
english('en');
|
||||
|
||||
final String languageCode;
|
||||
|
||||
const Language(this.languageCode);
|
||||
}
|
||||
|
||||
extension LanguageExtension on Language {
|
||||
String l10nText(BuildContext context) {
|
||||
switch (this) {
|
||||
case Language.system:
|
||||
return context.l10n.settingLanguageSystem;
|
||||
case Language.chinese:
|
||||
return context.l10n.settingLanguageSimpleChinese;
|
||||
case Language.english:
|
||||
return context.l10n.settingLanguageEnglish;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
class ChinaRegions {
|
||||
// 定义中国所有省份的瓦片区域
|
||||
static final regions = {
|
||||
'Beijing': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(39.4427, 115.4213), const LatLng(41.0599, 117.5143)),
|
||||
),
|
||||
'Tianjin': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(38.5547, 116.7257), const LatLng(40.2555, 118.0481)),
|
||||
),
|
||||
'Hebei': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(36.0513, 113.4620), const LatLng(42.6502, 119.8485)),
|
||||
),
|
||||
'Shanxi': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(34.4824, 110.1619), const LatLng(40.9982, 114.7482)),
|
||||
),
|
||||
'Inner Mongolia': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(37.4229, 97.1681), const LatLng(53.3318, 126.0386)),
|
||||
),
|
||||
'Liaoning': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(38.7216, 118.9151), const LatLng(43.4845, 125.5690)),
|
||||
),
|
||||
'Jilin': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(40.8624, 121.3644), const LatLng(46.6387, 131.2433)),
|
||||
),
|
||||
'Heilongjiang': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(43.4329, 121.1836), const LatLng(53.5581, 135.0865)),
|
||||
),
|
||||
'Shanghai': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(30.6647, 120.8526), const LatLng(31.8832, 122.1084)),
|
||||
),
|
||||
'Jiangsu': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(30.4505, 116.8286), const LatLng(35.1224, 121.1320)),
|
||||
),
|
||||
'Zhejiang': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(27.1934, 118.0219), const LatLng(31.0895, 122.2274)),
|
||||
),
|
||||
'Anhui': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(29.4119, 114.8926), const LatLng(34.6568, 119.6455)),
|
||||
),
|
||||
'Fujian': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(23.5636, 116.7407), const LatLng(28.4387, 120.8369)),
|
||||
),
|
||||
'Jiangxi': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(24.4124, 113.5877), const LatLng(30.0756, 118.6083)),
|
||||
),
|
||||
'Shandong': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(34.3944, 114.8054), const LatLng(38.3072, 122.6978)),
|
||||
),
|
||||
'Henan': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(31.3802, 110.3787), const LatLng(36.5819, 116.6942)),
|
||||
),
|
||||
'Hubei': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(29.0470, 108.4110), const LatLng(33.4238, 116.0797)),
|
||||
),
|
||||
'Hunan': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(24.6366, 108.7877), const LatLng(30.1238, 114.2341)),
|
||||
),
|
||||
'Guangdong': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(20.0268, 109.6642), const LatLng(25.5186, 117.2037)),
|
||||
),
|
||||
'Guangxi': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(20.5400, 104.4759), const LatLng(26.2504, 112.0472)),
|
||||
),
|
||||
'Hainan': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(18.1460, 108.5117), const LatLng(20.2706, 111.0257)),
|
||||
),
|
||||
'Chongqing': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(28.1124, 105.2875), const LatLng(32.1310, 110.4740)),
|
||||
),
|
||||
'Sichuan': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(26.0490, 97.3516), const LatLng(34.3143, 108.5740)),
|
||||
),
|
||||
'Guizhou': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(24.3965, 103.5901), const LatLng(29.2275, 109.2114)),
|
||||
),
|
||||
'Yunnan': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(21.1375, 97.6400), const LatLng(29.2227, 106.1124)),
|
||||
),
|
||||
'Tibet': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(26.0000, 78.3949), const LatLng(36.4538, 99.1089)),
|
||||
),
|
||||
'Shaanxi': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(31.7024, 105.4964), const LatLng(39.5957, 111.2605)),
|
||||
),
|
||||
'Gansu': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(32.1043, 92.1316), const LatLng(42.7932, 108.7309)),
|
||||
),
|
||||
'Qinghai': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(31.5875, 89.6198), const LatLng(39.7931, 101.8822)),
|
||||
),
|
||||
'Ningxia': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(35.3135, 104.1455), const LatLng(39.3749, 107.9047)),
|
||||
),
|
||||
'Xinjiang': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(34.2231, 73.4994), const LatLng(49.1720, 96.3877)),
|
||||
),
|
||||
'Hong Kong': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(22.1193, 113.8252), const LatLng(22.5645, 114.4462)),
|
||||
),
|
||||
'Macau': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(22.1092, 113.5286), const LatLng(22.2176, 113.6069)),
|
||||
),
|
||||
'Taiwan': RectangleRegion(
|
||||
LatLngBounds(
|
||||
const LatLng(20.5170, 119.4189), const LatLng(25.4152, 122.0184)),
|
||||
),
|
||||
};
|
||||
}
|
||||
32
lib/common/values/sync_status.dart
Normal file
32
lib/common/values/sync_status.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
/// 同步状态枚举
|
||||
enum SyncStatus {
|
||||
/// 已分配任务但还未执行
|
||||
pending,
|
||||
|
||||
/// 正在同步中
|
||||
syncing,
|
||||
|
||||
/// 同步成功
|
||||
success,
|
||||
|
||||
/// 同步失败
|
||||
failure,
|
||||
|
||||
/// 验证失败
|
||||
invalid,
|
||||
|
||||
/// 未知状态
|
||||
unknown,
|
||||
}
|
||||
|
||||
/// 连接状态枚举
|
||||
enum ConnectivityStatus {
|
||||
/// 未连接
|
||||
disconnected,
|
||||
|
||||
/// 正在连接
|
||||
connecting,
|
||||
|
||||
/// 已连接
|
||||
connected,
|
||||
}
|
||||
@@ -18,8 +18,4 @@ class WebDavOptions {
|
||||
static const Color connectingColor = Color(0xFFFFC107);
|
||||
}
|
||||
|
||||
enum WebDavConnectivityStatus {
|
||||
connected,
|
||||
unconnected,
|
||||
connecting,
|
||||
}
|
||||
enum WebDavConnectivityStatus { connected, unconnected, connecting }
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mood_diary/common/values/keyboard_state.dart';
|
||||
import 'package:mood_diary/utils/literunner.dart';
|
||||
import 'package:mood_diary/utils/tokenization.dart';
|
||||
import 'package:refreshed/refreshed.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:moodiary/common/values/keyboard_state.dart';
|
||||
import 'package:moodiary/components/keyboard_listener/keyboard_listener.dart';
|
||||
import 'package:moodiary/utils/literunner.dart';
|
||||
import 'package:moodiary/utils/tokenization.dart';
|
||||
|
||||
import 'ask_question_state.dart';
|
||||
|
||||
class AskQuestionLogic extends GetxController with WidgetsBindingObserver {
|
||||
class AskQuestionLogic extends GetxController {
|
||||
final AskQuestionState state = AskQuestionState();
|
||||
|
||||
//输入框控制器
|
||||
@@ -23,42 +24,31 @@ class AskQuestionLogic extends GetxController with WidgetsBindingObserver {
|
||||
|
||||
List<double> heightList = [];
|
||||
|
||||
late final KeyboardObserver keyboardObserver;
|
||||
|
||||
@override
|
||||
void didChangeMetrics() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
var height = MediaQuery.viewInsetsOf(Get.context!).bottom;
|
||||
if (heightList.isNotEmpty && height != heightList.last) {
|
||||
if (height > heightList.last &&
|
||||
state.keyboardState != KeyboardState.opening) {
|
||||
state.keyboardState = KeyboardState.opening;
|
||||
//正在打开
|
||||
} else if (height < heightList.last &&
|
||||
state.keyboardState != KeyboardState.closing) {
|
||||
state.keyboardState = KeyboardState.closing;
|
||||
//正在关闭
|
||||
unFocus();
|
||||
void onInit() {
|
||||
keyboardObserver = KeyboardObserver(
|
||||
onStateChanged: (state) {
|
||||
switch (state) {
|
||||
case KeyboardState.opening:
|
||||
break;
|
||||
case KeyboardState.closing:
|
||||
unFocus();
|
||||
break;
|
||||
case KeyboardState.closed:
|
||||
toBottom();
|
||||
break;
|
||||
case KeyboardState.unknown:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 只在高度变化时记录高度
|
||||
if (heightList.isEmpty || height != heightList.last) {
|
||||
heightList.add(height);
|
||||
}
|
||||
|
||||
// 当高度为0且键盘经历了开启关闭过程时,认为键盘已完全关闭
|
||||
if (height == 0 && state.keyboardState != KeyboardState.closed) {
|
||||
state.keyboardState = KeyboardState.closed;
|
||||
heightList.clear();
|
||||
toBottom();
|
||||
//已经关闭
|
||||
}
|
||||
});
|
||||
super.didChangeMetrics();
|
||||
},
|
||||
);
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() async {
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
//await fullTokenizer.init();
|
||||
//await liteRunner.initializeInterpreter(state.modelPath, fullTokenizer);
|
||||
super.onReady();
|
||||
@@ -66,11 +56,10 @@ class AskQuestionLogic extends GetxController with WidgetsBindingObserver {
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
keyboardObserver.stop();
|
||||
textEditingController.dispose();
|
||||
scrollController.dispose();
|
||||
focusNode.dispose();
|
||||
// 销毁实例
|
||||
liteRunner.close();
|
||||
super.onClose();
|
||||
}
|
||||
@@ -85,7 +74,7 @@ class AskQuestionLogic extends GetxController with WidgetsBindingObserver {
|
||||
// 添加提问
|
||||
state.qaList.add(question);
|
||||
|
||||
var answer = await liteRunner.ask(content, question);
|
||||
final answer = await liteRunner.ask(content, question);
|
||||
// 添加回答
|
||||
if (answer != null) {
|
||||
state.qaList.add(answer);
|
||||
@@ -98,12 +87,15 @@ class AskQuestionLogic extends GetxController with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
Future<void> toBottom() async {
|
||||
await scrollController.animateTo(scrollController.position.maxScrollExtent,
|
||||
duration: const Duration(milliseconds: 100), curve: Curves.linear);
|
||||
await scrollController.animateTo(
|
||||
scrollController.position.maxScrollExtent,
|
||||
duration: const Duration(milliseconds: 100),
|
||||
curve: Curves.linear,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> ask(String content) async {
|
||||
var text = textEditingController.text;
|
||||
final text = textEditingController.text;
|
||||
if (text.isNotEmpty) {
|
||||
//await getAnswer(content, text);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:mood_diary/common/values/keyboard_state.dart';
|
||||
import 'package:refreshed/refreshed.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:moodiary/common/values/keyboard_state.dart';
|
||||
|
||||
class AskQuestionState {
|
||||
late String modelPath;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mood_diary/common/values/border.dart';
|
||||
import 'package:refreshed/refreshed.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:moodiary/common/values/border.dart';
|
||||
|
||||
import 'ask_question_logic.dart';
|
||||
|
||||
@@ -13,7 +13,7 @@ class AskQuestionComponent extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final logic = Get.put(AskQuestionLogic());
|
||||
final state = Bind.find<AskQuestionLogic>().state;
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
Widget buildInput() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
@@ -21,25 +21,28 @@ class AskQuestionComponent extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
focusNode: logic.focusNode,
|
||||
controller: logic.textEditingController,
|
||||
maxLines: 1,
|
||||
decoration: InputDecoration(
|
||||
fillColor: colorScheme.surfaceContainerHighest,
|
||||
child: TextField(
|
||||
focusNode: logic.focusNode,
|
||||
controller: logic.textEditingController,
|
||||
maxLines: 1,
|
||||
decoration: InputDecoration(
|
||||
fillColor: context.theme.colorScheme.surfaceContainerHighest,
|
||||
filled: true,
|
||||
isDense: true,
|
||||
hintText: '提问',
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: AppBorderRadius.largeBorderRadius,
|
||||
borderSide: BorderSide.none,
|
||||
)),
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton.filled(
|
||||
onPressed: () async {
|
||||
await logic.ask(content);
|
||||
},
|
||||
icon: const Icon(Icons.arrow_upward))
|
||||
onPressed: () async {
|
||||
await logic.ask(content);
|
||||
},
|
||||
icon: const Icon(Icons.arrow_upward),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -52,12 +55,14 @@ class AskQuestionComponent extends StatelessWidget {
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: constraint.maxWidth * 0.618),
|
||||
child: Card.filled(
|
||||
color: colorScheme.surfaceContainerHigh,
|
||||
color: context.theme.colorScheme.surfaceContainerHigh,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(color: colorScheme.onSecondaryContainer),
|
||||
style: TextStyle(
|
||||
color: context.theme.colorScheme.onSecondaryContainer,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -72,12 +77,14 @@ class AskQuestionComponent extends StatelessWidget {
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: constraint.maxWidth * 0.618),
|
||||
child: Card.filled(
|
||||
color: colorScheme.primaryContainer,
|
||||
color: context.theme.colorScheme.primaryContainer,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(color: colorScheme.onPrimaryContainer),
|
||||
style: TextStyle(
|
||||
color: context.theme.colorScheme.onPrimaryContainer,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -106,10 +113,12 @@ class AskQuestionComponent extends StatelessWidget {
|
||||
builder: (_) {
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(child: Obx(() {
|
||||
return buildChat(constraint);
|
||||
})),
|
||||
buildInput()
|
||||
Expanded(
|
||||
child: Obx(() {
|
||||
return buildChat(constraint);
|
||||
}),
|
||||
),
|
||||
buildInput(),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:mood_diary/pages/edit/edit_logic.dart';
|
||||
import 'package:refreshed/refreshed.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:moodiary/pages/edit/edit_logic.dart';
|
||||
|
||||
import 'audio_player_state.dart';
|
||||
|
||||
@@ -11,7 +11,9 @@ class AudioPlayerLogic extends GetxController
|
||||
|
||||
final AudioPlayer audioPlayer = AudioPlayer();
|
||||
late final AnimationController animationController = AnimationController(
|
||||
vsync: this, duration: const Duration(milliseconds: 100));
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 100),
|
||||
);
|
||||
late final EditLogic editLogic = Bind.find<EditLogic>();
|
||||
|
||||
@override
|
||||
@@ -67,7 +69,7 @@ class AudioPlayerLogic extends GetxController
|
||||
Future<void> changeValue(value) async {
|
||||
state.handleChange.value = true;
|
||||
state.currentDuration.value = Duration(
|
||||
milliseconds:
|
||||
(state.totalDuration.value.inMilliseconds * value).toInt());
|
||||
milliseconds: (state.totalDuration.value.inMilliseconds * value).toInt(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:refreshed/refreshed.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class AudioPlayerState {
|
||||
late String audioPath;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:refreshed/refreshed.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:syncfusion_flutter_sliders/sliders.dart';
|
||||
|
||||
import 'audio_player_logic.dart';
|
||||
@@ -27,31 +27,38 @@ class SmallThumbShape extends SfThumbShape {
|
||||
}) {
|
||||
// 使用原有逻辑绘制缩小的滑块
|
||||
final double radius = getPreferredSize(themeData).width / 2;
|
||||
final Paint thumbPaint = Paint()
|
||||
..color = themeData.thumbColor ?? Colors.blue
|
||||
..isAntiAlias = true;
|
||||
final Paint thumbPaint =
|
||||
Paint()
|
||||
..color = themeData.thumbColor ?? Colors.blue
|
||||
..isAntiAlias = true;
|
||||
|
||||
context.canvas.drawCircle(center, radius, thumbPaint);
|
||||
|
||||
if (child != null) {
|
||||
context.paintChild(
|
||||
child,
|
||||
Offset(center.dx - child.size.width / 2,
|
||||
center.dy - child.size.height / 2));
|
||||
child,
|
||||
Offset(
|
||||
center.dx - child.size.width / 2,
|
||||
center.dy - child.size.height / 2,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NoOverlayShape extends SfOverlayShape {
|
||||
@override
|
||||
void paint(PaintingContext context, Offset center,
|
||||
{required RenderBox parentBox,
|
||||
required dynamic themeData,
|
||||
SfRangeValues? currentValues,
|
||||
currentValue,
|
||||
required Paint? paint,
|
||||
required Animation<double> animation,
|
||||
required SfThumb? thumb}) {}
|
||||
void paint(
|
||||
PaintingContext context,
|
||||
Offset center, {
|
||||
required RenderBox parentBox,
|
||||
required dynamic themeData,
|
||||
SfRangeValues? currentValues,
|
||||
currentValue,
|
||||
required Paint? paint,
|
||||
required Animation<double> animation,
|
||||
required SfThumb? thumb,
|
||||
}) {}
|
||||
}
|
||||
|
||||
class AudioPlayerComponent extends StatelessWidget {
|
||||
@@ -64,7 +71,6 @@ class AudioPlayerComponent extends StatelessWidget {
|
||||
final logic = Get.put(AudioPlayerLogic(), tag: path);
|
||||
final state = Bind.find<AudioPlayerLogic>(tag: path).state;
|
||||
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return GetBuilder<AudioPlayerLogic>(
|
||||
tag: path,
|
||||
initState: (_) async {
|
||||
@@ -73,7 +79,8 @@ class AudioPlayerComponent extends StatelessWidget {
|
||||
assignId: true,
|
||||
builder: (_) {
|
||||
return Card.filled(
|
||||
color: colorScheme.secondaryContainer,
|
||||
color: context.theme.colorScheme.secondaryContainer,
|
||||
margin: EdgeInsets.zero,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
@@ -84,18 +91,26 @@ class AudioPlayerComponent extends StatelessWidget {
|
||||
children: [
|
||||
Obx(() {
|
||||
return SfSlider(
|
||||
value: state.totalDuration.value != Duration.zero
|
||||
? ((state.currentDuration.value.inMilliseconds /
|
||||
state.totalDuration.value.inMilliseconds)
|
||||
.clamp(0, 1))
|
||||
: 0,
|
||||
value:
|
||||
state.totalDuration.value != Duration.zero
|
||||
? ((state
|
||||
.currentDuration
|
||||
.value
|
||||
.inMilliseconds /
|
||||
state
|
||||
.totalDuration
|
||||
.value
|
||||
.inMilliseconds)
|
||||
.clamp(0, 1))
|
||||
: 0,
|
||||
onChangeEnd: (value) {
|
||||
logic.to(value);
|
||||
},
|
||||
onChanged: (value) {
|
||||
logic.changeValue(value);
|
||||
},
|
||||
inactiveColor: colorScheme.surfaceContainer,
|
||||
inactiveColor:
|
||||
context.theme.colorScheme.surfaceContainer,
|
||||
overlayShape: NoOverlayShape(),
|
||||
thumbShape: SmallThumbShape(),
|
||||
);
|
||||
@@ -112,7 +127,12 @@ class AudioPlayerComponent extends StatelessWidget {
|
||||
.split('.')[0]
|
||||
.padLeft(8, '0'),
|
||||
style: TextStyle(
|
||||
color: colorScheme.onSecondaryContainer),
|
||||
color:
|
||||
context
|
||||
.theme
|
||||
.colorScheme
|
||||
.onSecondaryContainer,
|
||||
),
|
||||
);
|
||||
}),
|
||||
IconButton.filled(
|
||||
@@ -121,12 +141,9 @@ class AudioPlayerComponent extends StatelessWidget {
|
||||
? logic.pause()
|
||||
: logic.play(path);
|
||||
},
|
||||
style: const ButtonStyle(
|
||||
tapTargetSize:
|
||||
MaterialTapTargetSize.shrinkWrap),
|
||||
icon: AnimatedIcon(
|
||||
icon: AnimatedIcons.play_pause,
|
||||
color: colorScheme.onPrimary,
|
||||
color: context.theme.colorScheme.onPrimary,
|
||||
progress: logic.animationController,
|
||||
),
|
||||
),
|
||||
@@ -137,7 +154,12 @@ class AudioPlayerComponent extends StatelessWidget {
|
||||
.split('.')[0]
|
||||
.padLeft(8, '0'),
|
||||
style: TextStyle(
|
||||
color: colorScheme.onSecondaryContainer),
|
||||
color:
|
||||
context
|
||||
.theme
|
||||
.colorScheme
|
||||
.onSecondaryContainer,
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:moodiary/l10n/l10n.dart';
|
||||
|
||||
class FrostedGlassButton extends StatelessWidget {
|
||||
final Widget child;
|
||||
final double size;
|
||||
final Function()? onPressed;
|
||||
|
||||
const FrostedGlassButton(
|
||||
{super.key, required this.child, required this.size, this.onPressed});
|
||||
const FrostedGlassButton({
|
||||
super.key,
|
||||
required this.child,
|
||||
required this.size,
|
||||
this.onPressed,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -29,10 +35,8 @@ class FrostedGlassButton extends StatelessWidget {
|
||||
}
|
||||
|
||||
class MultiFabLayoutDelegate extends MultiChildLayoutDelegate {
|
||||
MultiFabLayoutDelegate({
|
||||
required this.controller,
|
||||
required this.layoutIds,
|
||||
}) : super(relayout: controller);
|
||||
MultiFabLayoutDelegate({required this.controller, required this.layoutIds})
|
||||
: super(relayout: controller);
|
||||
|
||||
final Animation<double> controller;
|
||||
final List<int> layoutIds;
|
||||
@@ -53,8 +57,10 @@ class MultiFabLayoutDelegate extends MultiChildLayoutDelegate {
|
||||
);
|
||||
positionChild(
|
||||
0,
|
||||
Offset(size.width - mainButtonSize.width,
|
||||
size.height - mainButtonSize.height),
|
||||
Offset(
|
||||
size.width - mainButtonSize.width,
|
||||
size.height - mainButtonSize.height,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -64,18 +70,17 @@ class MultiFabLayoutDelegate extends MultiChildLayoutDelegate {
|
||||
if (hasChild(layoutId)) {
|
||||
final childButtonSize = layoutChild(
|
||||
layoutId,
|
||||
BoxConstraints(
|
||||
maxWidth: size.width,
|
||||
maxHeight: childButtonHeight,
|
||||
),
|
||||
BoxConstraints(maxWidth: size.width, maxHeight: childButtonHeight),
|
||||
);
|
||||
|
||||
// 动态计算子按钮的垂直偏移量
|
||||
final dyOffset = (mainButtonHeight + buttonSpacing) +
|
||||
final dyOffset =
|
||||
(mainButtonHeight + buttonSpacing) +
|
||||
(i - 1) * (childButtonSize.height + buttonSpacing) * animationValue;
|
||||
|
||||
// 动态计算水平偏移量,使子按钮完全隐藏在主按钮底部时的水平位置对齐
|
||||
final dxOffset = (mainButtonHeight - childButtonSize.width) /
|
||||
final dxOffset =
|
||||
(mainButtonHeight - childButtonSize.width) /
|
||||
2 *
|
||||
(1 - animationValue);
|
||||
|
||||
@@ -96,3 +101,23 @@ class MultiFabLayoutDelegate extends MultiChildLayoutDelegate {
|
||||
oldDelegate.layoutIds != layoutIds;
|
||||
}
|
||||
}
|
||||
|
||||
class PageBackButton extends StatelessWidget {
|
||||
final Function()? onBack;
|
||||
|
||||
final Color? color;
|
||||
|
||||
const PageBackButton({super.key, this.onBack, this.color});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: IconButton(
|
||||
onPressed: onBack ?? Get.back,
|
||||
icon: const Icon(Icons.arrow_back_rounded),
|
||||
color: color ?? context.theme.colorScheme.onSurface,
|
||||
tooltip: context.l10n.back,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
44
lib/components/base/clipper.dart
Normal file
44
lib/components/base/clipper.dart
Normal file
@@ -0,0 +1,44 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:moodiary/common/values/border.dart';
|
||||
|
||||
class TopRRectClipper extends CustomClipper<RRect> {
|
||||
final double topOffset;
|
||||
|
||||
TopRRectClipper({this.topOffset = 0});
|
||||
|
||||
@override
|
||||
RRect getClip(Size size) {
|
||||
final Rect rect = Rect.fromLTWH(
|
||||
0,
|
||||
topOffset,
|
||||
size.width,
|
||||
size.height - topOffset,
|
||||
);
|
||||
const Radius radius = Radius.circular(12.0);
|
||||
return RRect.fromRectAndRadius(rect, radius);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReclip(covariant TopRRectClipper oldClipper) {
|
||||
return oldClipper.topOffset != topOffset;
|
||||
}
|
||||
}
|
||||
|
||||
class PageClipper extends StatelessWidget {
|
||||
final Widget child;
|
||||
final CustomClipper<RRect>? clipper;
|
||||
|
||||
const PageClipper({super.key, required this.child, this.clipper});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: ClipRRect(
|
||||
borderRadius: AppBorderRadius.mediumBorderRadius,
|
||||
clipper: clipper,
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
185
lib/components/base/expand_tap_area.dart
Normal file
185
lib/components/base/expand_tap_area.dart
Normal file
@@ -0,0 +1,185 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
Color debugPaintExpandAreaColor = const Color(
|
||||
0xFFFF0000,
|
||||
).withValues(alpha: 0.03);
|
||||
|
||||
Color debugPaintClipAreaColor = const Color(0xFF0000FF).withValues(alpha: 0.02);
|
||||
|
||||
class ExpandTapWidget extends SingleChildRenderObjectWidget {
|
||||
const ExpandTapWidget({
|
||||
super.key,
|
||||
super.child,
|
||||
required this.onTap,
|
||||
required this.tapPadding,
|
||||
});
|
||||
|
||||
final VoidCallback onTap;
|
||||
final EdgeInsets tapPadding;
|
||||
|
||||
@override
|
||||
RenderObject createRenderObject(BuildContext context) =>
|
||||
_ExpandTapRenderBox(onTap: onTap, tapPadding: tapPadding);
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderBox renderObject) {
|
||||
renderObject as _ExpandTapRenderBox;
|
||||
if (renderObject.tapPadding != tapPadding) {
|
||||
renderObject.tapPadding = tapPadding;
|
||||
}
|
||||
if (renderObject.onTap != onTap) {
|
||||
renderObject.onTap = onTap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _TmpGestureArenaMember extends GestureArenaMember {
|
||||
_TmpGestureArenaMember({required this.onTap});
|
||||
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
void acceptGesture(int key) {
|
||||
onTap();
|
||||
}
|
||||
|
||||
@override
|
||||
void rejectGesture(int key) {}
|
||||
}
|
||||
|
||||
class _ExpandTapRenderBox extends RenderBox
|
||||
with RenderObjectWithChildMixin<RenderBox> {
|
||||
_ExpandTapRenderBox({
|
||||
required VoidCallback onTap,
|
||||
required EdgeInsets tapPadding,
|
||||
}) : _onTap = onTap,
|
||||
_tapPadding = tapPadding;
|
||||
|
||||
VoidCallback _onTap;
|
||||
EdgeInsets _tapPadding;
|
||||
|
||||
set onTap(VoidCallback value) {
|
||||
if (_onTap != value) {
|
||||
_onTap = value;
|
||||
}
|
||||
}
|
||||
|
||||
set tapPadding(EdgeInsets value) {
|
||||
if (_tapPadding == value) return;
|
||||
_tapPadding = value;
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
EdgeInsets get tapPadding => _tapPadding;
|
||||
|
||||
VoidCallback get onTap => _onTap;
|
||||
|
||||
@override
|
||||
void performLayout() {
|
||||
child!.layout(constraints, parentUsesSize: true);
|
||||
size = child!.size;
|
||||
if (size.isEmpty) {
|
||||
_tapPadding = EdgeInsets.zero;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
if (child != null) {
|
||||
final BoxParentData childParentData = child!.parentData! as BoxParentData;
|
||||
context.paintChild(child!, childParentData.offset + offset);
|
||||
}
|
||||
assert(() {
|
||||
debugPaintExpandArea(context, offset);
|
||||
return true;
|
||||
}());
|
||||
}
|
||||
|
||||
void debugPaintExpandArea(PaintingContext context, Offset offset) {
|
||||
if (size.isEmpty) return;
|
||||
|
||||
final RenderBox parentBox = parent as RenderBox;
|
||||
|
||||
Offset parentPosition = Offset.zero;
|
||||
parentPosition = offset - localToGlobal(Offset.zero, ancestor: parentBox);
|
||||
|
||||
final Size parentSize = parentBox.size;
|
||||
final Rect parentRect = Rect.fromLTWH(
|
||||
parentPosition.dx,
|
||||
parentPosition.dy,
|
||||
parentSize.width,
|
||||
parentSize.height,
|
||||
);
|
||||
final BoxParentData childParentData = child!.parentData! as BoxParentData;
|
||||
final Offset paintOffset =
|
||||
childParentData.offset + offset - tapPadding.topLeft;
|
||||
final Rect paintRect = Rect.fromLTWH(
|
||||
paintOffset.dx,
|
||||
paintOffset.dy,
|
||||
size.width + tapPadding.horizontal,
|
||||
size.height + tapPadding.vertical,
|
||||
);
|
||||
final Paint paint =
|
||||
Paint()
|
||||
..style = PaintingStyle.fill
|
||||
..strokeWidth = 1.0
|
||||
..color = debugPaintExpandAreaColor;
|
||||
|
||||
final Paint paint2 =
|
||||
Paint()
|
||||
..style = PaintingStyle.fill
|
||||
..strokeWidth = 1.0
|
||||
..color = debugPaintClipAreaColor;
|
||||
context.canvas.drawRect(paintRect, paint);
|
||||
context.canvas.drawRect(paintRect.intersect(parentRect), paint2);
|
||||
}
|
||||
|
||||
@override
|
||||
void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
|
||||
if (event is PointerDownEvent) {
|
||||
final _TmpGestureArenaMember member = _TmpGestureArenaMember(
|
||||
onTap: onTap,
|
||||
);
|
||||
GestureBinding.instance.gestureArena.add(event.pointer, member);
|
||||
} else if (event is PointerUpEvent) {
|
||||
GestureBinding.instance.gestureArena.sweep(event.pointer);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool hitTestSelf(Offset position) => true;
|
||||
|
||||
@override
|
||||
bool hitTestChildren(BoxHitTestResult result, {Offset? position}) {
|
||||
visitChildren((child) {
|
||||
if (child is RenderBox) {
|
||||
final BoxParentData parentData = child.parentData! as BoxParentData;
|
||||
if (child.hitTest(result, position: position! - parentData.offset)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
bool hitTest(BoxHitTestResult result, {Offset? position}) {
|
||||
final Rect expandRect = Rect.fromLTWH(
|
||||
0 - tapPadding.left,
|
||||
0 - tapPadding.top,
|
||||
size.width + tapPadding.right + tapPadding.left,
|
||||
size.height + tapPadding.top + tapPadding.bottom,
|
||||
);
|
||||
if (expandRect.contains(position!)) {
|
||||
final bool hitTarget =
|
||||
hitTestChildren(result, position: position) || hitTestSelf(position);
|
||||
if (hitTarget) {
|
||||
result.add(BoxHitTestEntry(this, position));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
321
lib/components/base/image.dart
Normal file
321
lib/components/base/image.dart
Normal file
@@ -0,0 +1,321 @@
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:moodiary/utils/cache_util.dart';
|
||||
|
||||
final kTransparentImage = Uint8List.fromList(<int>[
|
||||
0x89,
|
||||
0x50,
|
||||
0x4E,
|
||||
0x47,
|
||||
0x0D,
|
||||
0x0A,
|
||||
0x1A,
|
||||
0x0A,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x0D,
|
||||
0x49,
|
||||
0x48,
|
||||
0x44,
|
||||
0x52,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
0x08,
|
||||
0x06,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x1F,
|
||||
0x15,
|
||||
0xC4,
|
||||
0x89,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x0A,
|
||||
0x49,
|
||||
0x44,
|
||||
0x41,
|
||||
0x54,
|
||||
0x78,
|
||||
0x9C,
|
||||
0x63,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
0x05,
|
||||
0x00,
|
||||
0x01,
|
||||
0x0D,
|
||||
0x0A,
|
||||
0x2D,
|
||||
0xB4,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x49,
|
||||
0x45,
|
||||
0x4E,
|
||||
0x44,
|
||||
0xAE,
|
||||
0x42,
|
||||
0x60,
|
||||
0x82,
|
||||
]);
|
||||
|
||||
enum _ImageLoadState { loading, error, success }
|
||||
|
||||
class _ImageState {
|
||||
final int width;
|
||||
final int height;
|
||||
final String path;
|
||||
final double aspectRatio;
|
||||
|
||||
_ImageState({
|
||||
required this.width,
|
||||
required this.height,
|
||||
required this.path,
|
||||
required this.aspectRatio,
|
||||
});
|
||||
}
|
||||
|
||||
class MoodiaryImage extends StatefulWidget {
|
||||
final String imagePath;
|
||||
final int size;
|
||||
final BoxFit? fit;
|
||||
final VoidCallback? onTap;
|
||||
final String? heroTag;
|
||||
final BorderRadius? borderRadius;
|
||||
final bool showBorder;
|
||||
final EdgeInsets? padding;
|
||||
|
||||
const MoodiaryImage({
|
||||
super.key,
|
||||
required this.imagePath,
|
||||
required this.size,
|
||||
this.fit,
|
||||
this.onTap,
|
||||
this.heroTag,
|
||||
this.borderRadius,
|
||||
this.showBorder = false,
|
||||
this.padding,
|
||||
});
|
||||
|
||||
@override
|
||||
State<MoodiaryImage> createState() => _MoodiaryImageState();
|
||||
}
|
||||
|
||||
class _MoodiaryImageState extends State<MoodiaryImage> {
|
||||
final Rx<_ImageLoadState> _loadState = Rx<_ImageLoadState>(
|
||||
_ImageLoadState.loading,
|
||||
);
|
||||
|
||||
late _ImageState _imageState;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadImage();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_loadState.close();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant MoodiaryImage oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.imagePath != oldWidget.imagePath ||
|
||||
widget.size != oldWidget.size) {
|
||||
_loadImage();
|
||||
}
|
||||
}
|
||||
|
||||
void _loadImage() async {
|
||||
_loadState.value = _ImageLoadState.loading;
|
||||
try {
|
||||
//logger.d('Image loaded from path: ${widget.imagePath}');
|
||||
final imageAspect = await ImageCacheUtil().getImageAspectRatioWithCache(
|
||||
imagePath: widget.imagePath,
|
||||
);
|
||||
|
||||
final imageSize = widget.size;
|
||||
final width =
|
||||
imageAspect < 1.0 ? imageSize : (imageSize * imageAspect).ceil();
|
||||
final height =
|
||||
imageAspect >= 1.0 ? imageSize : (imageSize / imageAspect).ceil();
|
||||
|
||||
final path = await ImageCacheUtil().getLocalImagePathWithCache(
|
||||
imagePath: widget.imagePath,
|
||||
imageWidth: width * 2,
|
||||
imageHeight: height * 2,
|
||||
imageAspectRatio: imageAspect,
|
||||
);
|
||||
|
||||
_imageState = _ImageState(
|
||||
width: width,
|
||||
height: height,
|
||||
path: path,
|
||||
aspectRatio: imageAspect,
|
||||
);
|
||||
|
||||
_loadState.value = _ImageLoadState.success;
|
||||
} catch (e) {
|
||||
_loadState.value = _ImageLoadState.error;
|
||||
}
|
||||
}
|
||||
|
||||
BorderRadius _shrinkBorderRadius(BorderRadius radius, double amount) {
|
||||
return BorderRadius.only(
|
||||
topLeft: Radius.elliptical(
|
||||
(radius.topLeft.x - amount).clamp(0, double.infinity),
|
||||
(radius.topLeft.y - amount).clamp(0, double.infinity),
|
||||
),
|
||||
topRight: Radius.elliptical(
|
||||
(radius.topRight.x - amount).clamp(0, double.infinity),
|
||||
(radius.topRight.y - amount).clamp(0, double.infinity),
|
||||
),
|
||||
bottomLeft: Radius.elliptical(
|
||||
(radius.bottomLeft.x - amount).clamp(0, double.infinity),
|
||||
(radius.bottomLeft.y - amount).clamp(0, double.infinity),
|
||||
),
|
||||
bottomRight: Radius.elliptical(
|
||||
(radius.bottomRight.x - amount).clamp(0, double.infinity),
|
||||
(radius.bottomRight.y - amount).clamp(0, double.infinity),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const borderWidth = 1.0;
|
||||
|
||||
final outerRadius = widget.borderRadius ?? BorderRadius.zero;
|
||||
final innerRadius =
|
||||
widget.showBorder
|
||||
? _shrinkBorderRadius(outerRadius, borderWidth)
|
||||
: outerRadius;
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: outerRadius,
|
||||
border:
|
||||
widget.showBorder
|
||||
? Border.all(
|
||||
color: context.theme.colorScheme.outline.withValues(
|
||||
alpha: 0.6,
|
||||
),
|
||||
width: borderWidth,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
margin: widget.padding,
|
||||
child: ClipRRect(
|
||||
borderRadius: innerRadius,
|
||||
child: AnimatedSwitcher(
|
||||
duration: Durations.short3,
|
||||
switchInCurve: Curves.easeOut,
|
||||
switchOutCurve: Curves.easeIn,
|
||||
child: Obx(() {
|
||||
switch (_loadState.value) {
|
||||
case _ImageLoadState.loading:
|
||||
return const _LoadingPlaceholder(key: ValueKey('loading'));
|
||||
case _ImageLoadState.error:
|
||||
return const _ErrorPlaceholder(key: ValueKey('error'));
|
||||
case _ImageLoadState.success:
|
||||
final imagePath = _imageState.path;
|
||||
final width = _imageState.width;
|
||||
final height = _imageState.height;
|
||||
|
||||
return GestureDetector(
|
||||
key: const ValueKey('image'),
|
||||
onTap:
|
||||
widget.onTap != null
|
||||
? () async {
|
||||
if (widget.heroTag != null) {
|
||||
await precacheImage(
|
||||
FileImage(File(widget.imagePath)),
|
||||
context,
|
||||
);
|
||||
}
|
||||
widget.onTap?.call();
|
||||
}
|
||||
: null,
|
||||
behavior: HitTestBehavior.translucent,
|
||||
child: HeroMode(
|
||||
enabled: widget.heroTag != null,
|
||||
child: Hero(
|
||||
tag: widget.heroTag ?? '',
|
||||
child: FadeInImage(
|
||||
key: ValueKey(imagePath),
|
||||
image: FileImage(File(imagePath)),
|
||||
placeholder: MemoryImage(kTransparentImage),
|
||||
fadeInDuration: Durations.short2,
|
||||
fadeOutDuration: Durations.short1,
|
||||
fit: widget.fit ?? BoxFit.cover,
|
||||
width: width.toDouble(),
|
||||
height: height.toDouble(),
|
||||
imageErrorBuilder: (_, __, ___) {
|
||||
return const _ErrorPlaceholder(
|
||||
key: ValueKey('image_error'),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ErrorPlaceholder extends StatelessWidget {
|
||||
const _ErrorPlaceholder({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ColoredBox(
|
||||
color: context.theme.colorScheme.errorContainer,
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.error_rounded,
|
||||
color: context.theme.colorScheme.onErrorContainer,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _LoadingPlaceholder extends StatelessWidget {
|
||||
const _LoadingPlaceholder({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ColoredBox(
|
||||
color: context.theme.colorScheme.surfaceContainer,
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.image_search_rounded,
|
||||
color: context.theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
64
lib/components/base/loading.dart
Normal file
64
lib/components/base/loading.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MoodiaryLoading extends StatelessWidget {
|
||||
const MoodiaryLoading({super.key, this.size = 24, this.color});
|
||||
|
||||
final double size;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(child: CircularProgressIndicator(color: color));
|
||||
}
|
||||
}
|
||||
|
||||
class MoodiarySyncing extends StatefulWidget {
|
||||
const MoodiarySyncing({super.key});
|
||||
|
||||
@override
|
||||
State<MoodiarySyncing> createState() => _MoodiarySyncingState();
|
||||
}
|
||||
|
||||
class _MoodiarySyncingState extends State<MoodiarySyncing>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
late Animation<double> _animation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(seconds: 2),
|
||||
)..repeat();
|
||||
|
||||
_animation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.elasticInOut,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: AnimatedBuilder(
|
||||
animation: _animation,
|
||||
builder: (context, child) {
|
||||
return Transform.rotate(
|
||||
angle: _animation.value * 2 * pi,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: const Icon(Icons.sync_rounded),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
301
lib/components/base/marquee.dart
Normal file
301
lib/components/base/marquee.dart
Normal file
@@ -0,0 +1,301 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class IntegralCurve extends Curve {
|
||||
static double delta = 0.01;
|
||||
|
||||
const IntegralCurve._(this.original, this.integral, this._values);
|
||||
|
||||
final Curve original;
|
||||
final double integral;
|
||||
final Map<double, double> _values;
|
||||
|
||||
factory IntegralCurve(Curve original) {
|
||||
double integral = 0.0;
|
||||
final values = <double, double>{};
|
||||
|
||||
for (double t = 0.0; t <= 1.0; t += delta) {
|
||||
integral += original.transform(t) * delta;
|
||||
values[t] = integral;
|
||||
}
|
||||
values[1.0] = integral;
|
||||
|
||||
// Normalize.
|
||||
for (final double t in values.keys) {
|
||||
values[t] = values[t]! / integral;
|
||||
}
|
||||
|
||||
return IntegralCurve._(original, integral, values);
|
||||
}
|
||||
|
||||
@override
|
||||
double transform(double t) {
|
||||
if (t < 0) return 0.0;
|
||||
for (final key in _values.keys) {
|
||||
if (key > t) return _values[key]!;
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
class Marquee extends StatefulWidget {
|
||||
Marquee({
|
||||
super.key,
|
||||
required this.text,
|
||||
this.style,
|
||||
this.textScaler,
|
||||
this.textDirection = TextDirection.ltr,
|
||||
this.scrollAxis = Axis.horizontal,
|
||||
this.crossAxisAlignment = CrossAxisAlignment.center,
|
||||
this.blankSpace = 0.0,
|
||||
this.velocity = 50.0,
|
||||
this.startAfter = Duration.zero,
|
||||
this.pauseAfterRound = Duration.zero,
|
||||
this.fadingEdgeStartFraction = 0.0,
|
||||
this.fadingEdgeEndFraction = 0.0,
|
||||
this.numberOfRounds,
|
||||
this.startPadding = 0.0,
|
||||
this.accelerationDuration = Duration.zero,
|
||||
Curve accelerationCurve = Curves.decelerate,
|
||||
this.decelerationDuration = Duration.zero,
|
||||
Curve decelerationCurve = Curves.decelerate,
|
||||
this.onDone,
|
||||
}) : assert(!blankSpace.isNaN),
|
||||
assert(blankSpace >= 0, "The blankSpace needs to be positive or zero."),
|
||||
assert(blankSpace.isFinite),
|
||||
assert(!velocity.isNaN),
|
||||
assert(velocity != 0.0, "The velocity cannot be zero."),
|
||||
assert(velocity.isFinite),
|
||||
assert(
|
||||
pauseAfterRound >= Duration.zero,
|
||||
"The pauseAfterRound cannot be negative as time travel isn't "
|
||||
"invented yet.",
|
||||
),
|
||||
assert(
|
||||
fadingEdgeStartFraction >= 0 && fadingEdgeStartFraction <= 1,
|
||||
"The fadingEdgeGradientFractionOnStart value should be between 0 and "
|
||||
"1, inclusive",
|
||||
),
|
||||
assert(
|
||||
fadingEdgeEndFraction >= 0 && fadingEdgeEndFraction <= 1,
|
||||
"The fadingEdgeGradientFractionOnEnd value should be between 0 and "
|
||||
"1, inclusive",
|
||||
),
|
||||
assert(numberOfRounds == null || numberOfRounds > 0),
|
||||
assert(
|
||||
accelerationDuration >= Duration.zero,
|
||||
"The accelerationDuration cannot be negative as time travel isn't "
|
||||
"invented yet.",
|
||||
),
|
||||
assert(
|
||||
decelerationDuration >= Duration.zero,
|
||||
"The decelerationDuration must be positive or zero as time travel "
|
||||
"isn't invented yet.",
|
||||
),
|
||||
accelerationCurve = IntegralCurve(accelerationCurve),
|
||||
decelerationCurve = IntegralCurve(decelerationCurve);
|
||||
final String text;
|
||||
final TextStyle? style;
|
||||
final TextScaler? textScaler;
|
||||
final TextDirection textDirection;
|
||||
final Axis scrollAxis;
|
||||
final CrossAxisAlignment crossAxisAlignment;
|
||||
final double blankSpace;
|
||||
final double velocity;
|
||||
final Duration startAfter;
|
||||
final Duration pauseAfterRound;
|
||||
final int? numberOfRounds;
|
||||
final double fadingEdgeStartFraction;
|
||||
final double fadingEdgeEndFraction;
|
||||
final double startPadding;
|
||||
final Duration accelerationDuration;
|
||||
final IntegralCurve accelerationCurve;
|
||||
final Duration decelerationDuration;
|
||||
final IntegralCurve decelerationCurve;
|
||||
final VoidCallback? onDone;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _MarqueeState();
|
||||
}
|
||||
|
||||
class _MarqueeState extends State<Marquee> with SingleTickerProviderStateMixin {
|
||||
final ScrollController _controller = ScrollController();
|
||||
|
||||
late double _startPosition;
|
||||
late double _accelerationTarget;
|
||||
late double _linearTarget;
|
||||
late double _decelerationTarget;
|
||||
|
||||
late Duration _totalDuration;
|
||||
|
||||
Duration get _accelerationDuration => widget.accelerationDuration;
|
||||
Duration? _linearDuration;
|
||||
|
||||
Duration get _decelerationDuration => widget.decelerationDuration;
|
||||
|
||||
bool _running = false;
|
||||
int _roundCounter = 0;
|
||||
|
||||
bool get isDone =>
|
||||
widget.numberOfRounds == null
|
||||
? false
|
||||
: widget.numberOfRounds == _roundCounter;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
if (!_running) {
|
||||
_running = true;
|
||||
if (_controller.hasClients) {
|
||||
_controller.jumpTo(_startPosition);
|
||||
await Future<void>.delayed(widget.startAfter);
|
||||
Future.doWhile(_scroll);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<bool> _scroll() async {
|
||||
await _makeRoundTrip();
|
||||
if (isDone && widget.onDone != null) {
|
||||
widget.onDone!();
|
||||
}
|
||||
return _running && !isDone && _controller.hasClients;
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(Widget oldWidget) {
|
||||
super.didUpdateWidget(oldWidget as Marquee);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_running = false;
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _initialize(BuildContext context) {
|
||||
final totalLength = _getTextWidth(context) + widget.blankSpace;
|
||||
final accelerationLength =
|
||||
widget.accelerationCurve.integral *
|
||||
widget.velocity *
|
||||
_accelerationDuration.inMilliseconds /
|
||||
1000.0;
|
||||
final decelerationLength =
|
||||
widget.decelerationCurve.integral *
|
||||
widget.velocity *
|
||||
_decelerationDuration.inMilliseconds /
|
||||
1000.0;
|
||||
final linearLength =
|
||||
(totalLength - accelerationLength.abs() - decelerationLength.abs()) *
|
||||
(widget.velocity > 0 ? 1 : -1);
|
||||
|
||||
_startPosition = 2 * totalLength - widget.startPadding;
|
||||
_accelerationTarget = _startPosition + accelerationLength;
|
||||
_linearTarget = _accelerationTarget + linearLength;
|
||||
_decelerationTarget = _linearTarget + decelerationLength;
|
||||
|
||||
_totalDuration =
|
||||
_accelerationDuration +
|
||||
_decelerationDuration +
|
||||
Duration(milliseconds: (linearLength / widget.velocity * 1000).toInt());
|
||||
_linearDuration =
|
||||
_totalDuration - _accelerationDuration - _decelerationDuration;
|
||||
}
|
||||
|
||||
Future<void> _makeRoundTrip() async {
|
||||
if (!_controller.hasClients) return;
|
||||
_controller.jumpTo(_startPosition);
|
||||
if (!_running) return;
|
||||
|
||||
await _accelerate();
|
||||
if (!_running) return;
|
||||
|
||||
await _moveLinearly();
|
||||
if (!_running) return;
|
||||
|
||||
await _decelerate();
|
||||
|
||||
_roundCounter++;
|
||||
|
||||
if (!_running || !mounted) return;
|
||||
}
|
||||
|
||||
Future<void> _accelerate() async {
|
||||
await _animateTo(
|
||||
_accelerationTarget,
|
||||
_accelerationDuration,
|
||||
widget.accelerationCurve,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _moveLinearly() async {
|
||||
await _animateTo(_linearTarget, _linearDuration, Curves.linear);
|
||||
}
|
||||
|
||||
Future<void> _decelerate() async {
|
||||
await _animateTo(
|
||||
_decelerationTarget,
|
||||
_decelerationDuration,
|
||||
widget.decelerationCurve.flipped,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _animateTo(
|
||||
double? target,
|
||||
Duration? duration,
|
||||
Curve curve,
|
||||
) async {
|
||||
if (!_controller.hasClients) return;
|
||||
if (duration! > Duration.zero) {
|
||||
await _controller.animateTo(target!, duration: duration, curve: curve);
|
||||
} else {
|
||||
_controller.jumpTo(target!);
|
||||
}
|
||||
}
|
||||
|
||||
double _getTextWidth(BuildContext context) {
|
||||
final span = TextSpan(text: widget.text, style: widget.style);
|
||||
const constraints = BoxConstraints(maxWidth: double.infinity);
|
||||
final richTextWidget = Text.rich(span).build(context) as RichText;
|
||||
final renderObject = richTextWidget.createRenderObject(context);
|
||||
renderObject.layout(constraints);
|
||||
final boxes = renderObject.getBoxesForSelection(
|
||||
TextSelection(
|
||||
baseOffset: 0,
|
||||
extentOffset: TextSpan(text: widget.text).toPlainText().length,
|
||||
),
|
||||
);
|
||||
return boxes.last.right;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_initialize(context);
|
||||
return ListView.builder(
|
||||
controller: _controller,
|
||||
scrollDirection: widget.scrollAxis,
|
||||
reverse: widget.textDirection == TextDirection.rtl,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (_, i) {
|
||||
return i.isEven
|
||||
? Text(
|
||||
widget.text,
|
||||
style: widget.style,
|
||||
textScaler: widget.textScaler,
|
||||
)
|
||||
: SizedBox(
|
||||
width:
|
||||
widget.scrollAxis == Axis.horizontal
|
||||
? widget.blankSpace
|
||||
: null,
|
||||
height:
|
||||
widget.scrollAxis == Axis.vertical ? widget.blankSpace : null,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
28
lib/components/base/modal.dart
Normal file
28
lib/components/base/modal.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class Modal extends StatelessWidget {
|
||||
final Animation<double> animation;
|
||||
final Function() onTap;
|
||||
|
||||
const Modal({super.key, required this.animation, required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: animation,
|
||||
builder: (context, child) {
|
||||
return Visibility(
|
||||
visible: animation.value > 0,
|
||||
child: ModalBarrier(
|
||||
color: context.theme.colorScheme.surfaceContainer.withValues(
|
||||
alpha: 0.6 * animation.value,
|
||||
),
|
||||
barrierSemanticsDismissible: false,
|
||||
onDismiss: onTap,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
64
lib/components/base/popup.dart
Normal file
64
lib/components/base/popup.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:moodiary/common/values/border.dart';
|
||||
|
||||
class _TrianglePainter extends CustomPainter {
|
||||
final Color color;
|
||||
|
||||
final Size size;
|
||||
|
||||
_TrianglePainter({required this.color, required this.size});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint =
|
||||
Paint()
|
||||
..color = color
|
||||
..style = PaintingStyle.fill;
|
||||
|
||||
final path =
|
||||
Path()
|
||||
..moveTo(0, size.height)
|
||||
..lineTo(size.width, size.height)
|
||||
..lineTo(size.width / 2, 0)
|
||||
..close();
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant _TrianglePainter oldDelegate) => false;
|
||||
}
|
||||
|
||||
void showPopupWidget({
|
||||
required BuildContext targetContext,
|
||||
required Widget child,
|
||||
}) {
|
||||
SmartDialog.showAttach(
|
||||
targetContext: targetContext,
|
||||
maskColor: Colors.transparent,
|
||||
builder: (context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CustomPaint(
|
||||
size: const Size(12, 6),
|
||||
painter: _TrianglePainter(
|
||||
color: context.theme.colorScheme.surfaceContainer,
|
||||
size: const Size(12, 6),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6.0),
|
||||
decoration: BoxDecoration(
|
||||
color: context.theme.colorScheme.surfaceContainer,
|
||||
borderRadius: AppBorderRadius.mediumBorderRadius,
|
||||
),
|
||||
child: child,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
134
lib/components/base/qr/qr_code.dart
Normal file
134
lib/components/base/qr/qr_code.dart
Normal file
@@ -0,0 +1,134 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:moodiary/utils/aes_util.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
|
||||
class EncryptQrCode extends StatefulWidget {
|
||||
final String data;
|
||||
final double size;
|
||||
final Duration validDuration;
|
||||
final String? prefix;
|
||||
|
||||
const EncryptQrCode({
|
||||
super.key,
|
||||
required this.data,
|
||||
this.size = 64,
|
||||
this.validDuration = const Duration(minutes: 2),
|
||||
this.prefix,
|
||||
});
|
||||
|
||||
@override
|
||||
State<EncryptQrCode> createState() => _EncryptQrCodeState();
|
||||
}
|
||||
|
||||
class _EncryptQrCodeState extends State<EncryptQrCode> {
|
||||
Uint8List? encryptedData;
|
||||
late int expireAt; // Unix 时间戳
|
||||
bool isExpired = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_encryptData();
|
||||
}
|
||||
|
||||
Future<void> _encryptData() async {
|
||||
final now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
expireAt = now + widget.validDuration.inSeconds;
|
||||
|
||||
final aesData = await AesUtil.encryptWithTimeWindow(
|
||||
data: '${widget.prefix}${widget.data}',
|
||||
validDuration: widget.validDuration,
|
||||
);
|
||||
|
||||
setState(() {
|
||||
isExpired = false;
|
||||
encryptedData = aesData;
|
||||
});
|
||||
|
||||
_startExpirationChecker();
|
||||
}
|
||||
|
||||
void _startExpirationChecker() {
|
||||
Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
final now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
if (now >= expireAt) {
|
||||
setState(() {
|
||||
isExpired = true;
|
||||
});
|
||||
timer.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildQrChild() {
|
||||
if (encryptedData == null) {
|
||||
return Center(
|
||||
key: const ValueKey('loading'),
|
||||
child: CircularProgressIndicator(
|
||||
color: context.theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (isExpired) {
|
||||
return GestureDetector(
|
||||
key: const ValueKey('expired'),
|
||||
onTap: _encryptData,
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.error_rounded,
|
||||
color: context.theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'已过期',
|
||||
style: context.textTheme.labelMedium?.copyWith(
|
||||
color: context.theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return QrImageView(
|
||||
key: const ValueKey('qr'),
|
||||
data: base64Encode(encryptedData!),
|
||||
size: widget.size,
|
||||
backgroundColor: Colors.transparent,
|
||||
dataModuleStyle: QrDataModuleStyle(
|
||||
color: context.theme.colorScheme.onSurface,
|
||||
dataModuleShape: QrDataModuleShape.circle,
|
||||
),
|
||||
eyeStyle: QrEyeStyle(
|
||||
color: context.theme.colorScheme.onSurface,
|
||||
eyeShape: QrEyeShape.circle,
|
||||
),
|
||||
gapless: false,
|
||||
padding: EdgeInsets.zero,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: widget.size,
|
||||
height: widget.size,
|
||||
child: AnimatedSwitcher(
|
||||
duration: Durations.medium2,
|
||||
switchInCurve: Curves.easeIn,
|
||||
switchOutCurve: Curves.easeOut,
|
||||
child: _buildQrChild(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
334
lib/components/base/qr/qr_scanner.dart
Normal file
334
lib/components/base/qr/qr_scanner.dart
Normal file
@@ -0,0 +1,334 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:dartx/dartx.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobile_scanner/mobile_scanner.dart';
|
||||
import 'package:moodiary/l10n/l10n.dart';
|
||||
import 'package:moodiary/router/app_pages.dart';
|
||||
import 'package:moodiary/utils/aes_util.dart';
|
||||
import 'package:moodiary/utils/log_util.dart';
|
||||
import 'package:moodiary/utils/notice_util.dart';
|
||||
import 'package:throttling/throttling.dart';
|
||||
|
||||
Future<String?> showQrScanner({
|
||||
required BuildContext context,
|
||||
Duration? validDuration,
|
||||
String? prefix,
|
||||
}) async {
|
||||
return Navigator.push<String?>(
|
||||
context,
|
||||
MoodiaryFadeInPageRoute(
|
||||
builder: (context) {
|
||||
return QrScanner(validDuration: validDuration, prefix: prefix);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class QrScanner extends StatefulWidget {
|
||||
final Duration? validDuration;
|
||||
|
||||
final String? prefix;
|
||||
|
||||
const QrScanner({super.key, this.validDuration, this.prefix});
|
||||
|
||||
@override
|
||||
State<QrScanner> createState() => _QrScannerState();
|
||||
}
|
||||
|
||||
class _QrScannerState extends State<QrScanner>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final AnimationController _animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: Durations.long4,
|
||||
)..repeat(reverse: true);
|
||||
|
||||
late final Animation<double> _curvedAnimation = CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
|
||||
late final MobileScannerController _scannerController =
|
||||
MobileScannerController(
|
||||
invertImage: true,
|
||||
autoStart: false,
|
||||
cameraResolution: const Size.square(640),
|
||||
formats: [BarcodeFormat.qrCode],
|
||||
);
|
||||
|
||||
late final Throttling _throttling = Throttling();
|
||||
|
||||
late final AppLifecycleListener _appLifecycleListener;
|
||||
|
||||
StreamSubscription<Object?>? _subscription;
|
||||
|
||||
late final ValueNotifier<TorchState> _torchState = ValueNotifier(
|
||||
TorchState.unavailable,
|
||||
);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_subscription = _scannerController.barcodes.listen(_handleBarcode);
|
||||
|
||||
_appLifecycleListener = AppLifecycleListener(
|
||||
onStateChange: (state) {
|
||||
if (!_scannerController.value.hasCameraPermission) {
|
||||
return;
|
||||
}
|
||||
switch (state) {
|
||||
case AppLifecycleState.detached:
|
||||
case AppLifecycleState.hidden:
|
||||
case AppLifecycleState.paused:
|
||||
return;
|
||||
case AppLifecycleState.resumed:
|
||||
_subscription = _scannerController.barcodes.listen(_handleBarcode);
|
||||
unawaited(_scannerController.start());
|
||||
case AppLifecycleState.inactive:
|
||||
unawaited(_subscription?.cancel());
|
||||
_subscription = null;
|
||||
unawaited(_scannerController.stop());
|
||||
}
|
||||
},
|
||||
);
|
||||
_scannerController.addListener(() {
|
||||
if (_scannerController.value.torchState != _torchState.value) {
|
||||
_torchState.value = _scannerController.value.torchState;
|
||||
}
|
||||
});
|
||||
unawaited(_scannerController.start());
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() async {
|
||||
unawaited(_subscription?.cancel());
|
||||
_subscription = null;
|
||||
_animationController.dispose();
|
||||
_throttling.close();
|
||||
_appLifecycleListener.dispose();
|
||||
super.dispose();
|
||||
await _scannerController.dispose();
|
||||
}
|
||||
|
||||
void _handleBarcode(BarcodeCapture value) {
|
||||
_throttling.throttle(() async {
|
||||
final raw = value.barcodes.firstOrNull?.rawValue;
|
||||
if (raw == null) return;
|
||||
|
||||
try {
|
||||
if (widget.validDuration != null) {
|
||||
final resBytes = base64Decode(raw);
|
||||
final decrypted = await AesUtil.decryptWithTimeWindow(
|
||||
encryptedData: resBytes,
|
||||
validDuration: widget.validDuration!,
|
||||
);
|
||||
if (decrypted.isNullOrBlank) {
|
||||
_handleInvalidQr();
|
||||
return;
|
||||
}
|
||||
if (widget.prefix.isNotNullOrBlank) {
|
||||
if (!decrypted!.startsWith(widget.prefix!)) {
|
||||
_handleInvalidQr();
|
||||
return;
|
||||
}
|
||||
final realData = decrypted.substring(widget.prefix!.length);
|
||||
if (mounted) Navigator.pop(context, realData);
|
||||
} else {
|
||||
if (mounted) Navigator.pop(context, decrypted);
|
||||
}
|
||||
} else {
|
||||
if (raw.isNullOrBlank) {
|
||||
_handleInvalidQr();
|
||||
} else {
|
||||
if (mounted) Navigator.pop(context, raw);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logger.d(e);
|
||||
_handleInvalidQr();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _handleInvalidQr() {
|
||||
if (mounted) {
|
||||
toast.info(message: context.l10n.qrCodeInvalid);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scanWindow = Rect.fromCenter(
|
||||
center: MediaQuery.sizeOf(context).center(Offset.zero),
|
||||
width: 200,
|
||||
height: 200,
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
leading: BackButton(
|
||||
color: Colors.white,
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
extendBodyBehindAppBar: true,
|
||||
body: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
MobileScanner(
|
||||
scanWindow: scanWindow,
|
||||
controller: _scannerController,
|
||||
overlayBuilder: (context, constraints) {
|
||||
return AnimatedBuilder(
|
||||
animation: _curvedAnimation,
|
||||
builder: (context, child) {
|
||||
return Stack(
|
||||
children: [
|
||||
CustomPaint(
|
||||
size: constraints.biggest,
|
||||
painter: _ScannerOverlayPainter(
|
||||
centerSize: _curvedAnimation.value * 20 + 200,
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: CustomPaint(
|
||||
size: Size.square(_curvedAnimation.value * 20 + 200),
|
||||
painter: _CornerBorderPainter(
|
||||
color: Colors.white,
|
||||
strokeWidth: 4,
|
||||
cornerLength: _curvedAnimation.value * 2 + 20,
|
||||
radius: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
Positioned(
|
||||
bottom: MediaQuery.sizeOf(context).height / 2 - 300,
|
||||
child: ValueListenableBuilder(
|
||||
valueListenable: _torchState,
|
||||
builder: (context, value, child) {
|
||||
if (value == TorchState.unavailable) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return IconButton(
|
||||
onPressed: () async {
|
||||
await _scannerController.toggleTorch();
|
||||
},
|
||||
iconSize: 56,
|
||||
icon: switch (_torchState.value) {
|
||||
TorchState.auto => const Icon(
|
||||
Icons.flash_auto_rounded,
|
||||
color: Colors.white,
|
||||
),
|
||||
TorchState.off => const Icon(
|
||||
Icons.flashlight_off_rounded,
|
||||
color: Colors.white54,
|
||||
),
|
||||
TorchState.on => const Icon(
|
||||
Icons.flashlight_on_rounded,
|
||||
color: Colors.white,
|
||||
),
|
||||
TorchState.unavailable => throw UnimplementedError(),
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _CornerBorderPainter extends CustomPainter {
|
||||
final Color color;
|
||||
final double strokeWidth;
|
||||
final double cornerLength;
|
||||
final double radius;
|
||||
|
||||
_CornerBorderPainter({
|
||||
required this.color,
|
||||
this.strokeWidth = 2,
|
||||
this.cornerLength = 20,
|
||||
this.radius = 0,
|
||||
});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint =
|
||||
Paint()
|
||||
..color = color
|
||||
..strokeWidth = strokeWidth
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeCap = StrokeCap.round;
|
||||
|
||||
final path = Path();
|
||||
|
||||
final double w = size.width;
|
||||
final double h = size.height;
|
||||
final r = radius;
|
||||
|
||||
path.moveTo(0, r + cornerLength);
|
||||
path.lineTo(0, r);
|
||||
path.quadraticBezierTo(0, 0, r, 0);
|
||||
path.lineTo(r + cornerLength, 0);
|
||||
|
||||
path.moveTo(w - r - cornerLength, 0);
|
||||
path.lineTo(w - r, 0);
|
||||
path.quadraticBezierTo(w, 0, w, r);
|
||||
path.lineTo(w, r + cornerLength);
|
||||
|
||||
path.moveTo(w, h - r - cornerLength);
|
||||
path.lineTo(w, h - r);
|
||||
path.quadraticBezierTo(w, h, w - r, h);
|
||||
path.lineTo(w - r - cornerLength, h);
|
||||
|
||||
path.moveTo(r + cornerLength, h);
|
||||
path.lineTo(r, h);
|
||||
path.quadraticBezierTo(0, h, 0, h - r);
|
||||
path.lineTo(0, h - r - cornerLength);
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
}
|
||||
|
||||
class _ScannerOverlayPainter extends CustomPainter {
|
||||
final double centerSize;
|
||||
|
||||
_ScannerOverlayPainter({required this.centerSize});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint =
|
||||
Paint()
|
||||
..color = Colors.black54
|
||||
..style = PaintingStyle.fill;
|
||||
|
||||
final outer = Path()..addRect(Rect.fromLTWH(0, 0, size.width, size.height));
|
||||
|
||||
final scanSize = centerSize;
|
||||
final left = (size.width - scanSize) / 2;
|
||||
final top = (size.height - scanSize) / 2;
|
||||
final scanRect = Rect.fromLTWH(left, top, scanSize, scanSize);
|
||||
|
||||
final hole = Path()..addRRect(RRect.fromRectXY(scanRect, 12, 12));
|
||||
final overlay = Path.combine(PathOperation.difference, outer, hole);
|
||||
|
||||
canvas.drawPath(overlay, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
}
|
||||
@@ -1,33 +1,40 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
|
||||
import 'package:mood_diary/common/values/border.dart';
|
||||
import 'package:moodiary/common/values/border.dart';
|
||||
|
||||
class FloatingModal extends StatelessWidget {
|
||||
final Widget child;
|
||||
final bool isScrollControlled;
|
||||
|
||||
const FloatingModal(
|
||||
{super.key, required this.child, required this.isScrollControlled});
|
||||
const FloatingModal({
|
||||
super.key,
|
||||
required this.child,
|
||||
required this.isScrollControlled,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
final padding = MediaQuery.viewInsetsOf(context);
|
||||
final size = MediaQuery.sizeOf(context);
|
||||
final maxHeight = isScrollControlled
|
||||
? size.height - (padding.top - padding.bottom)
|
||||
: size.height * 9.0 / 16.0;
|
||||
final maxHeight =
|
||||
isScrollControlled
|
||||
? size.height - (padding.top - padding.bottom)
|
||||
: size.height * 9.0 / 16.0;
|
||||
return Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: maxHeight, maxWidth: 640),
|
||||
constraints: BoxConstraints(maxHeight: maxHeight+padding.bottom, maxWidth: 640),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 16, right: 16, bottom: max(padding.bottom, 16)),
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: max(padding.bottom + 16, 16),
|
||||
),
|
||||
child: Material(
|
||||
color: colorScheme.surfaceContainerHigh,
|
||||
color: context.theme.colorScheme.surfaceContainerHigh,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
borderRadius: AppBorderRadius.largeBorderRadius,
|
||||
child: child,
|
||||
@@ -44,14 +51,14 @@ Future<T> showFloatingModalBottomSheet<T>({
|
||||
bool isScrollControlled = false,
|
||||
}) async {
|
||||
final result = await showCustomModalBottomSheet(
|
||||
context: context,
|
||||
builder: builder,
|
||||
enableDrag: isScrollControlled,
|
||||
containerWidget: (_, animation, child) => FloatingModal(
|
||||
isScrollControlled: isScrollControlled,
|
||||
child: child,
|
||||
),
|
||||
expand: false);
|
||||
context: context,
|
||||
builder: builder,
|
||||
enableDrag: isScrollControlled,
|
||||
containerWidget:
|
||||
(_, animation, child) =>
|
||||
FloatingModal(isScrollControlled: isScrollControlled, child: child),
|
||||
expand: false,
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ class Tab extends StatelessWidget implements PreferredSizeWidget {
|
||||
this.iconMargin,
|
||||
this.height,
|
||||
this.child,
|
||||
}) : assert(text != null || child != null || icon != null),
|
||||
assert(text == null || child == null);
|
||||
}) : assert(text != null || child != null || icon != null),
|
||||
assert(text == null || child == null);
|
||||
|
||||
/// The text to display as the tab's label.
|
||||
///
|
||||
@@ -93,17 +93,15 @@ class Tab extends StatelessWidget implements PreferredSizeWidget {
|
||||
label = icon!;
|
||||
} else {
|
||||
calculatedHeight = _kTextAndIconTabHeight;
|
||||
final EdgeInsetsGeometry effectiveIconMargin = iconMargin ??
|
||||
final EdgeInsetsGeometry effectiveIconMargin =
|
||||
iconMargin ??
|
||||
(Theme.of(context).useMaterial3
|
||||
? _TabsPrimaryDefaultsM3.iconMargin
|
||||
: _TabsDefaultsM2.iconMargin);
|
||||
label = Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: effectiveIconMargin,
|
||||
child: icon,
|
||||
),
|
||||
Padding(padding: effectiveIconMargin, child: icon),
|
||||
_buildLabelText(),
|
||||
],
|
||||
);
|
||||
@@ -111,10 +109,7 @@ class Tab extends StatelessWidget implements PreferredSizeWidget {
|
||||
|
||||
return SizedBox(
|
||||
height: height ?? calculatedHeight,
|
||||
child: Center(
|
||||
widthFactor: 1.0,
|
||||
child: label,
|
||||
),
|
||||
child: Center(widthFactor: 1.0, child: label),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -166,7 +161,8 @@ class _TabStyle extends AnimatedWidget {
|
||||
// labelStyle.color (and tabBarTheme.labelStyle.color) is not considered
|
||||
// as it'll be a breaking change without a possible migration plan. for
|
||||
// details: https://github.com/flutter/flutter/pull/109541#issuecomment-1294241417
|
||||
Color selectedColor = labelColor ??
|
||||
Color selectedColor =
|
||||
labelColor ??
|
||||
tabBarTheme.labelColor ??
|
||||
labelStyle?.color ??
|
||||
tabBarTheme.labelStyle?.color ??
|
||||
@@ -176,12 +172,14 @@ class _TabStyle extends AnimatedWidget {
|
||||
|
||||
if (selectedColor is WidgetStateColor) {
|
||||
unselectedColor = selectedColor.resolve(const <WidgetState>{});
|
||||
selectedColor =
|
||||
selectedColor.resolve(const <WidgetState>{WidgetState.selected});
|
||||
selectedColor = selectedColor.resolve(const <WidgetState>{
|
||||
WidgetState.selected,
|
||||
});
|
||||
} else {
|
||||
// unselectedLabelColor and tabBarTheme.unselectedLabelColor are ignored
|
||||
// when labelColor is a WidgetStateColor.
|
||||
unselectedColor = unselectedLabelColor ??
|
||||
unselectedColor =
|
||||
unselectedLabelColor ??
|
||||
tabBarTheme.unselectedLabelColor ??
|
||||
unselectedLabelStyle?.color ??
|
||||
tabBarTheme.unselectedLabelStyle?.color ??
|
||||
@@ -207,31 +205,40 @@ class _TabStyle extends AnimatedWidget {
|
||||
final TabBarThemeData tabBarTheme = TabBarTheme.of(context);
|
||||
final Animation<double> animation = listenable as Animation<double>;
|
||||
|
||||
final Set<WidgetState> states = isSelected
|
||||
? const <WidgetState>{WidgetState.selected}
|
||||
: const <WidgetState>{};
|
||||
final Set<WidgetState> states =
|
||||
isSelected
|
||||
? const <WidgetState>{WidgetState.selected}
|
||||
: const <WidgetState>{};
|
||||
|
||||
// Ensure both styles have inherit=true for proper lerp behavior.
|
||||
final TextStyle selectedStyle =
|
||||
(labelStyle ?? tabBarTheme.labelStyle ?? defaults.labelStyle!)
|
||||
.copyWith(inherit: true);
|
||||
final TextStyle selectedStyle = (labelStyle ??
|
||||
tabBarTheme.labelStyle ??
|
||||
defaults.labelStyle!)
|
||||
.copyWith(inherit: true);
|
||||
final TextStyle unselectedStyle = (unselectedLabelStyle ??
|
||||
tabBarTheme.unselectedLabelStyle ??
|
||||
labelStyle ??
|
||||
defaults.unselectedLabelStyle!)
|
||||
.copyWith(inherit: true);
|
||||
|
||||
final TextStyle textStyle = isSelected
|
||||
? TextStyle.lerp(selectedStyle, unselectedStyle, animation.value)!
|
||||
: TextStyle.lerp(unselectedStyle, selectedStyle, animation.value)!;
|
||||
final TextStyle textStyle =
|
||||
isSelected
|
||||
? TextStyle.lerp(selectedStyle, unselectedStyle, animation.value)!
|
||||
: TextStyle.lerp(unselectedStyle, selectedStyle, animation.value)!;
|
||||
final Color color = _resolveWithLabelColor(context).resolve(states);
|
||||
|
||||
// Calculate adjusted height based on isSelected state.
|
||||
double adjustedHeight(
|
||||
double fontSize, double? currentHeight, bool isSelected) {
|
||||
double effectiveHeight =
|
||||
double fontSize,
|
||||
double? currentHeight,
|
||||
bool isSelected,
|
||||
) {
|
||||
final double effectiveHeight =
|
||||
currentHeight ?? 1.0; // Default height is 1.0 if null.
|
||||
double actualLineHeight = fixPrecision(fontSize * effectiveHeight, 6);
|
||||
final double actualLineHeight = fixPrecision(
|
||||
fontSize * effectiveHeight,
|
||||
6,
|
||||
);
|
||||
double adjustedLineHeight;
|
||||
if (isSelected) {
|
||||
// Use ceil for selected state to round up.
|
||||
@@ -259,18 +266,19 @@ class _TabStyle extends AnimatedWidget {
|
||||
height: adjustedHeightValue, // Use adjusted height.
|
||||
),
|
||||
child: IconTheme.merge(
|
||||
data: IconThemeData(
|
||||
size: 24.0,
|
||||
color: color,
|
||||
),
|
||||
data: IconThemeData(size: 24.0, color: color),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
typedef _LayoutCallback = void Function(
|
||||
List<double> xOffsets, TextDirection textDirection, double width);
|
||||
typedef _LayoutCallback =
|
||||
void Function(
|
||||
List<double> xOffsets,
|
||||
TextDirection textDirection,
|
||||
double width,
|
||||
);
|
||||
|
||||
class _TabLabelBarRenderer extends RenderFlex {
|
||||
_TabLabelBarRenderer({
|
||||
@@ -321,11 +329,11 @@ class _TabLabelBar extends Flex {
|
||||
required this.onPerformLayout,
|
||||
required super.mainAxisSize,
|
||||
}) : super(
|
||||
direction: Axis.horizontal,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
verticalDirection: VerticalDirection.down,
|
||||
);
|
||||
direction: Axis.horizontal,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
verticalDirection: VerticalDirection.down,
|
||||
);
|
||||
|
||||
final _LayoutCallback onPerformLayout;
|
||||
|
||||
@@ -344,7 +352,9 @@ class _TabLabelBar extends Flex {
|
||||
|
||||
@override
|
||||
void updateRenderObject(
|
||||
BuildContext context, _TabLabelBarRenderer renderObject) {
|
||||
BuildContext context,
|
||||
_TabLabelBarRenderer renderObject,
|
||||
) {
|
||||
super.updateRenderObject(context, renderObject);
|
||||
renderObject.onPerformLayout = onPerformLayout;
|
||||
}
|
||||
@@ -367,10 +377,7 @@ double _indexChangeProgress(TabController controller) {
|
||||
}
|
||||
|
||||
class _DividerPainter extends CustomPainter {
|
||||
_DividerPainter({
|
||||
required this.dividerColor,
|
||||
required this.dividerHeight,
|
||||
});
|
||||
_DividerPainter({required this.dividerColor, required this.dividerHeight});
|
||||
|
||||
final Color dividerColor;
|
||||
final double dividerHeight;
|
||||
@@ -381,9 +388,10 @@ class _DividerPainter extends CustomPainter {
|
||||
return;
|
||||
}
|
||||
|
||||
final Paint paint = Paint()
|
||||
..color = dividerColor
|
||||
..strokeWidth = dividerHeight;
|
||||
final Paint paint =
|
||||
Paint()
|
||||
..color = dividerColor
|
||||
..strokeWidth = dividerHeight;
|
||||
|
||||
canvas.drawLine(
|
||||
Offset(0, size.height - (paint.strokeWidth / 2)),
|
||||
@@ -488,13 +496,13 @@ class _IndicatorPainter extends CustomPainter {
|
||||
double tabLeft, tabRight;
|
||||
(tabLeft, tabRight) = switch (_currentTextDirection!) {
|
||||
TextDirection.rtl => (
|
||||
_currentTabOffsets![tabIndex + 1],
|
||||
_currentTabOffsets![tabIndex]
|
||||
),
|
||||
_currentTabOffsets![tabIndex + 1],
|
||||
_currentTabOffsets![tabIndex],
|
||||
),
|
||||
TextDirection.ltr => (
|
||||
_currentTabOffsets![tabIndex],
|
||||
_currentTabOffsets![tabIndex + 1]
|
||||
),
|
||||
_currentTabOffsets![tabIndex],
|
||||
_currentTabOffsets![tabIndex + 1],
|
||||
),
|
||||
};
|
||||
|
||||
if (indicatorSize == TabBarIndicatorSize.label) {
|
||||
@@ -508,8 +516,12 @@ class _IndicatorPainter extends CustomPainter {
|
||||
}
|
||||
|
||||
final EdgeInsets insets = indicatorPadding.resolve(_currentTextDirection);
|
||||
final Rect rect =
|
||||
Rect.fromLTWH(tabLeft, 0.0, tabRight - tabLeft, tabBarSize.height);
|
||||
final Rect rect = Rect.fromLTWH(
|
||||
tabLeft,
|
||||
0.0,
|
||||
tabRight - tabLeft,
|
||||
tabBarSize.height,
|
||||
);
|
||||
|
||||
if (!(rect.size >= insets.collapsedSize)) {
|
||||
throw FlutterError(
|
||||
@@ -536,8 +548,10 @@ class _IndicatorPainter extends CustomPainter {
|
||||
|
||||
_currentRect = switch (indicatorAnimation) {
|
||||
TabIndicatorAnimation.linear => _currentRect,
|
||||
TabIndicatorAnimation.elastic =>
|
||||
_applyElasticEffect(_currentRect!, fromRect),
|
||||
TabIndicatorAnimation.elastic => _applyElasticEffect(
|
||||
_currentRect!,
|
||||
fromRect,
|
||||
),
|
||||
};
|
||||
|
||||
assert(_currentRect != null);
|
||||
@@ -548,13 +562,18 @@ class _IndicatorPainter extends CustomPainter {
|
||||
devicePixelRatio: devicePixelRatio,
|
||||
);
|
||||
if (showDivider && dividerHeight! > 0) {
|
||||
final Paint dividerPaint = Paint()
|
||||
..color = dividerColor!
|
||||
..strokeWidth = dividerHeight!;
|
||||
final Offset dividerP1 =
|
||||
Offset(0, size.height - (dividerPaint.strokeWidth / 2));
|
||||
final Offset dividerP2 =
|
||||
Offset(size.width, size.height - (dividerPaint.strokeWidth / 2));
|
||||
final Paint dividerPaint =
|
||||
Paint()
|
||||
..color = dividerColor!
|
||||
..strokeWidth = dividerHeight!;
|
||||
final Offset dividerP1 = Offset(
|
||||
0,
|
||||
size.height - (dividerPaint.strokeWidth / 2),
|
||||
);
|
||||
final Offset dividerP2 = Offset(
|
||||
size.width,
|
||||
size.height - (dividerPaint.strokeWidth / 2),
|
||||
);
|
||||
canvas.drawLine(dividerP1, dividerP2, dividerPaint);
|
||||
}
|
||||
_painter!.paint(canvas, _currentRect!.topLeft, configuration);
|
||||
@@ -593,8 +612,11 @@ class _IndicatorPainter extends CustomPainter {
|
||||
false => decelerateInterpolation(tabChangeProgress),
|
||||
};
|
||||
|
||||
final Rect stretchedRect =
|
||||
_inflateRectHorizontally(rect, targetRect, fraction);
|
||||
final Rect stretchedRect = _inflateRectHorizontally(
|
||||
rect,
|
||||
targetRect,
|
||||
fraction,
|
||||
);
|
||||
return stretchedRect;
|
||||
}
|
||||
|
||||
@@ -674,8 +696,11 @@ class _DragAnimation extends Animation<double>
|
||||
double get value {
|
||||
assert(!controller.indexIsChanging);
|
||||
final double controllerMaxValue = (controller.length - 1).toDouble();
|
||||
final double controllerValue =
|
||||
clampDouble(controller.animation!.value, 0.0, controllerMaxValue);
|
||||
final double controllerValue = clampDouble(
|
||||
controller.animation!.value,
|
||||
0.0,
|
||||
controllerMaxValue,
|
||||
);
|
||||
return clampDouble((controllerValue - index.toDouble()).abs(), 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
@@ -690,9 +715,7 @@ class _TabBarScrollPosition extends ScrollPositionWithSingleContext {
|
||||
required super.context,
|
||||
required super.oldPosition,
|
||||
required this.tabBar,
|
||||
}) : super(
|
||||
initialPixels: null,
|
||||
);
|
||||
}) : super(initialPixels: null);
|
||||
|
||||
final _TabBarState tabBar;
|
||||
|
||||
@@ -715,8 +738,13 @@ class _TabBarScrollPosition extends ScrollPositionWithSingleContext {
|
||||
// guard because the super call below would start a ballistic scroll activity.
|
||||
if (!_viewportDimensionWasNonZero || _needsPixelsCorrection) {
|
||||
_needsPixelsCorrection = false;
|
||||
correctPixels(tabBar._initialScrollOffset(
|
||||
viewportDimension, minScrollExtent, maxScrollExtent));
|
||||
correctPixels(
|
||||
tabBar._initialScrollOffset(
|
||||
viewportDimension,
|
||||
minScrollExtent,
|
||||
maxScrollExtent,
|
||||
),
|
||||
);
|
||||
result = false;
|
||||
}
|
||||
return super.applyContentDimensions(minScrollExtent, maxScrollExtent) &&
|
||||
@@ -736,8 +764,11 @@ class _TabBarScrollController extends ScrollController {
|
||||
final _TabBarState tabBar;
|
||||
|
||||
@override
|
||||
ScrollPosition createScrollPosition(ScrollPhysics physics,
|
||||
ScrollContext context, ScrollPosition? oldPosition) {
|
||||
ScrollPosition createScrollPosition(
|
||||
ScrollPhysics physics,
|
||||
ScrollContext context,
|
||||
ScrollPosition? oldPosition,
|
||||
) {
|
||||
return _TabBarScrollPosition(
|
||||
physics: physics,
|
||||
context: context,
|
||||
@@ -841,8 +872,8 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
this.tabAlignment,
|
||||
this.textScaler,
|
||||
this.indicatorAnimation,
|
||||
}) : _isPrimary = true,
|
||||
assert(indicator != null || (indicatorWeight > 0.0));
|
||||
}) : _isPrimary = true,
|
||||
assert(indicator != null || (indicatorWeight > 0.0));
|
||||
|
||||
/// Creates a Material Design secondary tab bar.
|
||||
///
|
||||
@@ -894,8 +925,8 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
this.tabAlignment,
|
||||
this.textScaler,
|
||||
this.indicatorAnimation,
|
||||
}) : _isPrimary = false,
|
||||
assert(indicator != null || (indicatorWeight > 0.0));
|
||||
}) : _isPrimary = false,
|
||||
assert(indicator != null || (indicatorWeight > 0.0));
|
||||
|
||||
/// Typically a list of two or more [Tab] widgets.
|
||||
///
|
||||
@@ -1315,8 +1346,10 @@ class _TabBarState extends State<TabBar> {
|
||||
// the width of tab widget i. See _IndicatorPainter.indicatorRect().
|
||||
_tabKeys = widget.tabs.map((Widget tab) => GlobalKey()).toList();
|
||||
_labelPaddings = List<EdgeInsetsGeometry>.filled(
|
||||
widget.tabs.length, EdgeInsets.zero,
|
||||
growable: true);
|
||||
widget.tabs.length,
|
||||
EdgeInsets.zero,
|
||||
growable: true,
|
||||
);
|
||||
}
|
||||
|
||||
TabBarThemeData get _defaults {
|
||||
@@ -1340,7 +1373,8 @@ class _TabBarState extends State<TabBar> {
|
||||
return tabBarTheme.indicator!;
|
||||
}
|
||||
|
||||
Color color = widget.indicatorColor ??
|
||||
Color color =
|
||||
widget.indicatorColor ??
|
||||
tabBarTheme.indicatorColor ??
|
||||
_defaults.indicatorColor!;
|
||||
// ThemeData tries to avoid this by having indicatorColor avoid being the
|
||||
@@ -1362,15 +1396,13 @@ class _TabBarState extends State<TabBar> {
|
||||
color = Colors.white;
|
||||
}
|
||||
|
||||
final double effectiveIndicatorWeight = theme.useMaterial3
|
||||
? math.max(
|
||||
widget.indicatorWeight,
|
||||
switch (widget._isPrimary) {
|
||||
final double effectiveIndicatorWeight =
|
||||
theme.useMaterial3
|
||||
? math.max(widget.indicatorWeight, switch (widget._isPrimary) {
|
||||
true => _TabsPrimaryDefaultsM3.indicatorWeight(indicatorSize),
|
||||
false => _TabsSecondaryDefaultsM3.indicatorWeight,
|
||||
},
|
||||
)
|
||||
: widget.indicatorWeight;
|
||||
})
|
||||
: widget.indicatorWeight;
|
||||
// Only Material 3 primary TabBar with label indicatorSize should be rounded.
|
||||
final bool primaryWithLabelIndicator = switch (indicatorSize) {
|
||||
TabBarIndicatorSize.label => widget._isPrimary,
|
||||
@@ -1379,9 +1411,9 @@ class _TabBarState extends State<TabBar> {
|
||||
final BorderRadius? effectiveBorderRadius =
|
||||
theme.useMaterial3 && primaryWithLabelIndicator
|
||||
? BorderRadius.only(
|
||||
topLeft: Radius.circular(effectiveIndicatorWeight),
|
||||
topRight: Radius.circular(effectiveIndicatorWeight),
|
||||
)
|
||||
topLeft: Radius.circular(effectiveIndicatorWeight),
|
||||
topRight: Radius.circular(effectiveIndicatorWeight),
|
||||
)
|
||||
: null;
|
||||
return UnderlineTabIndicator(
|
||||
borderRadius: effectiveBorderRadius,
|
||||
@@ -1436,7 +1468,8 @@ class _TabBarState extends State<TabBar> {
|
||||
void _initIndicatorPainter() {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final TabBarThemeData tabBarTheme = TabBarTheme.of(context);
|
||||
final TabBarIndicatorSize indicatorSize = widget.indicatorSize ??
|
||||
final TabBarIndicatorSize indicatorSize =
|
||||
widget.indicatorSize ??
|
||||
tabBarTheme.indicatorSize ??
|
||||
_defaults.indicatorSize!;
|
||||
|
||||
@@ -1444,33 +1477,37 @@ class _TabBarState extends State<TabBar> {
|
||||
|
||||
final TabIndicatorAnimation defaultTabIndicatorAnimation =
|
||||
switch (indicatorSize) {
|
||||
TabBarIndicatorSize.label => TabIndicatorAnimation.elastic,
|
||||
TabBarIndicatorSize.tab => TabIndicatorAnimation.linear,
|
||||
};
|
||||
TabBarIndicatorSize.label => TabIndicatorAnimation.elastic,
|
||||
TabBarIndicatorSize.tab => TabIndicatorAnimation.linear,
|
||||
};
|
||||
|
||||
_indicatorPainter = !_controllerIsValid
|
||||
? null
|
||||
: _IndicatorPainter(
|
||||
controller: _controller!,
|
||||
indicator: _getIndicator(indicatorSize),
|
||||
indicatorSize: indicatorSize,
|
||||
indicatorPadding: widget.indicatorPadding,
|
||||
tabKeys: _tabKeys,
|
||||
// Passing old painter so that the constructor can copy some values from it.
|
||||
old: oldPainter,
|
||||
labelPaddings: _labelPaddings,
|
||||
dividerColor: widget.dividerColor ??
|
||||
tabBarTheme.dividerColor ??
|
||||
_defaults.dividerColor,
|
||||
dividerHeight: widget.dividerHeight ??
|
||||
tabBarTheme.dividerHeight ??
|
||||
_defaults.dividerHeight,
|
||||
showDivider: theme.useMaterial3 && !widget.isScrollable,
|
||||
devicePixelRatio: MediaQuery.devicePixelRatioOf(context),
|
||||
indicatorAnimation: widget.indicatorAnimation ??
|
||||
tabBarTheme.indicatorAnimation ??
|
||||
defaultTabIndicatorAnimation,
|
||||
);
|
||||
_indicatorPainter =
|
||||
!_controllerIsValid
|
||||
? null
|
||||
: _IndicatorPainter(
|
||||
controller: _controller!,
|
||||
indicator: _getIndicator(indicatorSize),
|
||||
indicatorSize: indicatorSize,
|
||||
indicatorPadding: widget.indicatorPadding,
|
||||
tabKeys: _tabKeys,
|
||||
// Passing old painter so that the constructor can copy some values from it.
|
||||
old: oldPainter,
|
||||
labelPaddings: _labelPaddings,
|
||||
dividerColor:
|
||||
widget.dividerColor ??
|
||||
tabBarTheme.dividerColor ??
|
||||
_defaults.dividerColor,
|
||||
dividerHeight:
|
||||
widget.dividerHeight ??
|
||||
tabBarTheme.dividerHeight ??
|
||||
_defaults.dividerHeight,
|
||||
showDivider: theme.useMaterial3 && !widget.isScrollable,
|
||||
devicePixelRatio: MediaQuery.devicePixelRatioOf(context),
|
||||
indicatorAnimation:
|
||||
widget.indicatorAnimation ??
|
||||
tabBarTheme.indicatorAnimation ??
|
||||
defaultTabIndicatorAnimation,
|
||||
);
|
||||
|
||||
oldPainter?.dispose();
|
||||
}
|
||||
@@ -1510,8 +1547,9 @@ class _TabBarState extends State<TabBar> {
|
||||
if (widget.tabs.length > _tabKeys.length) {
|
||||
final int delta = widget.tabs.length - _tabKeys.length;
|
||||
_tabKeys.addAll(List<GlobalKey>.generate(delta, (int n) => GlobalKey()));
|
||||
_labelPaddings
|
||||
.addAll(List<EdgeInsetsGeometry>.filled(delta, EdgeInsets.zero));
|
||||
_labelPaddings.addAll(
|
||||
List<EdgeInsetsGeometry>.filled(delta, EdgeInsets.zero),
|
||||
);
|
||||
} else if (widget.tabs.length < _tabKeys.length) {
|
||||
_tabKeys.removeRange(widget.tabs.length, _tabKeys.length);
|
||||
_labelPaddings.removeRange(widget.tabs.length, _tabKeys.length);
|
||||
@@ -1534,7 +1572,11 @@ class _TabBarState extends State<TabBar> {
|
||||
int get maxTabIndex => _indicatorPainter!.maxTabIndex;
|
||||
|
||||
double _tabScrollOffset(
|
||||
int index, double viewportWidth, double minExtent, double maxExtent) {
|
||||
int index,
|
||||
double viewportWidth,
|
||||
double minExtent,
|
||||
double maxExtent,
|
||||
) {
|
||||
if (!widget.isScrollable) {
|
||||
return 0.0;
|
||||
}
|
||||
@@ -1549,35 +1591,54 @@ class _TabBarState extends State<TabBar> {
|
||||
}
|
||||
|
||||
return clampDouble(
|
||||
tabCenter + paddingStart - viewportWidth / 2.0, minExtent, maxExtent);
|
||||
tabCenter + paddingStart - viewportWidth / 2.0,
|
||||
minExtent,
|
||||
maxExtent,
|
||||
);
|
||||
}
|
||||
|
||||
double _tabCenteredScrollOffset(int index) {
|
||||
final ScrollPosition position = _scrollController!.position;
|
||||
return _tabScrollOffset(index, position.viewportDimension,
|
||||
position.minScrollExtent, position.maxScrollExtent);
|
||||
return _tabScrollOffset(
|
||||
index,
|
||||
position.viewportDimension,
|
||||
position.minScrollExtent,
|
||||
position.maxScrollExtent,
|
||||
);
|
||||
}
|
||||
|
||||
double _initialScrollOffset(
|
||||
double viewportWidth, double minExtent, double maxExtent) {
|
||||
double viewportWidth,
|
||||
double minExtent,
|
||||
double maxExtent,
|
||||
) {
|
||||
return _tabScrollOffset(
|
||||
_currentIndex!, viewportWidth, minExtent, maxExtent);
|
||||
_currentIndex!,
|
||||
viewportWidth,
|
||||
minExtent,
|
||||
maxExtent,
|
||||
);
|
||||
}
|
||||
|
||||
void _scrollToCurrentIndex() {
|
||||
final double offset = _tabCenteredScrollOffset(_currentIndex!);
|
||||
_scrollController!
|
||||
.animateTo(offset, duration: kTabScrollDuration, curve: Curves.ease);
|
||||
_scrollController!.animateTo(
|
||||
offset,
|
||||
duration: kTabScrollDuration,
|
||||
curve: Curves.ease,
|
||||
);
|
||||
}
|
||||
|
||||
void _scrollToControllerValue() {
|
||||
final double? leadingPosition = _currentIndex! > 0
|
||||
? _tabCenteredScrollOffset(_currentIndex! - 1)
|
||||
: null;
|
||||
final double? leadingPosition =
|
||||
_currentIndex! > 0
|
||||
? _tabCenteredScrollOffset(_currentIndex! - 1)
|
||||
: null;
|
||||
final double middlePosition = _tabCenteredScrollOffset(_currentIndex!);
|
||||
final double? trailingPosition = _currentIndex! < maxTabIndex
|
||||
? _tabCenteredScrollOffset(_currentIndex! + 1)
|
||||
: null;
|
||||
final double? trailingPosition =
|
||||
_currentIndex! < maxTabIndex
|
||||
? _tabCenteredScrollOffset(_currentIndex! + 1)
|
||||
: null;
|
||||
|
||||
final double index = _controller!.index.toDouble();
|
||||
final double value = _controller!.animation!.value;
|
||||
@@ -1585,12 +1646,14 @@ class _TabBarState extends State<TabBar> {
|
||||
-1.0 => leadingPosition ?? middlePosition,
|
||||
1.0 => trailingPosition ?? middlePosition,
|
||||
0 => middlePosition,
|
||||
< 0 => leadingPosition == null
|
||||
? middlePosition
|
||||
: lerpDouble(middlePosition, leadingPosition, index - value)!,
|
||||
_ => trailingPosition == null
|
||||
? middlePosition
|
||||
: lerpDouble(middlePosition, trailingPosition, value - index)!,
|
||||
< 0 =>
|
||||
leadingPosition == null
|
||||
? middlePosition
|
||||
: lerpDouble(middlePosition, leadingPosition, index - value)!,
|
||||
_ =>
|
||||
trailingPosition == null
|
||||
? middlePosition
|
||||
: lerpDouble(middlePosition, trailingPosition, value - index)!,
|
||||
};
|
||||
|
||||
_scrollController!.jumpTo(offset);
|
||||
@@ -1620,7 +1683,10 @@ class _TabBarState extends State<TabBar> {
|
||||
|
||||
// Called each time layout completes.
|
||||
void _saveTabOffsets(
|
||||
List<double> tabOffsets, TextDirection textDirection, double width) {
|
||||
List<double> tabOffsets,
|
||||
TextDirection textDirection,
|
||||
double width,
|
||||
) {
|
||||
_tabStripWidth = width;
|
||||
_indicatorPainter?.saveTabOffsets(tabOffsets, textDirection);
|
||||
}
|
||||
@@ -1631,8 +1697,12 @@ class _TabBarState extends State<TabBar> {
|
||||
widget.onTap?.call(index);
|
||||
}
|
||||
|
||||
Widget _buildStyledTab(Widget child, bool isSelected,
|
||||
Animation<double> animation, TabBarThemeData defaults) {
|
||||
Widget _buildStyledTab(
|
||||
Widget child,
|
||||
bool isSelected,
|
||||
Animation<double> animation,
|
||||
TabBarThemeData defaults,
|
||||
) {
|
||||
return _TabStyle(
|
||||
animation: animation,
|
||||
isSelected: isSelected,
|
||||
@@ -1694,24 +1764,28 @@ class _TabBarState extends State<TabBar> {
|
||||
assert(_debugScheduleCheckHasValidTabsCount());
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final TabBarThemeData tabBarTheme = TabBarTheme.of(context);
|
||||
final TabAlignment effectiveTabAlignment = widget.tabAlignment ??
|
||||
final TabAlignment effectiveTabAlignment =
|
||||
widget.tabAlignment ??
|
||||
tabBarTheme.tabAlignment ??
|
||||
_defaults.tabAlignment!;
|
||||
assert(_debugTabAlignmentIsValid(effectiveTabAlignment));
|
||||
|
||||
final MaterialLocalizations localizations =
|
||||
MaterialLocalizations.of(context);
|
||||
final MaterialLocalizations localizations = MaterialLocalizations.of(
|
||||
context,
|
||||
);
|
||||
if (_controller!.length == 0) {
|
||||
return LimitedBox(
|
||||
maxWidth: 0.0,
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
height: _kTabHeight + widget.indicatorWeight),
|
||||
width: double.infinity,
|
||||
height: _kTabHeight + widget.indicatorWeight,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final List<Widget> wrappedTabs =
|
||||
List<Widget>.generate(widget.tabs.length, (int index) {
|
||||
final List<Widget> wrappedTabs = List<Widget>.generate(widget.tabs.length, (
|
||||
int index,
|
||||
) {
|
||||
EdgeInsetsGeometry padding =
|
||||
widget.labelPadding ?? tabBarTheme.labelPadding ?? kTabLabelPadding;
|
||||
const double verticalAdjustment =
|
||||
@@ -1721,8 +1795,9 @@ class _TabBarState extends State<TabBar> {
|
||||
if (tab is PreferredSizeWidget &&
|
||||
tab.preferredSize.height == _kTabHeight &&
|
||||
widget.tabHasTextAndIcon) {
|
||||
padding = padding
|
||||
.add(const EdgeInsets.symmetric(vertical: verticalAdjustment));
|
||||
padding = padding.add(
|
||||
const EdgeInsets.symmetric(vertical: verticalAdjustment),
|
||||
);
|
||||
}
|
||||
_labelPaddings[index] = padding;
|
||||
|
||||
@@ -1730,10 +1805,7 @@ class _TabBarState extends State<TabBar> {
|
||||
heightFactor: 1.0,
|
||||
child: Padding(
|
||||
padding: _labelPaddings[index],
|
||||
child: KeyedSubtree(
|
||||
key: _tabKeys[index],
|
||||
child: widget.tabs[index],
|
||||
),
|
||||
child: KeyedSubtree(key: _tabKeys[index], child: widget.tabs[index]),
|
||||
),
|
||||
);
|
||||
});
|
||||
@@ -1764,8 +1836,10 @@ class _TabBarState extends State<TabBar> {
|
||||
// The user is dragging the TabBarView's PageView left or right.
|
||||
if (_currentIndex! < widget.tabs.length) {
|
||||
final int tabIndex = _currentIndex!;
|
||||
final Animation<double> centerAnimation =
|
||||
_DragAnimation(_controller!, tabIndex);
|
||||
final Animation<double> centerAnimation = _DragAnimation(
|
||||
_controller!,
|
||||
tabIndex,
|
||||
);
|
||||
wrappedTabs[tabIndex] = _buildStyledTab(
|
||||
wrappedTabs[tabIndex],
|
||||
true,
|
||||
@@ -1775,8 +1849,9 @@ class _TabBarState extends State<TabBar> {
|
||||
}
|
||||
if (_currentIndex! > 0) {
|
||||
final int tabIndex = _currentIndex! - 1;
|
||||
final Animation<double> previousAnimation =
|
||||
ReverseAnimation(_DragAnimation(_controller!, tabIndex));
|
||||
final Animation<double> previousAnimation = ReverseAnimation(
|
||||
_DragAnimation(_controller!, tabIndex),
|
||||
);
|
||||
wrappedTabs[tabIndex] = _buildStyledTab(
|
||||
wrappedTabs[tabIndex],
|
||||
false,
|
||||
@@ -1786,8 +1861,9 @@ class _TabBarState extends State<TabBar> {
|
||||
}
|
||||
if (_currentIndex! < widget.tabs.length - 1) {
|
||||
final int tabIndex = _currentIndex! + 1;
|
||||
final Animation<double> nextAnimation =
|
||||
ReverseAnimation(_DragAnimation(_controller!, tabIndex));
|
||||
final Animation<double> nextAnimation = ReverseAnimation(
|
||||
_DragAnimation(_controller!, tabIndex),
|
||||
);
|
||||
wrappedTabs[tabIndex] = _buildStyledTab(
|
||||
wrappedTabs[tabIndex],
|
||||
false,
|
||||
@@ -1809,18 +1885,18 @@ class _TabBarState extends State<TabBar> {
|
||||
|
||||
final MouseCursor effectiveMouseCursor =
|
||||
WidgetStateProperty.resolveAs<MouseCursor?>(
|
||||
widget.mouseCursor, selectedState) ??
|
||||
tabBarTheme.mouseCursor?.resolve(selectedState) ??
|
||||
WidgetStateMouseCursor.clickable.resolve(selectedState);
|
||||
widget.mouseCursor,
|
||||
selectedState,
|
||||
) ??
|
||||
tabBarTheme.mouseCursor?.resolve(selectedState) ??
|
||||
WidgetStateMouseCursor.clickable.resolve(selectedState);
|
||||
|
||||
final WidgetStateProperty<Color?> defaultOverlay =
|
||||
WidgetStateProperty.resolveWith<Color?>(
|
||||
(Set<WidgetState> states) {
|
||||
final Set<WidgetState> effectiveStates = selectedState
|
||||
..addAll(states);
|
||||
return _defaults.overlayColor?.resolve(effectiveStates);
|
||||
},
|
||||
);
|
||||
WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
final Set<WidgetState> effectiveStates =
|
||||
selectedState..addAll(states);
|
||||
return _defaults.overlayColor?.resolve(effectiveStates);
|
||||
});
|
||||
wrappedTabs[index] = InkWell(
|
||||
mouseCursor: effectiveMouseCursor,
|
||||
onTap: () {
|
||||
@@ -1829,7 +1905,8 @@ class _TabBarState extends State<TabBar> {
|
||||
enableFeedback: widget.enableFeedback ?? true,
|
||||
overlayColor:
|
||||
widget.overlayColor ?? tabBarTheme.overlayColor ?? defaultOverlay,
|
||||
splashFactory: widget.splashFactory ??
|
||||
splashFactory:
|
||||
widget.splashFactory ??
|
||||
tabBarTheme.splashFactory ??
|
||||
_defaults.splashFactory,
|
||||
borderRadius: widget.splashBorderRadius,
|
||||
@@ -1841,7 +1918,9 @@ class _TabBarState extends State<TabBar> {
|
||||
Semantics(
|
||||
selected: index == _currentIndex,
|
||||
label: localizations.tabLabel(
|
||||
tabIndex: index + 1, tabCount: tabCount),
|
||||
tabIndex: index + 1,
|
||||
tabCount: tabCount,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -1865,9 +1944,10 @@ class _TabBarState extends State<TabBar> {
|
||||
defaults: _defaults,
|
||||
child: _TabLabelBar(
|
||||
onPerformLayout: _saveTabOffsets,
|
||||
mainAxisSize: effectiveTabAlignment == TabAlignment.fill
|
||||
? MainAxisSize.max
|
||||
: MainAxisSize.min,
|
||||
mainAxisSize:
|
||||
effectiveTabAlignment == TabAlignment.fill
|
||||
? MainAxisSize.max
|
||||
: MainAxisSize.min,
|
||||
children: wrappedTabs,
|
||||
),
|
||||
),
|
||||
@@ -1876,8 +1956,9 @@ class _TabBarState extends State<TabBar> {
|
||||
if (widget.isScrollable) {
|
||||
final EdgeInsetsGeometry? effectivePadding =
|
||||
effectiveTabAlignment == TabAlignment.startOffset
|
||||
? const EdgeInsetsDirectional.only(start: _kStartOffset)
|
||||
.add(widget.padding ?? EdgeInsets.zero)
|
||||
? const EdgeInsetsDirectional.only(
|
||||
start: _kStartOffset,
|
||||
).add(widget.padding ?? EdgeInsets.zero)
|
||||
: widget.padding;
|
||||
_scrollController ??= _TabBarScrollController(this);
|
||||
tabBar = ScrollConfiguration(
|
||||
@@ -1895,17 +1976,18 @@ class _TabBarState extends State<TabBar> {
|
||||
if (theme.useMaterial3) {
|
||||
final AlignmentGeometry effectiveAlignment =
|
||||
switch (effectiveTabAlignment) {
|
||||
TabAlignment.center => Alignment.center,
|
||||
TabAlignment.start ||
|
||||
TabAlignment.startOffset ||
|
||||
TabAlignment.fill =>
|
||||
AlignmentDirectional.centerStart,
|
||||
};
|
||||
TabAlignment.center => Alignment.center,
|
||||
TabAlignment.start ||
|
||||
TabAlignment.startOffset ||
|
||||
TabAlignment.fill => AlignmentDirectional.centerStart,
|
||||
};
|
||||
|
||||
final Color dividerColor = widget.dividerColor ??
|
||||
final Color dividerColor =
|
||||
widget.dividerColor ??
|
||||
tabBarTheme.dividerColor ??
|
||||
_defaults.dividerColor!;
|
||||
final double dividerHeight = widget.dividerHeight ??
|
||||
final double dividerHeight =
|
||||
widget.dividerHeight ??
|
||||
tabBarTheme.dividerHeight ??
|
||||
_defaults.dividerHeight!;
|
||||
|
||||
@@ -1927,15 +2009,13 @@ class _TabBarState extends State<TabBar> {
|
||||
}
|
||||
}
|
||||
} else if (widget.padding != null) {
|
||||
tabBar = Padding(
|
||||
padding: widget.padding!,
|
||||
child: tabBar,
|
||||
);
|
||||
tabBar = Padding(padding: widget.padding!, child: tabBar);
|
||||
}
|
||||
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context)
|
||||
.copyWith(textScaler: widget.textScaler ?? tabBarTheme.textScaler),
|
||||
data: MediaQuery.of(
|
||||
context,
|
||||
).copyWith(textScaler: widget.textScaler ?? tabBarTheme.textScaler),
|
||||
child: tabBar,
|
||||
);
|
||||
}
|
||||
@@ -2062,8 +2142,11 @@ class _TabBarViewState extends State<TabBarView> {
|
||||
required Curve curve,
|
||||
}) async {
|
||||
_warpUnderwayCount += 1;
|
||||
await _pageController!
|
||||
.animateToPage(page, duration: duration, curve: curve);
|
||||
await _pageController!.animateToPage(
|
||||
page,
|
||||
duration: duration,
|
||||
curve: curve,
|
||||
);
|
||||
_warpUnderwayCount -= 1;
|
||||
}
|
||||
|
||||
@@ -2154,8 +2237,11 @@ class _TabBarViewState extends State<TabBarView> {
|
||||
if (duration == Duration.zero) {
|
||||
_jumpToPage(_currentIndex!);
|
||||
} else {
|
||||
await _animateToPage(_currentIndex!,
|
||||
duration: duration, curve: Curves.ease);
|
||||
await _animateToPage(
|
||||
_currentIndex!,
|
||||
duration: duration,
|
||||
curve: Curves.ease,
|
||||
);
|
||||
}
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
@@ -2171,9 +2257,10 @@ class _TabBarViewState extends State<TabBarView> {
|
||||
|
||||
// initialPage defines which page is shown when starting the animation.
|
||||
// This page is adjacent to the destination page.
|
||||
final int initialPage = _currentIndex! > previousIndex
|
||||
? _currentIndex! - 1
|
||||
: _currentIndex! + 1;
|
||||
final int initialPage =
|
||||
_currentIndex! > previousIndex
|
||||
? _currentIndex! - 1
|
||||
: _currentIndex! + 1;
|
||||
|
||||
setState(() {
|
||||
// Needed for `RenderSliverMultiBoxAdaptor.move` and kept alive children.
|
||||
@@ -2192,8 +2279,11 @@ class _TabBarViewState extends State<TabBarView> {
|
||||
if (duration == Duration.zero) {
|
||||
_jumpToPage(_currentIndex!);
|
||||
} else {
|
||||
await _animateToPage(_currentIndex!,
|
||||
duration: duration, curve: Curves.ease);
|
||||
await _animateToPage(
|
||||
_currentIndex!,
|
||||
duration: duration,
|
||||
curve: Curves.ease,
|
||||
);
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
@@ -2204,8 +2294,11 @@ class _TabBarViewState extends State<TabBarView> {
|
||||
}
|
||||
|
||||
void _syncControllerOffset() {
|
||||
_controller!.offset =
|
||||
clampDouble(_pageController!.page! - _controller!.index, -1.0, 1.0);
|
||||
_controller!.offset = clampDouble(
|
||||
_pageController!.page! - _controller!.index,
|
||||
-1.0,
|
||||
1.0,
|
||||
);
|
||||
}
|
||||
|
||||
// Called when the PageView scrolls
|
||||
@@ -2277,9 +2370,12 @@ class _TabBarViewState extends State<TabBarView> {
|
||||
dragStartBehavior: widget.dragStartBehavior,
|
||||
clipBehavior: widget.clipBehavior,
|
||||
controller: _pageController,
|
||||
physics: widget.physics == null
|
||||
? const PageScrollPhysics().applyTo(const ClampingScrollPhysics())
|
||||
: const PageScrollPhysics().applyTo(widget.physics),
|
||||
physics:
|
||||
widget.physics == null
|
||||
? const PageScrollPhysics().applyTo(
|
||||
const ClampingScrollPhysics(),
|
||||
)
|
||||
: const PageScrollPhysics().applyTo(widget.physics),
|
||||
children: _childrenWithKey,
|
||||
),
|
||||
);
|
||||
@@ -2484,26 +2580,36 @@ class _TabPageSelectorState extends State<TabPageSelector> {
|
||||
final Color fixColor = widget.color ?? Colors.transparent;
|
||||
final Color fixSelectedColor =
|
||||
widget.selectedColor ?? Theme.of(context).colorScheme.secondary;
|
||||
final ColorTween selectedColorTween =
|
||||
ColorTween(begin: fixColor, end: fixSelectedColor);
|
||||
final ColorTween previousColorTween =
|
||||
ColorTween(begin: fixSelectedColor, end: fixColor);
|
||||
final MaterialLocalizations localizations =
|
||||
MaterialLocalizations.of(context);
|
||||
final ColorTween selectedColorTween = ColorTween(
|
||||
begin: fixColor,
|
||||
end: fixSelectedColor,
|
||||
);
|
||||
final ColorTween previousColorTween = ColorTween(
|
||||
begin: fixSelectedColor,
|
||||
end: fixColor,
|
||||
);
|
||||
final MaterialLocalizations localizations = MaterialLocalizations.of(
|
||||
context,
|
||||
);
|
||||
return AnimatedBuilder(
|
||||
animation: _animation!,
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
return Semantics(
|
||||
label: localizations.tabLabel(
|
||||
tabIndex: _tabController.index + 1,
|
||||
tabCount: _tabController.length),
|
||||
tabIndex: _tabController.index + 1,
|
||||
tabCount: _tabController.length,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children:
|
||||
List<Widget>.generate(_tabController.length, (int tabIndex) {
|
||||
return _buildTabIndicator(tabIndex, _tabController,
|
||||
selectedColorTween, previousColorTween);
|
||||
}).toList(),
|
||||
return _buildTabIndicator(
|
||||
tabIndex,
|
||||
_tabController,
|
||||
selectedColorTween,
|
||||
previousColorTween,
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -2514,7 +2620,7 @@ class _TabPageSelectorState extends State<TabPageSelector> {
|
||||
// Hand coded defaults based on Material Design 2.
|
||||
class _TabsDefaultsM2 extends TabBarThemeData {
|
||||
const _TabsDefaultsM2(this.context, this.isScrollable)
|
||||
: super(indicatorSize: TabBarIndicatorSize.tab);
|
||||
: super(indicatorSize: TabBarIndicatorSize.tab);
|
||||
|
||||
final BuildContext context;
|
||||
final bool isScrollable;
|
||||
@@ -2552,7 +2658,7 @@ class _TabsDefaultsM2 extends TabBarThemeData {
|
||||
|
||||
class _TabsPrimaryDefaultsM3 extends TabBarThemeData {
|
||||
_TabsPrimaryDefaultsM3(this.context, this.isScrollable)
|
||||
: super(indicatorSize: TabBarIndicatorSize.label);
|
||||
: super(indicatorSize: TabBarIndicatorSize.label);
|
||||
|
||||
final BuildContext context;
|
||||
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
||||
@@ -2633,7 +2739,7 @@ class _TabsPrimaryDefaultsM3 extends TabBarThemeData {
|
||||
|
||||
class _TabsSecondaryDefaultsM3 extends TabBarThemeData {
|
||||
_TabsSecondaryDefaultsM3(this.context, this.isScrollable)
|
||||
: super(indicatorSize: TabBarIndicatorSize.tab);
|
||||
: super(indicatorSize: TabBarIndicatorSize.tab);
|
||||
|
||||
final BuildContext context;
|
||||
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
||||
|
||||
283
lib/components/base/text.dart
Normal file
283
lib/components/base/text.dart
Normal file
@@ -0,0 +1,283 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:moodiary/components/base/marquee.dart';
|
||||
import 'package:moodiary/utils/lru.dart';
|
||||
|
||||
class AdaptiveText extends StatelessWidget {
|
||||
final String text;
|
||||
final TextStyle? style;
|
||||
final double? maxWidth;
|
||||
final bool? isTileTitle;
|
||||
final bool? isTileSubtitle;
|
||||
final bool? isPrimaryTitle;
|
||||
final bool? isTitle;
|
||||
|
||||
const AdaptiveText(
|
||||
this.text, {
|
||||
super.key,
|
||||
this.style,
|
||||
this.maxWidth,
|
||||
this.isTileTitle,
|
||||
this.isTileSubtitle,
|
||||
this.isPrimaryTitle,
|
||||
this.isTitle,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
final textScaler = MediaQuery.textScalerOf(context);
|
||||
var textStyle = style;
|
||||
if (isTileTitle == true) {
|
||||
textStyle = textTheme.bodyLarge?.copyWith(
|
||||
color: context.theme.colorScheme.onSurface,
|
||||
);
|
||||
}
|
||||
if (isTileSubtitle == true) {
|
||||
textStyle = textTheme.bodyMedium?.copyWith(
|
||||
color: context.theme.colorScheme.onSurfaceVariant,
|
||||
);
|
||||
}
|
||||
if (isTitle == true) {
|
||||
textStyle = textTheme.titleLarge;
|
||||
}
|
||||
if (isPrimaryTitle == true) {
|
||||
textStyle = textTheme.titleLarge?.copyWith(
|
||||
color: context.theme.colorScheme.primary,
|
||||
);
|
||||
}
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final textPainter = TextPainter(
|
||||
text: TextSpan(text: text, style: textStyle),
|
||||
textDirection: TextDirection.ltr,
|
||||
maxLines: 1,
|
||||
textScaler: textScaler,
|
||||
)..layout(maxWidth: maxWidth ?? constraints.maxWidth);
|
||||
return textPainter.didExceedMaxLines
|
||||
? SizedBox(
|
||||
height: textPainter.height,
|
||||
width: maxWidth ?? constraints.maxWidth,
|
||||
child: Marquee(
|
||||
text: text,
|
||||
velocity: 20,
|
||||
blankSpace: 20,
|
||||
textScaler: textScaler,
|
||||
pauseAfterRound: const Duration(seconds: 1),
|
||||
accelerationDuration: const Duration(seconds: 1),
|
||||
accelerationCurve: Curves.linear,
|
||||
decelerationDuration: const Duration(milliseconds: 300),
|
||||
decelerationCurve: Curves.easeOut,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
text,
|
||||
style: textStyle,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class EllipsisText extends StatelessWidget {
|
||||
final String text;
|
||||
final TextStyle? style;
|
||||
final String ellipsis;
|
||||
final int? maxLines;
|
||||
|
||||
static final _cache = LRUCache<int, String>(maxSize: 1000);
|
||||
|
||||
/// 当字体相关属性发生变化时,需要清空缓存
|
||||
static void clearCache() {
|
||||
_cache.clear();
|
||||
}
|
||||
|
||||
const EllipsisText(
|
||||
this.text, {
|
||||
super.key,
|
||||
this.style,
|
||||
this.ellipsis = '...',
|
||||
this.maxLines,
|
||||
});
|
||||
|
||||
int _getCacheKey(
|
||||
String text,
|
||||
String ellipsis,
|
||||
double maxWidth,
|
||||
int? maxLines,
|
||||
TextStyle? style,
|
||||
TextScaler textScaler,
|
||||
) {
|
||||
return Object.hash(
|
||||
text,
|
||||
ellipsis,
|
||||
maxWidth.toStringAsFixed(2),
|
||||
maxLines,
|
||||
style,
|
||||
textScaler,
|
||||
);
|
||||
}
|
||||
|
||||
double _calculateTextWidth(String text, TextScaler textScaler) {
|
||||
final span = TextSpan(text: text.fixAutoLines(), style: style);
|
||||
final tp = TextPainter(
|
||||
text: span,
|
||||
maxLines: 1,
|
||||
textDirection: TextDirection.ltr,
|
||||
textScaler: textScaler,
|
||||
)..layout();
|
||||
return tp.width;
|
||||
}
|
||||
|
||||
TextPainter _createTextPainter(
|
||||
String displayText,
|
||||
double maxWidth,
|
||||
TextScaler textScaler,
|
||||
) {
|
||||
return TextPainter(
|
||||
text: TextSpan(text: displayText.fixAutoLines(), style: style),
|
||||
maxLines: maxLines,
|
||||
textDirection: TextDirection.ltr,
|
||||
textScaler: textScaler,
|
||||
)..layout(maxWidth: maxWidth);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final textScaler = MediaQuery.textScalerOf(context);
|
||||
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final cacheKey = _getCacheKey(
|
||||
text,
|
||||
ellipsis,
|
||||
constraints.maxWidth,
|
||||
maxLines,
|
||||
style,
|
||||
textScaler,
|
||||
);
|
||||
if (text.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final cachedResult = _cache.get(cacheKey);
|
||||
if (cachedResult != null) {
|
||||
return Text(
|
||||
cachedResult,
|
||||
maxLines: maxLines,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: style,
|
||||
textScaler: textScaler,
|
||||
);
|
||||
}
|
||||
|
||||
if (!_createTextPainter(
|
||||
text,
|
||||
constraints.maxWidth,
|
||||
textScaler,
|
||||
).didExceedMaxLines) {
|
||||
_cache.put(cacheKey, text.fixAutoLines());
|
||||
return Text(
|
||||
text.fixAutoLines(),
|
||||
maxLines: maxLines,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: style,
|
||||
textScaler: textScaler,
|
||||
);
|
||||
}
|
||||
|
||||
int leftIndex = 0;
|
||||
int rightIndex = text.characters.length;
|
||||
double leftWidth = 0;
|
||||
double rightWidth = 0;
|
||||
|
||||
int lastValidLeftIndex = 0;
|
||||
int lastValidRightIndex = text.characters.length;
|
||||
|
||||
while (leftIndex < rightIndex) {
|
||||
final nextLeftWidth =
|
||||
_calculateTextWidth(
|
||||
text.characters.elementAt(leftIndex),
|
||||
textScaler,
|
||||
) +
|
||||
leftWidth;
|
||||
final nextRightWidth =
|
||||
_calculateTextWidth(
|
||||
text.characters.elementAt(rightIndex - 1),
|
||||
textScaler,
|
||||
) +
|
||||
rightWidth;
|
||||
final currentText =
|
||||
'${text.charSubstring(0, leftIndex)}$ellipsis${text.charSubstring(rightIndex)}';
|
||||
|
||||
if (_createTextPainter(
|
||||
currentText,
|
||||
constraints.maxWidth,
|
||||
textScaler,
|
||||
).didExceedMaxLines) {
|
||||
break;
|
||||
} else {
|
||||
lastValidLeftIndex = leftIndex;
|
||||
lastValidRightIndex = rightIndex;
|
||||
if (leftWidth <= rightWidth) {
|
||||
leftWidth = nextLeftWidth;
|
||||
leftIndex++;
|
||||
} else {
|
||||
rightWidth = nextRightWidth;
|
||||
rightIndex--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final truncatedText =
|
||||
'${text.charSubstring(0, lastValidLeftIndex)}$ellipsis${text.charSubstring(lastValidRightIndex)}';
|
||||
|
||||
_cache.put(cacheKey, truncatedText.fixAutoLines());
|
||||
|
||||
return Text(
|
||||
truncatedText.fixAutoLines(),
|
||||
maxLines: maxLines,
|
||||
style: style,
|
||||
textScaler: textScaler,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension StringExt on String {
|
||||
String fixAutoLines() => characters.join('\u{200B}');
|
||||
|
||||
String charSubstring(int start, [int? end]) =>
|
||||
characters.getRange(start, end).join();
|
||||
|
||||
String removeLineBreaks() => replaceAll(RegExp(r'[\r\n]+'), '');
|
||||
}
|
||||
|
||||
class AnimatedText extends StatelessWidget {
|
||||
const AnimatedText(
|
||||
this.text, {
|
||||
super.key,
|
||||
required this.style,
|
||||
required this.isFetching,
|
||||
this.placeholder = '...',
|
||||
});
|
||||
|
||||
final String placeholder;
|
||||
final String text;
|
||||
final TextStyle? style;
|
||||
final bool isFetching;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child:
|
||||
isFetching
|
||||
? Text(placeholder, key: const ValueKey('empty'), style: style)
|
||||
: Text(text, key: const ValueKey('text'), style: style),
|
||||
);
|
||||
}
|
||||
}
|
||||
169
lib/components/base/tile/qr_tile.dart
Normal file
169
lib/components/base/tile/qr_tile.dart
Normal file
@@ -0,0 +1,169 @@
|
||||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||
import 'package:dartx/dartx.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:moodiary/common/values/border.dart';
|
||||
import 'package:moodiary/components/base/popup.dart';
|
||||
import 'package:moodiary/components/base/qr/qr_code.dart';
|
||||
import 'package:moodiary/components/base/qr/qr_scanner.dart';
|
||||
import 'package:moodiary/components/base/tile/setting_tile.dart';
|
||||
import 'package:moodiary/l10n/l10n.dart';
|
||||
import 'package:moodiary/utils/notice_util.dart';
|
||||
|
||||
class QrInputTile extends StatelessWidget {
|
||||
final String title;
|
||||
final String? subtitle;
|
||||
|
||||
final String? prefix;
|
||||
|
||||
final String value;
|
||||
final bool withStyle;
|
||||
|
||||
final void Function(String)? onValue;
|
||||
|
||||
final Widget? leading;
|
||||
|
||||
final VoidCallback? onScan;
|
||||
final VoidCallback? onInput;
|
||||
|
||||
const QrInputTile({
|
||||
super.key,
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
required this.value,
|
||||
this.onValue,
|
||||
this.withStyle = true,
|
||||
this.onScan,
|
||||
this.onInput,
|
||||
this.leading,
|
||||
this.prefix,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const validDuration = Duration(minutes: 2);
|
||||
return AdaptiveListTile(
|
||||
title: Text(title),
|
||||
leading: leading,
|
||||
subtitle:
|
||||
subtitle ??
|
||||
(value.isNotNullOrBlank
|
||||
? Text(context.l10n.hasOption)
|
||||
: Text(context.l10n.noOption)),
|
||||
tileColor:
|
||||
withStyle ? context.theme.colorScheme.surfaceContainerLow : null,
|
||||
shape:
|
||||
withStyle
|
||||
? const RoundedRectangleBorder(
|
||||
borderRadius: AppBorderRadius.mediumBorderRadius,
|
||||
)
|
||||
: null,
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Builder(
|
||||
builder: (context) {
|
||||
return IconButton.filled(
|
||||
tooltip: context.l10n.genQrCodeTooltip,
|
||||
onPressed: () {
|
||||
if (value.isBlank) {
|
||||
toast.info(message: context.l10n.genQrCodeError1(title));
|
||||
return;
|
||||
}
|
||||
showPopupWidget(
|
||||
targetContext: context,
|
||||
child: EncryptQrCode(
|
||||
data: value,
|
||||
size: 96,
|
||||
prefix: prefix,
|
||||
validDuration: validDuration,
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.qr_code_rounded,
|
||||
color: context.theme.colorScheme.onPrimary,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton.filled(
|
||||
tooltip: context.l10n.inputTooltip,
|
||||
onPressed: () async {
|
||||
final choice = await showDialog<String?>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return SimpleDialog(
|
||||
title: Text(context.l10n.inputMethodTitle),
|
||||
children: [
|
||||
SimpleDialogOption(
|
||||
child: Row(
|
||||
spacing: 8.0,
|
||||
children: [
|
||||
const Icon(Icons.qr_code_scanner_rounded),
|
||||
Text(context.l10n.inputMethodScanQrCode),
|
||||
],
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'qr');
|
||||
},
|
||||
),
|
||||
SimpleDialogOption(
|
||||
child: Row(
|
||||
spacing: 8.0,
|
||||
children: [
|
||||
const Icon(Icons.keyboard_rounded),
|
||||
Text(context.l10n.inputMethodHandelInput),
|
||||
],
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'input');
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
if (choice == null) return;
|
||||
if (choice == 'qr' && context.mounted) {
|
||||
if (onScan != null) {
|
||||
onScan?.call();
|
||||
return;
|
||||
}
|
||||
final res = await showQrScanner(
|
||||
context: context,
|
||||
validDuration: validDuration,
|
||||
prefix: prefix,
|
||||
);
|
||||
if (res != null) {
|
||||
onValue?.call(res);
|
||||
}
|
||||
}
|
||||
if (choice == 'input' && context.mounted) {
|
||||
if (onInput != null) {
|
||||
onInput?.call();
|
||||
return;
|
||||
}
|
||||
final res = await showTextInputDialog(
|
||||
context: context,
|
||||
textFields: [DialogTextField(initialText: value)],
|
||||
title: title,
|
||||
message: context.l10n.getKeyFromConsole,
|
||||
style: AdaptiveStyle.material,
|
||||
);
|
||||
if (res != null && res.isNotEmpty) {
|
||||
final value = res[0];
|
||||
onValue?.call(value);
|
||||
}
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.input_rounded,
|
||||
color: context.theme.colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
183
lib/components/base/tile/setting_tile.dart
Normal file
183
lib/components/base/tile/setting_tile.dart
Normal file
@@ -0,0 +1,183 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:moodiary/components/base/text.dart';
|
||||
|
||||
class AdaptiveTitleTile extends StatelessWidget {
|
||||
const AdaptiveTitleTile({super.key, required this.title, this.subtitle});
|
||||
|
||||
final dynamic title;
|
||||
|
||||
final dynamic subtitle;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(
|
||||
title is String || title is Widget,
|
||||
'title must be a String or a Widget',
|
||||
);
|
||||
assert(
|
||||
subtitle == null || subtitle is String || subtitle is Widget,
|
||||
'subtitle must be a String or a Widget',
|
||||
);
|
||||
return ListTile(
|
||||
title:
|
||||
(title is String) ? AdaptiveText(title, isPrimaryTitle: true) : title,
|
||||
subtitle:
|
||||
(subtitle is String)
|
||||
? AdaptiveText(subtitle!, isTileSubtitle: true)
|
||||
: subtitle,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AdaptiveListTile extends StatelessWidget {
|
||||
const AdaptiveListTile({
|
||||
super.key,
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
this.trailing,
|
||||
this.onTap,
|
||||
this.leading,
|
||||
this.isFirst,
|
||||
this.isLast,
|
||||
this.contentPadding,
|
||||
this.tileColor,
|
||||
this.shape,
|
||||
});
|
||||
|
||||
final dynamic title;
|
||||
|
||||
final dynamic subtitle;
|
||||
|
||||
final Widget? trailing;
|
||||
|
||||
final Widget? leading;
|
||||
|
||||
final VoidCallback? onTap;
|
||||
|
||||
final bool? isFirst;
|
||||
|
||||
final bool? isLast;
|
||||
|
||||
final EdgeInsets? contentPadding;
|
||||
|
||||
final Color? tileColor;
|
||||
|
||||
final ShapeBorder? shape;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(
|
||||
title is String || title is Widget,
|
||||
'title must be a String or a Widget',
|
||||
);
|
||||
assert(
|
||||
subtitle == null || subtitle is String || subtitle is Widget,
|
||||
'subtitle must be a String or a Widget',
|
||||
);
|
||||
var realTitle = title;
|
||||
var realSubtitle = subtitle;
|
||||
if (title is Text) {
|
||||
realTitle = (title as Text).data;
|
||||
}
|
||||
if (subtitle is Text) {
|
||||
realSubtitle = (subtitle as Text).data;
|
||||
}
|
||||
return ListTile(
|
||||
tileColor: tileColor,
|
||||
title:
|
||||
(realTitle is String)
|
||||
? AdaptiveText(realTitle, isTileTitle: true)
|
||||
: realTitle,
|
||||
shape:
|
||||
shape ??
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: isFirst == true ? const Radius.circular(12) : Radius.zero,
|
||||
bottom: isLast == true ? const Radius.circular(12) : Radius.zero,
|
||||
),
|
||||
),
|
||||
contentPadding: contentPadding,
|
||||
subtitle:
|
||||
(realSubtitle is String)
|
||||
? AdaptiveText(realSubtitle, isTileSubtitle: true)
|
||||
: realSubtitle,
|
||||
trailing: trailing,
|
||||
leading: leading,
|
||||
onTap: onTap,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AdaptiveSwitchListTile extends StatelessWidget {
|
||||
const AdaptiveSwitchListTile({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.value,
|
||||
required this.onChanged,
|
||||
this.subtitle,
|
||||
this.isFirst,
|
||||
this.isLast,
|
||||
this.secondary,
|
||||
this.isSingle,
|
||||
});
|
||||
|
||||
final dynamic title;
|
||||
|
||||
final dynamic subtitle;
|
||||
|
||||
final bool value;
|
||||
|
||||
final ValueChanged<bool>? onChanged;
|
||||
|
||||
final Widget? secondary;
|
||||
|
||||
final bool? isFirst;
|
||||
|
||||
final bool? isLast;
|
||||
|
||||
final bool? isSingle;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(
|
||||
title is String || title is Widget,
|
||||
'title must be a String or a Widget',
|
||||
);
|
||||
assert(
|
||||
subtitle == null || subtitle is String || subtitle is Widget,
|
||||
'subtitle must be a String or a Widget',
|
||||
);
|
||||
var realTitle = title;
|
||||
var realSubtitle = subtitle;
|
||||
if (title is Text) {
|
||||
realTitle = (title as Text).data;
|
||||
}
|
||||
if (subtitle is Text) {
|
||||
realSubtitle = (subtitle as Text).data;
|
||||
}
|
||||
return SwitchListTile(
|
||||
title:
|
||||
(realTitle is String)
|
||||
? AdaptiveText(realTitle, isTileTitle: true)
|
||||
: realTitle,
|
||||
secondary: secondary,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
isSingle == true
|
||||
? BorderRadius.circular(12)
|
||||
: BorderRadius.vertical(
|
||||
top:
|
||||
isFirst == true ? const Radius.circular(12) : Radius.zero,
|
||||
bottom:
|
||||
isLast == true ? const Radius.circular(12) : Radius.zero,
|
||||
),
|
||||
),
|
||||
subtitle:
|
||||
(realSubtitle is String)
|
||||
? AdaptiveText(realSubtitle, isTileSubtitle: true)
|
||||
: realSubtitle,
|
||||
value: value,
|
||||
onChanged: onChanged,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,7 @@ class Bubble extends StatelessWidget {
|
||||
),
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: child,
|
||||
),
|
||||
child: Padding(padding: const EdgeInsets.all(4.0), child: child),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -38,9 +35,10 @@ class BubblePainter extends CustomPainter {
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()
|
||||
..color = color
|
||||
..style = PaintingStyle.fill;
|
||||
final paint =
|
||||
Paint()
|
||||
..color = color
|
||||
..style = PaintingStyle.fill;
|
||||
const arrowWidth = 16.0;
|
||||
const arrowHeight = 8.0;
|
||||
final rectWidth = size.width;
|
||||
@@ -56,11 +54,12 @@ class BubblePainter extends CustomPainter {
|
||||
);
|
||||
|
||||
// 创建路径
|
||||
final path = Path()
|
||||
..addRRect(rrect) // 添加圆角矩形
|
||||
..moveTo((rectWidth - arrowWidth) / 2, rectHeight) // 箭头左侧
|
||||
..lineTo(rectWidth / 2, rectHeight + arrowHeight) // 箭头尖端
|
||||
..lineTo((rectWidth + arrowWidth) / 2, rectHeight); // 箭头右侧
|
||||
final path =
|
||||
Path()
|
||||
..addRRect(rrect) // 添加圆角矩形
|
||||
..moveTo((rectWidth - arrowWidth) / 2, rectHeight) // 箭头左侧
|
||||
..lineTo(rectWidth / 2, rectHeight + arrowHeight) // 箭头尖端
|
||||
..lineTo((rectWidth + arrowWidth) / 2, rectHeight); // 箭头右侧
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user