Compare commits
126 Commits
faces_grow
...
f-droid
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
704b28815b | ||
|
|
8d55eb70fe | ||
|
|
49c90a802a | ||
|
|
8b2db5e576 | ||
|
|
b5d4839e04 | ||
|
|
ac57097eb4 | ||
|
|
4e08e38bf6 | ||
|
|
a7d3cf4178 | ||
|
|
c63dfc36e9 | ||
|
|
2985503254 | ||
|
|
9be023d68a | ||
|
|
6a6e1b3c47 | ||
|
|
7516363715 | ||
|
|
2b76b71db8 | ||
|
|
c32a70fb25 | ||
|
|
4098c1a072 | ||
|
|
972be1f41e | ||
|
|
3acb2136d0 | ||
|
|
eba729625f | ||
|
|
a477742cd0 | ||
|
|
c974bde11c | ||
|
|
ecc654bae0 | ||
|
|
201ef88305 | ||
|
|
742035d7cc | ||
|
|
8f29d5aa19 | ||
|
|
8a4e76fb6f | ||
|
|
c03eaf83aa | ||
|
|
378878538d | ||
|
|
01c3d6b105 | ||
|
|
c6f5c68f1e | ||
|
|
d0c8925ff3 | ||
|
|
d6c84421ce | ||
|
|
5cff5f49b7 | ||
|
|
3d90e37a00 | ||
|
|
eb9f5830a5 | ||
|
|
348ede2a03 | ||
|
|
5619b349b3 | ||
|
|
03cb74b90b | ||
|
|
2bddf7fcef | ||
|
|
86421d5472 | ||
|
|
4359c3f071 | ||
|
|
bab9d89d88 | ||
|
|
f7f0afdca6 | ||
|
|
f7f1227fa4 | ||
|
|
5ea93c0935 | ||
|
|
943fffbcf9 | ||
|
|
058543b287 | ||
|
|
dff77233db | ||
|
|
dab331535b | ||
|
|
3873946046 | ||
|
|
0f13558ae3 | ||
|
|
a2bb263c49 | ||
|
|
6d70678377 | ||
|
|
f08ccce1e3 | ||
|
|
4e3040a36b | ||
|
|
16345fa7a1 | ||
|
|
c0d88a2cac | ||
|
|
809ce0f24a | ||
|
|
cbd22523fd | ||
|
|
85d39dc097 | ||
|
|
703f2a67f8 | ||
|
|
68c2fbfec6 | ||
|
|
fd3bcbf2a8 | ||
|
|
78077e70c6 | ||
|
|
04e2fd0262 | ||
|
|
b377217ece | ||
|
|
7242176243 | ||
|
|
b3123a6440 | ||
|
|
f4eb511beb | ||
|
|
1a689b2c19 | ||
|
|
b0c6ffdbb2 | ||
|
|
b7ccf4aaf9 | ||
|
|
e7c8265ae1 | ||
|
|
21dc35355d | ||
|
|
f86994b1d3 | ||
|
|
260a26d45c | ||
|
|
cdfa368a8c | ||
|
|
d67c6aef53 | ||
|
|
6ebb5d5bf4 | ||
|
|
224b79b648 | ||
|
|
7e0a3cdd6c | ||
|
|
f6db381e20 | ||
|
|
f0c29fef5c | ||
|
|
2a3e317725 | ||
|
|
1a1b3ebf12 | ||
|
|
f995589a02 | ||
|
|
6e0990d658 | ||
|
|
4da4261f4c | ||
|
|
0abe66ea8c | ||
|
|
193b27a186 | ||
|
|
e323096172 | ||
|
|
e41f306ac8 | ||
|
|
01d45d7c14 | ||
|
|
d55a29336f | ||
|
|
cfcbd0fbb2 | ||
|
|
21174548b5 | ||
|
|
910f13e9a8 | ||
|
|
762688db28 | ||
|
|
9df1ea0c57 | ||
|
|
e48ab71fa4 | ||
|
|
246314367a | ||
|
|
ad70bbb571 | ||
|
|
3962c55140 | ||
|
|
82e478bb12 | ||
|
|
63c8e98492 | ||
|
|
ae92d2f759 | ||
|
|
761c3e6ac2 | ||
|
|
f9a3009c60 | ||
|
|
ca0474faca | ||
|
|
b469985277 | ||
|
|
2a5dacb460 | ||
|
|
d16f98cf07 | ||
|
|
8677cbb4f8 | ||
|
|
0e33299863 | ||
|
|
93ba4e011a | ||
|
|
7977bebcaa | ||
|
|
f28f49d724 | ||
|
|
d9a93ddad6 | ||
|
|
07808d6139 | ||
|
|
1e1633bb45 | ||
|
|
c0f33de0c8 | ||
|
|
417621b17c | ||
|
|
8322540732 | ||
|
|
2d61be37bb | ||
|
|
2a10aa7d61 | ||
|
|
004eb310b3 |
3
.gitmodules
vendored
@@ -9,3 +9,6 @@
|
||||
[submodule "auth/assets/simple-icons"]
|
||||
path = mobile/apps/auth/assets/simple-icons
|
||||
url = https://github.com/simple-icons/simple-icons.git
|
||||
[submodule "mobile/thirdparty/flutter"]
|
||||
path = mobile/thirdparty/flutter
|
||||
url = https://github.com/flutter/flutter.git
|
||||
|
||||
@@ -48,7 +48,11 @@ See [docs/](docs/README.md) for how to edit these documents.
|
||||
|
||||
## Code contributions
|
||||
|
||||
If you'd like to contribute code, it is best to start small. Consider some well-scoped changes, say like adding more [custom icons to auth](mobile/apps/auth/docs/adding-icons.md), or fixing a specific bug.
|
||||
If you'd like to contribute code, it is best to start small. Consider some well-scoped changes, say like adding more [custom icons to auth](mobile/apps/auth/docs/adding-icons.md), or fixing a specific bug. There is a (possibly outdated) list of tasks with the ["help wanted" or "good first issue"](<https://github.com/ente-io/ente/issues?q=state%3Aopen%20(label%3A%22good%20first%20issue%22%20OR%20label%3A%22help%20wanted%22%20)>) label too.
|
||||
|
||||
If you use any form of AI assistance, please include a co-author attribution in the commit for transparency.
|
||||
|
||||
In your PR, please include before / after screenshots, and clearly indicate the tests that you performed.
|
||||
|
||||
Code that changes the behaviour of the product might not get merged, at least not initially. The PR can serve as a discussion bed, but you might find it easier to just start a discussion instead, or post your perspective in the (likely) existing thread about the behaviour change or new feature you wish for.
|
||||
|
||||
|
||||
204
mobile/apps/photos/CLAUDE.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Philosophy
|
||||
|
||||
Ente is focused on privacy, transparency and trust. It's a fully open-source, end-to-end encrypted platform for storing data in the cloud. When contributing, always prioritize:
|
||||
- User privacy and data security
|
||||
- End-to-end encryption integrity
|
||||
- Transparent, auditable code
|
||||
- Zero-knowledge architecture principles
|
||||
|
||||
## Monorepo Context
|
||||
|
||||
This is the Ente Photos mobile app within the Ente monorepo. The monorepo contains:
|
||||
- Mobile apps (Photos, Auth, Locker) at `mobile/apps/`
|
||||
- Shared packages at `mobile/packages/`
|
||||
- Web, desktop, CLI, and server components in parent directories
|
||||
|
||||
### Package Architecture
|
||||
The Photos app uses two types of packages:
|
||||
- **Shared packages** (`../../packages/`): Common code shared across multiple Ente apps (Photos, Auth, Locker)
|
||||
- **Photos-specific plugins** (`./plugins/`): Custom Flutter plugins specific to Photos app for separation and testability
|
||||
|
||||
## Commit & PR Guidelines
|
||||
|
||||
⚠️ **CRITICAL: From the default template, use ONLY: Co-Authored-By: Claude <noreply@anthropic.com>** ⚠️
|
||||
|
||||
### Pre-commit/PR Checklist (RUN BEFORE EVERY COMMIT OR PR!)
|
||||
|
||||
**CRITICAL: CI will fail if ANY of these checks fail. Run ALL commands and ensure they ALL pass.**
|
||||
|
||||
```bash
|
||||
# 1. Analyze flutter code for errors and warnings
|
||||
flutter analyze
|
||||
```
|
||||
|
||||
**Why CI might fail even after running these:**
|
||||
|
||||
- Skipping any command above
|
||||
- Assuming auto-fix tools handle everything (they don't)
|
||||
- Not fixing warnings that flutter reports
|
||||
- Making changes after running the checks
|
||||
|
||||
### Commit & PR Message Rules
|
||||
|
||||
**These rules apply to BOTH commit messages AND pull request descriptions**
|
||||
|
||||
- Keep messages CONCISE (no walls of text)
|
||||
- Subject line under 72 chars (no body text unless critical)
|
||||
- NO emojis
|
||||
- NO promotional text or links (except Co-Authored-By line)
|
||||
|
||||
### Additional Guidelines
|
||||
|
||||
- Check `git status` before committing to avoid adding temporary/binary files
|
||||
- Never commit to main branch
|
||||
- All CI checks must pass - run the checklist commands above before committing or creating PR
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Using Melos (Monorepo Management)
|
||||
```bash
|
||||
# From mobile/ directory - bootstrap all packages
|
||||
melos bootstrap
|
||||
|
||||
# Run Photos app specifically
|
||||
melos run:photos:apk
|
||||
|
||||
# Build Photos APK
|
||||
melos build:photos:apk
|
||||
|
||||
# Clean Photos app
|
||||
melos clean:photos
|
||||
```
|
||||
|
||||
### Direct Flutter Commands
|
||||
```bash
|
||||
# Development run with environment variables
|
||||
./run.sh # Uses .env file with --flavor dev
|
||||
|
||||
# Development run without env file
|
||||
flutter run -t lib/main.dart --flavor independent
|
||||
|
||||
# Build release APK
|
||||
flutter build apk --release --flavor independent
|
||||
|
||||
# iOS build
|
||||
cd ios && pod install && cd ..
|
||||
flutter build ios
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
```bash
|
||||
# Static analysis and linting
|
||||
flutter analyze .
|
||||
|
||||
# Run tests
|
||||
flutter test
|
||||
```
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Service-Oriented Architecture
|
||||
The app uses a service layer pattern with 28+ specialized services:
|
||||
- **collections_service.dart**: Album and collection management
|
||||
- **search_service.dart**: Search functionality with ML support
|
||||
- **smart_memories_service.dart**: AI-powered memory curation
|
||||
- **sync_service.dart**: Local/remote synchronization
|
||||
- **Machine Learning Services**: Face recognition, semantic search, similar images
|
||||
|
||||
### Key Patterns
|
||||
- **Service Locator**: Dependency injection via `lib/service_locator.dart`
|
||||
- **Event Bus**: Loose coupling via `lib/core/event_bus.dart`
|
||||
- **Repository Pattern**: Database abstraction in `lib/db/`
|
||||
- **Rust Integration**: Performance-critical operations via Flutter Rust Bridge
|
||||
|
||||
### Security Architecture
|
||||
- End-to-end encryption with `ente_crypto` package
|
||||
- BIP39 mnemonic-based key generation (24 words)
|
||||
- Secure storage using platform-specific implementations
|
||||
- App lock and privacy screen features
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
lib/
|
||||
├── core/ # Configuration, constants, networking
|
||||
├── services/ # Business logic (28+ services)
|
||||
├── ui/ # UI components (18 subdirectories)
|
||||
├── models/ # Data models (17 subdirectories)
|
||||
├── db/ # SQLite database layer
|
||||
├── utils/ # Utilities and helpers
|
||||
├── gateways/ # API gateway interfaces
|
||||
├── events/ # Event system
|
||||
├── l10n/ # Localization files (intl_*.arb)
|
||||
└── generated/ # Auto-generated code including localizations
|
||||
```
|
||||
|
||||
## Localization (Flutter)
|
||||
|
||||
- Add new strings to `lib/l10n/intl_en.arb` (English base file)
|
||||
- Use `AppLocalizations` to access localized strings in code
|
||||
- Example: `AppLocalizations.of(context).yourStringKey`
|
||||
- Run code generation after adding new strings: `flutter pub get`
|
||||
- Translations managed via Crowdin for other languages
|
||||
|
||||
## Key Dependencies
|
||||
|
||||
- **Flutter 3.32.8** with Dart SDK >=3.3.0 <4.0.0
|
||||
- **Media**: `photo_manager`, `video_editor`, `ffmpeg_kit_flutter`
|
||||
- **Storage**: `sqlite_async`, `flutter_secure_storage`
|
||||
- **ML/AI**: Custom ONNX runtime, `ml_linalg`
|
||||
- **Rust**: Flutter Rust Bridge for performance
|
||||
|
||||
## Development Setup Requirements
|
||||
|
||||
1. Install Flutter v3.32.8 and Rust
|
||||
2. Install Flutter Rust Bridge: `cargo install flutter_rust_bridge_codegen`
|
||||
3. Generate Rust bindings: `flutter_rust_bridge_codegen generate`
|
||||
4. Update submodules: `git submodule update --init --recursive`
|
||||
5. Enable git hooks: `git config core.hooksPath hooks`
|
||||
|
||||
## Critical Coding Requirements
|
||||
|
||||
### 1. Code Quality - MANDATORY
|
||||
**Every code change MUST pass `flutter analyze` with zero issues**
|
||||
- Run `flutter analyze` after EVERY code modification
|
||||
- Resolve ALL issues (info, warning, error) - no exceptions
|
||||
- The codebase has zero issues by default, so any issue is from your changes
|
||||
- DO NOT commit or consider work complete until `flutter analyze` passes cleanly
|
||||
|
||||
### 2. Component Reuse - MANDATORY
|
||||
**Always try to reuse existing components**
|
||||
- Use a subagent to search for existing components before creating new ones
|
||||
- Only create new components if none exist that meet the requirements
|
||||
- Check both UI components in `lib/ui/` and shared components in `../../packages/`
|
||||
|
||||
### 3. Design System - MANDATORY
|
||||
**Never hardcode colors or text styles**
|
||||
- Always use the Ente design system for colors and typography
|
||||
- Use a subagent to find the appropriate design tokens
|
||||
- Access colors via theme: `getEnteColorScheme(context)`
|
||||
- Access text styles via theme: `getEnteTextTheme(context)`
|
||||
- Call above theme getters only at the top of (`build`) methods and re-use them throughout the component
|
||||
- If you MUST use custom colors/styles (extremely rare), explicitly inform the user with a clear warning
|
||||
|
||||
### 4. Documentation Sync - MANDATORY
|
||||
**Keep spec documents synchronized with code changes**
|
||||
- When modifying code, also update any associated spec documents
|
||||
- Check for related spec files in `docs/` or project directories
|
||||
- Ensure documentation reflects the current implementation
|
||||
- Update examples in specs if behavior changes
|
||||
|
||||
## Important Notes
|
||||
|
||||
- Large service files (some 70k+ lines) - consider file context when editing
|
||||
- 400+ dependencies - check existing libraries before adding new ones
|
||||
- When adding functionality, check both `../../packages/` for shared code and `./plugins/` for Photos-specific plugins
|
||||
- Performance-critical paths use Rust integration
|
||||
- Always follow existing code conventions and patterns in neighboring files
|
||||
|
||||
# Individual Preferences
|
||||
- @~/.claude/my-project-instructions.md
|
||||
@@ -1,7 +1,9 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="io.ente.photos">
|
||||
<application android:name="${applicationName}"
|
||||
<application
|
||||
tools:replace="android:label"
|
||||
android:name="${applicationName}"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@mipmap/icon_green"
|
||||
android:usesCleartextTraffic="true"
|
||||
|
||||
@@ -1,36 +1,49 @@
|
||||
Ente is a simple app to backup and share your photos and videos.
|
||||
Store, share and discover your memories with Ente Photos. With end-to-end encryption, only you—and those you share with—can see your photos and videos. Ente Photos has lovingly protected over 200 million memories for people who trust us across all major platforms. Get started with 10 GB free.
|
||||
|
||||
If you've been looking for a privacy-friendly alternative to Google Photos, you've come to the right place. With Ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them.
|
||||
Why Ente Photos?
|
||||
|
||||
We have open-source apps across Android, iOS, web and desktop, and your photos will seamlessly sync between all of them in an end-to-end encrypted (e2ee) manner.
|
||||
Ente Photos is designed for those who truly value their memories. With end-to-end encryption and secure backups in three locations, your photos stay truly private and safe. Powerful on-device AI helps you find faces and objects instantly, while curated stories bring cherished memories to the present. Share encrypted albums with loved ones, invite family at no extra cost, and lock sensitive images with a password. Available on mobile, desktop, and web, Ente preserves every pixel of your photos and videos.
|
||||
|
||||
Ente also makes it simple to share your albums with your loved ones, even if they aren't on Ente. You can share publicly viewable links, where they can view your album and collaborate by adding photos to it, even without an account or app.
|
||||
Features:
|
||||
|
||||
Your encrypted data is replicated to 3 different locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you.
|
||||
END-TO-END ENCRYPTED STORAGE: Your photos and videos are encrypted on your device, and then automatically backed up to the cloud.
|
||||
|
||||
We are here to make the safest photos app ever, come join our journey!
|
||||
SHARE AND COLLABORATE: Let your family or friends add photos and videos to your albums. Everything, end-to-end encrypted.
|
||||
|
||||
FEATURES
|
||||
- Original quality backups, because every pixel is important
|
||||
- Family plans, so you can share storage with your family
|
||||
- Collaborative albums, so you can pool together photos after a trip
|
||||
- Shared folders, in case you want your partner to enjoy your "Camera" clicks
|
||||
- Album links, that can be protected with a password
|
||||
- Ability to free up space, by removing files that have been safely backed up
|
||||
- Human support, because you're worth it
|
||||
- Descriptions, so you can caption your memories and find them easily
|
||||
- Image editor, to add finishing touches
|
||||
- Favorite, hide and relive your memories, for they are precious
|
||||
- One-click import from Google, Apple, your hard drive and more
|
||||
- Dark theme, because your photos look good in it
|
||||
- 2FA, 3FA, biometric auth
|
||||
- and a LOT more!
|
||||
RELIVE YOUR MEMORIES: Through the stories Ente curates for you, relive your memories from previous years. Easily spread the cheer by sharing them with your loved ones or friends.
|
||||
|
||||
PERMISSIONS
|
||||
Ente requests for certain permissions to serve the purpose of a photo storage provider, which can be reviewed here: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
|
||||
SEARCH FOR ANYONE AND ANYTHING: Using on-device AI, Ente helps you find faces and key elements in a photo, so you can search through your entire library using natural language search.
|
||||
|
||||
PRICING
|
||||
We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io.
|
||||
INVITE YOUR FAMILY: Invite up to 5 family members to any paid plan at no extra cost. Only your storage space is shared, not your data. Each member will receive their own private space.
|
||||
|
||||
SUPPORT
|
||||
We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours.
|
||||
AVAILABLE EVERYWHERE: Ente Photos is available on iOS, Android, Windows, Mac, Linux and the web, so you can access your photos and videos from any device you have.
|
||||
|
||||
NEVER LOSE YOUR PHOTOS: Ente stores your encrypted backups in 3 secure locations—including an underground facility—so your photos stay safe, no matter what.
|
||||
|
||||
EASY IMPORT: Use our powerful desktop app to import data from other providers. If you need any help moving, reach out, and we'll be there.
|
||||
|
||||
ORIGINAL QUALITY BACKUPS: All photos and videos are stored in their original quality, including the metadata, without any compression or loss in quality.
|
||||
|
||||
APP LOCK: Make sure no one else can see your photos and videos using the built in App Lock. You can set a pin, or use biometrics to lock the app only for yourself.
|
||||
|
||||
HIDDEN PHOTOS: Hide your most private photos and videos to the Hidden folder, which is password protected by default.
|
||||
|
||||
FREE DEVICE SPACE: Free up your device's space by clearing files that have already been backed, in a single click.
|
||||
|
||||
COLLECT PHOTOS: Went to a party and want to collect all the photos in one place? Just share a link with your friends and ask them to upload.
|
||||
|
||||
PARTNER SHARING: Share your camera album with your partner so they can automatically see your photos on their device.
|
||||
|
||||
LEGACY: Allow trusted contacts to access your account in your absence.
|
||||
|
||||
DARK & LIGHT THEMES: Choose the mode that will make your photos pop.
|
||||
|
||||
ADDITIONAL SECURITY: Turn on two-factor authentication or set a lock-screen for the app.
|
||||
|
||||
OPEN-SOURCE AND AUDITED: Ente Photos’s code is open-source, and has been audited by third-party security experts.
|
||||
|
||||
HUMAN SUPPORT: We take pride in providing real human support. If you need help, reach out to support@ente.io, and one of us will be there to assist you.
|
||||
|
||||
Keep your memories safe and private, with Ente Photos. Get started with 10 GB free.
|
||||
|
||||
Visit ente.io to learn more.
|
||||
|
After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 584 KiB |
|
Before Width: | Height: | Size: 690 KiB After Width: | Height: | Size: 522 KiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 662 KiB |
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 853 KiB After Width: | Height: | Size: 521 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 1.5 MiB |
@@ -1 +1 @@
|
||||
Ente Photos is an open source photos app, that provides end-to-end encrypted backups for your photos and videos.
|
||||
Backup, Organise, Share - Private photo storage with end-to-end encryption
|
||||
@@ -1 +1 @@
|
||||
Ente Photos - Open source, end-to-end encrypted alternative to Google Photos
|
||||
Ente Photos - Encrypted photo storage
|
||||
@@ -8,10 +8,10 @@ allprojects {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
// mavenLocal() // for FDroid
|
||||
maven {
|
||||
url "${project(':ffmpeg_kit_flutter').projectDir}/libs"
|
||||
}
|
||||
mavenLocal() // for FDroid
|
||||
// maven {
|
||||
// url "${project(':ffmpeg_kit_flutter').projectDir}/libs"
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +1,49 @@
|
||||
ente is a simple app to backup and share your photos and videos.
|
||||
Store, share and discover your memories with Ente Photos. With end-to-end encryption, only you—and those you share with—can see your photos and videos. Ente Photos has lovingly protected over 165 million memories for people who trust us across all major platforms. Get started with 10 GB free.
|
||||
|
||||
If you've been looking for a privacy-friendly alternative to Google Photos, you've come to the right place. With ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them.
|
||||
Why Ente Photos?
|
||||
|
||||
We have open-source apps across Android, iOS, web and desktop, and your photos will seamlessly sync between all of them in an end-to-end encrypted (e2ee) manner.
|
||||
Ente Photos is designed for those who truly value their memories. With end-to-end encryption and secure backups in three locations, your photos stay truly private and safe. Powerful on-device AI helps you find faces and objects instantly, while curated stories bring cherished memories to the present. Share encrypted albums with loved ones, invite family at no extra cost, and lock sensitive images with a password. Available on mobile, desktop, and web, Ente preserves every pixel of your photos and videos.
|
||||
|
||||
ente also makes it simple to share your albums with your loved ones, even if they aren't on ente. You can share publicly viewable links, where they can view your album and collaborate by adding photos to it, even without an account or app.
|
||||
Features:
|
||||
|
||||
Your encrypted data is replicated to 3 different locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you.
|
||||
END-TO-END ENCRYPTED STORAGE: Your photos and videos are encrypted on your device, and then automatically backed up to the cloud.
|
||||
|
||||
We are here to make the safest photos app ever, come join our journey!
|
||||
SHARE AND COLLABORATE: Let your family or friends add photos and videos to your albums. Everything, end-to-end encrypted.
|
||||
|
||||
FEATURES
|
||||
- Original quality backups, because every pixel is important
|
||||
- Family plans, so you can share storage with your family
|
||||
- Collaborative albums, so you can pool together photos after a trip
|
||||
- Shared folders, in case you want your partner to enjoy your "Camera" clicks
|
||||
- Album links, that can be protected with a password
|
||||
- Ability to free up space, by removing files that have been safely backed up
|
||||
- Human support, because you're worth it
|
||||
- Descriptions, so you can caption your memories and find them easily
|
||||
- Image editor, to add finishing touches
|
||||
- Favorite, hide and relive your memories, for they are precious
|
||||
- One-click import from Google, Apple, your hard drive and more
|
||||
- Dark theme, because your photos look good in it
|
||||
- 2FA, 3FA, biometric auth
|
||||
- and a LOT more!
|
||||
RELIVE YOUR MEMORIES: Through the stories Ente curates for you, relive your memories from previous years. Easily spread the cheer by sharing them with your loved ones or friends.
|
||||
|
||||
PERMISSIONS
|
||||
ente requests for certain permissions to serve the purpose of a photo storage provider, which can be reviewed here: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
|
||||
SEARCH FOR ANYONE AND ANYTHING: Using on-device AI, Ente helps you find faces and key elements in a photo, so you can search through your entire library using natural language search.
|
||||
|
||||
PRICING
|
||||
We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io.
|
||||
INVITE YOUR FAMILY: Invite up to 5 family members to any paid plan at no extra cost. Only your storage space is shared, not your data. Each member will receive their own private space.
|
||||
|
||||
SUPPORT
|
||||
We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours.
|
||||
AVAILABLE EVERYWHERE: Ente Photos is available on iOS, Android, Windows, Mac, Linux and the web, so you can access your photos and videos from any device you have.
|
||||
|
||||
NEVER LOSE YOUR PHOTOS: Ente stores your encrypted backups in 3 secure locations—including an underground facility—so your photos stay safe, no matter what.
|
||||
|
||||
EASY IMPORT: Use our powerful desktop app to import data from other providers. If you need any help moving, reach out, and we'll be there.
|
||||
|
||||
ORIGINAL QUALITY BACKUPS: All photos and videos are stored in their original quality, including the metadata, without any compression or loss in quality.
|
||||
|
||||
APP LOCK: Make sure no one else can see your photos and videos using the built in App Lock. You can set a pin, or use biometrics to lock the app only for yourself.
|
||||
|
||||
HIDDEN PHOTOS: Hide your most private photos and videos to the Hidden folder, which is password protected by default.
|
||||
|
||||
FREE DEVICE SPACE: Free up your device's space by clearing files that have already been backed, in a single click.
|
||||
|
||||
COLLECT PHOTOS: Went to a party and want to collect all the photos in one place? Just share a link with your friends and ask them to upload.
|
||||
|
||||
PARTNER SHARING: Share your camera album with your partner so they can automatically see your photos on their device.
|
||||
|
||||
LEGACY: Allow trusted contacts to access your account in your absence.
|
||||
|
||||
DARK & LIGHT THEMES: Choose the mode that will make your photos pop.
|
||||
|
||||
ADDITIONAL SECURITY: Turn on two-factor authentication or set a lock-screen for the app.
|
||||
|
||||
OPEN-SOURCE AND AUDITED: Ente Photos’s code is open-source, and has been audited by third-party security experts.
|
||||
|
||||
HUMAN SUPPORT: We take pride in providing real human support. If you need help, reach out to support@ente.io, and one of us will be there to assist you.
|
||||
|
||||
Keep your memories safe and private, with Ente Photos. Get started with 10 GB free.
|
||||
|
||||
Visit ente.io to learn more.
|
||||
@@ -1 +1 @@
|
||||
ente is an end-to-end encrypted photo storage app
|
||||
Backup, Organise, Share - Private photo storage with end-to-end encryption
|
||||
@@ -1 +1 @@
|
||||
ente - encrypted photo storage
|
||||
Ente Photos - Encrypted photo storage
|
||||
|
After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 584 KiB |
|
Before Width: | Height: | Size: 690 KiB After Width: | Height: | Size: 522 KiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 662 KiB |
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 853 KiB After Width: | Height: | Size: 521 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 1.5 MiB |
@@ -312,7 +312,7 @@ DEPENDENCIES:
|
||||
- workmanager (from `.symlinks/plugins/workmanager/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/ente-io/ffmpeg-kit-custom-repo-ios:
|
||||
https://github.com/ente-io/ffmpeg-kit-custom-repo-ios.git:
|
||||
- ffmpeg_kit_custom
|
||||
trunk:
|
||||
- Firebase
|
||||
@@ -457,85 +457,85 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/workmanager/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
app_links: 76b66b60cc809390ca1ad69bfd66b998d2387ac7
|
||||
battery_info: 83f3aae7be2fccefab1d2bf06b8aa96f11c8bcdd
|
||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||
cupertino_http: 94ac07f5ff090b8effa6c5e2c47871d48ab7c86c
|
||||
dart_ui_isolate: 46f6714abe6891313267153ef6f9748d8ecfcab1
|
||||
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||
emoji_picker_flutter: ed468d9746c21711e66b2788880519a9de5de211
|
||||
app_links: f3e17e4ee5e357b39d8b95290a9b2c299fca71c6
|
||||
battery_info: b6c551049266af31556b93c9d9b9452cfec0219f
|
||||
connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d
|
||||
cupertino_http: 947a233f40cfea55167a49f2facc18434ea117ba
|
||||
dart_ui_isolate: d5bcda83ca4b04f129d70eb90110b7a567aece14
|
||||
device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
|
||||
emoji_picker_flutter: fe2e6151c5b548e975d546e6eeb567daf0962a58
|
||||
ffmpeg_kit_custom: 682b4f2f1ff1f8abae5a92f6c3540f2441d5be99
|
||||
ffmpeg_kit_flutter: 915b345acc97d4142e8a9a8549d177ff10f043f5
|
||||
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
|
||||
ffmpeg_kit_flutter: 9dce4803991478c78c6fb9f972703301101095fe
|
||||
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
|
||||
Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e
|
||||
firebase_core: ece862f94b2bc72ee0edbeec7ab5c7cb09fe1ab5
|
||||
firebase_messaging: e1a5fae495603115be1d0183bc849da748734e2b
|
||||
firebase_core: cf4d42a8ac915e51c0c2dc103442f3036d941a2d
|
||||
firebase_messaging: fee490327c1aae28a0da1e65fca856547deca493
|
||||
FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e
|
||||
FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4
|
||||
FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843
|
||||
FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_email_sender: aa1e9772696691d02cd91fea829856c11efb8e58
|
||||
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
|
||||
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
|
||||
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
|
||||
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
|
||||
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
|
||||
flutter_sodium: 7e4621538491834eba53bd524547854bcbbd6987
|
||||
flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544
|
||||
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
|
||||
flutter_email_sender: e03bdda7637bcd3539bfe718fddd980e9508efaa
|
||||
flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e
|
||||
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
|
||||
flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f
|
||||
flutter_native_splash: df59bb2e1421aa0282cb2e95618af4dcb0c56c29
|
||||
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||
flutter_sodium: a00383520fc689c688b66fd3092984174712493e
|
||||
flutter_timezone: ac3da59ac941ff1c98a2e1f0293420e020120282
|
||||
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||
home_widget: f169fc41fd807b4d46ab6615dc44d62adbf9f64f
|
||||
in_app_purchase_storekit: d1a48cb0f8b29dbf5f85f782f5dd79b21b90a5e6
|
||||
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
|
||||
launcher_icon_switcher: 84c218d233505aa7d8655d8fa61a3ba802c022da
|
||||
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
|
||||
in_app_purchase_storekit: a1ce04056e23eecc666b086040239da7619cd783
|
||||
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
|
||||
launcher_icon_switcher: 8e0ad2131a20c51c1dd939896ee32e70cd845b37
|
||||
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
|
||||
local_auth_ios: f7a1841beef3151d140a967c2e46f30637cdf451
|
||||
local_auth_ios: 5046a18c018dd973247a0564496c8898dbb5adf9
|
||||
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
|
||||
maps_launcher: edf829809ba9e894d70e569bab11c16352dedb45
|
||||
media_extension: 671e2567880d96c95c65c9a82ccceed8f2e309fd
|
||||
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
|
||||
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
|
||||
motion_sensors: 741e702c17467b9569a92165dda8d4d88c6167f1
|
||||
motionphoto: 23e2aeb5c6380112f69468d71f970fa7438e5ed1
|
||||
move_to_background: 7e3467dd2a1d1013e98c9c1cb93fd53cd7ef9d84
|
||||
maps_launcher: 2e5b6a2d664ec6c27f82ffa81b74228d770ab203
|
||||
media_extension: 6618f07abd762cdbfaadf1b0c56a287e820f0c84
|
||||
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
||||
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
||||
motion_sensors: 03f55b7c637a7e365a0b5f9697a449f9059d5d91
|
||||
motionphoto: 8b65ce50c7d7ff3c767534fc3768b2eed9ac24e4
|
||||
move_to_background: cd3091014529ec7829e342ad2d75c0a11f4378a5
|
||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||
native_video_player: 6809dec117e8997161dbfb42a6f90d6df71a504d
|
||||
objective_c: 89e720c30d716b036faf9c9684022048eee1eee2
|
||||
onnxruntime: f9b296392c96c42882be020a59dbeac6310d81b2
|
||||
native_video_player: 29ab24a926804ac8c4a57eb6d744c7d927c2bc3e
|
||||
objective_c: 77e887b5ba1827970907e10e832eec1683f3431d
|
||||
onnxruntime: e7c2ae44385191eaad5ae64c935a72debaddc997
|
||||
onnxruntime-c: a909204639a1f035f575127ac406f781ac797c9c
|
||||
onnxruntime-objc: b6fab0f1787aa6f7190c2013f03037df4718bd8b
|
||||
open_mail_app: 7314a609e88eed22d53671279e189af7a0ab0f11
|
||||
open_mail_app: 70273c53f768beefdafbe310c3d9086e4da3cb02
|
||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||
photo_manager: 1d80ae07a89a67dfbcae95953a1e5a24af7c3e62
|
||||
privacy_screen: 3159a541f5d3a31bea916cfd4e58f9dc722b3fd4
|
||||
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
photo_manager: 81954a1bf804b6e882d0453b3b6bc7fad7b47d3d
|
||||
privacy_screen: 1a131c052ceb3c3659934b003b0d397c2381a24e
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
||||
rive_common: dd421daaf9ae69f0125aa761dd96abd278399952
|
||||
rust_lib_photos: 04d3901908d2972192944083310b65abf410774c
|
||||
receive_sharing_intent: 79c848f5b045674ad60b9fea3bafea59962ad2c1
|
||||
rive_common: 4743dbfd2911c99066547a3c6454681e0fa907df
|
||||
rust_lib_photos: 8813b31af48ff02ca75520cbc81a363a13d51a84
|
||||
SDWebImage: f29024626962457f3470184232766516dee8dfea
|
||||
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
|
||||
Sentry: da60d980b197a46db0b35ea12cb8f39af48d8854
|
||||
sentry_flutter: 27892878729f42701297c628eb90e7c6529f3684
|
||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||
sentry_flutter: 2df8b0aab7e4aba81261c230cbea31c82a62dd1b
|
||||
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
|
||||
sqlite3: 1d85290c3321153511f6e900ede7a1608718bbd5
|
||||
sqlite3_flutter_libs: e7fc8c9ea2200ff3271f08f127842131746b70e2
|
||||
system_info_plus: 555ce7047fbbf29154726db942ae785c29211740
|
||||
thermal: d4c48be750d1ddbab36b0e2dcb2471531bc8df41
|
||||
ua_client_hints: 92fe0d139619b73ec9fcb46cc7e079a26178f586
|
||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||
vibration: 8e2f50fc35bb736f9eecb7dd9f7047fbb6a6e888
|
||||
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
|
||||
video_thumbnail: b637e0ad5f588ca9945f6e2c927f73a69a661140
|
||||
volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12
|
||||
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
||||
workmanager: b89e4e4445d8b57ee2fdbf1c3925696ebe5b8990
|
||||
sqlite3_flutter_libs: 2c48c4ee7217fd653251975e43412250d5bcbbe2
|
||||
system_info_plus: 5393c8da281d899950d751713575fbf91c7709aa
|
||||
thermal: a9261044101ae8f532fa29cab4e8270b51b3f55c
|
||||
ua_client_hints: aeabd123262c087f0ce151ef96fa3ab77bfc8b38
|
||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||
vibration: 7d883d141656a1c1a6d8d238616b2042a51a1241
|
||||
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
|
||||
video_thumbnail: c4e2a3c539e247d4de13cd545344fd2d26ffafd1
|
||||
volume_controller: 2e3de73d6e7e81a0067310d17fb70f2f86d71ac7
|
||||
wakelock_plus: 76957ab028e12bfa4e66813c99e46637f367fc7e
|
||||
workmanager: 05afacf221f5086e18450250dce57f59bb23e6b0
|
||||
|
||||
PODFILE CHECKSUM: cce2cd3351d3488dca65b151118552b680e23635
|
||||
|
||||
|
||||
@@ -39,10 +39,26 @@ class ClipVectorDB {
|
||||
final documentsDirectory = await getApplicationDocumentsDirectory();
|
||||
final String dbPath = join(documentsDirectory.path, _databaseName);
|
||||
_logger.info("Opening vectorDB access: DB path " + dbPath);
|
||||
final vectorDB = VectorDb(
|
||||
filePath: dbPath,
|
||||
dimensions: _embeddingDimension,
|
||||
);
|
||||
late VectorDb vectorDB;
|
||||
try {
|
||||
vectorDB = VectorDb(
|
||||
filePath: dbPath,
|
||||
dimensions: _embeddingDimension,
|
||||
);
|
||||
} catch (e, s) {
|
||||
_logger.severe("Could not open VectorDB at path $dbPath", e, s);
|
||||
_logger.severe("Deleting the index file and trying again");
|
||||
await deleteIndexFile();
|
||||
try {
|
||||
vectorDB = VectorDb(
|
||||
filePath: dbPath,
|
||||
dimensions: _embeddingDimension,
|
||||
);
|
||||
} catch (e, s) {
|
||||
_logger.severe("Still can't open VectorDB at path $dbPath", e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
final stats = await getIndexStats(vectorDB);
|
||||
_logger.info("VectorDB connection opened with stats: ${stats.toString()}");
|
||||
|
||||
|
||||
@@ -1927,8 +1927,8 @@
|
||||
"hoorayyyy": "Hurraaaa!",
|
||||
"nothingToTidyUpHere": "Hier gibt es nichts zu bereinigen",
|
||||
"cLTitle1": "Ähnliche Bilder",
|
||||
"cLDesc1": "Wir führen ein neues ML-basiertes System ein, um ähnliche Bilder zu erkennen, mit dem du deine Bibliothek bereinigen kannst. Verfügbar unter Einstellungen->Sicherung->Speicherplatz freigeben",
|
||||
"cLTitle2": "Manuelle Video-Stream-Generierung",
|
||||
"cLDesc1": "Wir führen ein neues ML-basiertes System ein, um ähnliche Bilder zu erkennen, mit dem du deine Bibliothek bereinigen kannst. Verfügbar unter Einstellungen -> Sicherung -> Speicherplatz freigeben",
|
||||
"cLTitle2": "Video-Streaming-Verbesserungen",
|
||||
"cLDesc2": "Du kannst jetzt die Stream-Generierung für Videos direkt aus der App manuell auslösen. Wir haben auch einen neuen Video-Streaming-Einstellungsbildschirm hinzugefügt, der dir zeigt, welcher Prozentsatz deiner Videos für das Streaming verarbeitet wurde",
|
||||
"cLTitle3": "Leistungsverbesserungen",
|
||||
"cLDesc3": "Mehrere Verbesserungen im Hintergrund, einschließlich besserer Cache-Nutzung und einer flüssigeren Scroll-Erfahrung"
|
||||
|
||||
@@ -1932,10 +1932,10 @@
|
||||
"hoorayyyy": "Hoorayyyy!",
|
||||
"nothingToTidyUpHere": "Nothing to tidy up here",
|
||||
"deletingDash": "Deleting - ",
|
||||
"cLTitle1": "Similar Images",
|
||||
"cLDesc1": "We are introducing a new ML-based system to detect similar images, using which you can cleanup your library. Available in Settings->Backup->Free Up Space",
|
||||
"cLTitle2": "Manual video stream generation",
|
||||
"cLTitle1": "Similar images",
|
||||
"cLDesc1": "We are introducing a new ML-based system to detect similar images, using which you can cleanup your library. Available in Settings -> Backup -> Free up space",
|
||||
"cLTitle2": "Video streaming enhancements",
|
||||
"cLDesc2": "You can now manually trigger stream generation for videos directly from the app. We have also added a new video streaming settings screen which will show you what percentage of your videos have been processed for streaming",
|
||||
"cLTitle3": "Performance Improvements",
|
||||
"cLTitle3": "Performance improvements",
|
||||
"cLDesc3": "Multiple under the hood improvements, including better cache usage and a smoother scroll experience"
|
||||
}
|
||||
|
||||
@@ -1926,10 +1926,10 @@
|
||||
"related": "Relacionado",
|
||||
"hoorayyyy": "¡Hurraaaa!",
|
||||
"nothingToTidyUpHere": "Nada que limpiar aquí",
|
||||
"cLTitle1": "Imágenes Similares",
|
||||
"cLDesc1": "Estamos introduciendo un nuevo sistema basado en ML para detectar imágenes similares, con el cual puedes limpiar tu biblioteca. Disponible en Configuración->Copia de Seguridad->Liberar Espacio",
|
||||
"cLTitle2": "Generación manual de transmisión de video",
|
||||
"cLTitle1": "Imágenes similares",
|
||||
"cLDesc1": "Estamos introduciendo un nuevo sistema basado en ML para detectar imágenes similares, con el cual puedes limpiar tu biblioteca. Disponible en Configuración -> Copia de seguridad -> Liberar espacio",
|
||||
"cLTitle2": "Mejoras de transmisión de video",
|
||||
"cLDesc2": "Ahora puedes activar manualmente la generación de transmisión para videos directamente desde la aplicación. También hemos agregado una nueva pantalla de configuración de transmisión de video que te mostrará qué porcentaje de tus videos han sido procesados para transmisión",
|
||||
"cLTitle3": "Mejoras de Rendimiento",
|
||||
"cLTitle3": "Mejoras de rendimiento",
|
||||
"cLDesc3": "Múltiples mejoras internas, incluyendo mejor uso de caché y una experiencia de desplazamiento más fluida"
|
||||
}
|
||||
@@ -1918,10 +1918,10 @@
|
||||
"related": "Liés",
|
||||
"hoorayyyy": "Houraaa !",
|
||||
"nothingToTidyUpHere": "Rien à nettoyer ici",
|
||||
"cLTitle1": "Images Similaires",
|
||||
"cLDesc1": "Nous introduisons un nouveau système basé sur l'IA pour détecter les images similaires, avec lequel vous pouvez nettoyer votre bibliothèque. Disponible dans Paramètres->Sauvegarde->Libérer de l'espace",
|
||||
"cLTitle2": "Génération manuelle de flux vidéo",
|
||||
"cLDesc2": "Vous pouvez maintenant déclencher manuellement la génération de flux pour les vidéos directement depuis l'application. Nous avons également ajouté un nouvel écran de paramètres de streaming vidéo qui vous montrera quel pourcentage de vos vidéos ont été traitées pour le streaming",
|
||||
"cLTitle3": "Améliorations de performance",
|
||||
"cLTitle1": "Images similaires",
|
||||
"cLDesc1": "Nous introduisons un nouveau système basé sur l'IA pour détecter les images similaires, avec lequel vous pouvez nettoyer votre bibliothèque. Disponible dans Paramètres -> Sauvegarde -> Libérer de l'espace",
|
||||
"cLTitle2": "Améliorations de la diffusion vidéo",
|
||||
"cLDesc2": "Vous pouvez maintenant déclencher manuellement la génération de flux pour les vidéos directement depuis l'application. Nous avons également ajouté un nouvel écran de paramètres de diffusion vidéo qui vous montrera quel pourcentage de vos vidéos ont été traitées pour la diffusion",
|
||||
"cLTitle3": "Améliorations des performances",
|
||||
"cLDesc3": "Plusieurs améliorations internes, incluant une meilleure utilisation du cache et une expérience de défilement plus fluide"
|
||||
}
|
||||
@@ -1746,10 +1746,10 @@
|
||||
"receiveRemindersOnBirthdays": "Ricevi promemoria quando è il compleanno di qualcuno. Toccare la notifica ti porterà alle foto della persona che compie gli anni.",
|
||||
"happyBirthday": "Buon compleanno! 🥳",
|
||||
"birthdays": "Compleanni",
|
||||
"cLTitle1": "Immagini Simili",
|
||||
"cLDesc1": "Stiamo introducendo un nuovo sistema basato su ML per rilevare immagini simili, con il quale puoi pulire la tua libreria. Disponibile in Impostazioni->Backup->Libera Spazio",
|
||||
"cLTitle2": "Generazione manuale stream video",
|
||||
"cLTitle1": "Immagini simili",
|
||||
"cLDesc1": "Stiamo introducendo un nuovo sistema basato su ML per rilevare immagini simili, con il quale puoi pulire la tua libreria. Disponibile in Impostazioni -> Backup -> Libera spazio",
|
||||
"cLTitle2": "Miglioramenti streaming video",
|
||||
"cLDesc2": "Ora puoi attivare manualmente la generazione di stream per i video direttamente dall'app. Abbiamo anche aggiunto una nuova schermata delle impostazioni di streaming video che ti mostrerà quale percentuale dei tuoi video è stata elaborata per lo streaming",
|
||||
"cLTitle3": "Miglioramenti delle Prestazioni",
|
||||
"cLTitle3": "Miglioramenti delle prestazioni",
|
||||
"cLDesc3": "Multipli miglioramenti interni, incluso un miglior utilizzo della cache e un'esperienza di scorrimento più fluida"
|
||||
}
|
||||
@@ -1667,9 +1667,9 @@
|
||||
"food": "料理を楽しむ",
|
||||
"pets": "毛むくじゃらな仲間たち",
|
||||
"cLTitle1": "類似画像",
|
||||
"cLDesc1": "類似画像を検出する新しいML基盤システムを導入し、ライブラリをクリーンアップできます。設定->バックアップ->容量を空けるで利用可能",
|
||||
"cLTitle2": "手動ビデオストリーム生成",
|
||||
"cLDesc2": "アプリから直接、ビデオのストリーム生成を手動でトリガーできるようになりました。また、ビデオのうち何パーセントがストリーミング用に処理されたかを表示する新しいビデオストリーミング設定画面も追加しました",
|
||||
"cLDesc1": "類似画像を検出する新しいML基盤システムを導入し、ライブラリをクリーンアップできます。設定 -> バックアップ -> 容量を空ける で利用可能",
|
||||
"cLTitle2": "動画ストリーミングの強化",
|
||||
"cLDesc2": "アプリから直接、動画のストリーム生成を手動でトリガーできるようになりました。また、動画のうち何パーセントがストリーミング用に処理されたかを表示する新しい動画ストリーミング設定画面も追加しました",
|
||||
"cLTitle3": "パフォーマンスの改善",
|
||||
"cLDesc3": "より良いキャッシュ使用とよりスムーズなスクロール体験を含む、複数の内部改善"
|
||||
}
|
||||
@@ -1773,10 +1773,10 @@
|
||||
"areYouSureYouWantToMergeThem": "Weet je zeker dat je ze wilt samenvoegen?",
|
||||
"allUnnamedGroupsWillBeMergedIntoTheSelectedPerson": "Alle naamloze groepen worden samengevoegd met de geselecteerde persoon. Dit kan nog steeds ongedaan worden gemaakt vanuit het geschiedenisoverzicht van de persoon.",
|
||||
"yesIgnore": "Ja, negeer",
|
||||
"cLTitle1": "Vergelijkbare Afbeeldingen",
|
||||
"cLDesc1": "We introduceren een nieuw ML-gebaseerd systeem om vergelijkbare afbeeldingen te detecteren, waarmee je je bibliotheek kunt opschonen. Beschikbaar in Instellingen->Backup->Ruimte vrijmaken",
|
||||
"cLTitle2": "Handmatige video stream generatie",
|
||||
"cLTitle1": "Vergelijkbare afbeeldingen",
|
||||
"cLDesc1": "We introduceren een nieuw ML-gebaseerd systeem om vergelijkbare afbeeldingen te detecteren, waarmee je je bibliotheek kunt opschonen. Beschikbaar in Instellingen -> Backup -> Ruimte vrijmaken",
|
||||
"cLTitle2": "Video streaming verbeteringen",
|
||||
"cLDesc2": "Je kunt nu handmatig stream generatie voor video's activeren direct vanuit de app. We hebben ook een nieuw video streaming instellingenscherm toegevoegd dat toont welk percentage van je video's is verwerkt voor streaming",
|
||||
"cLTitle3": "Prestatie Verbeteringen",
|
||||
"cLTitle3": "Prestatieverbeteringen",
|
||||
"cLDesc3": "Meerdere verbeteringen onder de motorkap, inclusief beter cache gebruik en een vloeiendere scroll ervaring"
|
||||
}
|
||||
@@ -1737,10 +1737,10 @@
|
||||
"memoriesWidgetDesc": "Velg typen minner du ønsker å se på din hjemskjerm.",
|
||||
"smartMemories": "Smarte minner",
|
||||
"pastYearsMemories": "Tidligere års minner",
|
||||
"cLTitle1": "Lignende Bilder",
|
||||
"cLDesc1": "Vi introduserer et nytt ML-basert system for å oppdage lignende bilder, som du kan bruke til å rydde opp i biblioteket ditt. Tilgjengelig i Innstillinger->Sikkerhetskopi->Frigjør plass",
|
||||
"cLTitle2": "Manuell video stream generering",
|
||||
"cLTitle1": "Lignende bilder",
|
||||
"cLDesc1": "Vi introduserer et nytt ML-basert system for å oppdage lignende bilder, som du kan bruke til å rydde opp i biblioteket ditt. Tilgjengelig i Innstillinger -> Sikkerhetskopi -> Frigjør plass",
|
||||
"cLTitle2": "Video streaming forbedringer",
|
||||
"cLDesc2": "Du kan nå manuelt utløse stream generering for videoer direkte fra appen. Vi har også lagt til en ny video streaming innstillinger skjerm som viser deg hvor mange prosent av videoene dine som er behandlet for streaming",
|
||||
"cLTitle3": "Ytelsesforbedringar",
|
||||
"cLTitle3": "Ytelsesforbedringer",
|
||||
"cLDesc3": "Flere forbedringer under panseret, inkludert bedre cache bruk og en jevnere rullingsopplevelse"
|
||||
}
|
||||
@@ -1820,10 +1820,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"cLTitle1": "Podobne Obrazy",
|
||||
"cLTitle1": "Podobne obrazy",
|
||||
"cLDesc1": "Wprowadzamy nowy system oparty na ML do wykrywania podobnych obrazów, za pomocą którego możesz posprzątać swoją bibliotekę. Dostępne w Ustawienia->Kopia zapasowa->Zwolnij miejsce",
|
||||
"cLTitle2": "Ręczne generowanie strumienia wideo",
|
||||
"cLTitle2": "Ulepszenia streamingu wideo",
|
||||
"cLDesc2": "Możesz teraz ręcznie wyzwolić generowanie strumienia dla filmów bezpośrednio z aplikacji. Dodaliśmy również nowy ekran ustawień streamingu wideo, który pokaże ci, jaki procent twoich filmów zostało przetworzonych do streamingu",
|
||||
"cLTitle3": "Ulepszenia Wydajności",
|
||||
"cLTitle3": "Ulepszenia wydajności",
|
||||
"cLDesc3": "Liczne ulepszenia pod maską, w tym lepsze wykorzystanie pamięci podręcznej i płynniejsze przewijanie"
|
||||
}
|
||||
@@ -1820,10 +1820,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"cLTitle1": "Imagens Similares",
|
||||
"cLDesc1": "Estamos introduzindo um novo sistema baseado em ML para detectar imagens similares, com o qual você pode limpar sua biblioteca. Disponível em Configurações->Backup->Liberar Espaço",
|
||||
"cLTitle2": "Geração manual de stream de vídeo",
|
||||
"cLTitle1": "Imagens similares",
|
||||
"cLDesc1": "Estamos introduzindo um novo sistema baseado em ML para detectar imagens similares, com o qual você pode limpar sua biblioteca. Disponível em Configurações -> Backup -> Liberar espaço",
|
||||
"cLTitle2": "Melhorias do streaming de vídeo",
|
||||
"cLDesc2": "Agora você pode acionar manualmente a geração de stream para vídeos diretamente do aplicativo. Também adicionamos uma nova tela de configurações de streaming de vídeo que mostrará qual porcentagem dos seus vídeos foram processados para streaming",
|
||||
"cLTitle3": "Melhorias de Performance",
|
||||
"cLTitle3": "Melhorias de desempenho",
|
||||
"cLDesc3": "Múltiplas melhorias internas, incluindo melhor uso de cache e uma experiência de rolagem mais suave"
|
||||
}
|
||||
|
||||
@@ -1820,10 +1820,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"cLTitle1": "Imagens Similares",
|
||||
"cLDesc1": "Estamos a introduzir um novo sistema baseado em ML para detectar imagens similares, com o qual pode limpar a sua biblioteca. Disponível em Definições->Cópia de Segurança->Libertar Espaço",
|
||||
"cLTitle2": "Geração manual de stream de vídeo",
|
||||
"cLTitle1": "Imagens similares",
|
||||
"cLDesc1": "Estamos a introduzir um novo sistema baseado em ML para detectar imagens similares, com o qual pode limpar a sua biblioteca. Disponível em Definições -> Cópia de segurança -> Libertar espaço",
|
||||
"cLTitle2": "Melhorias do streaming de vídeo",
|
||||
"cLDesc2": "Agora pode accionar manualmente a geração de stream para vídeos directamente da aplicação. Também adicionámos um novo ecrã de definições de streaming de vídeo que mostrará que percentagem dos seus vídeos foram processados para streaming",
|
||||
"cLTitle3": "Melhorias de Performance",
|
||||
"cLTitle3": "Melhorias de desempenho",
|
||||
"cLDesc3": "Múltiplas melhorias internas, incluindo melhor uso de cache e uma experiência de deslocação mais suave"
|
||||
}
|
||||
|
||||
@@ -1522,9 +1522,9 @@
|
||||
"joinAlbumSubtext": "pentru a vedea și a adăuga fotografii",
|
||||
"joinAlbumSubtextViewer": "pentru a adăuga la albumele distribuite",
|
||||
"join": "Alăturare",
|
||||
"cLTitle1": "Imagini Similare",
|
||||
"cLTitle1": "Imagini similare",
|
||||
"cLDesc1": "Introducem un nou sistem bazat pe ML pentru detectarea imaginilor similare, cu care vă puteți curăța biblioteca. Disponibil în Setări->Backup->Eliberați Spațiu",
|
||||
"cLTitle2": "Generarea manuală a fluxului video",
|
||||
"cLTitle2": "Îmbunătățiri streaming video",
|
||||
"cLDesc2": "Acum puteți declanșa manual generarea fluxului pentru videoclipuri direct din aplicație. Am adăugat, de asemenea, un nou ecran de setări pentru streaming video care vă va arăta ce procent din videoclipurile dvs. au fost procesate pentru streaming",
|
||||
"cLTitle3": "Îmbunătățiri de Performanță",
|
||||
"cLDesc3": "Multiple îmbunătățiri în fundal, inclusiv o utilizare mai bună a cache-ului și o experiență de defilare mai fluidă"
|
||||
|
||||
@@ -1786,10 +1786,10 @@
|
||||
"day": "День",
|
||||
"filter": "Фильтр",
|
||||
"font": "Шрифт",
|
||||
"cLTitle1": "Похожие Изображения",
|
||||
"cLTitle1": "Похожие изображения",
|
||||
"cLDesc1": "Мы внедряем новую систему на основе ML для обнаружения похожих изображений, с помощью которой вы можете очистить свою библиотеку. Доступно в Настройки->Резервная копия->Освободить место",
|
||||
"cLTitle2": "Ручная генерация видео потока",
|
||||
"cLTitle2": "Улучшения видео стриминга",
|
||||
"cLDesc2": "Теперь вы можете вручную запустить генерацию потока для видео прямо из приложения. Мы также добавили новый экран настроек видео стриминга, который покажет вам, какой процент ваших видео был обработан для стриминга",
|
||||
"cLTitle3": "Улучшения Производительности",
|
||||
"cLTitle3": "Улучшения производительности",
|
||||
"cLDesc3": "Множественные улучшения под капотом, включая лучшее использование кэша и более плавную прокрутку"
|
||||
}
|
||||
@@ -1777,9 +1777,9 @@
|
||||
"different": "Farklı",
|
||||
"sameperson": "Aynı kişi mi?",
|
||||
"indexingPausedStatusDescription": "Dizin oluşturma duraklatıldı. Cihaz hazır olduğunda otomatik olarak devam edecektir. Cihaz, pil seviyesi, pil sağlığı ve termal durumu sağlıklı bir aralıkta olduğunda hazır kabul edilir.",
|
||||
"cLTitle1": "Benzer Görüntüler",
|
||||
"cLDesc1": "Benzer görüntüleri tespit etmek için yeni bir ML tabanlı sistem tanıtıyoruz, bununla kütüphanenizi temizleyebilirsiniz. Ayarlar->Yedekleme->Alan Boşalt kısmından ulaşabilirsiniz",
|
||||
"cLTitle2": "Manuel video akış oluşturma",
|
||||
"cLTitle1": "Benzer görüntüler",
|
||||
"cLDesc1": "Benzer görüntüleri tespit etmek için yeni bir ML tabanlı sistem tanıtıyoruz, bununla kütüphanenizi temizleyebilirsiniz. Ayarlar -> Yedekleme -> Alan boşalt kısmından ulaşabilirsiniz",
|
||||
"cLTitle2": "Video akış geliştirmeleri",
|
||||
"cLDesc2": "Artık doğrudan uygulamadan videolar için akış oluşturmayı manuel olarak tetikleyebilirsiniz. Ayrıca videolarınızın yüzde kaçının akış için işlendiğini gösteren yeni bir video akış ayarları ekranı da ekledik",
|
||||
"cLTitle3": "Performans İyileştirmeleri",
|
||||
"cLDesc3": "Daha iyi önbellek kullanımı ve daha pürüzsüz kaydırma deneyimi dahil olmak üzere perde arkasında birçok iyileştirme"
|
||||
|
||||
@@ -1510,10 +1510,10 @@
|
||||
"legacyInvite": "{email} запросив вас стати довіреною особою",
|
||||
"authToManageLegacy": "Авторизуйтесь, щоби керувати довіреними контактами",
|
||||
"useDifferentPlayerInfo": "Виникли проблеми з відтворенням цього відео? Натисніть і утримуйте тут, щоб спробувати інший плеєр.",
|
||||
"cLTitle1": "Схожі Зображення",
|
||||
"cLTitle1": "Схожі зображення",
|
||||
"cLDesc1": "Ми впроваджуємо нову систему на основі ML для виявлення схожих зображень, за допомогою якої ви можете очистити свою бібліотеку. Доступно в Налаштування->Резервна копія->Звільнити місце",
|
||||
"cLTitle2": "Ручна генерація відео потоку",
|
||||
"cLTitle2": "Покращення відео стрімінгу",
|
||||
"cLDesc2": "Тепер ви можете вручну запустити генерацію потоку для відео прямо з додатку. Ми також додали новий екран налаштувань відео стрімінгу, який покаже вам, який відсоток ваших відео було оброблено для стрімінгу",
|
||||
"cLTitle3": "Покращення Продуктивності",
|
||||
"cLTitle3": "Покращення продуктивності",
|
||||
"cLDesc3": "Численні покращення під капотом, включаючи краще використання кешу та більш плавну прокрутку"
|
||||
}
|
||||
@@ -1932,9 +1932,9 @@
|
||||
"hoorayyyy": "Hoorayyyy!",
|
||||
"nothingToTidyUpHere": "Ở đây đã ngon lành rồi",
|
||||
"deletingDash": "Đang xóa - ",
|
||||
"cLTitle1": "Hình Ảnh Tương Tự",
|
||||
"cLDesc1": "Chúng tôi đang giới thiệu một hệ thống dựa trên ML mới để phát hiện hình ảnh tương tự, bạn có thể dùng để dọn dẹp thư viện của mình. Có sẵn trong Cài đặt->Sao lưu->Giải phóng Dung lượng",
|
||||
"cLTitle2": "Tạo luồng video thủ công",
|
||||
"cLTitle1": "Hình ảnh tương tự",
|
||||
"cLDesc1": "Chúng tôi đang giới thiệu một hệ thống dựa trên ML mới để phát hiện hình ảnh tương tự, bạn có thể dùng để dọn dẹp thư viện của mình. Có sẵn trong Cài đặt -> Sao lưu -> Giải phóng dung lượng",
|
||||
"cLTitle2": "Cải thiện streaming video",
|
||||
"cLDesc2": "Bây giờ bạn có thể kích hoạt tạo luồng cho video trực tiếp từ ứng dụng. Chúng tôi cũng đã thêm màn hình cài đặt phát trực tuyến video mới sẽ cho bạn biết bao nhiêu phần trăm video của bạn đã được xử lý để phát trực tuyến",
|
||||
"cLTitle3": "Cải Thiện Hiệu Suất",
|
||||
"cLDesc3": "Nhiều cải thiện bên trong, bao gồm sử dụng bộ nhớ đệm tốt hơn và trải nghiệm cuộn mượt mà hơn"
|
||||
|
||||
@@ -1927,8 +1927,8 @@
|
||||
"hoorayyyy": "耶~~!",
|
||||
"nothingToTidyUpHere": "这里没什么可清理的",
|
||||
"cLTitle1": "相似图像",
|
||||
"cLDesc1": "我们正在推出一个基于机器学习的新系统来检测相似图像,您可以用它来清理您的图库。在 设置->备份->释放空间 中可用",
|
||||
"cLTitle2": "手动视频流生成",
|
||||
"cLDesc1": "我们正在推出一个基于机器学习的新系统来检测相似图像,您可以用它来清理您的图库。在 设置 -> 备份 -> 释放空间 中可用",
|
||||
"cLTitle2": "视频流媒体增强",
|
||||
"cLDesc2": "您现在可以直接从应用程序手动触发视频的流生成。我们还添加了一个新的视频流设置屏幕,它将显示您的视频中有百分之几已被处理用于流媒体播放",
|
||||
"cLTitle3": "性能改进",
|
||||
"cLDesc3": "多个底层改进,包括更好的缓存使用和更流畅的滚动体验"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'dart:async';
|
||||
import "dart:core";
|
||||
import 'dart:io';
|
||||
|
||||
import "package:adaptive_theme/adaptive_theme.dart";
|
||||
import "package:computer/computer.dart";
|
||||
import 'package:ente_crypto/ente_crypto.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import "package:flutter/rendering.dart";
|
||||
@@ -36,7 +36,6 @@ import "package:photos/services/machine_learning/face_ml/person/person_service.d
|
||||
import 'package:photos/services/machine_learning/ml_service.dart';
|
||||
import 'package:photos/services/machine_learning/semantic_search/semantic_search_service.dart';
|
||||
import "package:photos/services/notification_service.dart";
|
||||
import 'package:photos/services/push_service.dart';
|
||||
import 'package:photos/services/search_service.dart';
|
||||
import 'package:photos/services/sync/local_sync_service.dart';
|
||||
import 'package:photos/services/sync/remote_sync_service.dart';
|
||||
@@ -273,11 +272,12 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
|
||||
}
|
||||
|
||||
if (Platform.isIOS) {
|
||||
PushService.instance.init().then((_) {
|
||||
FirebaseMessaging.onBackgroundMessage(
|
||||
_firebaseMessagingBackgroundHandler,
|
||||
);
|
||||
}).ignore();
|
||||
// ignore: unawaited_futures
|
||||
// PushService.instance.init().then((_) {
|
||||
// FirebaseMessaging.onBackgroundMessage(
|
||||
// _firebaseMessagingBackgroundHandler,
|
||||
// );
|
||||
// });
|
||||
}
|
||||
_logger.info("PushService/HomeWidget done $tlog");
|
||||
unawaited(SemanticSearchService.instance.init());
|
||||
@@ -402,31 +402,6 @@ Future<bool> _isRunningInForeground() async {
|
||||
(currentTime - kFGTaskDeathTimeoutInMicroseconds);
|
||||
}
|
||||
|
||||
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
final bool isRunningInFG = await _isRunningInForeground(); // hb
|
||||
final bool isInForeground = AppLifecycleService.instance.isForeground;
|
||||
if (await _isRunningInForeground()) {
|
||||
_logger.info(
|
||||
"Background push received when app is alive and runningInFS: $isRunningInFG inForeground: $isInForeground",
|
||||
);
|
||||
if (PushService.shouldSync(message)) {
|
||||
await _sync('firebaseBgSyncActiveProcess');
|
||||
}
|
||||
} else {
|
||||
// App is dead
|
||||
runWithLogs(
|
||||
() async {
|
||||
_logger.info("Background push received");
|
||||
await _init(true, via: 'firebasePush');
|
||||
if (PushService.shouldSync(message)) {
|
||||
await _sync('firebaseBgSyncNoActiveProcess');
|
||||
}
|
||||
},
|
||||
prefix: "[fbg]",
|
||||
).ignore();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _logFGHeartBeatInfo(SharedPreferences prefs) async {
|
||||
final bool isRunningInFG = await _isRunningInForeground();
|
||||
await prefs.reload();
|
||||
|
||||
@@ -4,7 +4,6 @@ import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
// import 'package:flutter/foundation.dart';
|
||||
// import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
|
||||
import 'package:in_app_purchase/in_app_purchase.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:photos/core/errors.dart';
|
||||
import "package:photos/generated/l10n.dart";
|
||||
@@ -29,6 +28,7 @@ class BillingService {
|
||||
late final _logger = Logger("BillingService");
|
||||
final Dio _enteDio;
|
||||
|
||||
// ignore: unused_field
|
||||
bool _isOnSubscriptionPage = false;
|
||||
|
||||
Future<BillingPlans>? _future;
|
||||
@@ -42,23 +42,6 @@ class BillingService {
|
||||
// await FlutterInappPurchase.instance.initConnection;
|
||||
// FlutterInappPurchase.instance.clearTransactionIOS();
|
||||
// }
|
||||
InAppPurchase.instance.purchaseStream.listen((purchases) {
|
||||
if (_isOnSubscriptionPage) {
|
||||
return;
|
||||
}
|
||||
for (final purchase in purchases) {
|
||||
if (purchase.status == PurchaseStatus.purchased) {
|
||||
verifySubscription(
|
||||
purchase.productID,
|
||||
purchase.verificationData.serverVerificationData,
|
||||
).then((response) {
|
||||
InAppPurchase.instance.completePurchase(purchase);
|
||||
});
|
||||
} else if (Platform.isIOS && purchase.pendingCompletePurchase) {
|
||||
InAppPurchase.instance.completePurchase(purchase);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void clearCache() {
|
||||
|
||||
@@ -14,7 +14,7 @@ import 'package:url_launcher/url_launcher_string.dart';
|
||||
class UpdateService {
|
||||
static const kUpdateAvailableShownTimeKey = "update_available_shown_time_key";
|
||||
static const changeLogVersionKey = "update_change_log_key";
|
||||
static const currentChangeLogVersion = 32;
|
||||
static const currentChangeLogVersion = 36;
|
||||
|
||||
LatestVersionInfo? _latestVersion;
|
||||
final _logger = Logger("UpdateService");
|
||||
|
||||
@@ -77,7 +77,7 @@ class _ChangeLogPageState extends State<ChangeLogPage> {
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.trailingIconSecondary,
|
||||
buttonSize: ButtonSize.large,
|
||||
labelText: AppLocalizations.of(context).rateTheApp,
|
||||
labelText: AppLocalizations.of(context).rateUs,
|
||||
icon: Icons.favorite_rounded,
|
||||
iconColor: enteColorScheme.primary500,
|
||||
onTap: () async {
|
||||
@@ -113,7 +113,6 @@ class _ChangeLogPageState extends State<ChangeLogPage> {
|
||||
context.l10n.cLDesc3,
|
||||
),
|
||||
]);
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: Scrollbar(
|
||||
|
||||
@@ -1,24 +1,6 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import "package:photos/service_locator.dart";
|
||||
import "package:photos/ui/payment/store_subscription_page.dart";
|
||||
import 'package:photos/ui/payment/stripe_subscription_page.dart';
|
||||
|
||||
StatefulWidget getSubscriptionPage({bool isOnBoarding = false}) {
|
||||
if (updateService.isIndependentFlavor()) {
|
||||
return StripeSubscriptionPage(isOnboarding: isOnBoarding);
|
||||
}
|
||||
if (flagService.enableStripe && _isUserCreatedPostStripeSupport()) {
|
||||
return StripeSubscriptionPage(isOnboarding: isOnBoarding);
|
||||
} else {
|
||||
return StoreSubscriptionPage(isOnboarding: isOnBoarding);
|
||||
}
|
||||
}
|
||||
|
||||
// return true if the user was created after we added support for stripe payment
|
||||
// on frame. We do this check to avoid showing Stripe payment option for earlier
|
||||
// users who might have paid via playStore. This method should be removed once
|
||||
// we have better handling for active play/app store subscription & stripe plans.
|
||||
bool _isUserCreatedPostStripeSupport() {
|
||||
return Configuration.instance.getUserID()! > 1580559962386460;
|
||||
return StripeSubscriptionPage(isOnboarding: isOnBoarding);
|
||||
}
|
||||
|
||||
@@ -672,10 +672,7 @@ class _SimilarImagesPageState extends State<SimilarImagesPage>
|
||||
await showGenericErrorDialog(context: context, error: e);
|
||||
}
|
||||
if (_isDisposed) return;
|
||||
setState(() {
|
||||
_pageState = SimilarImagesPageState.setup;
|
||||
});
|
||||
return;
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -438,11 +438,16 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
|
||||
}
|
||||
|
||||
await relevantTaskQueue.addTask(_localThumbnailQueueTaskId!, () async {
|
||||
final thumbnailBytes = await getThumbnailFromLocal(
|
||||
widget.file,
|
||||
size: widget.thumbnailSize,
|
||||
);
|
||||
completer.complete(thumbnailBytes);
|
||||
late final Uint8List? thumbnailBytes;
|
||||
try {
|
||||
thumbnailBytes = await getThumbnailFromLocal(
|
||||
widget.file,
|
||||
size: widget.thumbnailSize,
|
||||
);
|
||||
completer.complete(thumbnailBytes);
|
||||
} catch (e) {
|
||||
completer.completeError(e);
|
||||
}
|
||||
});
|
||||
|
||||
return completer.future;
|
||||
|
||||
@@ -9,22 +9,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "85.0.0"
|
||||
_flutterfire_internals:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _flutterfire_internals
|
||||
sha256: a5788040810bd84400bc209913fbc40f388cded7cdf95ee2f5d2bff7e38d5241
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.58"
|
||||
adaptive_theme:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: adaptive_theme
|
||||
sha256: caa49b4c73b681bf12a641dff77aa1383262a00cf38b9d1a25b180e275ba5ab9
|
||||
sha256: "41b8af1bb5f3fb87db1aed8c8a2dc3eab79116d20793b5c9b6d2e8809402de9a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.7.0"
|
||||
version: "3.7.1+2"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -37,10 +29,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: android_intent_plus
|
||||
sha256: dfc1fd3a577205ae8f11e990fb4ece8c90cceabbee56fcf48e463ecf0bd6aae3
|
||||
sha256: "2329378af63f49b985cb2e110ac784d08374f1e2b1984be77ba9325b1c8cce11"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.3.0"
|
||||
version: "5.3.1"
|
||||
animated_list_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -69,10 +61,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: app_links
|
||||
sha256: "85ed8fc1d25a76475914fff28cc994653bd900bc2c26e4b57a49e097febb54ba"
|
||||
sha256: "5f88447519add627fe1cbcab4fd1da3d4fed15b9baf29f28b22535c95ecee3e8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.4.0"
|
||||
version: "6.4.1"
|
||||
app_links_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -166,10 +158,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
sha256: "7d95cbbb1526ab5ae977df9b4cc660963b9b27f6d1075c0b34653868911385e4"
|
||||
sha256: ce76b1d48875e3233fde17717c23d1f60a91cc631597e49a400c89b475395b1d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.1.0"
|
||||
build_cli_annotations:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -182,10 +174,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
|
||||
sha256: "4f64382b97504dc2fcdf487d5aae33418e08b4703fc21249e4db6d804a4d0187"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.2.0"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -198,26 +190,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "38c9c339333a09b090a638849a4c56e70a404c6bdd3b511493addfbc113b60c2"
|
||||
sha256: d1d57f7807debd7349b4726a19fd32ec8bc177c71ad0febf91a20f84cd2d4b46
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.0.3"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: b971d4a1c789eba7be3e6fe6ce5e5b50fd3719e3cb485b3fad6d04358304351d
|
||||
sha256: b24597fceb695969d47025c958f3837f9f0122e237c6a22cb082a5ac66c3ca30
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.0"
|
||||
version: "2.7.1"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: c04e612ca801cd0928ccdb891c263a2b1391cb27940a5ea5afcf9ba894de5d62
|
||||
sha256: "066dda7f73d8eb48ba630a55acb50c4a84a2e6b453b1cb4567f581729e794f7b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.2.0"
|
||||
version: "9.3.1"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -230,10 +222,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27"
|
||||
sha256: a30f0a0e38671e89a492c44d005b5545b830a961575bbd8336d42869ff71066d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.10.1"
|
||||
version: "8.12.0"
|
||||
cached_network_image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -279,10 +271,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: checked_yaml
|
||||
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
|
||||
sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
version: "2.0.4"
|
||||
chewie:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -345,10 +337,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: connectivity_plus
|
||||
sha256: "051849e2bd7c7b3bc5844ea0d096609ddc3a859890ec3a9ac4a65a2620cc1f99"
|
||||
sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.4"
|
||||
version: "6.1.5"
|
||||
connectivity_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -369,18 +361,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: coverage
|
||||
sha256: aa07dbe5f2294c827b7edb9a87bba44a9c15a3cc81bc8da2ca19b37322d30080
|
||||
sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.14.1"
|
||||
version: "1.15.0"
|
||||
cronet_http:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cronet_http
|
||||
sha256: "5ed075c59b2d4bd43af4e73d906b8082e98ecd2af9c625327370ef28361bf635"
|
||||
sha256: "1b99ad5ae81aa9d2f12900e5f17d3681f3828629bb7f7fe7ad88076a34209840"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.4"
|
||||
version: "1.5.0"
|
||||
cross_file:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -409,10 +401,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cupertino_http
|
||||
sha256: "8fb9e2c36d0732d9d96abd76683406b57e78a2514e27c962e0c603dbe6f2e3f8"
|
||||
sha256: "72187f715837290a63479a5b0ae709f4fedad0ed6bd0441c275eceaa02d5abae"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.3.0"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -433,10 +425,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "5b236382b47ee411741447c1f1e111459c941ea1b3f2b540dde54c210a3662af"
|
||||
sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.1.1"
|
||||
dart_ui_isolate:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -481,10 +473,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dio
|
||||
sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9"
|
||||
sha256: d90ee57923d1828ac14e492ca49440f65477f4bb1263575900be731a3dac66a9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.8.0+1"
|
||||
version: "5.9.0"
|
||||
dio_web_adapter:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -671,7 +663,7 @@ packages:
|
||||
description:
|
||||
path: "flutter/flutter"
|
||||
ref: remove-event-sub
|
||||
resolved-ref: "2c0f34797df830ef61e6ed479583b368c342cb37"
|
||||
resolved-ref: b7aac7903f70dce6d71506e221066af1a53ec7fc
|
||||
url: "https://github.com/ente-io/ffmpeg-kit"
|
||||
source: git
|
||||
version: "6.0.3"
|
||||
@@ -680,7 +672,7 @@ packages:
|
||||
description:
|
||||
path: "flutter/flutter_platform_interface"
|
||||
ref: remove-event-sub
|
||||
resolved-ref: "2c0f34797df830ef61e6ed479583b368c342cb37"
|
||||
resolved-ref: b7aac7903f70dce6d71506e221066af1a53ec7fc
|
||||
url: "https://github.com/ente-io/ffmpeg-kit"
|
||||
source: git
|
||||
version: "0.2.1"
|
||||
@@ -708,54 +700,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.14"
|
||||
firebase_core:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_core
|
||||
sha256: c6e8a6bf883d8ddd0dec39be90872daca65beaa6f4cff0051ed3b16c56b82e9f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.15.1"
|
||||
firebase_core_platform_interface:
|
||||
file_selector_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_platform_interface
|
||||
sha256: "5dbc900677dcbe5873d22ad7fbd64b047750124f1f9b7ebe2a33b9ddccc838eb"
|
||||
name: file_selector_linux
|
||||
sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
firebase_core_web:
|
||||
version: "0.9.3+2"
|
||||
file_selector_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_web
|
||||
sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37"
|
||||
name: file_selector_macos
|
||||
sha256: "19124ff4a3d8864fdc62072b6a2ef6c222d55a3404fe14893a3c02744907b60c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.24.1"
|
||||
firebase_messaging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_messaging
|
||||
sha256: "0f3363f97672eb9f65609fa00ed2f62cc8ec93e7e2d4def99726f9165d3d8a73"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "15.2.9"
|
||||
firebase_messaging_platform_interface:
|
||||
version: "0.9.4+4"
|
||||
file_selector_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_platform_interface
|
||||
sha256: "7a05ef119a14c5f6a9440d1e0223bcba20c8daf555450e119c4c477bf2c3baa9"
|
||||
name: file_selector_platform_interface
|
||||
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.6.9"
|
||||
firebase_messaging_web:
|
||||
version: "2.6.2"
|
||||
file_selector_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_web
|
||||
sha256: a4547f76da2a905190f899eb4d0150e1d0fd52206fce469d9f05ae15bb68b2c5
|
||||
name: file_selector_windows
|
||||
sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.10.9"
|
||||
version: "0.9.3+4"
|
||||
fixnum:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -954,10 +930,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_local_notifications
|
||||
sha256: edae0c34573233ab03f5ba1f07465e55c384743893042cb19e010b4ee8541c12
|
||||
sha256: a9966c850de5e445331b854fa42df96a8020066d67f125a5964cbc6556643f68
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "19.3.0"
|
||||
version: "19.4.1"
|
||||
flutter_local_notifications_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -978,10 +954,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_windows
|
||||
sha256: f8fc0652a601f83419d623c85723a3e82ad81f92b33eaa9bcc21ea1b94773e6e
|
||||
sha256: ed46d7ae4ec9d19e4c8fa2badac5fe27ba87a3fe387343ce726f927af074ec98
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.0.2"
|
||||
flutter_localizations:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -1031,10 +1007,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e
|
||||
sha256: b0694b7fb1689b0e6cc193b3f1fcac6423c4f93c74fb20b806c6b6f196db0c31
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.28"
|
||||
version: "2.0.30"
|
||||
flutter_rust_bridge:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1112,10 +1088,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_spinkit
|
||||
sha256: d2696eed13732831414595b98863260e33e8882fc069ee80ec35d4ac9ddb0472
|
||||
sha256: "77850df57c00dc218bfe96071d576a8babec24cf58b2ed121c83cca4a2fdce7f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.2.1"
|
||||
version: "5.2.2"
|
||||
flutter_staggered_grid_view:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1128,10 +1104,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_svg
|
||||
sha256: cd57f7969b4679317c17af6fd16ee233c1e60a82ed209d8a475c54fd6fd6f845
|
||||
sha256: b9c2ad5872518a27507ab432d1fb97e8813b05f0fc693f9d40fad06d073e0678
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.2.1"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@@ -1255,10 +1231,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
|
||||
sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
version: "1.5.0"
|
||||
http_client_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1299,38 +1275,102 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.4"
|
||||
in_app_purchase:
|
||||
image_editor:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: in_app_purchase
|
||||
sha256: "5cddd7f463f3bddb1d37a72b95066e840d5822d66291331d7f8f05ce32c24b6c"
|
||||
name: image_editor
|
||||
sha256: "38070067264fd9fea4328ca630d2ff7bd65ebe6aa4ed375d983b732d2ae7146b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.3"
|
||||
in_app_purchase_android:
|
||||
version: "1.6.0"
|
||||
image_editor_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: in_app_purchase_android
|
||||
sha256: fd76e5612da6facadcfe8a3477da092908227260a9f6ec7db9a66dd989c69b02
|
||||
name: image_editor_common
|
||||
sha256: "93d2f5c8b636f862775dd62a9ec20d09c8272598daa02f935955a4640e1844ee"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.0+2"
|
||||
in_app_purchase_platform_interface:
|
||||
version: "1.2.0"
|
||||
image_editor_ohos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: in_app_purchase_platform_interface
|
||||
sha256: "1d353d38251da5b9fea6635c0ebfc6bb17a2d28d0e86ea5e083bf64244f1fb4c"
|
||||
name: image_editor_ohos
|
||||
sha256: "06756859586d5acefec6e3b4f356f9b1ce05ef09213bcb9a0ce1680ecea2d054"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
in_app_purchase_storekit:
|
||||
version: "0.0.9"
|
||||
image_editor_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: in_app_purchase_storekit
|
||||
sha256: ceddd5a70d268f762d29993ed470054bc2baf8793e41800bc82cde05110260d0
|
||||
name: image_editor_platform_interface
|
||||
sha256: "474517efc770464f7d99942472d8cfb369a3c378e95466ec17f74d2b80bd40de"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.2"
|
||||
version: "1.1.0"
|
||||
image_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image_picker
|
||||
sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
image_picker_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_android
|
||||
sha256: "28f3987ca0ec702d346eae1d90eda59603a2101b52f1e234ded62cff1d5cfa6e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.13+1"
|
||||
image_picker_for_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_for_web
|
||||
sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
image_picker_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_ios
|
||||
sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.13"
|
||||
image_picker_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_linux
|
||||
sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.2"
|
||||
image_picker_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_macos
|
||||
sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.2"
|
||||
image_picker_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_platform_interface
|
||||
sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
image_picker_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_windows
|
||||
sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.2"
|
||||
integration_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@@ -1348,10 +1388,10 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: intl_utils
|
||||
sha256: "3b2655259dbebd26e3b1466d0839f389dc59a275337e1b760ac645bc7814d2d3"
|
||||
sha256: da67ac187b521445d745f7c68e7254c2090f6c3c9081c93cd515480af9e59569
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.8.10"
|
||||
version: "2.8.11"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1372,10 +1412,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: jni
|
||||
sha256: "459727a9daf91bdfb39b014cf3c186cf77f0136124a274ac83c186e12262ac4e"
|
||||
sha256: d2c361082d554d4593c3012e26f6b188f902acd291330f13d6427641a92b3da1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.2"
|
||||
version: "0.14.2"
|
||||
js:
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
@@ -1396,10 +1436,10 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: json_serializable
|
||||
sha256: ce2cf974ccdee13be2a510832d7fba0b94b364e0b0395dee42abaa51b855be27
|
||||
sha256: "33a040668b31b320aafa4822b7b1e177e163fc3c1e835c6750319d4ab23aa6fe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.10.0"
|
||||
version: "6.11.1"
|
||||
latlong2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1476,18 +1516,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: local_auth_android
|
||||
sha256: "63ad7ca6396290626dc0cb34725a939e4cfe965d80d36112f08d49cf13a8136e"
|
||||
sha256: "48924f4a8b3cc45994ad5993e2e232d3b00788a305c1bf1c7db32cef281ce9a3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.49"
|
||||
version: "1.0.52"
|
||||
local_auth_darwin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: local_auth_darwin
|
||||
sha256: "25163ce60a5a6c468cf7a0e3dc8a165f824cabc2aa9e39a5e9fc5c2311b7686f"
|
||||
sha256: "0e9706a8543a4a2eee60346294d6a633dd7c3ee60fae6b752570457c4ff32055"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
version: "1.6.0"
|
||||
local_auth_ios:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1516,10 +1556,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logger
|
||||
sha256: "2621da01aabaf223f8f961e751f2c943dbb374dc3559b982f200ccedadaa6999"
|
||||
sha256: "55d6c23a6c15db14920e037fe7e0dc32e7cdaf3b64b4b25df2d541b5b6b81c0c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.0"
|
||||
version: "2.6.1"
|
||||
logging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1749,10 +1789,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: native_dio_adapter
|
||||
sha256: "7420bc9517b2abe09810199a19924617b45690a44ecfb0616ac9babc11875c03"
|
||||
sha256: "1c51bd42027861d27ccad462ba0903f5e3197461cc6d59a0bb8658cb5ad7bd01"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
version: "1.5.0"
|
||||
native_video_player:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1838,18 +1878,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: package_info_plus
|
||||
sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191"
|
||||
sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.3.0"
|
||||
version: "8.3.1"
|
||||
package_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_info_plus_platform_interface
|
||||
sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c"
|
||||
sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
version: "3.2.1"
|
||||
panorama:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1903,18 +1943,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
|
||||
sha256: "993381400e94d18469750e5b9dcb8206f15bc09f9da86b9e44a9b0092a0066db"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.17"
|
||||
version: "2.2.18"
|
||||
path_provider_foundation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
|
||||
sha256: "16eef174aacb07e09c351502740fa6254c165757638eba1e9116b0a781201bbd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.2"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1991,10 +2031,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
|
||||
sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
version: "7.0.1"
|
||||
photo_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2023,10 +2063,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: pinput
|
||||
sha256: "8a73be426a91fefec90a7f130763ca39772d547e92f19a827cf4aa02e323d35a"
|
||||
sha256: c41f42ee301505ae2375ec32871c985d3717bf8aee845620465b286e0140aad2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.1"
|
||||
version: "5.0.2"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2120,10 +2160,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: provider
|
||||
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
|
||||
sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.5"
|
||||
version: "6.1.5+1"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2208,10 +2248,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: screen_brightness_android
|
||||
sha256: fb5fa43cb89d0c9b8534556c427db1e97e46594ac5d66ebdcf16063b773d54ed
|
||||
sha256: d34f5321abd03bc3474f4c381f53d189117eba0b039eac1916aa92cca5fd0a96
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.1.3"
|
||||
screen_brightness_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2256,18 +2296,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: share_plus
|
||||
sha256: b2961506569e28948d75ec346c28775bb111986bb69dc6a20754a457e3d97fa0
|
||||
sha256: d7dc0630a923883c6328ca31b89aa682bacbf2f8304162d29f7c6aaff03a27a1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.0.0"
|
||||
version: "11.1.0"
|
||||
share_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: share_plus_platform_interface
|
||||
sha256: "1032d392bc5d2095a77447a805aa3f804d2ae6a4d5eef5e6ebb3bd94c1bc19ef"
|
||||
sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
version: "6.1.0"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2280,10 +2320,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
|
||||
sha256: a2608114b1ffdcbc9c120eb71a0e207c71da56202852d4aab8a5e30a82269e74
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.10"
|
||||
version: "2.4.12"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2373,10 +2413,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
sha256: a447acb083d3a5ef17f983dd36201aeea33fedadb3228fa831f2f0c92f0f3aca
|
||||
sha256: "6a3c6cc82073a8797f8c4dc4572146114a39652851c157db37e964d9c7038723"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.7"
|
||||
version: "1.3.8"
|
||||
source_map_stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2429,10 +2469,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_common
|
||||
sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b"
|
||||
sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.5"
|
||||
version: "2.5.6"
|
||||
sqflite_darwin:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2461,34 +2501,34 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3
|
||||
sha256: c0503c69b44d5714e6abbf4c1f51a3c3cc42b75ce785f44404765e4635481d38
|
||||
sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.7.6"
|
||||
version: "2.9.0"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqlite3_flutter_libs
|
||||
sha256: e07232b998755fe795655c56d1f5426e0190c9c435e1752d39e7b1cd33699c71
|
||||
sha256: "2b03273e71867a8a4d030861fc21706200debe5c5858a4b9e58f4a1c129586a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.34"
|
||||
version: "0.5.39"
|
||||
sqlite3_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3_web
|
||||
sha256: "967e076442f7e1233bd7241ca61f3efe4c7fc168dac0f38411bdb3bdf471eb3c"
|
||||
sha256: "0f6ebcb4992d1892ac5c8b5ecd22a458ab9c5eb6428b11ae5ecb5d63545844da"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.1"
|
||||
version: "0.3.2"
|
||||
sqlite_async:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqlite_async
|
||||
sha256: "9332aedd311a19dd215dcb55729bc68dc587dc7655b569ab8819b68ee0be0082"
|
||||
sha256: "4da3b035bcce83d10beae879c6539e75230826bba95ed440565b6afbdd8b1550"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.11.7"
|
||||
version: "0.11.8"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2565,10 +2605,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: synchronized
|
||||
sha256: "0669c70faae6270521ee4f05bffd2919892d42d1276e6c495be80174b6bc0ef6"
|
||||
sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.1"
|
||||
version: "3.4.0"
|
||||
system_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2701,26 +2741,26 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603"
|
||||
sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.1"
|
||||
version: "6.3.2"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79"
|
||||
sha256: "69ee86740f2847b9a4ba6cffa74ed12ce500bbe2b07f3dc1e643439da60637b7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.16"
|
||||
version: "6.3.18"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb"
|
||||
sha256: d80b3f567a617cb923546034cc94bfe44eb15f989fe670b37f26abdb9d939cb7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.3"
|
||||
version: "6.3.4"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2733,10 +2773,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2"
|
||||
sha256: c043a77d6600ac9c38300567f33ef12b0ef4f4783a2c1f00231d2b1941fea13f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.2"
|
||||
version: "3.2.3"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2789,10 +2829,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_compiler
|
||||
sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331"
|
||||
sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.17"
|
||||
version: "1.1.19"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2839,18 +2879,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_android
|
||||
sha256: "4a5135754a62dbc827a64a42ef1f8ed72c962e191c97e2d48744225c2b9ebb73"
|
||||
sha256: "59e5a457ddcc1688f39e9aef0efb62aa845cf0cbbac47e44ac9730dc079a2385"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.8.7"
|
||||
version: "2.8.13"
|
||||
video_player_avfoundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_avfoundation
|
||||
sha256: "0d47db6cbf72db61d86369219efd35c7f9d93515e1319da941ece81b1f21c49c"
|
||||
sha256: f9a780aac57802b2892f93787e5ea53b5f43cc57dc107bee9436458365be71cd
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.7.2"
|
||||
version: "2.8.4"
|
||||
video_player_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2863,10 +2903,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_web
|
||||
sha256: e8bba2e5d1e159d5048c9a491bb2a7b29c535c612bb7d10c1e21107f5bd365ba
|
||||
sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.5"
|
||||
version: "2.4.0"
|
||||
video_thumbnail:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2919,10 +2959,10 @@ packages:
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a"
|
||||
sha256: "5bf046f41320ac97a469d506261797f35254fa61c641741ef32dacda98b7d39c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.1.3"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2967,18 +3007,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: wechat_assets_picker
|
||||
sha256: cafe3d32564ed3cacf9822f251941f7b44fe9885c17c8de4fca7e939a459e1ef
|
||||
sha256: c307e50394c1e6dfcd5c4701e84efb549fce71444fedcf2e671c50d809b3e2a1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.5.1"
|
||||
version: "9.8.0"
|
||||
wechat_picker_library:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wechat_picker_library
|
||||
sha256: a42e09cb85b15fc9410f6a69671371cc60aa99c4a1f7967f6593a7f665f6f47a
|
||||
sha256: "5cb61b9aa935b60da5b043f8446fbb9c5077419f20ccc4856bf444aec4f44bc1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
version: "1.0.7"
|
||||
widgets_to_image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -3031,10 +3071,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: xml
|
||||
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.5.0"
|
||||
version: "6.6.1"
|
||||
xmlstream:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -12,7 +12,7 @@ description: ente photos application
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
|
||||
version: 1.2.2+1205
|
||||
version: 1.2.4+1205
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
@@ -77,8 +77,6 @@ dependencies:
|
||||
ref: remove-event-sub
|
||||
figma_squircle: ^0.6.3
|
||||
file_saver: ^0.2.14
|
||||
firebase_core: ^3.6.0
|
||||
firebase_messaging: ^15.1.3
|
||||
fixnum: ^1.1.1
|
||||
flutter:
|
||||
sdk: flutter
|
||||
@@ -115,7 +113,8 @@ dependencies:
|
||||
html_unescape: ^2.0.0
|
||||
http: ^1.1.0
|
||||
image: ^4.0.17
|
||||
in_app_purchase: ^3.0.7
|
||||
image_editor: ^1.6.0
|
||||
image_picker: ^1.1.1
|
||||
intl: ^0.19.0
|
||||
latlong2: ^0.9.0
|
||||
launcher_icon_switcher: ^0.0.2
|
||||
|
||||
@@ -32,8 +32,11 @@ impl VectorDB {
|
||||
|
||||
if file_exists {
|
||||
println!("Loading index from disk.");
|
||||
// Use view to not load the index into memory. https://docs.rs/usearch/latest/usearch/struct.Index.html#method.view
|
||||
db.index.view(file_path).expect("Failed to load index");
|
||||
// Must use load() instead of view() because:
|
||||
// - view() creates a read-only memory-mapped view (immutable)
|
||||
// - load() loads the index into RAM for read/write operations (mutable)
|
||||
// Using view() causes "Can't add to an immutable index" error
|
||||
db.index.load(file_path).expect("Failed to load index");
|
||||
} else {
|
||||
println!("Creating new index.");
|
||||
db.save_index();
|
||||
@@ -46,9 +49,37 @@ impl VectorDB {
|
||||
if let Some(parent) = self.path.parent() {
|
||||
std::fs::create_dir_all(parent).expect("Failed to create directory");
|
||||
}
|
||||
self.index
|
||||
.save(self.path.to_str().expect("Invalid path"))
|
||||
.expect("Failed to save index");
|
||||
|
||||
// Use atomic write: save to temp file first, then rename
|
||||
let temp_path = self.path.with_extension("tmp");
|
||||
let temp_path_str = temp_path.to_str().expect("Invalid temp path");
|
||||
|
||||
// Save to temporary file
|
||||
match self.index.save(temp_path_str) {
|
||||
Ok(_) => {
|
||||
// Atomic rename - guaranteed atomic on iOS/Android
|
||||
// This will atomically replace the existing file
|
||||
// The rename ensures we never have a partially written file,
|
||||
// even if the app is suspended or crashes
|
||||
match std::fs::rename(&temp_path, &self.path) {
|
||||
Ok(_) => {
|
||||
println!("Successfully saved index atomically");
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to rename temp index file: {:?}", e);
|
||||
// Try to clean up temp file
|
||||
let _ = std::fs::remove_file(&temp_path);
|
||||
panic!("Failed to atomically save index: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to save index to temp file: {:?}", e);
|
||||
// Try to clean up temp file if it exists
|
||||
let _ = std::fs::remove_file(&temp_path);
|
||||
panic!("Failed to save index: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_capacity(&self, margin: usize) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
- Ashil: Changes meant for figuring out thumbnail not loading issue (this change has no scope for regressions or bugs)
|
||||
- Ashil: Add new section (show local ID & config local thumb queue) in debug section in settings to help in debugging thumbnail not loading issue.
|
||||
- Ashil: Revert diskLoadDeferDuration to 80ms (Fixes local thumbnails taking ~1 sec to load on scrolling gallery)
|
||||
- Ashil: Revert diskLoadDeferDuration to 500ms (Was 80ms before but fixes local thumbnail taking very long to load or never loading)
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
- Video streaming improvements
|
||||
- Added support for custom domain links
|
||||
- Image editor fixes:
|
||||
- Fixed bottom navigation bar color in light theme
|
||||
- Resolved initial color issue in paint editor
|
||||
- Added tap-to-reset with haptics for tune adjustments (brightness/exposure)
|
||||
- Similar images detection and deletion
|
||||
- Video streaming enhancements
|
||||
- Performance improvements
|
||||
1
mobile/thirdparty/flutter
vendored
Submodule
19
mobile/thirdparty/transistor-background-fetch/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2017 Transistor Software <info@transistorsoft.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
22
mobile/thirdparty/transistor-background-fetch/README.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
Transistor Background Fetch
|
||||
===========================================================================
|
||||
|
||||
Copyright (c) 2017 Transistor Software <info@transistorsoft.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
28
mobile/thirdparty/transistor-background-fetch/TSBackgroundFetch.podspec
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#
|
||||
# Be sure to run `pod lib lint TSBackgroundFetch.podspec' to ensure this is a
|
||||
# valid spec before submitting.
|
||||
#
|
||||
# Any lines starting with a # are optional, but their use is encouraged
|
||||
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
|
||||
#
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'TSBackgroundFetch'
|
||||
s.version = '0.0.1'
|
||||
s.summary = 'iOS Background Fetch API Manager'
|
||||
|
||||
s.description = <<-DESC
|
||||
iOS Background Fetch API Manager with ability to handle multiple listeners.
|
||||
DESC
|
||||
|
||||
s.homepage = 'http://www.transistorsoft.com'
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
s.author = { 'christocracy' => 'christocracy@gmail.com' }
|
||||
s.source = { :git => 'https://github.com/transistorsoft/transistor-background-fetch.git', :tag => s.version.to_s }
|
||||
s.social_media_url = 'https://twitter.com/christocracy'
|
||||
|
||||
s.ios.deployment_target = '8.0'
|
||||
|
||||
s.source_files = 'ios/TSBackgroundFetch/TSBackgroundFetch/*.{h,m}'
|
||||
s.vendored_frameworks = 'ios/TSBackgroundFetch/TSBackgroundFetch.framework'
|
||||
end
|
||||
9
mobile/thirdparty/transistor-background-fetch/android/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
1
mobile/thirdparty/transistor-background-fetch/android/app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
28
mobile/thirdparty/transistor-background-fetch/android/app/build.gradle
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
defaultConfig {
|
||||
applicationId "com.transistorsoft.backgroundfetch"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
}
|
||||
21
mobile/thirdparty/transistor-background-fetch/android/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.transistorsoft.backgroundfetch;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() throws Exception {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("com.transistorsoft.backgroundfetch", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
11
mobile/thirdparty/transistor-background-fetch/android/app/src/main/AndroidManifest.xml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.transistorsoft.backgroundfetch">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme" />
|
||||
</manifest>
|
||||
@@ -0,0 +1,34 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1" />
|
||||
</vector>
|
||||
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillColor="#26A69A"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
</vector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
BIN
mobile/thirdparty/transistor-background-fetch/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
vendored
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
BIN
mobile/thirdparty/transistor-background-fetch/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
vendored
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
BIN
mobile/thirdparty/transistor-background-fetch/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
vendored
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
BIN
mobile/thirdparty/transistor-background-fetch/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
vendored
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 15 KiB |
6
mobile/thirdparty/transistor-background-fetch/android/app/src/main/res/values/colors.xml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
</resources>
|
||||
3
mobile/thirdparty/transistor-background-fetch/android/app/src/main/res/values/strings.xml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">BackgroundFetch</string>
|
||||
</resources>
|
||||
11
mobile/thirdparty/transistor-background-fetch/android/app/src/main/res/values/styles.xml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.transistorsoft.backgroundfetch;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() throws Exception {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
34
mobile/thirdparty/transistor-background-fetch/android/build.gradle
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
ext {
|
||||
compileSdkVersion = 32
|
||||
targetSdkVersion = 31
|
||||
buildToolsVersion = "29.0.6"
|
||||
appCompatVersion = "1.4.1"
|
||||
}
|
||||
23
mobile/thirdparty/transistor-background-fetch/android/gradle.properties
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
VERSION_NAME=0.5.6
|
||||
VERSION_CODE=21
|
||||
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
BIN
mobile/thirdparty/transistor-background-fetch/android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Thu Jul 15 09:21:17 EDT 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
|
||||
160
mobile/thirdparty/transistor-background-fetch/android/gradlew
vendored
Executable file
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
90
mobile/thirdparty/transistor-background-fetch/android/gradlew.bat
vendored
Normal 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
|
||||
1
mobile/thirdparty/transistor-background-fetch/android/settings.gradle
vendored
Normal file
@@ -0,0 +1 @@
|
||||
include ':app', ':tsbackgroundfetch'
|
||||
1
mobile/thirdparty/transistor-background-fetch/android/tsbackgroundfetch/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
152
mobile/thirdparty/transistor-background-fetch/android/tsbackgroundfetch/build.gradle
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.compileSdkVersion
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion rootProject.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
publishing {
|
||||
publications {
|
||||
tslocationmanager(MavenPublication) {
|
||||
groupId 'com.transistorsoft'
|
||||
artifactId 'tsbackgroundfetch'
|
||||
version VERSION_NAME
|
||||
artifact("$buildDir/outputs/aar/tsbackgroundfetch-release.aar")
|
||||
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-runtime:2.5.1"
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
|
||||
//implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion"
|
||||
|
||||
}
|
||||
|
||||
// Build Release
|
||||
task buildRelease { task ->
|
||||
task.dependsOn 'flutterRelease'
|
||||
}
|
||||
|
||||
// Publish Release.
|
||||
task publishRelease { task ->
|
||||
task.dependsOn 'assembleRelease'
|
||||
}
|
||||
tasks["publishRelease"].mustRunAfter("assembleRelease")
|
||||
tasks["publishRelease"].finalizedBy("publish")
|
||||
|
||||
def WORKSPACE_PATH = "/Users/chris/workspace"
|
||||
|
||||
// Build local maven repo.
|
||||
def LIBRARY_PATH = "com/transistorsoft/tsbackgroundfetch"
|
||||
task buildLocalRepository { task ->
|
||||
task.dependsOn 'publishRelease'
|
||||
doLast {
|
||||
delete "$buildDir/repo-local"
|
||||
copy {
|
||||
from "$buildDir/repo/$LIBRARY_PATH/$VERSION_NAME"
|
||||
into "$buildDir/repo-local/$LIBRARY_PATH/$VERSION_NAME"
|
||||
}
|
||||
copy {
|
||||
from("$buildDir/repo/$LIBRARY_PATH/maven-metadata.xml")
|
||||
into("$buildDir/repo-local/$LIBRARY_PATH")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def cordovaDir = "$WORKSPACE_PATH/background-geolocation/cordova/cordova-plugin-background-fetch"
|
||||
task cordovaRelease { task ->
|
||||
task.dependsOn 'buildLocalRepository'
|
||||
doLast {
|
||||
delete "$cordovaDir/src/android/libs"
|
||||
copy {
|
||||
// Maven repo format.
|
||||
from("$buildDir/repo-local")
|
||||
into("$cordovaDir/src/android/libs")
|
||||
// OLD FORMAT
|
||||
//from("$buildDir/outputs/aar/tsbackgroundfetch-release.aar")
|
||||
//into("$cordovaDir/src/android/libs/tsbackgroundfetch")
|
||||
//rename(/(.*)-release/, '$1-' + VERSION_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def reactNativeDir = "$WORKSPACE_PATH/background-geolocation/react/react-native-background-fetch"
|
||||
task reactNativeRelease { task ->
|
||||
task.dependsOn 'buildLocalRepository'
|
||||
doLast {
|
||||
delete "$reactNativeDir/android/libs"
|
||||
copy {
|
||||
// Maven repo format.
|
||||
from("$buildDir/repo-local")
|
||||
into("$reactNativeDir/android/libs")
|
||||
// OLD format.
|
||||
//from("$buildDir/outputs/aar/tsbackgroundfetch-release.aar")
|
||||
//into("$reactNativeDir/android/libs")
|
||||
//rename(/(.*)-release/, '$1-' + VERSION_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def flutterDir = "$WORKSPACE_PATH/background-geolocation/flutter/flutter_background_fetch"
|
||||
task flutterRelease { task ->
|
||||
task.dependsOn 'buildLocalRepository'
|
||||
doLast {
|
||||
delete "$flutterDir/android/libs"
|
||||
copy {
|
||||
// Maven repo format.
|
||||
from("$buildDir/repo-local")
|
||||
into("$flutterDir/android/libs")
|
||||
// OLD format.
|
||||
//from("$buildDir/outputs/aar/tsbackgroundfetch-release.aar")
|
||||
//into("$flutterDir/android/libs")
|
||||
//rename(/(.*)-release/, '$1-' + VERSION_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def capacitorDir = "$WORKSPACE_PATH/background-geolocation/capacitor/capacitor-background-fetch"
|
||||
task capacitorRelease { task ->
|
||||
task.dependsOn 'buildLocalRepository'
|
||||
doLast {
|
||||
delete "$capacitorDir/android/libs"
|
||||
copy {
|
||||
// Maven repo format.
|
||||
from("$buildDir/repo-local")
|
||||
into("$capacitorDir/android/libs")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task nativeScriptRelease(type: Copy) {
|
||||
from('./build/outputs/aar/tsbackgroundfetch-release.aar')
|
||||
into("$WORKSPACE_PATH/NativeScript/background-geolocation/nativescript-background-fetch/src/platforms/android/libs")
|
||||
rename('tsbackgroundfetch-release.aar', 'tsbackgroundfetch.aar')
|
||||
}
|
||||
21
mobile/thirdparty/transistor-background-fetch/android/tsbackgroundfetch/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.transistorsoft.tsbackgroundfetch;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() throws Exception {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("com.transistorsoft.tsbackgroundfetch.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.transistorsoft.tsbackgroundfetch">
|
||||
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
|
||||
<application>
|
||||
<receiver android:name="com.transistorsoft.tsbackgroundfetch.FetchAlarmReceiver" />
|
||||
<service android:name="com.transistorsoft.tsbackgroundfetch.FetchJobService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true" />
|
||||
<receiver android:name="com.transistorsoft.tsbackgroundfetch.BootReceiver" android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,291 @@
|
||||
package com.transistorsoft.tsbackgroundfetch;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobScheduler;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.PersistableBundle;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BGTask {
|
||||
static int MAX_TIME = 60000;
|
||||
|
||||
private static final List<BGTask> mTasks = new ArrayList<>();
|
||||
|
||||
static BGTask getTask(String taskId) {
|
||||
synchronized (mTasks) {
|
||||
for (BGTask task : mTasks) {
|
||||
if (task.hasTaskId(taskId)) return task;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static void addTask(BGTask task) {
|
||||
synchronized (mTasks) {
|
||||
mTasks.add(task);
|
||||
}
|
||||
}
|
||||
|
||||
static void removeTask(String taskId) {
|
||||
synchronized (mTasks) {
|
||||
BGTask found = null;
|
||||
for (BGTask task : mTasks) {
|
||||
if (task.hasTaskId(taskId)) {
|
||||
found = task;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found != null) {
|
||||
mTasks.remove(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void clear() {
|
||||
synchronized (mTasks) {
|
||||
mTasks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private FetchJobService.CompletionHandler mCompletionHandler;
|
||||
private String mTaskId;
|
||||
private int mJobId;
|
||||
private Runnable mTimeoutTask;
|
||||
private boolean mTimedout = false;
|
||||
|
||||
BGTask(final Context context, String taskId, FetchJobService.CompletionHandler handler, int jobId) {
|
||||
mTaskId = taskId;
|
||||
mCompletionHandler = handler;
|
||||
mJobId = jobId;
|
||||
|
||||
mTimeoutTask = new Runnable() {
|
||||
@Override public void run() {
|
||||
onTimeout(context);
|
||||
}
|
||||
};
|
||||
BackgroundFetch.getUiHandler().postDelayed(mTimeoutTask, MAX_TIME);
|
||||
}
|
||||
|
||||
public boolean getTimedOut() {
|
||||
return mTimedout;
|
||||
}
|
||||
|
||||
public String getTaskId() { return mTaskId; }
|
||||
|
||||
int getJobId() { return mJobId; }
|
||||
|
||||
boolean hasTaskId(String taskId) {
|
||||
return ((mTaskId != null) && mTaskId.equalsIgnoreCase(taskId));
|
||||
}
|
||||
|
||||
void setCompletionHandler(FetchJobService.CompletionHandler handler) {
|
||||
mCompletionHandler = handler;
|
||||
}
|
||||
|
||||
void finish() {
|
||||
if (mCompletionHandler != null) {
|
||||
mCompletionHandler.finish();
|
||||
}
|
||||
if (mTimeoutTask != null) {
|
||||
BackgroundFetch.getUiHandler().removeCallbacks(mTimeoutTask);
|
||||
}
|
||||
mCompletionHandler = null;
|
||||
removeTask(mTaskId);
|
||||
}
|
||||
|
||||
static void reschedule(Context context, BackgroundFetchConfig existing, BackgroundFetchConfig config) {
|
||||
BGTask existingTask = BGTask.getTask(existing.getTaskId());
|
||||
if (existingTask != null) {
|
||||
existingTask.finish();
|
||||
}
|
||||
cancel(context, existing.getTaskId(), existing.getJobId());
|
||||
|
||||
schedule(context, config);
|
||||
}
|
||||
|
||||
static void schedule(Context context, BackgroundFetchConfig config) {
|
||||
Log.d(BackgroundFetch.TAG, config.toString());
|
||||
|
||||
long interval = (config.isFetchTask()) ? (TimeUnit.MINUTES.toMillis(config.getMinimumFetchInterval())) : config.getDelay();
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !config.getForceAlarmManager()) {
|
||||
// API 21+ uses new JobScheduler API
|
||||
|
||||
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
JobInfo.Builder builder = new JobInfo.Builder(config.getJobId(), new ComponentName(context, FetchJobService.class))
|
||||
.setRequiredNetworkType(config.getRequiredNetworkType())
|
||||
.setRequiresDeviceIdle(config.getRequiresDeviceIdle())
|
||||
.setRequiresCharging(config.getRequiresCharging())
|
||||
.setPersisted(config.getStartOnBoot() && !config.getStopOnTerminate());
|
||||
|
||||
if (config.getPeriodic()) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= 24) {
|
||||
builder.setPeriodic(interval, interval);
|
||||
} else {
|
||||
builder.setPeriodic(interval);
|
||||
}
|
||||
} else {
|
||||
builder.setMinimumLatency(interval);
|
||||
}
|
||||
PersistableBundle extras = new PersistableBundle();
|
||||
extras.putString(BackgroundFetchConfig.FIELD_TASK_ID, config.getTaskId());
|
||||
extras.putLong("scheduled_at", System.currentTimeMillis());
|
||||
|
||||
builder.setExtras(extras);
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= 26) {
|
||||
builder.setRequiresStorageNotLow(config.getRequiresStorageNotLow());
|
||||
builder.setRequiresBatteryNotLow(config.getRequiresBatteryNotLow());
|
||||
}
|
||||
if (jobScheduler != null) {
|
||||
jobScheduler.schedule(builder.build());
|
||||
}
|
||||
} else {
|
||||
// Everyone else get AlarmManager
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
if (alarmManager != null) {
|
||||
PendingIntent pi = getAlarmPI(context, config.getTaskId());
|
||||
long delay = System.currentTimeMillis() + interval;
|
||||
if (config.getPeriodic()) {
|
||||
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, delay, interval, pi);
|
||||
} else {
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, delay, pi);
|
||||
} else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, delay, pi);
|
||||
} else {
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, delay, pi);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onTimeout(Context context) {
|
||||
mTimedout = true;
|
||||
Log.d(BackgroundFetch.TAG, "[BGTask] timeout: " + mTaskId);
|
||||
|
||||
BackgroundFetch adapter = BackgroundFetch.getInstance(context);
|
||||
|
||||
if (!LifecycleManager.getInstance().isHeadless()) {
|
||||
BackgroundFetch.Callback callback = adapter.getFetchCallback();
|
||||
if (callback != null) {
|
||||
callback.onTimeout(mTaskId);
|
||||
}
|
||||
} else {
|
||||
BackgroundFetchConfig config = adapter.getConfig(mTaskId);
|
||||
if (config != null) {
|
||||
if (config.getJobService() != null) {
|
||||
fireHeadlessEvent(context, config);
|
||||
} else {
|
||||
adapter.finish(mTaskId);
|
||||
}
|
||||
} else {
|
||||
Log.e(BackgroundFetch.TAG, "[BGTask] failed to load config for taskId: " + mTaskId);
|
||||
adapter.finish(mTaskId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fire a headless background-fetch event by reflecting an instance of Config.jobServiceClass.
|
||||
// Will attempt to reflect upon two different forms of Headless class:
|
||||
// 1: new HeadlessTask(context, taskId)
|
||||
// or
|
||||
// 2: new HeadlessTask().onFetch(context, taskId);
|
||||
//
|
||||
void fireHeadlessEvent(Context context, BackgroundFetchConfig config) throws Error {
|
||||
try {
|
||||
// Get class via reflection.
|
||||
Class<?> HeadlessClass = Class.forName(config.getJobService());
|
||||
Class[] types = { Context.class, BGTask.class };
|
||||
Object[] params = { context, this};
|
||||
try {
|
||||
// 1: new HeadlessTask(context, taskId);
|
||||
Constructor<?> constructor = HeadlessClass.getDeclaredConstructor(types);
|
||||
constructor.newInstance(params);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// 2: new HeadlessTask().onFetch(context, taskId);
|
||||
Constructor<?> constructor = HeadlessClass.getConstructor();
|
||||
Object instance = constructor.newInstance();
|
||||
Method onFetch = instance.getClass().getDeclaredMethod("onFetch", types);
|
||||
onFetch.invoke(instance, params);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new Error(e.getMessage());
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new Error(e.getMessage());
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new Error(e.getMessage());
|
||||
} catch (InstantiationException e) {
|
||||
throw new Error(e.getMessage());
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new Error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
static void cancel(Context context, String taskId, int jobId) {
|
||||
Log.i(BackgroundFetch.TAG, "- cancel taskId=" + taskId + ", jobId=" + jobId);
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && (jobId != 0)) {
|
||||
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
if (jobScheduler != null) {
|
||||
jobScheduler.cancel(jobId);
|
||||
}
|
||||
} else {
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
if (alarmManager != null) {
|
||||
alarmManager.cancel(BGTask.getAlarmPI(context, taskId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static PendingIntent getAlarmPI(Context context, String taskId) {
|
||||
Intent intent = new Intent(context, FetchAlarmReceiver.class);
|
||||
intent.setAction(taskId);
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_IMMUTABLE);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "[BGTask taskId=" + mTaskId + "]";
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("taskId", mTaskId);
|
||||
map.put("timeout", mTimedout);
|
||||
return map;
|
||||
}
|
||||
|
||||
public JSONObject toJson() {
|
||||
JSONObject json = new JSONObject();
|
||||
try {
|
||||
json.put("taskId", mTaskId);
|
||||
json.put("timeout", mTimedout);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
static class Error extends RuntimeException {
|
||||
public Error(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
package com.transistorsoft.tsbackgroundfetch;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* Created by chris on 2018-01-11.
|
||||
*/
|
||||
|
||||
public class BackgroundFetch {
|
||||
public static final String TAG = "TSBackgroundFetch";
|
||||
|
||||
public static final String ACTION_CONFIGURE = "configure";
|
||||
public static final String ACTION_START = "start";
|
||||
public static final String ACTION_STOP = "stop";
|
||||
public static final String ACTION_FINISH = "finish";
|
||||
public static final String ACTION_STATUS = "status";
|
||||
public static final String ACTION_FORCE_RELOAD = TAG + "-forceReload";
|
||||
|
||||
public static final String EVENT_FETCH = ".event.BACKGROUND_FETCH";
|
||||
|
||||
public static final int STATUS_AVAILABLE = 2;
|
||||
|
||||
private static BackgroundFetch mInstance = null;
|
||||
|
||||
private static ExecutorService sThreadPool;
|
||||
|
||||
private static Handler uiHandler;
|
||||
|
||||
@SuppressWarnings({"WeakerAccess"})
|
||||
public static Handler getUiHandler() {
|
||||
if (uiHandler == null) {
|
||||
uiHandler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
return uiHandler;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"WeakerAccess"})
|
||||
public static ExecutorService getThreadPool() {
|
||||
if (sThreadPool == null) {
|
||||
sThreadPool = Executors.newCachedThreadPool();
|
||||
}
|
||||
return sThreadPool;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"WeakerAccess"})
|
||||
public static BackgroundFetch getInstance(Context context) {
|
||||
if (mInstance == null) {
|
||||
mInstance = getInstanceSynchronized(context.getApplicationContext());
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
private static synchronized BackgroundFetch getInstanceSynchronized(Context context) {
|
||||
if (mInstance == null) mInstance = new BackgroundFetch(context.getApplicationContext());
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
private Context mContext;
|
||||
private BackgroundFetch.Callback mFetchCallback;
|
||||
|
||||
private final Map<String, BackgroundFetchConfig> mConfig = new HashMap<>();
|
||||
|
||||
private BackgroundFetch(Context context) {
|
||||
mContext = context;
|
||||
// Start Lifecycle Observer to be notified when app enters background.
|
||||
getUiHandler().post(LifecycleManager.getInstance());
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unused"})
|
||||
public void configure(BackgroundFetchConfig config, BackgroundFetch.Callback callback) {
|
||||
Log.d(TAG, "- " + ACTION_CONFIGURE);
|
||||
mFetchCallback = callback;
|
||||
|
||||
synchronized (mConfig) {
|
||||
if (mConfig.containsKey(config.getTaskId())) {
|
||||
// Developer called `.configure` again. Re-configure the plugin by re-scheduling the fetch task.
|
||||
BackgroundFetchConfig existing = mConfig.get(config.getTaskId());
|
||||
Log.d(TAG, "Re-configured existing task");
|
||||
BGTask.reschedule(mContext, existing, config);
|
||||
mConfig.put(config.getTaskId(), config);
|
||||
return;
|
||||
} else {
|
||||
mConfig.put(config.getTaskId(), config);
|
||||
}
|
||||
}
|
||||
start(config.getTaskId());
|
||||
}
|
||||
|
||||
void onBoot() {
|
||||
BackgroundFetchConfig.load(mContext, new BackgroundFetchConfig.OnLoadCallback() {
|
||||
@Override public void onLoad(List<BackgroundFetchConfig> result) {
|
||||
for (BackgroundFetchConfig config : result) {
|
||||
if (!config.getStartOnBoot() || config.getStopOnTerminate()) {
|
||||
config.destroy(mContext);
|
||||
continue;
|
||||
}
|
||||
synchronized (mConfig) {
|
||||
mConfig.put(config.getTaskId(), config);
|
||||
}
|
||||
if ((android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) || config.getForceAlarmManager()) {
|
||||
if (config.isFetchTask()) {
|
||||
start(config.getTaskId());
|
||||
} else {
|
||||
scheduleTask(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings({"WeakerAccess"})
|
||||
@TargetApi(21)
|
||||
public void start(String fetchTaskId) {
|
||||
Log.d(TAG, "- " + ACTION_START);
|
||||
|
||||
BGTask task = BGTask.getTask(fetchTaskId);
|
||||
if (task != null) {
|
||||
Log.e(TAG, "[" + TAG + " start] Task " + fetchTaskId + " already registered");
|
||||
return;
|
||||
}
|
||||
registerTask(fetchTaskId);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"WeakerAccess"})
|
||||
public void stop(String taskId) {
|
||||
String msg = "- " + ACTION_STOP;
|
||||
if (taskId != null) {
|
||||
msg += ": " + taskId;
|
||||
}
|
||||
Log.d(TAG, msg);
|
||||
|
||||
if (taskId == null) {
|
||||
synchronized (mConfig) {
|
||||
for (BackgroundFetchConfig config : mConfig.values()) {
|
||||
BGTask task = BGTask.getTask(config.getTaskId());
|
||||
if (task != null) {
|
||||
task.finish();
|
||||
BGTask.removeTask(config.getTaskId());
|
||||
}
|
||||
BGTask.cancel(mContext, config.getTaskId(), config.getJobId());
|
||||
config.destroy(mContext);
|
||||
}
|
||||
BGTask.clear();
|
||||
}
|
||||
} else {
|
||||
BGTask task = BGTask.getTask(taskId);
|
||||
if (task != null) {
|
||||
task.finish();
|
||||
BGTask.removeTask(task.getTaskId());
|
||||
}
|
||||
BackgroundFetchConfig config = getConfig(taskId);
|
||||
if (config != null) {
|
||||
config.destroy(mContext);
|
||||
BGTask.cancel(mContext, config.getTaskId(), config.getJobId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"WeakerAccess"})
|
||||
public void scheduleTask(BackgroundFetchConfig config) {
|
||||
synchronized (mConfig) {
|
||||
if (mConfig.containsKey(config.getTaskId())) {
|
||||
// This BackgroundFetchConfig already exists? Should we halt any existing Job/Alarm here?
|
||||
}
|
||||
config.save(mContext);
|
||||
mConfig.put(config.getTaskId(), config);
|
||||
}
|
||||
String taskId = config.getTaskId();
|
||||
registerTask(taskId);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"WeakerAccess"})
|
||||
public void finish(String taskId) {
|
||||
Log.d(TAG, "- " + ACTION_FINISH + ": " + taskId);
|
||||
|
||||
BGTask task = BGTask.getTask(taskId);
|
||||
if (task != null) {
|
||||
task.finish();
|
||||
}
|
||||
|
||||
BackgroundFetchConfig config = getConfig(taskId);
|
||||
|
||||
if ((config != null) && !config.getPeriodic()) {
|
||||
config.destroy(mContext);
|
||||
synchronized (mConfig) {
|
||||
mConfig.remove(taskId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int status() {
|
||||
return STATUS_AVAILABLE;
|
||||
}
|
||||
|
||||
BackgroundFetch.Callback getFetchCallback() {
|
||||
return mFetchCallback;
|
||||
}
|
||||
|
||||
void onFetch(final BGTask task) {
|
||||
BGTask.addTask(task);
|
||||
Log.d(TAG, "- Background Fetch event received: " + task.getTaskId());
|
||||
synchronized (mConfig) {
|
||||
if (mConfig.isEmpty()) {
|
||||
BackgroundFetchConfig.load(mContext, new BackgroundFetchConfig.OnLoadCallback() {
|
||||
@Override
|
||||
public void onLoad(List<BackgroundFetchConfig> result) {
|
||||
synchronized (mConfig) {
|
||||
for (BackgroundFetchConfig config : result) {
|
||||
mConfig.put(config.getTaskId(), config);
|
||||
}
|
||||
}
|
||||
doFetch(task);
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
doFetch(task);
|
||||
}
|
||||
|
||||
private void registerTask(String taskId) {
|
||||
BackgroundFetchConfig config = getConfig(taskId);
|
||||
|
||||
if (config == null) {
|
||||
Log.e(TAG, "- registerTask failed to find BackgroundFetchConfig for taskId " + taskId);
|
||||
return;
|
||||
}
|
||||
config.save(mContext);
|
||||
|
||||
String msg = "- registerTask: " + taskId;
|
||||
if (!config.getForceAlarmManager()) {
|
||||
msg += " (jobId: " + config.getJobId() + ")";
|
||||
}
|
||||
Log.d(TAG, msg);
|
||||
|
||||
BGTask.schedule(mContext, config);
|
||||
}
|
||||
|
||||
private void doFetch(BGTask task) {
|
||||
BackgroundFetchConfig config = getConfig(task.getTaskId());
|
||||
|
||||
if (config == null) {
|
||||
BGTask.cancel(mContext, task.getTaskId(), task.getJobId());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LifecycleManager.getInstance().isHeadless()) {
|
||||
if (mFetchCallback != null) {
|
||||
mFetchCallback.onFetch(task.getTaskId());
|
||||
}
|
||||
} else if (config.getStopOnTerminate()) {
|
||||
Log.d(TAG, "- Stopping on terminate");
|
||||
stop(task.getTaskId());
|
||||
} else if (config.getJobService() != null) {
|
||||
try {
|
||||
task.fireHeadlessEvent(mContext, config);
|
||||
} catch (BGTask.Error e) {
|
||||
Log.e(TAG, "Headless task error: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
// {stopOnTerminate: false, forceReload: false} with no Headless JobService?? Don't know what else to do here but stop
|
||||
Log.w(TAG, "- BackgroundFetch event has occurred while app is terminated but there's no jobService configured to handle the event. BackgroundFetch will terminate.");
|
||||
finish(task.getTaskId());
|
||||
stop(task.getTaskId());
|
||||
}
|
||||
}
|
||||
|
||||
BackgroundFetchConfig getConfig(String taskId) {
|
||||
synchronized (mConfig) {
|
||||
return (mConfig.containsKey(taskId)) ? mConfig.get(taskId) : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface BackgroundFetch.Callback
|
||||
*/
|
||||
public interface Callback {
|
||||
void onFetch(String taskId);
|
||||
void onTimeout(String taskId);
|
||||
}
|
||||
}
|
||||