mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-09-01 09:44:07 +00:00
Compare commits
51 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7412daf373 | |||
| 2ce240279f | |||
| ba09002d04 | |||
| 195f6091f2 | |||
| 39122476ce | |||
| b3f0324066 | |||
| 463ae81a51 | |||
| 25bc253b91 | |||
| 35133d2ebb | |||
| 2a6fd61a32 | |||
| 77d057c248 | |||
| 0c16188877 | |||
| 280519d63a | |||
| c13b80990f | |||
| 4b11031560 | |||
| 4792f5aac8 | |||
| 41e174becb | |||
| cf1cbb058e | |||
| 4183ebd8e6 | |||
| 1027856691 | |||
| a89f9cb5de | |||
| 56a14411ae | |||
| cc51e604a0 | |||
| eade1d87e6 | |||
| d19f4ce3c9 | |||
| 8505ed865a | |||
| 8094949c76 | |||
| 1f269ae5b3 | |||
| 185ac49de9 | |||
| ce0cd5342a | |||
| 6487efce35 | |||
| cf6e46f976 | |||
| b2274ee9f5 | |||
| b92ff26e81 | |||
| 7e6bfa49ea | |||
| 3345a2a297 | |||
| 484b43cd08 | |||
| 9d41dc4eb6 | |||
| 70ed3759d2 | |||
| c2607a99e3 | |||
| dbe48b5802 | |||
| 60c553e53c | |||
| 753500ebfa | |||
| 3c8244b977 | |||
| dafa7603d8 | |||
| 3171541b6a | |||
| 0e06a21948 | |||
| 0291a4c3a2 | |||
| e8e3254278 | |||
| 79d668e004 | |||
| 64c7595b6a |
182 changed files with 43864 additions and 3618 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -56,3 +56,4 @@ devtools_options.yaml
|
||||||
rust/target
|
rust/target
|
||||||
rust_dependencies/target
|
rust_dependencies/target
|
||||||
fastlane/repo/status/running.json
|
fastlane/repo/status/running.json
|
||||||
|
.cache/
|
||||||
235
CHANGELOG.md
235
CHANGELOG.md
|
|
@ -1,5 +1,25 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.5.2
|
||||||
|
|
||||||
|
- Hotfix: Fixed an infinite loop involving delivery receipts
|
||||||
|
|
||||||
|
## 0.5.1
|
||||||
|
|
||||||
|
- Improve: Show delivery and read receipt indicators for text messages
|
||||||
|
- Improve: Backup screen clearer and easier to understand
|
||||||
|
- Improve: Show username above messages in group chats
|
||||||
|
- Fix: Background audio correctly pauses and resumes when viewing videos
|
||||||
|
- Fix: Sometimes old messages were being received as duplicates
|
||||||
|
- Fix: Multiple smaller bug fixes
|
||||||
|
|
||||||
|
## 0.5.0
|
||||||
|
|
||||||
|
- New: Update to Signal's new PQC-ready key agreement PQXDH
|
||||||
|
- New: Contact labels
|
||||||
|
- Fix: Multiple bug fixes
|
||||||
|
- Fix: Multiple black screens
|
||||||
|
|
||||||
## 0.4.0
|
## 0.4.0
|
||||||
|
|
||||||
- New: Encrypted Cloud Backup of Memories
|
- New: Encrypted Cloud Backup of Memories
|
||||||
|
|
@ -42,8 +62,8 @@
|
||||||
|
|
||||||
## 0.3.0
|
## 0.3.0
|
||||||
|
|
||||||
- Improved: Design of some UI components
|
- Improve: Design of some UI components
|
||||||
- Improved: Memories viewer shows state for batch operations and has improved performance
|
- Improve: Memories viewer shows state for batch operations and has improved performance
|
||||||
- Fix: Issue with background notifications on Android
|
- Fix: Issue with background notifications on Android
|
||||||
- Fix: Changed minimum threshold for the user discovery to 3
|
- Fix: Changed minimum threshold for the user discovery to 3
|
||||||
- Fix: Multiple UI issues
|
- Fix: Multiple UI issues
|
||||||
|
|
@ -52,24 +72,24 @@
|
||||||
## 0.2.26
|
## 0.2.26
|
||||||
|
|
||||||
- New: Import images from the gallery
|
- New: Import images from the gallery
|
||||||
- Improved: Media files are now stored in the dedicated "twonly" album
|
- Improve: Media files are now stored in the dedicated "twonly" album
|
||||||
- Improved: UI components adapt to native styling (iOS/Android)
|
- Improve: UI components adapt to native styling (iOS/Android)
|
||||||
- Fix: Migration issue that resulted in a corrupted backup mechanism
|
- Fix: Migration issue that resulted in a corrupted backup mechanism
|
||||||
- Fix: Database issues causing messages to be lost or the database to be corrupted
|
- Fix: Database issues causing messages to be lost or the database to be corrupted
|
||||||
- Fix: Permission view did not disappear after they were granted
|
- Fix: Permission view did not disappear after they were granted
|
||||||
|
|
||||||
## 0.2.23
|
## 0.2.23
|
||||||
|
|
||||||
- Improved: Smaller UI changes
|
- Improve: Smaller UI changes
|
||||||
- Fix: Some messages were not marked as opened.
|
- Fix: Some messages were not marked as opened.
|
||||||
|
|
||||||
## 0.2.20
|
## 0.2.20
|
||||||
|
|
||||||
- New: Adds an "Ask a Friend" button to new contact suggestions.
|
- New: Adds an "Ask a Friend" button to new contact suggestions.
|
||||||
- New: Adds security profiles.
|
- New: Adds security profiles.
|
||||||
- Improved: Onboarding flow for new users.
|
- Improve: Onboarding flow for new users.
|
||||||
- Improved: Flame restore experience.
|
- Improve: Flame restore experience.
|
||||||
- Improved: The blue verification checkmark now displays the total number of verifications.
|
- Improve: The blue verification checkmark now displays the total number of verifications.
|
||||||
- Fix: Issue with receiving messages when user closed app while decrypting
|
- Fix: Issue with receiving messages when user closed app while decrypting
|
||||||
- Fix: Background message fetching reliability.
|
- Fix: Background message fetching reliability.
|
||||||
- Fix: Issue with focus changing when taking a picture
|
- Fix: Issue with focus changing when taking a picture
|
||||||
|
|
@ -88,22 +108,22 @@
|
||||||
|
|
||||||
- New: Tutorial on how to use zoom.
|
- New: Tutorial on how to use zoom.
|
||||||
- New: Manage storage view.
|
- New: Manage storage view.
|
||||||
- Improved: Media thumbnails for faster loading.
|
- Improve: Media thumbnails for faster loading.
|
||||||
- Fix: Some messages were not marked as opened.
|
- Fix: Some messages were not marked as opened.
|
||||||
|
|
||||||
## 0.2.12
|
## 0.2.12
|
||||||
|
|
||||||
- New: Automatically mark identical media as opened across all chats (Settings > Chats).
|
- New: Automatically mark identical media as opened across all chats (Settings > Chats).
|
||||||
- Improved: Memories viewer redesigned with smoother animations and new quick-action controls.
|
- Improve: Memories viewer redesigned with smoother animations and new quick-action controls.
|
||||||
- Fix: Reliability of receiving media files.
|
- Fix: Reliability of receiving media files.
|
||||||
|
|
||||||
## 0.2.11
|
## 0.2.11
|
||||||
|
|
||||||
- New: Create custom shortcuts to quickly share images with pre-selected groups
|
- New: Create custom shortcuts to quickly share images with pre-selected groups
|
||||||
- New: Seamless recovery for iOS reinstallations
|
- New: Seamless recovery for iOS reinstallations
|
||||||
- Improved: Redesigned snackbar notifications
|
- Improve: Redesigned snackbar notifications
|
||||||
- Improved: New backup mechanism to allow larger backup files
|
- Improve: New backup mechanism to allow larger backup files
|
||||||
- Improved: Move keys into a centralized Rust-owned structure stored in secure storage
|
- Improve: Move keys into a centralized Rust-owned structure stored in secure storage
|
||||||
- Fix: Messages occasionally not received until app restart
|
- Fix: Messages occasionally not received until app restart
|
||||||
- Fix: Multiple smaller issues
|
- Fix: Multiple smaller issues
|
||||||
|
|
||||||
|
|
@ -113,7 +133,7 @@
|
||||||
|
|
||||||
## 0.2.9
|
## 0.2.9
|
||||||
|
|
||||||
- Improved: Make contact avatars clickable
|
- Improve: Make contact avatars clickable
|
||||||
- Fix: Messages occasionally not received until app restart
|
- Fix: Messages occasionally not received until app restart
|
||||||
- Fix: Complete setup would sometimes get stuck
|
- Fix: Complete setup would sometimes get stuck
|
||||||
|
|
||||||
|
|
@ -126,21 +146,21 @@
|
||||||
- New: Feature to find friends without a phone number
|
- New: Feature to find friends without a phone number
|
||||||
- New: The verification state is now transferred to the scanned user
|
- New: The verification state is now transferred to the scanned user
|
||||||
- New: Registration setup to configure the most important configurations
|
- New: Registration setup to configure the most important configurations
|
||||||
- Improved: Show ⌛ instead of the flame icon when it is about to expire
|
- Improve: Show ⌛ instead of the flame icon when it is about to expire
|
||||||
- Improved: FAQ is now in the app rather than opening in the browser
|
- Improve: FAQ is now in the app rather than opening in the browser
|
||||||
- Improved: Videos can now be paused
|
- Improve: Videos can now be paused
|
||||||
- Improved: Lock to record hands-free
|
- Improve: Lock to record hands-free
|
||||||
- Fix: Many smaller issues
|
- Fix: Many smaller issues
|
||||||
|
|
||||||
## 0.1.8
|
## 0.1.8
|
||||||
|
|
||||||
- Improved: Typos and grammar issues thanks to @AlbertUnruh
|
- Improve: Typos and grammar issues thanks to @AlbertUnruh
|
||||||
- Fix: App becomes unresponsive when clicking notifications.
|
- Fix: App becomes unresponsive when clicking notifications.
|
||||||
|
|
||||||
## 0.1.7
|
## 0.1.7
|
||||||
|
|
||||||
- Improved: Show input indicator in the chat overview as well
|
- Improve: Show input indicator in the chat overview as well
|
||||||
- Improved: Username change error handling
|
- Improve: Username change error handling
|
||||||
- Fix: Phantom push notification
|
- Fix: Phantom push notification
|
||||||
- Fix: Start in chat, if configured
|
- Fix: Start in chat, if configured
|
||||||
- Fix: Smaller UI fixes
|
- Fix: Smaller UI fixes
|
||||||
|
|
@ -192,7 +212,7 @@
|
||||||
|
|
||||||
## 0.0.96
|
## 0.0.96
|
||||||
|
|
||||||
- Feature: Show link in chat if the saved media file contains one
|
- New: Show link in chat if the saved media file contains one
|
||||||
- Improve: Verification badge for groups
|
- Improve: Verification badge for groups
|
||||||
- Improve: Huge reduction in app size
|
- Improve: Huge reduction in app size
|
||||||
- Fix: Crash on older devices when compressing a video
|
- Fix: Crash on older devices when compressing a video
|
||||||
|
|
@ -200,7 +220,7 @@
|
||||||
|
|
||||||
## 0.0.93
|
## 0.0.93
|
||||||
|
|
||||||
- Feature: Verification checkmark for friends
|
- New: Verification checkmark for friends
|
||||||
- Fix: Added contacts in contact sharing that were not clickable.
|
- Fix: Added contacts in contact sharing that were not clickable.
|
||||||
- Fix: Open chat after the image expires in case a draft message exists
|
- Fix: Open chat after the image expires in case a draft message exists
|
||||||
- Fix: Restore flames as a plus user
|
- Fix: Restore flames as a plus user
|
||||||
|
|
@ -213,139 +233,138 @@
|
||||||
|
|
||||||
## 0.0.92
|
## 0.0.92
|
||||||
|
|
||||||
- Adds the option to share contacts
|
- New: The option to share contacts
|
||||||
- Adds option to zoom in received images / videos
|
- New: Option to zoom in received images / videos
|
||||||
- Fixes issue with "reuploaded requested" not working
|
- Fix: Issue with "reuploaded requested" not working
|
||||||
- Fixes race condition while writing to the log file
|
- Fix: Race condition while writing to the log file
|
||||||
|
|
||||||
## 0.0.91
|
## 0.0.91
|
||||||
|
|
||||||
- Fixes link preview on iOS
|
- Fix: Link preview on iOS
|
||||||
- Fixes sharing images from other apps on iOS
|
- Fix: Sharing images from other apps on iOS
|
||||||
|
|
||||||
## 0.0.90
|
## 0.0.90
|
||||||
|
|
||||||
- Fixes issue that media files where not reuploaded
|
- Fix: Issue that media files were not reuploaded
|
||||||
- Fixes iOS zooming issue when switching between .5 and x1
|
- Fix: iOS zooming issue when switching between .5 and x1
|
||||||
- Fixes biometric auth bypass when opening a twonly/reopen send image
|
- Fix: Biometric auth bypass when opening a twonly/reopen send image
|
||||||
- Fixes that media files could not be downloaded in case the contact deleted his account
|
- Fix: That media files could not be downloaded in case the contact deleted his account
|
||||||
- Fixes database issue in case twonly is opened multiple times
|
- Fix: Database issue in case twonly is opened multiple times
|
||||||
- Fixes typos in translation
|
- Fix: Typos in translation
|
||||||
|
|
||||||
## 0.0.87
|
## 0.0.87
|
||||||
|
|
||||||
- Adds link preview to shared links
|
- New: Link preview to shared links
|
||||||
- Adds option to manual focus in the camera
|
- New: Option to manual focus in the camera
|
||||||
- Adds support to switch between front and back cameras during video recording
|
- New: Support to switch between front and back cameras during video recording
|
||||||
- Adds basic face filters
|
- New: Basic face filters
|
||||||
- Improves image editor, like emojis or text under a drawing can be moved
|
- Improve: Image editor, like emojis or text under a drawing can be moved
|
||||||
- Improves speed after taking a picture
|
- Improve: Speed after taking a picture
|
||||||
- Fixes issue with emojis disappearing in the image editor
|
- Fix: Issue with emojis disappearing in the image editor
|
||||||
|
|
||||||
## 0.0.86
|
## 0.0.86
|
||||||
|
|
||||||
- Allows to reopen send images (if send without time limit or enabled auth)
|
- New: Allows to reopen send images (if send without time limit or enabled auth)
|
||||||
- Added support for front camera zoom
|
- New: Support for front camera zoom
|
||||||
- Several bug fixes
|
- Fix: Several bug fixes
|
||||||
|
|
||||||
## 0.0.83
|
## 0.0.83
|
||||||
|
|
||||||
- Improved view of the diagnostic log
|
- Improve: View of the diagnostic log
|
||||||
- Several bug fixes
|
- Fix: Several bug fixes
|
||||||
|
|
||||||
## 0.0.82
|
## 0.0.82
|
||||||
|
|
||||||
- Added an option in the settings to automatically save all sent images
|
- New: An option in the settings to automatically save all sent images
|
||||||
- Hides duplicate images in the memory
|
- New: Hides duplicate images in the memory
|
||||||
- Fixes a bug where messages were not being received
|
- Improve: Several other minor improvements
|
||||||
- Several other minor improvements
|
- Fix: A bug where messages were not being received
|
||||||
|
|
||||||
## 0.0.81
|
## 0.0.81
|
||||||
|
|
||||||
- Fixes the issue where black/blank images were sometimes received
|
- Fix: The issue where black/blank images were sometimes received
|
||||||
- Fixes an issue in the image editor
|
- Fix: An issue in the image editor
|
||||||
|
|
||||||
## 0.0.80
|
## 0.0.80
|
||||||
|
|
||||||
- Share images/videos directly from other applications
|
- New: Share images/videos directly from other applications
|
||||||
- More customization options in the appearance settings
|
- New: More customization options in the appearance settings
|
||||||
- Improved UI for changing the display time of images
|
- Improve: UI for changing the display time of images
|
||||||
- Several minor UI improvements
|
- Improve: Several minor UI improvements
|
||||||
- Several bug fixes
|
- Fix: Several bug fixes
|
||||||
|
|
||||||
## 0.0.74
|
## 0.0.74
|
||||||
|
|
||||||
- Improving uploading speed
|
- Improve: Uploading speed
|
||||||
- Fixing issue with ffmpeg for android
|
- Fix: Issue with ffmpeg for android
|
||||||
|
|
||||||
## 0.0.73
|
## 0.0.73
|
||||||
|
|
||||||
- Integrated QR code scanner in the main camera
|
- New: Integrated QR code scanner in the main camera
|
||||||
- New profile share page
|
- New: Profile share page
|
||||||
- New workflow for checking the security number
|
- New: Workflow for checking the security number
|
||||||
- Improved user interface for creating voice messages
|
- Improve: User interface for creating voice messages
|
||||||
|
|
||||||
## 0.0.69
|
## 0.0.69
|
||||||
|
|
||||||
- Option to export and import memories
|
- New: Option to export and import memories
|
||||||
- iOS support for ultra-wide-angle camera
|
- New: iOS support for ultra-wide-angle camera
|
||||||
- Support Android Monochrome Icon
|
- New: Support Android Monochrome Icon
|
||||||
- Multiple layout issues fixed
|
- Fix: Multiple layout issues fixed
|
||||||
- Multiple bug fixes
|
- Fix: Multiple bug fixes
|
||||||
|
|
||||||
## 0.0.67
|
## 0.0.67
|
||||||
|
|
||||||
- Adds crash reports (optional). Please consider enabling this under Settings > Help > “Share errors and crashes with us.”
|
- New: Crash reports (optional). Please consider enabling this under Settings > Help > “Share errors and crashes with us.”
|
||||||
- Fixes bug when saving images to the gallery
|
- Fix: Bug when saving images to the gallery
|
||||||
- Multiple layout issues fixed
|
- Fix: Multiple layout issues fixed
|
||||||
- Multiple bug fixes
|
- Fix: Multiple bug fixes
|
||||||
|
|
||||||
## 0.0.62
|
## 0.0.62
|
||||||
|
|
||||||
- Support for groups with multiple administrators
|
- New: Support for groups with multiple administrators
|
||||||
- Edit and delete messages
|
- New: Edit and delete messages
|
||||||
- Create images using volume buttons
|
- New: Create images using volume buttons
|
||||||
- New and improved emoji picker
|
- New: Removing audio after recording is possible
|
||||||
- Removing audio after recording is possible
|
- New: Edited image is now embedded into the video
|
||||||
- Edited image is now embedded into the video
|
- New: Video max length increased to 60 seconds
|
||||||
- Video max length increased to 60 seconds
|
- New: Context menu and other UI enhancements
|
||||||
- Switched to FFmpeg for improved video compression
|
- New: Client-to-client protocol migrated to Protocol Buffers (Protobuf)
|
||||||
- New context menu and other UI enhancements
|
- New: Database identifiers converted to UUIDs and the database schema completely redesigned
|
||||||
- Client-to-client protocol migrated to Protocol Buffers (Protobuf)
|
- Improve: Emoji picker
|
||||||
- Database identifiers converted to UUIDs and the database schema completely redesigned
|
- Improve: Switched to FFmpeg for improved video compression
|
||||||
- Improved reliability of client-to-client messaging
|
- Improve: Reliability of client-to-client messaging
|
||||||
- Multiple bug fixes
|
- Fix: Multiple bug fixes
|
||||||
|
|
||||||
## 0.0.61
|
## 0.0.61
|
||||||
|
|
||||||
- Improving image editor when changing colors
|
- New: Image editor when changing colors
|
||||||
- Fixing message decryption error
|
- New: Dependency and Flutter upgrade
|
||||||
- Fixing issue with user deletion
|
- Fix: Message decryption error
|
||||||
- Fixing issue with flame counter sync
|
- Fix: Issue with user deletion
|
||||||
- Dependency and Flutter upgrade
|
- Fix: Issue with flame counter sync
|
||||||
|
|
||||||
## 0.0.60
|
## 0.0.60
|
||||||
|
|
||||||
- Improved logging to debug the 'Tap to load' issue.
|
- New: Display your own avatar in the title bar of the chat list.
|
||||||
- Display your own avatar in the title bar of the chat list.
|
- New: Created a default avatar image in case none was set.
|
||||||
- Created a default avatar image in case none was set.
|
- New: Flutter SDK and dependencies upgraded.
|
||||||
- Improved UI handling when requesting microphone access for the first time.
|
- Improve: Logging to debug the 'Tap to load' issue.
|
||||||
- Flutter SDK and dependencies upgraded.
|
- Improve: UI handling when requesting microphone access for the first time.
|
||||||
- Multiple bug fixes.
|
- Fix: Multiple bug fixes.
|
||||||
|
|
||||||
## 0.0.59
|
## 0.0.59
|
||||||
|
|
||||||
- Fixing media download error
|
- New: Location Filter are now stored as WebP instead of PNG
|
||||||
- Fixing issue with video recording
|
- Fix: Media download error
|
||||||
- Location Filter are now stored as WebP instead of PNG
|
- Fix: Issue with video recording
|
||||||
|
|
||||||
## 0.0.58
|
## 0.0.58
|
||||||
|
|
||||||
- twonly now has a free plan and is now financed by donations and an optional subscription with more features (coming soon)
|
- New: iOS gestures to close images
|
||||||
- iOS gestures to close images
|
- New: Onboarding screens updated and registration view simplified
|
||||||
- Improved chat messages view, including better citation view and display times
|
- New: The sender is displayed in the top right corner when a media file is opened
|
||||||
- Onboarding screens updated and registration view simplified
|
- New: Images are now stored as WebP to save storage
|
||||||
- The sender is displayed in the top right corner when a media file is opened
|
- New: Button to report users
|
||||||
- Images are now stored as WebP to save storage
|
- Improve: Chat messages view, including better citation view and display times
|
||||||
- Button to report users
|
- Fix: Multiple bug fixes
|
||||||
- Multiple bug fixes
|
|
||||||
|
|
|
||||||
13
README.md
13
README.md
|
|
@ -32,7 +32,7 @@ If you decide to give twonly a try, please keep in mind that it is still in its
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Offer a Snapchat™ like experience
|
- Offer a Snapchat™ like experience
|
||||||
- End-to-End encryption using the [Signal Protocol](https://de.wikipedia.org/wiki/Signal-Protokoll)
|
- End-to-End encryption using the [Signal Protocol](https://signal.org/docs/specifications/pqxdh/)
|
||||||
- Open Source and can be downloaded directly from GitHub
|
- Open Source and can be downloaded directly from GitHub
|
||||||
- No email or phone number required to register
|
- No email or phone number required to register
|
||||||
- The backend is hosted exclusively in Europe
|
- The backend is hosted exclusively in Europe
|
||||||
|
|
@ -40,19 +40,12 @@ If you decide to give twonly a try, please keep in mind that it is still in its
|
||||||
- [User Discovery](https://twonly.eu/en/blog/2026-mutual-friends.html) without a phone number
|
- [User Discovery](https://twonly.eu/en/blog/2026-mutual-friends.html) without a phone number
|
||||||
- E2EE cloud backup of memories
|
- E2EE cloud backup of memories
|
||||||
|
|
||||||
## Roadmap
|
## Next on the bucket list
|
||||||
|
|
||||||
### Currently
|
|
||||||
|
|
||||||
- Implementation of features so that Snapchat can actually be replaced
|
|
||||||
- Importing memories from Snapchat
|
- Importing memories from Snapchat
|
||||||
|
|
||||||
### Next on the bucket list
|
|
||||||
|
|
||||||
- For Android: Support for [UnifiedPush] (https://unifiedpush.org/)
|
- For Android: Support for [UnifiedPush] (https://unifiedpush.org/)
|
||||||
- For Android: Reproducible builds
|
- For Android: Reproducible builds
|
||||||
- Implementation of [Sealed Sender](https://signal.org/blog/sealed-sender/) (or a similar protocol) to minimize metadata
|
- Implementation of [Sealed Sender](https://signal.org/blog/sealed-sender/) (or a similar protocol) to minimize metadata
|
||||||
- Switch from the Signal protocol to [MLS](https://github.com/openmls/openmls) for post-quantum crypto support
|
|
||||||
- Decentralize the server so that anyone can run their own server
|
- Decentralize the server so that anyone can run their own server
|
||||||
|
|
||||||
## Security Issues
|
## Security Issues
|
||||||
|
|
@ -63,7 +56,7 @@ guarantee a bounty currently :/
|
||||||
|
|
||||||
## Contribution
|
## Contribution
|
||||||
|
|
||||||
Currently there are still some core features and rewrites open I want to do like the switch to the MLS protocol involving a huge rewrite in Rust. Because of this, contributions are currently not wanted. You can still view the code (if you find any security issues please contact me!). Also, issues are currently closed. If you find a bug, please use the in-app option as there you can upload your debug log which helps a lot.
|
Currently there are still some core features and rewrites open I want to do involving a huge rewrite in Rust. Because of this, contributions are currently not wanted. You can still view the code (if you find any security issues please contact me!). Also, issues are currently closed. If you find a bug, please use the in-app option as there you can upload your debug log which helps a lot.
|
||||||
|
|
||||||
## Signing Keys
|
## Signing Keys
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,13 @@ analyzer:
|
||||||
- "**.arb"
|
- "**.arb"
|
||||||
- "test/drift/**"
|
- "test/drift/**"
|
||||||
- "**.g.dart"
|
- "**.g.dart"
|
||||||
|
- build/**
|
||||||
|
- android/**
|
||||||
|
- ios/**
|
||||||
|
- web/**
|
||||||
|
- windows/**
|
||||||
|
- macos/**
|
||||||
|
- linux/**
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
rules:
|
rules:
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ android {
|
||||||
targetSdk = flutter.targetSdkVersion
|
targetSdk = flutter.targetSdkVersion
|
||||||
versionCode = flutter.versionCode
|
versionCode = flutter.versionCode
|
||||||
versionName = flutter.versionName
|
versionName = flutter.versionName
|
||||||
|
manifestPlaceholders = [appName: "twonly"]
|
||||||
}
|
}
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
release {
|
release {
|
||||||
|
|
@ -53,6 +54,7 @@ android {
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
applicationIdSuffix ".testing"
|
applicationIdSuffix ".testing"
|
||||||
|
manifestPlaceholders = [appName: "twonly [dev]"]
|
||||||
}
|
}
|
||||||
// profile {
|
// profile {
|
||||||
// applicationIdSuffix ".STOP"
|
// applicationIdSuffix ".STOP"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
|
||||||
<application
|
<application
|
||||||
android:label="twonly"
|
android:label="${appName}"
|
||||||
android:name=".MyApplication"
|
android:name=".MyApplication"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:fullBackupContent="false"
|
android:fullBackupContent="false"
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 32882a31904a0c1ffd38974bf5158ceee0f3ecb7
|
Subproject commit b874b9cc309822d90b940fdfbc8fd1ad3afc2450
|
||||||
204
dependencies.py
Normal file
204
dependencies.py
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
import yaml
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def print_blue(text):
|
||||||
|
BLUE = '\x1b[34m'
|
||||||
|
RESET = '\x1b[0m'
|
||||||
|
print(f"{BLUE}{text}{RESET}")
|
||||||
|
|
||||||
|
def print_yellow(text):
|
||||||
|
YELLOW = '\x1b[33m'
|
||||||
|
RESET = '\x1b[0m'
|
||||||
|
print(f"{YELLOW}{text}{RESET}")
|
||||||
|
|
||||||
|
def get_git_head(repo_path='.'):
|
||||||
|
result = subprocess.run(
|
||||||
|
['git', 'rev-parse', 'HEAD'],
|
||||||
|
cwd=repo_path,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
text=True,
|
||||||
|
check=False
|
||||||
|
)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise RuntimeError(f"git error: {result.stderr.strip()}")
|
||||||
|
return result.stdout.strip()
|
||||||
|
|
||||||
|
def get_default_branch(repo_path='.'):
|
||||||
|
result = subprocess.run(
|
||||||
|
['git', 'symbolic-ref', 'refs/remotes/origin/HEAD'],
|
||||||
|
cwd=repo_path,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
text=True,
|
||||||
|
check=False
|
||||||
|
)
|
||||||
|
if result.returncode == 0:
|
||||||
|
return result.stdout.strip().split('/')[-1]
|
||||||
|
return 'main'
|
||||||
|
|
||||||
|
def integrate_package(folder_name, data, cache_dir, out_dir):
|
||||||
|
repo_url = data['git']
|
||||||
|
keep_list = ["lib", "LICENSE", "pubspec.yaml", "android", "ios", "darwin"]
|
||||||
|
if "keep" in data:
|
||||||
|
keep_list += [item.rstrip('/') for item in data['keep']]
|
||||||
|
|
||||||
|
print(f"Processing {folder_name}...")
|
||||||
|
|
||||||
|
cache_path = os.path.join(cache_dir, folder_name)
|
||||||
|
if not os.path.exists(cache_path):
|
||||||
|
subprocess.run(["git", "clone", repo_url, cache_path], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
|
else:
|
||||||
|
result = subprocess.run(["git", "fetch", "--all"], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=cache_path)
|
||||||
|
if result.returncode != 0:
|
||||||
|
print_yellow(f"Warning: Could not fetch updates for {folder_name}. You might be offline.")
|
||||||
|
|
||||||
|
if "commit" in data:
|
||||||
|
commit_hash = data["commit"]
|
||||||
|
subprocess.run(["git", "checkout", commit_hash], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=cache_path)
|
||||||
|
elif "tag" in data:
|
||||||
|
tag_name = data["tag"]
|
||||||
|
subprocess.run(["git", "checkout", tag_name], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=cache_path)
|
||||||
|
else:
|
||||||
|
print_yellow(f"Warning: No commit or tag specified for {folder_name}. Using default branch.")
|
||||||
|
default_branch = get_default_branch(cache_path)
|
||||||
|
subprocess.run(["git", "checkout", default_branch], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=cache_path)
|
||||||
|
subprocess.run(["git", "pull"], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=cache_path)
|
||||||
|
last_commit_hash = get_git_head(cache_path)
|
||||||
|
data["commit"] = last_commit_hash
|
||||||
|
print_blue(f"Recorded commit {last_commit_hash} for {folder_name}")
|
||||||
|
|
||||||
|
results = [] # List of (pkg_name, version)
|
||||||
|
|
||||||
|
if "subpackages" in data:
|
||||||
|
packages_to_extract = data["subpackages"]
|
||||||
|
else:
|
||||||
|
packages_to_extract = [{"name": folder_name, "path": data.get("path", "")}]
|
||||||
|
|
||||||
|
for pkg in packages_to_extract:
|
||||||
|
pkg_name = pkg["name"]
|
||||||
|
subpath = pkg.get("path", "")
|
||||||
|
|
||||||
|
out_path = os.path.join(out_dir, pkg_name)
|
||||||
|
if os.path.exists(out_path):
|
||||||
|
shutil.rmtree(out_path)
|
||||||
|
os.makedirs(out_path)
|
||||||
|
|
||||||
|
package_src_path = os.path.join(cache_path, subpath) if subpath else cache_path
|
||||||
|
|
||||||
|
for item in keep_list:
|
||||||
|
src_item = os.path.join(package_src_path, item)
|
||||||
|
dst_item = os.path.join(out_path, item)
|
||||||
|
|
||||||
|
if os.path.exists(src_item):
|
||||||
|
os.makedirs(os.path.dirname(dst_item), exist_ok=True)
|
||||||
|
if os.path.isdir(src_item):
|
||||||
|
shutil.copytree(src_item, dst_item, dirs_exist_ok=True)
|
||||||
|
else:
|
||||||
|
shutil.copy2(src_item, dst_item)
|
||||||
|
|
||||||
|
version = "any"
|
||||||
|
try:
|
||||||
|
pubspec_path = os.path.join(package_src_path, "pubspec.yaml")
|
||||||
|
if os.path.exists(pubspec_path):
|
||||||
|
with open(pubspec_path, "r") as f:
|
||||||
|
ps = yaml.safe_load(f)
|
||||||
|
if ps and isinstance(ps, dict):
|
||||||
|
version = ps.get("version", "any")
|
||||||
|
except Exception as e:
|
||||||
|
print_yellow(f"Warning: Could not read version from {pkg_name}/pubspec.yaml")
|
||||||
|
|
||||||
|
results.append((pkg_name, version))
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Update specific or all repositories.")
|
||||||
|
parser.add_argument('repo_name', nargs='?', default=None, help="Name of the repository to update (optional)")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
with open("dependencies.yaml", "r") as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
|
||||||
|
cache_dir = config.get('cache', './.cache')
|
||||||
|
out_dir = config.get('outdir', './dependencies')
|
||||||
|
deps = config.get('dependencies', {})
|
||||||
|
|
||||||
|
if not os.path.exists(cache_dir):
|
||||||
|
os.makedirs(cache_dir)
|
||||||
|
if not os.path.exists(out_dir):
|
||||||
|
os.makedirs(out_dir)
|
||||||
|
|
||||||
|
repos_to_update = [args.repo_name] if args.repo_name else list(deps.keys())
|
||||||
|
|
||||||
|
pubspec_overrides = []
|
||||||
|
pubspec_deps = []
|
||||||
|
|
||||||
|
def process_deps_recursive(deps_dict, to_update=None):
|
||||||
|
for name, data in deps_dict.items():
|
||||||
|
if to_update is None or name in to_update:
|
||||||
|
extracted_packages = integrate_package(name, data, cache_dir, out_dir)
|
||||||
|
for pkg_name, version in extracted_packages:
|
||||||
|
pubspec_overrides.append(f" {pkg_name}:\n path: {out_dir}/{pkg_name}\n")
|
||||||
|
if version and version != "any":
|
||||||
|
pubspec_deps.append(f" {pkg_name}: ^{version}\n")
|
||||||
|
else:
|
||||||
|
pubspec_deps.append(f" {pkg_name}: any\n")
|
||||||
|
if "dependencies" in data:
|
||||||
|
# If we updated the parent, we should update children? Or if no args provided, update all.
|
||||||
|
# Actually, the original logic updated children automatically if parent is updated.
|
||||||
|
process_deps_recursive(data["dependencies"], None if (to_update is None or name in to_update) else [])
|
||||||
|
|
||||||
|
process_deps_recursive(deps, repos_to_update if args.repo_name else None)
|
||||||
|
|
||||||
|
def sort_dependencies(d):
|
||||||
|
sorted_d = {k: d[k] for k in sorted(d.keys())}
|
||||||
|
for k, v in sorted_d.items():
|
||||||
|
if "dependencies" in v and isinstance(v["dependencies"], dict):
|
||||||
|
v["dependencies"] = sort_dependencies(v["dependencies"])
|
||||||
|
return sorted_d
|
||||||
|
|
||||||
|
if "dependencies" in config:
|
||||||
|
config["dependencies"] = sort_dependencies(config["dependencies"])
|
||||||
|
|
||||||
|
with open("dependencies.yaml", "w") as f:
|
||||||
|
yaml.safe_dump(config, f, sort_keys=False)
|
||||||
|
|
||||||
|
# Update pubspec.yaml
|
||||||
|
if not args.repo_name:
|
||||||
|
with open("pubspec.yaml", "r") as f:
|
||||||
|
pubspec_lines = f.readlines()
|
||||||
|
|
||||||
|
start_marker_overrides = "## --- Start Managed Dependency Overrides ---"
|
||||||
|
end_marker_overrides = "## --- End Managed Dependency Overrides ---"
|
||||||
|
|
||||||
|
start_marker_deps = "## --- Start Managed Dependencies ---"
|
||||||
|
end_marker_deps = "## --- End Managed Dependencies ---"
|
||||||
|
|
||||||
|
try:
|
||||||
|
start_idx_overrides = next(i for i, line in enumerate(pubspec_lines) if line.strip() == start_marker_overrides)
|
||||||
|
end_idx_overrides = next(i for i, line in enumerate(pubspec_lines) if line.strip() == end_marker_overrides)
|
||||||
|
|
||||||
|
# Update overrides section
|
||||||
|
new_lines = pubspec_lines[:start_idx_overrides + 1] + pubspec_overrides + pubspec_lines[end_idx_overrides:]
|
||||||
|
|
||||||
|
# Now find the deps markers in the updated lines
|
||||||
|
start_idx_deps = next(i for i, line in enumerate(new_lines) if line.strip() == start_marker_deps)
|
||||||
|
end_idx_deps = next(i for i, line in enumerate(new_lines) if line.strip() == end_marker_deps)
|
||||||
|
|
||||||
|
# Update dependencies section
|
||||||
|
final_lines = new_lines[:start_idx_deps + 1] + pubspec_deps + new_lines[end_idx_deps:]
|
||||||
|
|
||||||
|
with open("pubspec.yaml", "w") as f:
|
||||||
|
f.writelines(final_lines)
|
||||||
|
print_blue("Updated pubspec.yaml successfully.")
|
||||||
|
except ValueError as e:
|
||||||
|
print_yellow("Error: Could not find professional markers in pubspec.yaml.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
109
dependencies.yaml
Normal file
109
dependencies.yaml
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
cache: ./.cache
|
||||||
|
outdir: ./dependencies
|
||||||
|
dependencies:
|
||||||
|
audio_waveforms:
|
||||||
|
git: https://github.com/SimformSolutionsPvtLtd/audio_waveforms.git
|
||||||
|
tag: 2.0.2
|
||||||
|
avatar_maker:
|
||||||
|
git: https://github.com/RoadTripMoustache/avatar_maker.git
|
||||||
|
tag: 1.5.0
|
||||||
|
keep:
|
||||||
|
- assets/icons
|
||||||
|
blurhash_dart:
|
||||||
|
git: https://github.com/justacid/blurhash-dart.git
|
||||||
|
tag: v1.2.1
|
||||||
|
exif:
|
||||||
|
git: https://github.com/bigflood/dartexif.git
|
||||||
|
dependencies:
|
||||||
|
sprintf:
|
||||||
|
git: https://github.com/Naddiseo/dart-sprintf.git
|
||||||
|
commit: f1e74f2f4c339d983f9d011b4ba1df4ec8b8857c
|
||||||
|
commit: bf170d5639f0b6fcb0947060cf8bd7b623df9069
|
||||||
|
flutter_blurhash:
|
||||||
|
git: https://github.com/fluttercommunity/flutter_blurhash.git
|
||||||
|
commit: c5cdec4986432e835bb91f5ce00564534450cdc7
|
||||||
|
flutter_markdown_plus:
|
||||||
|
git: https://github.com/foresightmobile/flutter_markdown_plus.git
|
||||||
|
commit: dc1185c933fbf9dba559ef6c91586ff1503be3ee
|
||||||
|
flutter_packages:
|
||||||
|
git: https://github.com/otsmr/flutter-packages.git
|
||||||
|
subpackages:
|
||||||
|
- name: video_player
|
||||||
|
path: packages/video_player/video_player
|
||||||
|
- name: video_player_android
|
||||||
|
path: packages/video_player/video_player_android
|
||||||
|
- name: video_player_avfoundation
|
||||||
|
path: packages/video_player/video_player_avfoundation
|
||||||
|
- name: camera_android_camerax
|
||||||
|
path: packages/camera/camera_android_camerax
|
||||||
|
commit: b4f7d807a822a8ce327aae21353ac2217e928f6d
|
||||||
|
flutter_sharing_intent:
|
||||||
|
git: https://github.com/bhagat-techind/flutter_sharing_intent.git
|
||||||
|
commit: aa1672f547d6579585fa27df0b28ffa2a2544aaa
|
||||||
|
hand_signature:
|
||||||
|
git: https://github.com/RomanBase/hand_signature.git
|
||||||
|
commit: 1beedb164d093643365b0832277c377353c7464f
|
||||||
|
hashlib:
|
||||||
|
git: https://github.com/bitanon/hashlib.git
|
||||||
|
replace:
|
||||||
|
- - abstract class MACHashBase
|
||||||
|
- abstract mixin class MACHashBase
|
||||||
|
dependencies:
|
||||||
|
hashlib_codecs:
|
||||||
|
git: https://github.com/bitanon/hashlib_codecs.git
|
||||||
|
commit: 2a966c37c3b9b1f5541ae88e99ab34acf3fc968b
|
||||||
|
commit: bc9c2f8dd7bbc72f47ccab0ce1111d40259c49bc
|
||||||
|
image:
|
||||||
|
git: https://github.com/brendan-duncan/image.git
|
||||||
|
tag: v4.9.2
|
||||||
|
introduction_screen:
|
||||||
|
git: https://github.com/Pyozer/introduction_screen.git
|
||||||
|
dependencies:
|
||||||
|
dots_indicator:
|
||||||
|
git: https://github.com/Pyozer/dots_indicator.git
|
||||||
|
commit: 508f5883ac79bdbc10254092de3f28f571d261cd
|
||||||
|
commit: 4a90e557630b28834479ed9c64a9d2d0185d8e48
|
||||||
|
libsignal_protocol_dart:
|
||||||
|
git: https://github.com/MixinNetwork/libsignal_protocol_dart.git
|
||||||
|
dependencies:
|
||||||
|
adaptive_number:
|
||||||
|
git: https://github.com/lemoony/adaptive_number_dart
|
||||||
|
commit: ea9178fdd4d82ac45cf0ec966ac870dae661124f
|
||||||
|
ed25519_edwards:
|
||||||
|
git: https://github.com/Tougee/ed25519.git
|
||||||
|
commit: 7353ba759ea9f4646cbf481c2ef949625c8ce4cf
|
||||||
|
optional:
|
||||||
|
git: https://github.com/tonio-ramirez/optional.dart.git
|
||||||
|
commit: 71c638891ce4f2aff35c7387727989f31f9d877d
|
||||||
|
pointycastle:
|
||||||
|
git: https://github.com/bcgit/pc-dart.git
|
||||||
|
commit: bbd8569f68a7fccbdf0b92d0b44a9219c126c8dd
|
||||||
|
x25519:
|
||||||
|
git: https://github.com/Tougee/curve25519.git
|
||||||
|
commit: ecb1d357714537bba6e276ef45f093846d4beaee
|
||||||
|
commit: c95a1586057022acdbb9c76b1692d94cc549bcc7
|
||||||
|
lottie:
|
||||||
|
git: https://github.com/xvrh/lottie-flutter.git
|
||||||
|
commit: 127bc29f2c6bd8b32ec4064a09e54e6b31cd0a88
|
||||||
|
mutex:
|
||||||
|
git: https://github.com/hoylen/dart-mutex.git
|
||||||
|
commit: 84ca903a3ac863735e3228c75a212133621f680f
|
||||||
|
photo_view:
|
||||||
|
git: https://github.com/bluefireteam/photo_view.git
|
||||||
|
commit: a13ca2fc387a3fb1276126959e092c44d0029987
|
||||||
|
pro_video_editor:
|
||||||
|
git: https://github.com/hm21/pro_video_editor.git
|
||||||
|
tag: v2.11.3
|
||||||
|
qr_flutter:
|
||||||
|
git: https://github.com/theyakka/qr.flutter.git
|
||||||
|
dependencies:
|
||||||
|
qr:
|
||||||
|
git: https://github.com/kevmoo/qr.dart.git
|
||||||
|
commit: 7b1e9665ca976f484e7975356cf26fc7a0ccf02e
|
||||||
|
commit: d5e7206396105d643113618290bbcc755d05f492
|
||||||
|
restart_app:
|
||||||
|
git: https://github.com/gabrimatic/restart_app
|
||||||
|
commit: 66897cb67e235bab85421647bfae036acb4438cb
|
||||||
|
screen_protector:
|
||||||
|
git: https://github.com/prongbang/screen_protector.git
|
||||||
|
commit: 019c04d622d7b610d2903d3a347edc3ba76a6ed0
|
||||||
|
|
@ -92,8 +92,6 @@ PODS:
|
||||||
- nanopb/encode (3.30910.0)
|
- nanopb/encode (3.30910.0)
|
||||||
- permission_handler_apple (9.3.0):
|
- permission_handler_apple (9.3.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- pro_video_editor (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- PromisesObjC (2.4.0)
|
- PromisesObjC (2.4.0)
|
||||||
- rust_lib_twonly (0.0.1):
|
- rust_lib_twonly (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
|
@ -122,7 +120,6 @@ DEPENDENCIES:
|
||||||
- google_mlkit_commons (from `.symlinks/plugins/google_mlkit_commons/ios`)
|
- google_mlkit_commons (from `.symlinks/plugins/google_mlkit_commons/ios`)
|
||||||
- google_mlkit_face_detection (from `.symlinks/plugins/google_mlkit_face_detection/ios`)
|
- google_mlkit_face_detection (from `.symlinks/plugins/google_mlkit_face_detection/ios`)
|
||||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||||
- pro_video_editor (from `.symlinks/plugins/pro_video_editor/ios`)
|
|
||||||
- rust_lib_twonly (from `.symlinks/plugins/rust_lib_twonly/ios`)
|
- rust_lib_twonly (from `.symlinks/plugins/rust_lib_twonly/ios`)
|
||||||
- screen_protector (from `.symlinks/plugins/screen_protector/ios`)
|
- screen_protector (from `.symlinks/plugins/screen_protector/ios`)
|
||||||
- SwiftProtobuf
|
- SwiftProtobuf
|
||||||
|
|
@ -170,8 +167,6 @@ EXTERNAL SOURCES:
|
||||||
:path: ".symlinks/plugins/google_mlkit_face_detection/ios"
|
:path: ".symlinks/plugins/google_mlkit_face_detection/ios"
|
||||||
permission_handler_apple:
|
permission_handler_apple:
|
||||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||||
pro_video_editor:
|
|
||||||
:path: ".symlinks/plugins/pro_video_editor/ios"
|
|
||||||
rust_lib_twonly:
|
rust_lib_twonly:
|
||||||
:path: ".symlinks/plugins/rust_lib_twonly/ios"
|
:path: ".symlinks/plugins/rust_lib_twonly/ios"
|
||||||
screen_protector:
|
screen_protector:
|
||||||
|
|
@ -182,7 +177,7 @@ EXTERNAL SOURCES:
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
audio_waveforms: a6dde7fe7c0ea05f06ffbdb0f7c1b2b2ba6cedcf
|
audio_waveforms: a6dde7fe7c0ea05f06ffbdb0f7c1b2b2ba6cedcf
|
||||||
cryptography_flutter_plus: 44f4e9e4079395fcbb3e7809c0ac2c6ae2d9576f
|
cryptography_flutter_plus: 44f4e9e4079395fcbb3e7809c0ac2c6ae2d9576f
|
||||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
Flutter: 71a624a5bc0c04062bf19101d501e466baf2fb47
|
||||||
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
|
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
|
||||||
flutter_sharing_intent: 0c1e53949f09fa8df8ac2268505687bde8ff264c
|
flutter_sharing_intent: 0c1e53949f09fa8df8ac2268505687bde8ff264c
|
||||||
flutter_volume_controller: c2be490cb0487e8b88d0d9fc2b7e1c139a4ebccb
|
flutter_volume_controller: c2be490cb0487e8b88d0d9fc2b7e1c139a4ebccb
|
||||||
|
|
@ -203,7 +198,6 @@ SPEC CHECKSUMS:
|
||||||
MLKitVision: 39a5a812db83c4a0794445088e567f3631c11961
|
MLKitVision: 39a5a812db83c4a0794445088e567f3631c11961
|
||||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||||
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||||
pro_video_editor: 44ef9a6d48dbd757ed428cf35396dd05f35c7830
|
|
||||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
rust_lib_twonly: 73165b05d0cda50db45852db63f49caa7f319520
|
rust_lib_twonly: 73165b05d0cda50db45852db63f49caa7f319520
|
||||||
screen_protector: 18c6aca2dc5d2a832f6787a5318f97f03e9d3150
|
screen_protector: 18c6aca2dc5d2a832f6787a5318f97f03e9d3150
|
||||||
|
|
|
||||||
|
|
@ -742,7 +742,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
|
@ -886,7 +886,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
|
@ -939,7 +939,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
|
|
||||||
30
lib/app.dart
30
lib/app.dart
|
|
@ -10,6 +10,7 @@ import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/constants/keyvalue.keys.dart';
|
import 'package:twonly/src/constants/keyvalue.keys.dart';
|
||||||
import 'package:twonly/src/constants/routes.keys.dart';
|
import 'package:twonly/src/constants/routes.keys.dart';
|
||||||
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||||
import 'package:twonly/src/localization/generated/app_localizations.dart';
|
import 'package:twonly/src/localization/generated/app_localizations.dart';
|
||||||
import 'package:twonly/src/model/json/onboarding_state.model.dart';
|
import 'package:twonly/src/model/json/onboarding_state.model.dart';
|
||||||
import 'package:twonly/src/providers/routing.provider.dart';
|
import 'package:twonly/src/providers/routing.provider.dart';
|
||||||
|
|
@ -89,15 +90,17 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
Locale('de', ''),
|
Locale('de', ''),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
final settings = context.watch<SettingsChangeProvider>();
|
||||||
|
|
||||||
if (widget.storageError) {
|
if (widget.storageError) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
localizationsDelegates: localizationsDelegates,
|
localizationsDelegates: localizationsDelegates,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
supportedLocales: supportedLocales,
|
supportedLocales: supportedLocales,
|
||||||
title: 'twonly',
|
title: 'twonly',
|
||||||
theme: lightTheme,
|
theme: getLightTheme(settings.primaryColor),
|
||||||
darkTheme: darkTheme,
|
darkTheme: getDarkTheme(settings.primaryColor),
|
||||||
themeMode: context.read<SettingsChangeProvider>().themeMode,
|
themeMode: settings.themeMode,
|
||||||
home: const CriticalErrorView(),
|
home: const CriticalErrorView(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -108,9 +111,9 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
supportedLocales: supportedLocales,
|
supportedLocales: supportedLocales,
|
||||||
title: 'twonly',
|
title: 'twonly',
|
||||||
theme: lightTheme,
|
theme: getLightTheme(settings.primaryColor),
|
||||||
darkTheme: darkTheme,
|
darkTheme: getDarkTheme(settings.primaryColor),
|
||||||
themeMode: context.read<SettingsChangeProvider>().themeMode,
|
themeMode: settings.themeMode,
|
||||||
home: const RecoveryView(),
|
home: const RecoveryView(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -121,9 +124,9 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
supportedLocales: supportedLocales,
|
supportedLocales: supportedLocales,
|
||||||
title: 'twonly',
|
title: 'twonly',
|
||||||
theme: lightTheme,
|
theme: getLightTheme(settings.primaryColor),
|
||||||
darkTheme: darkTheme,
|
darkTheme: getDarkTheme(settings.primaryColor),
|
||||||
themeMode: context.read<SettingsChangeProvider>().themeMode,
|
themeMode: settings.themeMode,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -161,6 +164,7 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
||||||
initAsync();
|
initAsync();
|
||||||
|
|
||||||
void handleShareLink(Uri uri) {
|
void handleShareLink(Uri uri) {
|
||||||
|
HomeViewState.pendingSharedLink = uri;
|
||||||
routerProvider.go(Routes.home);
|
routerProvider.go(Routes.home);
|
||||||
HomeViewState.streamHomeViewPageIndex.add(1);
|
HomeViewState.streamHomeViewPageIndex.add(1);
|
||||||
HomeViewState.streamSharedLink.add(uri);
|
HomeViewState.streamSharedLink.add(uri);
|
||||||
|
|
@ -177,9 +181,17 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
void handleShareMedia(String path, MediaType type) {
|
||||||
|
HomeViewState.pendingSharedMedia = (path, type);
|
||||||
|
routerProvider.go(Routes.home);
|
||||||
|
HomeViewState.streamHomeViewPageIndex.add(0);
|
||||||
|
HomeViewState.streamSharedMedia.add((path, type));
|
||||||
|
}
|
||||||
|
|
||||||
_intentStreamSub = initIntentStreams(
|
_intentStreamSub = initIntentStreams(
|
||||||
context,
|
context,
|
||||||
handleShareLink,
|
handleShareLink,
|
||||||
|
handleShareMedia,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
57
lib/core/bridge/wrapper/signal.dart
Normal file
57
lib/core/bridge/wrapper/signal.dart
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
// This file is automatically generated, so please do not edit it.
|
||||||
|
// @generated by `flutter_rust_bridge`@ 2.12.0.
|
||||||
|
|
||||||
|
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
|
||||||
|
|
||||||
|
import '../../frb_generated.dart';
|
||||||
|
import '../../signal/engine.dart';
|
||||||
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
||||||
|
|
||||||
|
class RustSignal {
|
||||||
|
const RustSignal();
|
||||||
|
|
||||||
|
static Future<Uint8List> decrypt({
|
||||||
|
required String name,
|
||||||
|
required int deviceId,
|
||||||
|
required List<int> ciphertext,
|
||||||
|
}) => RustLib.instance.api.crateBridgeWrapperSignalRustSignalDecrypt(
|
||||||
|
name: name,
|
||||||
|
deviceId: deviceId,
|
||||||
|
ciphertext: ciphertext,
|
||||||
|
);
|
||||||
|
|
||||||
|
static Future<Uint8List> encrypt({
|
||||||
|
required String name,
|
||||||
|
required int deviceId,
|
||||||
|
required List<int> plaintext,
|
||||||
|
}) => RustLib.instance.api.crateBridgeWrapperSignalRustSignalEncrypt(
|
||||||
|
name: name,
|
||||||
|
deviceId: deviceId,
|
||||||
|
plaintext: plaintext,
|
||||||
|
);
|
||||||
|
|
||||||
|
static Future<FrbPreKeyBundle> generateBundle() =>
|
||||||
|
RustLib.instance.api.crateBridgeWrapperSignalRustSignalGenerateBundle();
|
||||||
|
|
||||||
|
static Future<List<FrbPqcPreKey>> generatePqcPrekeys() => RustLib.instance.api
|
||||||
|
.crateBridgeWrapperSignalRustSignalGeneratePqcPrekeys();
|
||||||
|
|
||||||
|
static Future<void> processPrekeyBundle({
|
||||||
|
required String name,
|
||||||
|
required int deviceId,
|
||||||
|
required FrbPreKeyBundle bundle,
|
||||||
|
}) => RustLib.instance.api
|
||||||
|
.crateBridgeWrapperSignalRustSignalProcessPrekeyBundle(
|
||||||
|
name: name,
|
||||||
|
deviceId: deviceId,
|
||||||
|
bundle: bundle,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is RustSignal && runtimeType == other.runtimeType;
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@ import 'bridge/callbacks/user_discovery.dart';
|
||||||
import 'bridge/wrapper.dart';
|
import 'bridge/wrapper.dart';
|
||||||
import 'bridge/wrapper/backup.dart';
|
import 'bridge/wrapper/backup.dart';
|
||||||
import 'bridge/wrapper/key_manager.dart';
|
import 'bridge/wrapper/key_manager.dart';
|
||||||
|
import 'bridge/wrapper/signal.dart';
|
||||||
import 'bridge/wrapper/user_discovery.dart';
|
import 'bridge/wrapper/user_discovery.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
@ -18,6 +19,7 @@ import 'frb_generated.io.dart'
|
||||||
import 'keys/backup_password_keys.dart';
|
import 'keys/backup_password_keys.dart';
|
||||||
import 'lib.dart';
|
import 'lib.dart';
|
||||||
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
||||||
|
import 'signal/engine.dart';
|
||||||
|
|
||||||
/// Main entrypoint of the Rust API
|
/// Main entrypoint of the Rust API
|
||||||
class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
|
class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
|
||||||
|
|
@ -76,7 +78,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
|
||||||
String get codegenVersion => '2.12.0';
|
String get codegenVersion => '2.12.0';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get rustContentHash => 1788847092;
|
int get rustContentHash => 1109927244;
|
||||||
|
|
||||||
static const kDefaultExternalLibraryLoaderConfig =
|
static const kDefaultExternalLibraryLoaderConfig =
|
||||||
ExternalLibraryLoaderConfig(
|
ExternalLibraryLoaderConfig(
|
||||||
|
|
@ -259,6 +261,29 @@ abstract class RustLibApi extends BaseApi {
|
||||||
required List<int> record,
|
required List<int> record,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Future<Uint8List> crateBridgeWrapperSignalRustSignalDecrypt({
|
||||||
|
required String name,
|
||||||
|
required int deviceId,
|
||||||
|
required List<int> ciphertext,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Uint8List> crateBridgeWrapperSignalRustSignalEncrypt({
|
||||||
|
required String name,
|
||||||
|
required int deviceId,
|
||||||
|
required List<int> plaintext,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<FrbPreKeyBundle> crateBridgeWrapperSignalRustSignalGenerateBundle();
|
||||||
|
|
||||||
|
Future<List<FrbPqcPreKey>>
|
||||||
|
crateBridgeWrapperSignalRustSignalGeneratePqcPrekeys();
|
||||||
|
|
||||||
|
Future<void> crateBridgeWrapperSignalRustSignalProcessPrekeyBundle({
|
||||||
|
required String name,
|
||||||
|
required int deviceId,
|
||||||
|
required FrbPreKeyBundle bundle,
|
||||||
|
});
|
||||||
|
|
||||||
Future<List<Uint8List>> crateBridgeWrapperRustUtilsGenerateShares({
|
Future<List<Uint8List>> crateBridgeWrapperRustUtilsGenerateShares({
|
||||||
required List<int> secret,
|
required List<int> secret,
|
||||||
required int total,
|
required int total,
|
||||||
|
|
@ -1651,6 +1676,183 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
argNames: ["signedPreKeyId", "record"],
|
argNames: ["signedPreKeyId", "record"],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> crateBridgeWrapperSignalRustSignalDecrypt({
|
||||||
|
required String name,
|
||||||
|
required int deviceId,
|
||||||
|
required List<int> ciphertext,
|
||||||
|
}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||||
|
sse_encode_String(name, serializer);
|
||||||
|
sse_encode_u_32(deviceId, serializer);
|
||||||
|
sse_encode_list_prim_u_8_loose(ciphertext, serializer);
|
||||||
|
pdeCallFfi(
|
||||||
|
generalizedFrbRustBinding,
|
||||||
|
serializer,
|
||||||
|
funcId: 32,
|
||||||
|
port: port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: SseCodec(
|
||||||
|
decodeSuccessData: sse_decode_list_prim_u_8_strict,
|
||||||
|
decodeErrorData: sse_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateBridgeWrapperSignalRustSignalDecryptConstMeta,
|
||||||
|
argValues: [name, deviceId, ciphertext],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateBridgeWrapperSignalRustSignalDecryptConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "rust_signal_decrypt",
|
||||||
|
argNames: ["name", "deviceId", "ciphertext"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> crateBridgeWrapperSignalRustSignalEncrypt({
|
||||||
|
required String name,
|
||||||
|
required int deviceId,
|
||||||
|
required List<int> plaintext,
|
||||||
|
}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||||
|
sse_encode_String(name, serializer);
|
||||||
|
sse_encode_u_32(deviceId, serializer);
|
||||||
|
sse_encode_list_prim_u_8_loose(plaintext, serializer);
|
||||||
|
pdeCallFfi(
|
||||||
|
generalizedFrbRustBinding,
|
||||||
|
serializer,
|
||||||
|
funcId: 33,
|
||||||
|
port: port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: SseCodec(
|
||||||
|
decodeSuccessData: sse_decode_list_prim_u_8_strict,
|
||||||
|
decodeErrorData: sse_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateBridgeWrapperSignalRustSignalEncryptConstMeta,
|
||||||
|
argValues: [name, deviceId, plaintext],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateBridgeWrapperSignalRustSignalEncryptConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "rust_signal_encrypt",
|
||||||
|
argNames: ["name", "deviceId", "plaintext"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<FrbPreKeyBundle> crateBridgeWrapperSignalRustSignalGenerateBundle() {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||||
|
pdeCallFfi(
|
||||||
|
generalizedFrbRustBinding,
|
||||||
|
serializer,
|
||||||
|
funcId: 34,
|
||||||
|
port: port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: SseCodec(
|
||||||
|
decodeSuccessData: sse_decode_frb_pre_key_bundle,
|
||||||
|
decodeErrorData: sse_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateBridgeWrapperSignalRustSignalGenerateBundleConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta
|
||||||
|
get kCrateBridgeWrapperSignalRustSignalGenerateBundleConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "rust_signal_generate_bundle",
|
||||||
|
argNames: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<FrbPqcPreKey>>
|
||||||
|
crateBridgeWrapperSignalRustSignalGeneratePqcPrekeys() {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||||
|
pdeCallFfi(
|
||||||
|
generalizedFrbRustBinding,
|
||||||
|
serializer,
|
||||||
|
funcId: 35,
|
||||||
|
port: port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: SseCodec(
|
||||||
|
decodeSuccessData: sse_decode_list_frb_pqc_pre_key,
|
||||||
|
decodeErrorData: sse_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta:
|
||||||
|
kCrateBridgeWrapperSignalRustSignalGeneratePqcPrekeysConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta
|
||||||
|
get kCrateBridgeWrapperSignalRustSignalGeneratePqcPrekeysConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "rust_signal_generate_pqc_prekeys",
|
||||||
|
argNames: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> crateBridgeWrapperSignalRustSignalProcessPrekeyBundle({
|
||||||
|
required String name,
|
||||||
|
required int deviceId,
|
||||||
|
required FrbPreKeyBundle bundle,
|
||||||
|
}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||||
|
sse_encode_String(name, serializer);
|
||||||
|
sse_encode_u_32(deviceId, serializer);
|
||||||
|
sse_encode_box_autoadd_frb_pre_key_bundle(bundle, serializer);
|
||||||
|
pdeCallFfi(
|
||||||
|
generalizedFrbRustBinding,
|
||||||
|
serializer,
|
||||||
|
funcId: 36,
|
||||||
|
port: port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: SseCodec(
|
||||||
|
decodeSuccessData: sse_decode_unit,
|
||||||
|
decodeErrorData: sse_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta:
|
||||||
|
kCrateBridgeWrapperSignalRustSignalProcessPrekeyBundleConstMeta,
|
||||||
|
argValues: [name, deviceId, bundle],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta
|
||||||
|
get kCrateBridgeWrapperSignalRustSignalProcessPrekeyBundleConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "rust_signal_process_prekey_bundle",
|
||||||
|
argNames: ["name", "deviceId", "bundle"],
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<Uint8List>> crateBridgeWrapperRustUtilsGenerateShares({
|
Future<List<Uint8List>> crateBridgeWrapperRustUtilsGenerateShares({
|
||||||
required List<int> secret,
|
required List<int> secret,
|
||||||
|
|
@ -1667,7 +1869,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 32,
|
funcId: 37,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -1702,7 +1904,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 33,
|
funcId: 38,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -1738,7 +1940,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 34,
|
funcId: 39,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -1775,7 +1977,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 35,
|
funcId: 40,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -1813,7 +2015,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 36,
|
funcId: 41,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -1851,7 +2053,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 37,
|
funcId: 42,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -1889,7 +2091,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 38,
|
funcId: 43,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -1928,7 +2130,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 39,
|
funcId: 44,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -1967,7 +2169,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 40,
|
funcId: 45,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -2012,7 +2214,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 41,
|
funcId: 46,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -2064,7 +2266,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 42,
|
funcId: 47,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -2105,7 +2307,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 43,
|
funcId: 48,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -2143,7 +2345,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 44,
|
funcId: 49,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -2181,7 +2383,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 45,
|
funcId: 50,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -2219,7 +2421,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 46,
|
funcId: 51,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -2257,7 +2459,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 47,
|
funcId: 52,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -2299,7 +2501,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 48,
|
funcId: 53,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -2339,7 +2541,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 49,
|
funcId: 54,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -2978,6 +3180,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return dco_decode_backup_password_keys(raw);
|
return dco_decode_backup_password_keys(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPreKeyBundle dco_decode_box_autoadd_frb_pre_key_bundle(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return dco_decode_frb_pre_key_bundle(raw);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw) {
|
PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
|
@ -2996,6 +3204,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return dco_decode_other_promotion(raw);
|
return dco_decode_other_promotion(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int dco_decode_box_autoadd_u_32(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return raw as int;
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
UserDiscoveryStoreFlutter dco_decode_box_autoadd_user_discovery_store_flutter(
|
UserDiscoveryStoreFlutter dco_decode_box_autoadd_user_discovery_store_flutter(
|
||||||
dynamic raw,
|
dynamic raw,
|
||||||
|
|
@ -3021,6 +3235,42 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return FlutterUserDiscovery();
|
return FlutterUserDiscovery();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPqcPreKey dco_decode_frb_pqc_pre_key(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
final arr = raw as List<dynamic>;
|
||||||
|
if (arr.length != 5)
|
||||||
|
throw Exception('unexpected arr length: expect 5 but see ${arr.length}');
|
||||||
|
return FrbPqcPreKey(
|
||||||
|
eccPreKeyId: dco_decode_u_32(arr[0]),
|
||||||
|
eccPreKey: dco_decode_list_prim_u_8_strict(arr[1]),
|
||||||
|
kyberPreKeyId: dco_decode_u_32(arr[2]),
|
||||||
|
kyberPreKey: dco_decode_list_prim_u_8_strict(arr[3]),
|
||||||
|
kyberPreKeySignature: dco_decode_list_prim_u_8_strict(arr[4]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPreKeyBundle dco_decode_frb_pre_key_bundle(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
final arr = raw as List<dynamic>;
|
||||||
|
if (arr.length != 11)
|
||||||
|
throw Exception('unexpected arr length: expect 11 but see ${arr.length}');
|
||||||
|
return FrbPreKeyBundle(
|
||||||
|
registrationId: dco_decode_u_32(arr[0]),
|
||||||
|
deviceId: dco_decode_u_32(arr[1]),
|
||||||
|
preKeyId: dco_decode_opt_box_autoadd_u_32(arr[2]),
|
||||||
|
preKeyPublic: dco_decode_opt_list_prim_u_8_strict(arr[3]),
|
||||||
|
signedPreKeyId: dco_decode_u_32(arr[4]),
|
||||||
|
signedPreKeyPublic: dco_decode_list_prim_u_8_strict(arr[5]),
|
||||||
|
signedPreKeySignature: dco_decode_list_prim_u_8_strict(arr[6]),
|
||||||
|
kyberPreKeyId: dco_decode_u_32(arr[7]),
|
||||||
|
kyberPreKeyPublic: dco_decode_list_prim_u_8_strict(arr[8]),
|
||||||
|
kyberPreKeySignature: dco_decode_list_prim_u_8_strict(arr[9]),
|
||||||
|
identityKey: dco_decode_list_prim_u_8_strict(arr[10]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 dco_decode_i_64(dynamic raw) {
|
PlatformInt64 dco_decode_i_64(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
|
@ -3045,6 +3295,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return dcoDecodeI64(raw);
|
return dcoDecodeI64(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<FrbPqcPreKey> dco_decode_list_frb_pqc_pre_key(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return (raw as List<dynamic>).map(dco_decode_frb_pqc_pre_key).toList();
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<Uint8List> dco_decode_list_list_prim_u_8_strict(dynamic raw) {
|
List<Uint8List> dco_decode_list_list_prim_u_8_strict(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
|
@ -3096,6 +3352,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return raw == null ? null : dco_decode_box_autoadd_i_64(raw);
|
return raw == null ? null : dco_decode_box_autoadd_i_64(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int? dco_decode_opt_box_autoadd_u_32(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return raw == null ? null : dco_decode_box_autoadd_u_32(raw);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<Uint8List>? dco_decode_opt_list_list_prim_u_8_strict(dynamic raw) {
|
List<Uint8List>? dco_decode_opt_list_list_prim_u_8_strict(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
|
@ -3200,6 +3462,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return RustKeyManager();
|
return RustKeyManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
RustSignal dco_decode_rust_signal(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
final arr = raw as List<dynamic>;
|
||||||
|
if (arr.length != 0)
|
||||||
|
throw Exception('unexpected arr length: expect 0 but see ${arr.length}');
|
||||||
|
return RustSignal();
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
RustUtils dco_decode_rust_utils(dynamic raw) {
|
RustUtils dco_decode_rust_utils(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
|
@ -3347,6 +3618,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return (sse_decode_backup_password_keys(deserializer));
|
return (sse_decode_backup_password_keys(deserializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPreKeyBundle sse_decode_box_autoadd_frb_pre_key_bundle(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return (sse_decode_frb_pre_key_bundle(deserializer));
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer) {
|
PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
@ -3367,6 +3646,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return (sse_decode_other_promotion(deserializer));
|
return (sse_decode_other_promotion(deserializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int sse_decode_box_autoadd_u_32(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return (sse_decode_u_32(deserializer));
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
UserDiscoveryStoreFlutter sse_decode_box_autoadd_user_discovery_store_flutter(
|
UserDiscoveryStoreFlutter sse_decode_box_autoadd_user_discovery_store_flutter(
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
|
|
@ -3391,6 +3676,58 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return FlutterUserDiscovery();
|
return FlutterUserDiscovery();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPqcPreKey sse_decode_frb_pqc_pre_key(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var var_eccPreKeyId = sse_decode_u_32(deserializer);
|
||||||
|
var var_eccPreKey = sse_decode_list_prim_u_8_strict(deserializer);
|
||||||
|
var var_kyberPreKeyId = sse_decode_u_32(deserializer);
|
||||||
|
var var_kyberPreKey = sse_decode_list_prim_u_8_strict(deserializer);
|
||||||
|
var var_kyberPreKeySignature = sse_decode_list_prim_u_8_strict(
|
||||||
|
deserializer,
|
||||||
|
);
|
||||||
|
return FrbPqcPreKey(
|
||||||
|
eccPreKeyId: var_eccPreKeyId,
|
||||||
|
eccPreKey: var_eccPreKey,
|
||||||
|
kyberPreKeyId: var_kyberPreKeyId,
|
||||||
|
kyberPreKey: var_kyberPreKey,
|
||||||
|
kyberPreKeySignature: var_kyberPreKeySignature,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPreKeyBundle sse_decode_frb_pre_key_bundle(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var var_registrationId = sse_decode_u_32(deserializer);
|
||||||
|
var var_deviceId = sse_decode_u_32(deserializer);
|
||||||
|
var var_preKeyId = sse_decode_opt_box_autoadd_u_32(deserializer);
|
||||||
|
var var_preKeyPublic = sse_decode_opt_list_prim_u_8_strict(deserializer);
|
||||||
|
var var_signedPreKeyId = sse_decode_u_32(deserializer);
|
||||||
|
var var_signedPreKeyPublic = sse_decode_list_prim_u_8_strict(deserializer);
|
||||||
|
var var_signedPreKeySignature = sse_decode_list_prim_u_8_strict(
|
||||||
|
deserializer,
|
||||||
|
);
|
||||||
|
var var_kyberPreKeyId = sse_decode_u_32(deserializer);
|
||||||
|
var var_kyberPreKeyPublic = sse_decode_list_prim_u_8_strict(deserializer);
|
||||||
|
var var_kyberPreKeySignature = sse_decode_list_prim_u_8_strict(
|
||||||
|
deserializer,
|
||||||
|
);
|
||||||
|
var var_identityKey = sse_decode_list_prim_u_8_strict(deserializer);
|
||||||
|
return FrbPreKeyBundle(
|
||||||
|
registrationId: var_registrationId,
|
||||||
|
deviceId: var_deviceId,
|
||||||
|
preKeyId: var_preKeyId,
|
||||||
|
preKeyPublic: var_preKeyPublic,
|
||||||
|
signedPreKeyId: var_signedPreKeyId,
|
||||||
|
signedPreKeyPublic: var_signedPreKeyPublic,
|
||||||
|
signedPreKeySignature: var_signedPreKeySignature,
|
||||||
|
kyberPreKeyId: var_kyberPreKeyId,
|
||||||
|
kyberPreKeyPublic: var_kyberPreKeyPublic,
|
||||||
|
kyberPreKeySignature: var_kyberPreKeySignature,
|
||||||
|
identityKey: var_identityKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 sse_decode_i_64(SseDeserializer deserializer) {
|
PlatformInt64 sse_decode_i_64(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
@ -3411,6 +3748,20 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return deserializer.buffer.getPlatformInt64();
|
return deserializer.buffer.getPlatformInt64();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<FrbPqcPreKey> sse_decode_list_frb_pqc_pre_key(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
||||||
|
var len_ = sse_decode_i_32(deserializer);
|
||||||
|
var ans_ = <FrbPqcPreKey>[];
|
||||||
|
for (var idx_ = 0; idx_ < len_; ++idx_) {
|
||||||
|
ans_.add(sse_decode_frb_pqc_pre_key(deserializer));
|
||||||
|
}
|
||||||
|
return ans_;
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<Uint8List> sse_decode_list_list_prim_u_8_strict(
|
List<Uint8List> sse_decode_list_list_prim_u_8_strict(
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
|
|
@ -3503,6 +3854,17 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int? sse_decode_opt_box_autoadd_u_32(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
||||||
|
if (sse_decode_bool(deserializer)) {
|
||||||
|
return (sse_decode_box_autoadd_u_32(deserializer));
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<Uint8List>? sse_decode_opt_list_list_prim_u_8_strict(
|
List<Uint8List>? sse_decode_opt_list_list_prim_u_8_strict(
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
|
|
@ -3613,6 +3975,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return RustKeyManager();
|
return RustKeyManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
RustSignal sse_decode_rust_signal(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return RustSignal();
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
RustUtils sse_decode_rust_utils(SseDeserializer deserializer) {
|
RustUtils sse_decode_rust_utils(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
@ -3946,6 +4314,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
sse_encode_backup_password_keys(self, serializer);
|
sse_encode_backup_password_keys(self, serializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_box_autoadd_frb_pre_key_bundle(
|
||||||
|
FrbPreKeyBundle self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_frb_pre_key_bundle(self, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_box_autoadd_i_64(
|
void sse_encode_box_autoadd_i_64(
|
||||||
PlatformInt64 self,
|
PlatformInt64 self,
|
||||||
|
|
@ -3973,6 +4350,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
sse_encode_other_promotion(self, serializer);
|
sse_encode_other_promotion(self, serializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_box_autoadd_u_32(int self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_u_32(self, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_box_autoadd_user_discovery_store_flutter(
|
void sse_encode_box_autoadd_user_discovery_store_flutter(
|
||||||
UserDiscoveryStoreFlutter self,
|
UserDiscoveryStoreFlutter self,
|
||||||
|
|
@ -3999,6 +4382,35 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_frb_pqc_pre_key(FrbPqcPreKey self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_u_32(self.eccPreKeyId, serializer);
|
||||||
|
sse_encode_list_prim_u_8_strict(self.eccPreKey, serializer);
|
||||||
|
sse_encode_u_32(self.kyberPreKeyId, serializer);
|
||||||
|
sse_encode_list_prim_u_8_strict(self.kyberPreKey, serializer);
|
||||||
|
sse_encode_list_prim_u_8_strict(self.kyberPreKeySignature, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_frb_pre_key_bundle(
|
||||||
|
FrbPreKeyBundle self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_u_32(self.registrationId, serializer);
|
||||||
|
sse_encode_u_32(self.deviceId, serializer);
|
||||||
|
sse_encode_opt_box_autoadd_u_32(self.preKeyId, serializer);
|
||||||
|
sse_encode_opt_list_prim_u_8_strict(self.preKeyPublic, serializer);
|
||||||
|
sse_encode_u_32(self.signedPreKeyId, serializer);
|
||||||
|
sse_encode_list_prim_u_8_strict(self.signedPreKeyPublic, serializer);
|
||||||
|
sse_encode_list_prim_u_8_strict(self.signedPreKeySignature, serializer);
|
||||||
|
sse_encode_u_32(self.kyberPreKeyId, serializer);
|
||||||
|
sse_encode_list_prim_u_8_strict(self.kyberPreKeyPublic, serializer);
|
||||||
|
sse_encode_list_prim_u_8_strict(self.kyberPreKeySignature, serializer);
|
||||||
|
sse_encode_list_prim_u_8_strict(self.identityKey, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer) {
|
void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
@ -4018,6 +4430,18 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
serializer.buffer.putPlatformInt64(self);
|
serializer.buffer.putPlatformInt64(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_frb_pqc_pre_key(
|
||||||
|
List<FrbPqcPreKey> self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_i_32(self.length, serializer);
|
||||||
|
for (final item in self) {
|
||||||
|
sse_encode_frb_pqc_pre_key(item, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_list_list_prim_u_8_strict(
|
void sse_encode_list_list_prim_u_8_strict(
|
||||||
List<Uint8List> self,
|
List<Uint8List> self,
|
||||||
|
|
@ -4112,6 +4536,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_opt_box_autoadd_u_32(int? self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
||||||
|
sse_encode_bool(self != null, serializer);
|
||||||
|
if (self != null) {
|
||||||
|
sse_encode_box_autoadd_u_32(self, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_opt_list_list_prim_u_8_strict(
|
void sse_encode_opt_list_list_prim_u_8_strict(
|
||||||
List<Uint8List>? self,
|
List<Uint8List>? self,
|
||||||
|
|
@ -4222,6 +4656,11 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_rust_signal(RustSignal self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_rust_utils(RustUtils self, SseSerializer serializer) {
|
void sse_encode_rust_utils(RustUtils self, SseSerializer serializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import 'bridge/callbacks/user_discovery.dart';
|
||||||
import 'bridge/wrapper.dart';
|
import 'bridge/wrapper.dart';
|
||||||
import 'bridge/wrapper/backup.dart';
|
import 'bridge/wrapper/backup.dart';
|
||||||
import 'bridge/wrapper/key_manager.dart';
|
import 'bridge/wrapper/key_manager.dart';
|
||||||
|
import 'bridge/wrapper/signal.dart';
|
||||||
import 'bridge/wrapper/user_discovery.dart';
|
import 'bridge/wrapper/user_discovery.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
@ -17,6 +18,7 @@ import 'frb_generated.dart';
|
||||||
import 'keys/backup_password_keys.dart';
|
import 'keys/backup_password_keys.dart';
|
||||||
import 'lib.dart';
|
import 'lib.dart';
|
||||||
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart';
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart';
|
||||||
|
import 'signal/engine.dart';
|
||||||
|
|
||||||
abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
RustLibApiImplPlatform({
|
RustLibApiImplPlatform({
|
||||||
|
|
@ -130,6 +132,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
BackupPasswordKeys dco_decode_box_autoadd_backup_password_keys(dynamic raw);
|
BackupPasswordKeys dco_decode_box_autoadd_backup_password_keys(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPreKeyBundle dco_decode_box_autoadd_frb_pre_key_bundle(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw);
|
PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw);
|
||||||
|
|
||||||
|
|
@ -139,6 +144,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
OtherPromotion dco_decode_box_autoadd_other_promotion(dynamic raw);
|
OtherPromotion dco_decode_box_autoadd_other_promotion(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int dco_decode_box_autoadd_u_32(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
UserDiscoveryStoreFlutter dco_decode_box_autoadd_user_discovery_store_flutter(
|
UserDiscoveryStoreFlutter dco_decode_box_autoadd_user_discovery_store_flutter(
|
||||||
dynamic raw,
|
dynamic raw,
|
||||||
|
|
@ -152,6 +160,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
FlutterUserDiscovery dco_decode_flutter_user_discovery(dynamic raw);
|
FlutterUserDiscovery dco_decode_flutter_user_discovery(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPqcPreKey dco_decode_frb_pqc_pre_key(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPreKeyBundle dco_decode_frb_pre_key_bundle(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 dco_decode_i_64(dynamic raw);
|
PlatformInt64 dco_decode_i_64(dynamic raw);
|
||||||
|
|
||||||
|
|
@ -161,6 +175,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 dco_decode_isize(dynamic raw);
|
PlatformInt64 dco_decode_isize(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<FrbPqcPreKey> dco_decode_list_frb_pqc_pre_key(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<Uint8List> dco_decode_list_list_prim_u_8_strict(dynamic raw);
|
List<Uint8List> dco_decode_list_list_prim_u_8_strict(dynamic raw);
|
||||||
|
|
||||||
|
|
@ -186,6 +203,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw);
|
PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int? dco_decode_opt_box_autoadd_u_32(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<Uint8List>? dco_decode_opt_list_list_prim_u_8_strict(dynamic raw);
|
List<Uint8List>? dco_decode_opt_list_list_prim_u_8_strict(dynamic raw);
|
||||||
|
|
||||||
|
|
@ -220,6 +240,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
RustKeyManager dco_decode_rust_key_manager(dynamic raw);
|
RustKeyManager dco_decode_rust_key_manager(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
RustSignal dco_decode_rust_signal(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
RustUtils dco_decode_rust_utils(dynamic raw);
|
RustUtils dco_decode_rust_utils(dynamic raw);
|
||||||
|
|
||||||
|
|
@ -288,6 +311,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPreKeyBundle sse_decode_box_autoadd_frb_pre_key_bundle(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer);
|
PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
|
@ -299,6 +327,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int sse_decode_box_autoadd_u_32(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
UserDiscoveryStoreFlutter sse_decode_box_autoadd_user_discovery_store_flutter(
|
UserDiscoveryStoreFlutter sse_decode_box_autoadd_user_discovery_store_flutter(
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
|
|
@ -314,6 +345,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPqcPreKey sse_decode_frb_pqc_pre_key(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPreKeyBundle sse_decode_frb_pre_key_bundle(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 sse_decode_i_64(SseDeserializer deserializer);
|
PlatformInt64 sse_decode_i_64(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
|
@ -323,6 +360,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 sse_decode_isize(SseDeserializer deserializer);
|
PlatformInt64 sse_decode_isize(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<FrbPqcPreKey> sse_decode_list_frb_pqc_pre_key(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<Uint8List> sse_decode_list_list_prim_u_8_strict(
|
List<Uint8List> sse_decode_list_list_prim_u_8_strict(
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
|
|
@ -356,6 +398,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer);
|
PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int? sse_decode_opt_box_autoadd_u_32(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<Uint8List>? sse_decode_opt_list_list_prim_u_8_strict(
|
List<Uint8List>? sse_decode_opt_list_list_prim_u_8_strict(
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
|
|
@ -400,6 +445,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
RustKeyManager sse_decode_rust_key_manager(SseDeserializer deserializer);
|
RustKeyManager sse_decode_rust_key_manager(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
RustSignal sse_decode_rust_signal(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
RustUtils sse_decode_rust_utils(SseDeserializer deserializer);
|
RustUtils sse_decode_rust_utils(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
|
@ -561,6 +609,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseSerializer serializer,
|
SseSerializer serializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_box_autoadd_frb_pre_key_bundle(
|
||||||
|
FrbPreKeyBundle self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_box_autoadd_i_64(
|
void sse_encode_box_autoadd_i_64(
|
||||||
PlatformInt64 self,
|
PlatformInt64 self,
|
||||||
|
|
@ -579,6 +633,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseSerializer serializer,
|
SseSerializer serializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_box_autoadd_u_32(int self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_box_autoadd_user_discovery_store_flutter(
|
void sse_encode_box_autoadd_user_discovery_store_flutter(
|
||||||
UserDiscoveryStoreFlutter self,
|
UserDiscoveryStoreFlutter self,
|
||||||
|
|
@ -597,6 +654,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseSerializer serializer,
|
SseSerializer serializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_frb_pqc_pre_key(FrbPqcPreKey self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_frb_pre_key_bundle(
|
||||||
|
FrbPreKeyBundle self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer);
|
void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer);
|
||||||
|
|
||||||
|
|
@ -606,6 +672,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_isize(PlatformInt64 self, SseSerializer serializer);
|
void sse_encode_isize(PlatformInt64 self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_frb_pqc_pre_key(
|
||||||
|
List<FrbPqcPreKey> self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_list_list_prim_u_8_strict(
|
void sse_encode_list_list_prim_u_8_strict(
|
||||||
List<Uint8List> self,
|
List<Uint8List> self,
|
||||||
|
|
@ -648,6 +720,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseSerializer serializer,
|
SseSerializer serializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_opt_box_autoadd_u_32(int? self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_opt_list_list_prim_u_8_strict(
|
void sse_encode_opt_list_list_prim_u_8_strict(
|
||||||
List<Uint8List>? self,
|
List<Uint8List>? self,
|
||||||
|
|
@ -708,6 +783,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseSerializer serializer,
|
SseSerializer serializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_rust_signal(RustSignal self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_rust_utils(RustUtils self, SseSerializer serializer);
|
void sse_encode_rust_utils(RustUtils self, SseSerializer serializer);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import 'bridge/callbacks/user_discovery.dart';
|
||||||
import 'bridge/wrapper.dart';
|
import 'bridge/wrapper.dart';
|
||||||
import 'bridge/wrapper/backup.dart';
|
import 'bridge/wrapper/backup.dart';
|
||||||
import 'bridge/wrapper/key_manager.dart';
|
import 'bridge/wrapper/key_manager.dart';
|
||||||
|
import 'bridge/wrapper/signal.dart';
|
||||||
import 'bridge/wrapper/user_discovery.dart';
|
import 'bridge/wrapper/user_discovery.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
@ -19,6 +20,7 @@ import 'frb_generated.dart';
|
||||||
import 'keys/backup_password_keys.dart';
|
import 'keys/backup_password_keys.dart';
|
||||||
import 'lib.dart';
|
import 'lib.dart';
|
||||||
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart';
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart';
|
||||||
|
import 'signal/engine.dart';
|
||||||
|
|
||||||
abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
RustLibApiImplPlatform({
|
RustLibApiImplPlatform({
|
||||||
|
|
@ -132,6 +134,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
BackupPasswordKeys dco_decode_box_autoadd_backup_password_keys(dynamic raw);
|
BackupPasswordKeys dco_decode_box_autoadd_backup_password_keys(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPreKeyBundle dco_decode_box_autoadd_frb_pre_key_bundle(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw);
|
PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw);
|
||||||
|
|
||||||
|
|
@ -141,6 +146,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
OtherPromotion dco_decode_box_autoadd_other_promotion(dynamic raw);
|
OtherPromotion dco_decode_box_autoadd_other_promotion(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int dco_decode_box_autoadd_u_32(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
UserDiscoveryStoreFlutter dco_decode_box_autoadd_user_discovery_store_flutter(
|
UserDiscoveryStoreFlutter dco_decode_box_autoadd_user_discovery_store_flutter(
|
||||||
dynamic raw,
|
dynamic raw,
|
||||||
|
|
@ -154,6 +162,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
FlutterUserDiscovery dco_decode_flutter_user_discovery(dynamic raw);
|
FlutterUserDiscovery dco_decode_flutter_user_discovery(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPqcPreKey dco_decode_frb_pqc_pre_key(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPreKeyBundle dco_decode_frb_pre_key_bundle(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 dco_decode_i_64(dynamic raw);
|
PlatformInt64 dco_decode_i_64(dynamic raw);
|
||||||
|
|
||||||
|
|
@ -163,6 +177,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 dco_decode_isize(dynamic raw);
|
PlatformInt64 dco_decode_isize(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<FrbPqcPreKey> dco_decode_list_frb_pqc_pre_key(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<Uint8List> dco_decode_list_list_prim_u_8_strict(dynamic raw);
|
List<Uint8List> dco_decode_list_list_prim_u_8_strict(dynamic raw);
|
||||||
|
|
||||||
|
|
@ -188,6 +205,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw);
|
PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int? dco_decode_opt_box_autoadd_u_32(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<Uint8List>? dco_decode_opt_list_list_prim_u_8_strict(dynamic raw);
|
List<Uint8List>? dco_decode_opt_list_list_prim_u_8_strict(dynamic raw);
|
||||||
|
|
||||||
|
|
@ -222,6 +242,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
RustKeyManager dco_decode_rust_key_manager(dynamic raw);
|
RustKeyManager dco_decode_rust_key_manager(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
RustSignal dco_decode_rust_signal(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
RustUtils dco_decode_rust_utils(dynamic raw);
|
RustUtils dco_decode_rust_utils(dynamic raw);
|
||||||
|
|
||||||
|
|
@ -290,6 +313,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPreKeyBundle sse_decode_box_autoadd_frb_pre_key_bundle(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer);
|
PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
|
@ -301,6 +329,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int sse_decode_box_autoadd_u_32(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
UserDiscoveryStoreFlutter sse_decode_box_autoadd_user_discovery_store_flutter(
|
UserDiscoveryStoreFlutter sse_decode_box_autoadd_user_discovery_store_flutter(
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
|
|
@ -316,6 +347,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPqcPreKey sse_decode_frb_pqc_pre_key(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
FrbPreKeyBundle sse_decode_frb_pre_key_bundle(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 sse_decode_i_64(SseDeserializer deserializer);
|
PlatformInt64 sse_decode_i_64(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
|
@ -325,6 +362,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64 sse_decode_isize(SseDeserializer deserializer);
|
PlatformInt64 sse_decode_isize(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<FrbPqcPreKey> sse_decode_list_frb_pqc_pre_key(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<Uint8List> sse_decode_list_list_prim_u_8_strict(
|
List<Uint8List> sse_decode_list_list_prim_u_8_strict(
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
|
|
@ -358,6 +400,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer);
|
PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int? sse_decode_opt_box_autoadd_u_32(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<Uint8List>? sse_decode_opt_list_list_prim_u_8_strict(
|
List<Uint8List>? sse_decode_opt_list_list_prim_u_8_strict(
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
|
|
@ -402,6 +447,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
RustKeyManager sse_decode_rust_key_manager(SseDeserializer deserializer);
|
RustKeyManager sse_decode_rust_key_manager(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
RustSignal sse_decode_rust_signal(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
RustUtils sse_decode_rust_utils(SseDeserializer deserializer);
|
RustUtils sse_decode_rust_utils(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
|
@ -563,6 +611,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseSerializer serializer,
|
SseSerializer serializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_box_autoadd_frb_pre_key_bundle(
|
||||||
|
FrbPreKeyBundle self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_box_autoadd_i_64(
|
void sse_encode_box_autoadd_i_64(
|
||||||
PlatformInt64 self,
|
PlatformInt64 self,
|
||||||
|
|
@ -581,6 +635,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseSerializer serializer,
|
SseSerializer serializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_box_autoadd_u_32(int self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_box_autoadd_user_discovery_store_flutter(
|
void sse_encode_box_autoadd_user_discovery_store_flutter(
|
||||||
UserDiscoveryStoreFlutter self,
|
UserDiscoveryStoreFlutter self,
|
||||||
|
|
@ -599,6 +656,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseSerializer serializer,
|
SseSerializer serializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_frb_pqc_pre_key(FrbPqcPreKey self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_frb_pre_key_bundle(
|
||||||
|
FrbPreKeyBundle self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer);
|
void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer);
|
||||||
|
|
||||||
|
|
@ -608,6 +674,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_isize(PlatformInt64 self, SseSerializer serializer);
|
void sse_encode_isize(PlatformInt64 self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_frb_pqc_pre_key(
|
||||||
|
List<FrbPqcPreKey> self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_list_list_prim_u_8_strict(
|
void sse_encode_list_list_prim_u_8_strict(
|
||||||
List<Uint8List> self,
|
List<Uint8List> self,
|
||||||
|
|
@ -650,6 +722,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseSerializer serializer,
|
SseSerializer serializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_opt_box_autoadd_u_32(int? self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_opt_list_list_prim_u_8_strict(
|
void sse_encode_opt_list_list_prim_u_8_strict(
|
||||||
List<Uint8List>? self,
|
List<Uint8List>? self,
|
||||||
|
|
@ -710,6 +785,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
SseSerializer serializer,
|
SseSerializer serializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_rust_signal(RustSignal self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_rust_utils(RustUtils self, SseSerializer serializer);
|
void sse_encode_rust_utils(RustUtils self, SseSerializer serializer);
|
||||||
|
|
||||||
|
|
|
||||||
101
lib/core/signal/engine.dart
Normal file
101
lib/core/signal/engine.dart
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
// This file is automatically generated, so please do not edit it.
|
||||||
|
// @generated by `flutter_rust_bridge`@ 2.12.0.
|
||||||
|
|
||||||
|
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
|
||||||
|
|
||||||
|
import '../frb_generated.dart';
|
||||||
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
||||||
|
|
||||||
|
class FrbPqcPreKey {
|
||||||
|
final int eccPreKeyId;
|
||||||
|
final Uint8List eccPreKey;
|
||||||
|
final int kyberPreKeyId;
|
||||||
|
final Uint8List kyberPreKey;
|
||||||
|
final Uint8List kyberPreKeySignature;
|
||||||
|
|
||||||
|
const FrbPqcPreKey({
|
||||||
|
required this.eccPreKeyId,
|
||||||
|
required this.eccPreKey,
|
||||||
|
required this.kyberPreKeyId,
|
||||||
|
required this.kyberPreKey,
|
||||||
|
required this.kyberPreKeySignature,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
eccPreKeyId.hashCode ^
|
||||||
|
eccPreKey.hashCode ^
|
||||||
|
kyberPreKeyId.hashCode ^
|
||||||
|
kyberPreKey.hashCode ^
|
||||||
|
kyberPreKeySignature.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is FrbPqcPreKey &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
eccPreKeyId == other.eccPreKeyId &&
|
||||||
|
eccPreKey == other.eccPreKey &&
|
||||||
|
kyberPreKeyId == other.kyberPreKeyId &&
|
||||||
|
kyberPreKey == other.kyberPreKey &&
|
||||||
|
kyberPreKeySignature == other.kyberPreKeySignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FrbPreKeyBundle {
|
||||||
|
final int registrationId;
|
||||||
|
final int deviceId;
|
||||||
|
final int? preKeyId;
|
||||||
|
final Uint8List? preKeyPublic;
|
||||||
|
final int signedPreKeyId;
|
||||||
|
final Uint8List signedPreKeyPublic;
|
||||||
|
final Uint8List signedPreKeySignature;
|
||||||
|
final int kyberPreKeyId;
|
||||||
|
final Uint8List kyberPreKeyPublic;
|
||||||
|
final Uint8List kyberPreKeySignature;
|
||||||
|
final Uint8List identityKey;
|
||||||
|
|
||||||
|
const FrbPreKeyBundle({
|
||||||
|
required this.registrationId,
|
||||||
|
required this.deviceId,
|
||||||
|
this.preKeyId,
|
||||||
|
this.preKeyPublic,
|
||||||
|
required this.signedPreKeyId,
|
||||||
|
required this.signedPreKeyPublic,
|
||||||
|
required this.signedPreKeySignature,
|
||||||
|
required this.kyberPreKeyId,
|
||||||
|
required this.kyberPreKeyPublic,
|
||||||
|
required this.kyberPreKeySignature,
|
||||||
|
required this.identityKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
registrationId.hashCode ^
|
||||||
|
deviceId.hashCode ^
|
||||||
|
preKeyId.hashCode ^
|
||||||
|
preKeyPublic.hashCode ^
|
||||||
|
signedPreKeyId.hashCode ^
|
||||||
|
signedPreKeyPublic.hashCode ^
|
||||||
|
signedPreKeySignature.hashCode ^
|
||||||
|
kyberPreKeyId.hashCode ^
|
||||||
|
kyberPreKeyPublic.hashCode ^
|
||||||
|
kyberPreKeySignature.hashCode ^
|
||||||
|
identityKey.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is FrbPreKeyBundle &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
registrationId == other.registrationId &&
|
||||||
|
deviceId == other.deviceId &&
|
||||||
|
preKeyId == other.preKeyId &&
|
||||||
|
preKeyPublic == other.preKeyPublic &&
|
||||||
|
signedPreKeyId == other.signedPreKeyId &&
|
||||||
|
signedPreKeyPublic == other.signedPreKeyPublic &&
|
||||||
|
signedPreKeySignature == other.signedPreKeySignature &&
|
||||||
|
kyberPreKeyId == other.kyberPreKeyId &&
|
||||||
|
kyberPreKeyPublic == other.kyberPreKeyPublic &&
|
||||||
|
kyberPreKeySignature == other.kyberPreKeySignature &&
|
||||||
|
identityKey == other.identityKey;
|
||||||
|
}
|
||||||
|
|
@ -175,13 +175,15 @@ Future<void> postStartupTasks() async {
|
||||||
// 2. Service initializations
|
// 2. Service initializations
|
||||||
unawaited(finishStartedPreprocessing());
|
unawaited(finishStartedPreprocessing());
|
||||||
unawaited(createPushAvatars());
|
unawaited(createPushAvatars());
|
||||||
unawaited(newsService.init().then((_) {
|
unawaited(
|
||||||
|
newsService.init().then((_) {
|
||||||
final lastDownload = newsService.lastDownloadedAt;
|
final lastDownload = newsService.lastDownloadedAt;
|
||||||
if (lastDownload == null ||
|
if (lastDownload == null ||
|
||||||
DateTime.now().difference(lastDownload) >= const Duration(days: 7)) {
|
DateTime.now().difference(lastDownload) >= const Duration(days: 7)) {
|
||||||
newsService.fetchFeed();
|
newsService.fetchFeed();
|
||||||
}
|
}
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
unawaited(UserDiscoveryService.verifyInitializationOnStartup());
|
unawaited(UserDiscoveryService.verifyInitializationOnStartup());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,7 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)..where(groups.isDirectChat.equals(false)));
|
)..where(groups.isDirectChat.equals(false)));
|
||||||
return query.map((row) => row.readTable(groupMembers)).get();
|
return await query.map((row) => row.readTable(groupMembers)).get();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error(e);
|
Log.error(e);
|
||||||
return [];
|
return [];
|
||||||
|
|
@ -340,6 +340,25 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
|
||||||
.write(GroupsCompanion(lastMessageExchange: Value(clampedLastMessage)));
|
.write(GroupsCompanion(lastMessageExchange: Value(clampedLastMessage)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> increaseMemberLastMessage(
|
||||||
|
String groupId,
|
||||||
|
int contactId,
|
||||||
|
DateTime newLastMessage,
|
||||||
|
) async {
|
||||||
|
final now = clock.now();
|
||||||
|
final clampedLastMessage = newLastMessage.isAfter(now)
|
||||||
|
? now
|
||||||
|
: newLastMessage;
|
||||||
|
await (update(groupMembers)..where(
|
||||||
|
(t) =>
|
||||||
|
t.groupId.equals(groupId) &
|
||||||
|
t.contactId.equals(contactId) &
|
||||||
|
(t.lastMessage.isNull() |
|
||||||
|
t.lastMessage.isSmallerThanValue(clampedLastMessage)),
|
||||||
|
))
|
||||||
|
.write(GroupMembersCompanion(lastMessage: Value(clampedLastMessage)));
|
||||||
|
}
|
||||||
|
|
||||||
Stream<List<Group>> watchNonDirectGroupsForMember(int contactId) {
|
Stream<List<Group>> watchNonDirectGroupsForMember(int contactId) {
|
||||||
final query =
|
final query =
|
||||||
select(groups).join([
|
select(groups).join([
|
||||||
|
|
|
||||||
91
lib/src/database/daos/labels.dao.dart
Normal file
91
lib/src/database/daos/labels.dao.dart
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:twonly/src/database/tables/labels.table.dart';
|
||||||
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
|
||||||
|
part 'labels.dao.g.dart';
|
||||||
|
|
||||||
|
@DriftAccessor(
|
||||||
|
tables: [
|
||||||
|
Labels,
|
||||||
|
ContactLabels,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class LabelsDao extends DatabaseAccessor<TwonlyDB> with _$LabelsDaoMixin {
|
||||||
|
LabelsDao(super.db);
|
||||||
|
|
||||||
|
Stream<List<Label>> watchAllLabels() {
|
||||||
|
return (select(labels)..orderBy([(t) => OrderingTerm(expression: t.name)])).watch();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Label>> getAllLabels() {
|
||||||
|
return (select(labels)..orderBy([(t) => OrderingTerm(expression: t.name)])).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<List<Label>> watchContactLabels(int contactId) {
|
||||||
|
final query = select(contactLabels).join([
|
||||||
|
innerJoin(labels, labels.id.equalsExp(contactLabels.labelId)),
|
||||||
|
])..where(contactLabels.contactId.equals(contactId));
|
||||||
|
|
||||||
|
return query.watch().map(
|
||||||
|
(rows) => rows.map((row) => row.readTable(labels)).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Label>> getContactLabels(int contactId) {
|
||||||
|
final query = select(contactLabels).join([
|
||||||
|
innerJoin(labels, labels.id.equalsExp(contactLabels.labelId)),
|
||||||
|
])..where(contactLabels.contactId.equals(contactId));
|
||||||
|
|
||||||
|
return query.get().then(
|
||||||
|
(rows) => rows.map((row) => row.readTable(labels)).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setContactLabels(int contactId, List<int> labelIds) async {
|
||||||
|
final sanitizedLabelIds = labelIds.take(3).toList();
|
||||||
|
await transaction(() async {
|
||||||
|
await (delete(contactLabels)..where((t) => t.contactId.equals(contactId))).go();
|
||||||
|
if (sanitizedLabelIds.isNotEmpty) {
|
||||||
|
await batch((b) {
|
||||||
|
b.insertAll(
|
||||||
|
contactLabels,
|
||||||
|
sanitizedLabelIds.map(
|
||||||
|
(lId) => ContactLabelsCompanion.insert(
|
||||||
|
contactId: contactId,
|
||||||
|
labelId: lId,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> createLabel(String name, int textColor, int backgroundColor) {
|
||||||
|
final sanitizedName = name.length > 8 ? name.substring(0, 8) : name;
|
||||||
|
return into(labels).insert(
|
||||||
|
LabelsCompanion.insert(
|
||||||
|
name: sanitizedName,
|
||||||
|
textColor: textColor,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> updateLabel(int id, String name, int textColor, int backgroundColor) {
|
||||||
|
final sanitizedName = name.length > 8 ? name.substring(0, 8) : name;
|
||||||
|
return (update(labels)..where((t) => t.id.equals(id)))
|
||||||
|
.write(
|
||||||
|
LabelsCompanion(
|
||||||
|
name: Value(sanitizedName),
|
||||||
|
textColor: Value(textColor),
|
||||||
|
backgroundColor: Value(backgroundColor),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.then((rows) => rows > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> deleteLabel(int id) {
|
||||||
|
return (delete(labels)..where((t) => t.id.equals(id))).go();
|
||||||
|
}
|
||||||
|
}
|
||||||
22
lib/src/database/daos/labels.dao.g.dart
Normal file
22
lib/src/database/daos/labels.dao.g.dart
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'labels.dao.dart';
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
mixin _$LabelsDaoMixin on DatabaseAccessor<TwonlyDB> {
|
||||||
|
$LabelsTable get labels => attachedDatabase.labels;
|
||||||
|
$ContactsTable get contacts => attachedDatabase.contacts;
|
||||||
|
$ContactLabelsTable get contactLabels => attachedDatabase.contactLabels;
|
||||||
|
LabelsDaoManager get managers => LabelsDaoManager(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class LabelsDaoManager {
|
||||||
|
final _$LabelsDaoMixin _db;
|
||||||
|
LabelsDaoManager(this._db);
|
||||||
|
$$LabelsTableTableManager get labels =>
|
||||||
|
$$LabelsTableTableManager(_db.attachedDatabase, _db.labels);
|
||||||
|
$$ContactsTableTableManager get contacts =>
|
||||||
|
$$ContactsTableTableManager(_db.attachedDatabase, _db.contacts);
|
||||||
|
$$ContactLabelsTableTableManager get contactLabels =>
|
||||||
|
$$ContactLabelsTableTableManager(_db.attachedDatabase, _db.contactLabels);
|
||||||
|
}
|
||||||
|
|
@ -489,22 +489,28 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
|
||||||
|
|
||||||
await into(messages).insertOnConflictUpdate(insertMessage);
|
await into(messages).insertOnConflictUpdate(insertMessage);
|
||||||
|
|
||||||
|
final msgTime = insertMessage.createdAt.present
|
||||||
|
? insertMessage.createdAt.value
|
||||||
|
: clock.now();
|
||||||
|
|
||||||
await twonlyDB.groupsDao.updateGroup(
|
await twonlyDB.groupsDao.updateGroup(
|
||||||
message.groupId.value,
|
message.groupId.value,
|
||||||
GroupsCompanion(
|
const GroupsCompanion(
|
||||||
lastMessageExchange: Value(clock.now()),
|
archived: Value(false),
|
||||||
archived: const Value(false),
|
deletedContent: Value(false),
|
||||||
deletedContent: const Value(false),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (message.senderId.present) {
|
await twonlyDB.groupsDao.increaseLastMessageExchange(
|
||||||
await twonlyDB.groupsDao.updateMember(
|
message.groupId.value,
|
||||||
|
msgTime,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (message.senderId.present && message.senderId.value != null) {
|
||||||
|
await twonlyDB.groupsDao.increaseMemberLastMessage(
|
||||||
message.groupId.value,
|
message.groupId.value,
|
||||||
message.senderId.value!,
|
message.senderId.value!,
|
||||||
GroupMembersCompanion(
|
msgTime,
|
||||||
lastMessage: Value(clock.now()),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ class ReceiptsDao extends DatabaseAccessor<TwonlyDB> with _$ReceiptsDaoMixin {
|
||||||
await (delete(receivedReceipts)..where(
|
await (delete(receivedReceipts)..where(
|
||||||
(t) => (t.createdAt.isSmallerThanValue(
|
(t) => (t.createdAt.isSmallerThanValue(
|
||||||
clock.now().subtract(
|
clock.now().subtract(
|
||||||
const Duration(days: 25),
|
const Duration(days: 45),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
))
|
))
|
||||||
|
|
@ -250,6 +250,25 @@ class ReceiptsDao extends DatabaseAccessor<TwonlyDB> with _$ReceiptsDaoMixin {
|
||||||
null;
|
null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Claims a new delivery-receipt attempt after [cooldown] has elapsed.
|
||||||
|
///
|
||||||
|
/// Updating the timestamp before sending prevents repeated server batches from
|
||||||
|
/// starting multiple delivery-receipt attempts during the same cooldown.
|
||||||
|
Future<bool> claimDuplicateReceiptResend(
|
||||||
|
String receiptId,
|
||||||
|
Duration cooldown,
|
||||||
|
) async {
|
||||||
|
final now = clock.now();
|
||||||
|
final updated =
|
||||||
|
await (update(receivedReceipts)..where(
|
||||||
|
(t) =>
|
||||||
|
t.receiptId.equals(receiptId) &
|
||||||
|
t.createdAt.isSmallerOrEqualValue(now.subtract(cooldown)),
|
||||||
|
))
|
||||||
|
.write(ReceivedReceiptsCompanion(createdAt: Value(now)));
|
||||||
|
return updated > 0;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> gotReceipt(String receiptId) async {
|
Future<void> gotReceipt(String receiptId) async {
|
||||||
await into(
|
await into(
|
||||||
receivedReceipts,
|
receivedReceipts,
|
||||||
|
|
|
||||||
3322
lib/src/database/schemas/twonly_db/drift_schema_v24.json
Normal file
3322
lib/src/database/schemas/twonly_db/drift_schema_v24.json
Normal file
File diff suppressed because it is too large
Load diff
3091
lib/src/database/schemas/twonly_db/drift_schema_v25.json
Normal file
3091
lib/src/database/schemas/twonly_db/drift_schema_v25.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -63,6 +63,7 @@ class SignalSignedPreKeyStore extends SignedPreKeyStore {
|
||||||
.insert(companion, mode: InsertMode.insertOrReplace);
|
.insert(companion, mode: InsertMode.insertOrReplace);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error('$e');
|
Log.error('$e');
|
||||||
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
|
|
||||||
|
|
||||||
|
enum SignalVersion { v1, v2 }
|
||||||
|
|
||||||
@DataClassName('Contact')
|
@DataClassName('Contact')
|
||||||
class Contacts extends Table {
|
class Contacts extends Table {
|
||||||
IntColumn get userId => integer()();
|
IntColumn get userId => integer()();
|
||||||
|
|
@ -23,6 +26,9 @@ class Contacts extends Table {
|
||||||
|
|
||||||
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||||
|
|
||||||
|
TextColumn get signalVersion =>
|
||||||
|
textEnum<SignalVersion>().withDefault(const Constant('v1'))();
|
||||||
|
|
||||||
// User Discovery
|
// User Discovery
|
||||||
BlobColumn get userDiscoveryVersion => blob().nullable()();
|
BlobColumn get userDiscoveryVersion => blob().nullable()();
|
||||||
BoolColumn get userDiscoveryExcluded =>
|
BoolColumn get userDiscoveryExcluded =>
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ class Groups extends Table {
|
||||||
boolean().withDefault(const Constant(false))();
|
boolean().withDefault(const Constant(false))();
|
||||||
|
|
||||||
IntColumn get deleteMessagesAfterMilliseconds => integer().withDefault(
|
IntColumn get deleteMessagesAfterMilliseconds => integer().withDefault(
|
||||||
const Constant(defaultDeleteMessagesAfterMilliseconds),
|
const Constant(1000 * 60 * 60 * 24),
|
||||||
)();
|
)();
|
||||||
|
|
||||||
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||||
|
|
|
||||||
28
lib/src/database/tables/labels.table.dart
Normal file
28
lib/src/database/tables/labels.table.dart
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:twonly/src/database/tables/contacts.table.dart';
|
||||||
|
|
||||||
|
@DataClassName('Label')
|
||||||
|
class Labels extends Table {
|
||||||
|
IntColumn get id => integer().autoIncrement()();
|
||||||
|
TextColumn get name => text()();
|
||||||
|
IntColumn get textColor => integer()();
|
||||||
|
IntColumn get backgroundColor => integer()();
|
||||||
|
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DataClassName('ContactLabel')
|
||||||
|
class ContactLabels extends Table {
|
||||||
|
IntColumn get contactId => integer().references(
|
||||||
|
Contacts,
|
||||||
|
#userId,
|
||||||
|
onDelete: KeyAction.cascade,
|
||||||
|
)();
|
||||||
|
IntColumn get labelId => integer().references(
|
||||||
|
Labels,
|
||||||
|
#id,
|
||||||
|
onDelete: KeyAction.cascade,
|
||||||
|
)();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<Column> get primaryKey => {contactId, labelId};
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||||
enum MessageType { media, text, contacts, restoreFlameCounter, askAboutUser }
|
enum MessageType { media, text, contacts, restoreFlameCounter, askAboutUser }
|
||||||
|
|
||||||
@DataClassName('Message')
|
@DataClassName('Message')
|
||||||
|
@TableIndex(name: 'idx_messages_group_id_created_at', columns: {#groupId, #createdAt})
|
||||||
class Messages extends Table {
|
class Messages extends Table {
|
||||||
TextColumn get groupId =>
|
TextColumn get groupId =>
|
||||||
text().references(Groups, #groupId, onDelete: KeyAction.cascade)();
|
text().references(Groups, #groupId, onDelete: KeyAction.cascade)();
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import 'package:twonly/src/database/tables/contacts.table.dart';
|
||||||
import 'package:twonly/src/database/tables/messages.table.dart';
|
import 'package:twonly/src/database/tables/messages.table.dart';
|
||||||
|
|
||||||
@DataClassName('Receipt')
|
@DataClassName('Receipt')
|
||||||
|
@TableIndex(name: 'idx_receipts_message_id', columns: {#messageId})
|
||||||
class Receipts extends Table {
|
class Receipts extends Table {
|
||||||
TextColumn get receiptId => text()();
|
TextColumn get receiptId => text()();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/database/daos/groups.dao.dart';
|
import 'package:twonly/src/database/daos/groups.dao.dart';
|
||||||
import 'package:twonly/src/database/daos/key_verification.dao.dart';
|
import 'package:twonly/src/database/daos/key_verification.dao.dart';
|
||||||
|
import 'package:twonly/src/database/daos/labels.dao.dart';
|
||||||
import 'package:twonly/src/database/daos/mediafiles.dao.dart';
|
import 'package:twonly/src/database/daos/mediafiles.dao.dart';
|
||||||
import 'package:twonly/src/database/daos/messages.dao.dart';
|
import 'package:twonly/src/database/daos/messages.dao.dart';
|
||||||
import 'package:twonly/src/database/daos/reactions.dao.dart';
|
import 'package:twonly/src/database/daos/reactions.dao.dart';
|
||||||
|
|
@ -15,6 +16,7 @@ import 'package:twonly/src/database/daos/user_discovery.dao.dart';
|
||||||
import 'package:twonly/src/database/drift_logging_interceptor.dart';
|
import 'package:twonly/src/database/drift_logging_interceptor.dart';
|
||||||
import 'package:twonly/src/database/tables/contacts.table.dart';
|
import 'package:twonly/src/database/tables/contacts.table.dart';
|
||||||
import 'package:twonly/src/database/tables/groups.table.dart';
|
import 'package:twonly/src/database/tables/groups.table.dart';
|
||||||
|
import 'package:twonly/src/database/tables/labels.table.dart';
|
||||||
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||||
import 'package:twonly/src/database/tables/messages.table.dart';
|
import 'package:twonly/src/database/tables/messages.table.dart';
|
||||||
import 'package:twonly/src/database/tables/reactions.table.dart';
|
import 'package:twonly/src/database/tables/reactions.table.dart';
|
||||||
|
|
@ -59,6 +61,8 @@ part 'twonly.db.g.dart';
|
||||||
UserDiscoveryShares,
|
UserDiscoveryShares,
|
||||||
Shortcuts,
|
Shortcuts,
|
||||||
ShortcutMembers,
|
ShortcutMembers,
|
||||||
|
Labels,
|
||||||
|
ContactLabels,
|
||||||
],
|
],
|
||||||
daos: [
|
daos: [
|
||||||
MessagesDao,
|
MessagesDao,
|
||||||
|
|
@ -70,6 +74,7 @@ part 'twonly.db.g.dart';
|
||||||
UserDiscoveryDao,
|
UserDiscoveryDao,
|
||||||
KeyVerificationDao,
|
KeyVerificationDao,
|
||||||
ShortcutsDao,
|
ShortcutsDao,
|
||||||
|
LabelsDao,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
class TwonlyDB extends _$TwonlyDB {
|
class TwonlyDB extends _$TwonlyDB {
|
||||||
|
|
@ -82,7 +87,7 @@ class TwonlyDB extends _$TwonlyDB {
|
||||||
TwonlyDB.forTesting(DatabaseConnection super.connection);
|
TwonlyDB.forTesting(DatabaseConnection super.connection);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 23;
|
int get schemaVersion => 25;
|
||||||
|
|
||||||
static QueryExecutor _openConnection() {
|
static QueryExecutor _openConnection() {
|
||||||
final connection = driftDatabase(
|
final connection = driftDatabase(
|
||||||
|
|
@ -285,6 +290,13 @@ class TwonlyDB extends _$TwonlyDB {
|
||||||
schema.mediaFiles.blurhash,
|
schema.mediaFiles.blurhash,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
from23To24: (m, schema) async {
|
||||||
|
await m.createTable(schema.labels);
|
||||||
|
await m.createTable(schema.contactLabels);
|
||||||
|
},
|
||||||
|
from24To25: (m, schema) async {
|
||||||
|
await m.addColumn(schema.contacts, schema.contacts.signalVersion);
|
||||||
|
},
|
||||||
)(m, from, to);
|
)(m, from, to);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1424,6 +1424,12 @@ abstract class AppLocalizations {
|
||||||
/// **'Delete for me'**
|
/// **'Delete for me'**
|
||||||
String get deleteOkBtnForMe;
|
String get deleteOkBtnForMe;
|
||||||
|
|
||||||
|
/// No description provided for @deleteOnlyForMe.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Delete only for me'**
|
||||||
|
String get deleteOnlyForMe;
|
||||||
|
|
||||||
/// No description provided for @deleteImageTitle.
|
/// No description provided for @deleteImageTitle.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -1541,7 +1547,7 @@ abstract class AppLocalizations {
|
||||||
/// No description provided for @backupArchiveHeader.
|
/// No description provided for @backupArchiveHeader.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Contacts, Settings and Messages'**
|
/// **'Contacts & Messages'**
|
||||||
String get backupArchiveHeader;
|
String get backupArchiveHeader;
|
||||||
|
|
||||||
/// No description provided for @backupLastBackupDate.
|
/// No description provided for @backupLastBackupDate.
|
||||||
|
|
@ -1595,7 +1601,7 @@ abstract class AppLocalizations {
|
||||||
/// No description provided for @backupSelectStrongPassword.
|
/// No description provided for @backupSelectStrongPassword.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Choose a secure password. This is required if you want to restore your twonly Backup.'**
|
/// **'Select a secure password. It is recommended to generate and store it via your password manager of choice.'**
|
||||||
String get backupSelectStrongPassword;
|
String get backupSelectStrongPassword;
|
||||||
|
|
||||||
/// No description provided for @password.
|
/// No description provided for @password.
|
||||||
|
|
@ -1625,7 +1631,7 @@ abstract class AppLocalizations {
|
||||||
/// No description provided for @backupEnableBackup.
|
/// No description provided for @backupEnableBackup.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Activate automatic backup'**
|
/// **'Enable Password Backup'**
|
||||||
String get backupEnableBackup;
|
String get backupEnableBackup;
|
||||||
|
|
||||||
/// No description provided for @backupTwonlySaveNow.
|
/// No description provided for @backupTwonlySaveNow.
|
||||||
|
|
@ -1652,6 +1658,36 @@ abstract class AppLocalizations {
|
||||||
/// **'You can only change your password after you have authenticated!'**
|
/// **'You can only change your password after you have authenticated!'**
|
||||||
String get backupChangePasswordAuthFailed;
|
String get backupChangePasswordAuthFailed;
|
||||||
|
|
||||||
|
/// No description provided for @backupFreeSpaceWithCloud.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Free Space with Cloud Backup'**
|
||||||
|
String get backupFreeSpaceWithCloud;
|
||||||
|
|
||||||
|
/// No description provided for @backupMemoriesNotEnabled.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Not enabled'**
|
||||||
|
String get backupMemoriesNotEnabled;
|
||||||
|
|
||||||
|
/// No description provided for @backupMemoriesUpgradeRequired.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Upgrade required'**
|
||||||
|
String get backupMemoriesUpgradeRequired;
|
||||||
|
|
||||||
|
/// No description provided for @todayAt.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Today at {time}'**
|
||||||
|
String todayAt(Object time);
|
||||||
|
|
||||||
|
/// No description provided for @yesterdayAt.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Yesterday at {time}'**
|
||||||
|
String yesterdayAt(Object time);
|
||||||
|
|
||||||
/// No description provided for @twonlySafeRecoverTitle.
|
/// No description provided for @twonlySafeRecoverTitle.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -3404,6 +3440,12 @@ abstract class AppLocalizations {
|
||||||
/// **'Zero ads. Total privacy.'**
|
/// **'Zero ads. Total privacy.'**
|
||||||
String get subscriptionPledgeSubtitle;
|
String get subscriptionPledgeSubtitle;
|
||||||
|
|
||||||
|
/// No description provided for @subscriptionManage.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Manage subscription'**
|
||||||
|
String get subscriptionManage;
|
||||||
|
|
||||||
/// No description provided for @dragToZoom.
|
/// No description provided for @dragToZoom.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -3671,7 +3713,7 @@ abstract class AppLocalizations {
|
||||||
/// No description provided for @passwordlessRecovery.
|
/// No description provided for @passwordlessRecovery.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Passwordless Recovery'**
|
/// **'Trusted Friends'**
|
||||||
String get passwordlessRecovery;
|
String get passwordlessRecovery;
|
||||||
|
|
||||||
/// No description provided for @passwordlessRecoveryNotConfigured.
|
/// No description provided for @passwordlessRecoveryNotConfigured.
|
||||||
|
|
@ -3791,7 +3833,7 @@ abstract class AppLocalizations {
|
||||||
/// No description provided for @passwordlessRecoveryEnableSuccess.
|
/// No description provided for @passwordlessRecoveryEnableSuccess.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Passwordless recovery successfully enabled!'**
|
/// **'Trusted Friends successfully set up!'**
|
||||||
String get passwordlessRecoveryEnableSuccess;
|
String get passwordlessRecoveryEnableSuccess;
|
||||||
|
|
||||||
/// No description provided for @passwordlessRecoveryEnterPin.
|
/// No description provided for @passwordlessRecoveryEnterPin.
|
||||||
|
|
@ -3809,19 +3851,19 @@ abstract class AppLocalizations {
|
||||||
/// No description provided for @passwordlessRecoveryEnableBtn.
|
/// No description provided for @passwordlessRecoveryEnableBtn.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Enable Passwordless Recovery'**
|
/// **'Enable Trusted Friends'**
|
||||||
String get passwordlessRecoveryEnableBtn;
|
String get passwordlessRecoveryEnableBtn;
|
||||||
|
|
||||||
/// No description provided for @passwordlessRecoveryRecoverBtn.
|
/// No description provided for @passwordlessRecoveryRecoverBtn.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Recover passwordless'**
|
/// **'Recover via Trusted Friends'**
|
||||||
String get passwordlessRecoveryRecoverBtn;
|
String get passwordlessRecoveryRecoverBtn;
|
||||||
|
|
||||||
/// No description provided for @passwordlessRecoveryModifyBtn.
|
/// No description provided for @passwordlessRecoveryModifyBtn.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Modify Passwordless Recovery'**
|
/// **'Modify Trusted Friends'**
|
||||||
String get passwordlessRecoveryModifyBtn;
|
String get passwordlessRecoveryModifyBtn;
|
||||||
|
|
||||||
/// No description provided for @passwordlessRecoveryStatusEnabled.
|
/// No description provided for @passwordlessRecoveryStatusEnabled.
|
||||||
|
|
@ -3917,7 +3959,7 @@ abstract class AppLocalizations {
|
||||||
/// No description provided for @passwordlessRecoveryTrustedFriends.
|
/// No description provided for @passwordlessRecoveryTrustedFriends.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Trusted Friends'**
|
/// **'Account recovery'**
|
||||||
String get passwordlessRecoveryTrustedFriends;
|
String get passwordlessRecoveryTrustedFriends;
|
||||||
|
|
||||||
/// No description provided for @passwordlessRecoveryDoneBtn.
|
/// No description provided for @passwordlessRecoveryDoneBtn.
|
||||||
|
|
@ -4097,7 +4139,7 @@ abstract class AppLocalizations {
|
||||||
/// No description provided for @missingRecoveryContactsCardTitle.
|
/// No description provided for @missingRecoveryContactsCardTitle.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Recovery Contacts'**
|
/// **'Account Recovery'**
|
||||||
String get missingRecoveryContactsCardTitle;
|
String get missingRecoveryContactsCardTitle;
|
||||||
|
|
||||||
/// No description provided for @missingRecoveryContactsCardDesc.
|
/// No description provided for @missingRecoveryContactsCardDesc.
|
||||||
|
|
@ -4193,7 +4235,7 @@ abstract class AppLocalizations {
|
||||||
/// No description provided for @settingsStorageContents.
|
/// No description provided for @settingsStorageContents.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Storage contents'**
|
/// **'Free up space'**
|
||||||
String get settingsStorageContents;
|
String get settingsStorageContents;
|
||||||
|
|
||||||
/// No description provided for @settingsStorageSortStorage.
|
/// No description provided for @settingsStorageSortStorage.
|
||||||
|
|
@ -4273,6 +4315,228 @@ abstract class AppLocalizations {
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'All memories are up to date.'**
|
/// **'All memories are up to date.'**
|
||||||
String get settingsStorageSyncUpToDate;
|
String get settingsStorageSyncUpToDate;
|
||||||
|
|
||||||
|
/// No description provided for @restoreLostFlames.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Restore your {count} lost flames'**
|
||||||
|
String restoreLostFlames(int count);
|
||||||
|
|
||||||
|
/// No description provided for @settingsShowRestoreFlameTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Show flame restore warning'**
|
||||||
|
String get settingsShowRestoreFlameTitle;
|
||||||
|
|
||||||
|
/// No description provided for @contactLabelsTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Contact Labels'**
|
||||||
|
String get contactLabelsTitle;
|
||||||
|
|
||||||
|
/// No description provided for @contactLabelsSubtitleEmpty.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No labels selected'**
|
||||||
|
String get contactLabelsSubtitleEmpty;
|
||||||
|
|
||||||
|
/// No description provided for @contactLabelsMaxLimit.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Maximum 3 labels per contact'**
|
||||||
|
String get contactLabelsMaxLimit;
|
||||||
|
|
||||||
|
/// No description provided for @createLabel.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Create new label'**
|
||||||
|
String get createLabel;
|
||||||
|
|
||||||
|
/// No description provided for @editLabel.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Edit label'**
|
||||||
|
String get editLabel;
|
||||||
|
|
||||||
|
/// No description provided for @deleteLabel.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Delete label'**
|
||||||
|
String get deleteLabel;
|
||||||
|
|
||||||
|
/// No description provided for @deleteLabelConfirmation.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Are you sure you want to delete this label? It will be removed from all contacts.'**
|
||||||
|
String get deleteLabelConfirmation;
|
||||||
|
|
||||||
|
/// No description provided for @labelNameHint.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Label name'**
|
||||||
|
String get labelNameHint;
|
||||||
|
|
||||||
|
/// No description provided for @labelTextColor.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Text color'**
|
||||||
|
String get labelTextColor;
|
||||||
|
|
||||||
|
/// No description provided for @labelBackgroundColor.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Background color'**
|
||||||
|
String get labelBackgroundColor;
|
||||||
|
|
||||||
|
/// No description provided for @customColor.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Custom Color'**
|
||||||
|
String get customColor;
|
||||||
|
|
||||||
|
/// No description provided for @hue.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Hue'**
|
||||||
|
String get hue;
|
||||||
|
|
||||||
|
/// No description provided for @saturation.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Saturation'**
|
||||||
|
String get saturation;
|
||||||
|
|
||||||
|
/// No description provided for @brightness.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Brightness'**
|
||||||
|
String get brightness;
|
||||||
|
|
||||||
|
/// No description provided for @settingsAppearancePrimaryColor.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Primary Color'**
|
||||||
|
String get settingsAppearancePrimaryColor;
|
||||||
|
|
||||||
|
/// No description provided for @themeSystemDefault.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'System default'**
|
||||||
|
String get themeSystemDefault;
|
||||||
|
|
||||||
|
/// No description provided for @themeLight.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Light'**
|
||||||
|
String get themeLight;
|
||||||
|
|
||||||
|
/// No description provided for @themeDark.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Dark'**
|
||||||
|
String get themeDark;
|
||||||
|
|
||||||
|
/// No description provided for @backupRecoverySectionTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Secure Account Access'**
|
||||||
|
String get backupRecoverySectionTitle;
|
||||||
|
|
||||||
|
/// No description provided for @backupRecoverySectionDescNone.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'You must select at least one recovery option, as otherwise no one can help you if you lose access to your device.'**
|
||||||
|
String get backupRecoverySectionDescNone;
|
||||||
|
|
||||||
|
/// No description provided for @backupRecoverySectionDescSome.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'You can recover your account with the recovery options below. It is recommended to enable both options.'**
|
||||||
|
String get backupRecoverySectionDescSome;
|
||||||
|
|
||||||
|
/// No description provided for @backupRecoveryOptionAFriends.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Via trusted friends'**
|
||||||
|
String get backupRecoveryOptionAFriends;
|
||||||
|
|
||||||
|
/// No description provided for @backupRecoveryOptionAMicrocopy.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Select friends who can help you recover your account.'**
|
||||||
|
String get backupRecoveryOptionAMicrocopy;
|
||||||
|
|
||||||
|
/// No description provided for @backupRecoveryOptionBPassword.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Classic Password'**
|
||||||
|
String get backupRecoveryOptionBPassword;
|
||||||
|
|
||||||
|
/// No description provided for @backupRecoveryOptionBMicrocopy.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Set a password for your access.'**
|
||||||
|
String get backupRecoveryOptionBMicrocopy;
|
||||||
|
|
||||||
|
/// No description provided for @backupCloudSectionTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Backup Your Data'**
|
||||||
|
String get backupCloudSectionTitle;
|
||||||
|
|
||||||
|
/// No description provided for @backupCloudSectionDesc.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Backup your content so nothing gets lost.'**
|
||||||
|
String get backupCloudSectionDesc;
|
||||||
|
|
||||||
|
/// No description provided for @backupCloudContactsMessages.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Contacts & Messages'**
|
||||||
|
String get backupCloudContactsMessages;
|
||||||
|
|
||||||
|
/// No description provided for @backupCloudFreeActive.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Free Active'**
|
||||||
|
String get backupCloudFreeActive;
|
||||||
|
|
||||||
|
/// No description provided for @backupCloudImagesMedia.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Images & Media'**
|
||||||
|
String get backupCloudImagesMedia;
|
||||||
|
|
||||||
|
/// No description provided for @backupCloudProBadge.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Pro'**
|
||||||
|
String get backupCloudProBadge;
|
||||||
|
|
||||||
|
/// No description provided for @memoriesAddingToFavorites.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Adding to favorites...'**
|
||||||
|
String get memoriesAddingToFavorites;
|
||||||
|
|
||||||
|
/// No description provided for @memoriesRemovingFromFavorites.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Removing from favorites...'**
|
||||||
|
String get memoriesRemovingFromFavorites;
|
||||||
|
|
||||||
|
/// No description provided for @memoriesDeletingProgress.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Deleting memories...'**
|
||||||
|
String get memoriesDeletingProgress;
|
||||||
|
|
||||||
|
/// No description provided for @memoriesExportingProgress.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Exporting memories...'**
|
||||||
|
String get memoriesExportingProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppLocalizationsDelegate
|
class _AppLocalizationsDelegate
|
||||||
|
|
|
||||||
|
|
@ -741,6 +741,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get deleteOkBtnForMe => 'Für mich löschen';
|
String get deleteOkBtnForMe => 'Für mich löschen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get deleteOnlyForMe => 'Nur für mich löschen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get deleteImageTitle => 'Bist du dir sicher?';
|
String get deleteImageTitle => 'Bist du dir sicher?';
|
||||||
|
|
||||||
|
|
@ -817,7 +820,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
String get backupIdentityHeader => 'Identität';
|
String get backupIdentityHeader => 'Identität';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupArchiveHeader => 'Kontakte, Einstellungen und Nachrichten';
|
String get backupArchiveHeader => 'Kontakte & Nachrichten';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupLastBackupDate => 'Letztes Backup';
|
String get backupLastBackupDate => 'Letztes Backup';
|
||||||
|
|
@ -847,7 +850,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupSelectStrongPassword =>
|
String get backupSelectStrongPassword =>
|
||||||
'Wähle ein sicheres Passwort. Dies ist erforderlich, wenn du dein twonly Backup wiederherstellen möchtest.';
|
'Wähle ein sicheres Passwort. Es wird empfohlen, dieses über deinen bevorzugten Passwort-Manager zu generieren und zu speichern.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get password => 'Passwort';
|
String get password => 'Passwort';
|
||||||
|
|
@ -863,7 +866,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
'Das Passwort muss mindestens 10 Zeichen lang sein.';
|
'Das Passwort muss mindestens 10 Zeichen lang sein.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupEnableBackup => 'Automatische Sicherung aktivieren';
|
String get backupEnableBackup => 'Passwort-Backup aktivieren';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupTwonlySaveNow => 'Jetzt speichern';
|
String get backupTwonlySaveNow => 'Jetzt speichern';
|
||||||
|
|
@ -878,6 +881,26 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
String get backupChangePasswordAuthFailed =>
|
String get backupChangePasswordAuthFailed =>
|
||||||
'Du kannst dein Passwort nur ändern, wenn du dich authentifiziert hast!';
|
'Du kannst dein Passwort nur ändern, wenn du dich authentifiziert hast!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupFreeSpaceWithCloud =>
|
||||||
|
'Speicherplatz mit Cloud-Backup freigeben';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupMemoriesNotEnabled => 'Nicht aktiviert';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupMemoriesUpgradeRequired => 'Upgrade erforderlich';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String todayAt(Object time) {
|
||||||
|
return 'Heute um $time';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String yesterdayAt(Object time) {
|
||||||
|
return 'Gestern um $time';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get twonlySafeRecoverTitle => 'Backup wiederherstellen';
|
String get twonlySafeRecoverTitle => 'Backup wiederherstellen';
|
||||||
|
|
||||||
|
|
@ -1960,6 +1983,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get subscriptionPledgeSubtitle => 'Keine Werbung. Volle Privatsphäre.';
|
String get subscriptionPledgeSubtitle => 'Keine Werbung. Volle Privatsphäre.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get subscriptionManage => 'Abonnement verwalten';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get dragToZoom => 'Zum Zoomen ziehen';
|
String get dragToZoom => 'Zum Zoomen ziehen';
|
||||||
|
|
||||||
|
|
@ -2118,7 +2144,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
String get avatarCustomizeReset => 'Zurücksetzen';
|
String get avatarCustomizeReset => 'Zurücksetzen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecovery => 'Passwortloses Backup';
|
String get passwordlessRecovery => 'Vertraute Freunde';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryNotConfigured => 'Nicht konfiguriert';
|
String get passwordlessRecoveryNotConfigured => 'Nicht konfiguriert';
|
||||||
|
|
@ -2184,7 +2210,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryEnableSuccess =>
|
String get passwordlessRecoveryEnableSuccess =>
|
||||||
'Passwortloses Backup erfolgreich aktiviert!';
|
'Vertraute Freunde erfolgreich eingerichtet!';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryEnterPin => 'Bitte gib eine PIN ein.';
|
String get passwordlessRecoveryEnterPin => 'Bitte gib eine PIN ein.';
|
||||||
|
|
@ -2194,13 +2220,14 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
'Bitte gib eine E-Mail-Adresse ein.';
|
'Bitte gib eine E-Mail-Adresse ein.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryEnableBtn => 'Passwortloses Backup aktivieren';
|
String get passwordlessRecoveryEnableBtn => 'Vertraute Freunde aktivieren';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryRecoverBtn => 'Passwortlos wiederherstellen';
|
String get passwordlessRecoveryRecoverBtn =>
|
||||||
|
'Mithilfe von vertrauten Freunden wiederherstellen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryModifyBtn => 'Passwortloses Backup bearbeiten';
|
String get passwordlessRecoveryModifyBtn => 'Vertraute Freunde bearbeiten';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String passwordlessRecoveryStatusEnabled(num count) {
|
String passwordlessRecoveryStatusEnabled(num count) {
|
||||||
|
|
@ -2261,7 +2288,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
String get passwordlessRecoverySelectFriends => 'Freunde auswählen';
|
String get passwordlessRecoverySelectFriends => 'Freunde auswählen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryTrustedFriends => 'Vertrauenswürdige Freunde';
|
String get passwordlessRecoveryTrustedFriends => 'Kontowiederherstellung';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String passwordlessRecoveryDoneBtn(num count) {
|
String passwordlessRecoveryDoneBtn(num count) {
|
||||||
|
|
@ -2375,7 +2402,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
String get recoverPasswordlessRecoverNowBtn => 'Jetzt wiederherstellen';
|
String get recoverPasswordlessRecoverNowBtn => 'Jetzt wiederherstellen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get missingRecoveryContactsCardTitle => 'Vertrauenswürdige Kontakte';
|
String get missingRecoveryContactsCardTitle => 'Kontowiederherstellung';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get missingRecoveryContactsCardDesc =>
|
String get missingRecoveryContactsCardDesc =>
|
||||||
|
|
@ -2426,7 +2453,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
String get settingsHelpNews => 'Neuigkeiten';
|
String get settingsHelpNews => 'Neuigkeiten';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsStorageContents => 'Speicherinhalte';
|
String get settingsStorageContents => 'Speicherplatz freigeben';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsStorageSortStorage => 'Belegter Speicher';
|
String get settingsStorageSortStorage => 'Belegter Speicher';
|
||||||
|
|
@ -2475,4 +2502,124 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get settingsStorageSyncUpToDate =>
|
String get settingsStorageSyncUpToDate =>
|
||||||
'Alle Memories sind auf dem neuesten Stand.';
|
'Alle Memories sind auf dem neuesten Stand.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String restoreLostFlames(int count) {
|
||||||
|
return 'Stelle deine $count verlorenen Flammen wieder her';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settingsShowRestoreFlameTitle =>
|
||||||
|
'Hinweis zur Flammen-Wiederherstellung anzeigen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contactLabelsTitle => 'Kontaktlabels';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contactLabelsSubtitleEmpty => 'Keine Labels ausgewählt';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contactLabelsMaxLimit => 'Maximal 3 Labels pro Kontakt';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get createLabel => 'Neues Label erstellen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get editLabel => 'Label bearbeiten';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get deleteLabel => 'Label löschen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get deleteLabelConfirmation =>
|
||||||
|
'Möchtest du dieses Label wirklich löschen? Es wird von allen Kontakten entfernt.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelNameHint => 'Label-Name';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelTextColor => 'Textfarbe';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelBackgroundColor => 'Hintergrundfarbe';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get customColor => 'Eigene Farbe';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get hue => 'Farbton';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get saturation => 'Sättigung';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get brightness => 'Helligkeit';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settingsAppearancePrimaryColor => 'Hauptfarbe';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeSystemDefault => 'Systemstandard';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeLight => 'Hell';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeDark => 'Dunkel';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoverySectionTitle => 'Konto-Zugang sichern';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoverySectionDescNone =>
|
||||||
|
'Du musst mindestens eine Wiederherstellungsoption auswählen, da dir sonst niemand helfen kann, falls du den Zugriff auf dein Gerät verlierst.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoverySectionDescSome =>
|
||||||
|
'Mit den untenstehenden Wiederherstellungsoptionen kannst du dein Konto wiederherstellen. Es wird empfohlen, beide Optionen zu aktivieren.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoveryOptionAFriends => 'Über vertraute Freunde';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoveryOptionAMicrocopy =>
|
||||||
|
'Wähle Freunde aus, die dir helfen, dein Konto wiederherzustellen.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoveryOptionBPassword => 'Klassisches Passwort';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoveryOptionBMicrocopy =>
|
||||||
|
'Lege ein Passwort für deinen Zugang fest.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupCloudSectionTitle => 'Deine Daten sichern';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupCloudSectionDesc =>
|
||||||
|
'Sichere deine Inhalte, damit nichts verloren geht.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupCloudContactsMessages => 'Kontakte & Nachrichten';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupCloudFreeActive => 'Kostenlos aktiv';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupCloudImagesMedia => 'Bilder & Medien';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupCloudProBadge => 'Pro';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memoriesAddingToFavorites => 'Zu Favoriten hinzufügen...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memoriesRemovingFromFavorites => 'Aus Favoriten entfernen...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memoriesDeletingProgress => 'Erinnerungen werden gelöscht...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memoriesExportingProgress => 'Erinnerungen werden exportiert...';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -736,6 +736,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get deleteOkBtnForMe => 'Delete for me';
|
String get deleteOkBtnForMe => 'Delete for me';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get deleteOnlyForMe => 'Delete only for me';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get deleteImageTitle => 'Are you sure?';
|
String get deleteImageTitle => 'Are you sure?';
|
||||||
|
|
||||||
|
|
@ -812,7 +815,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
String get backupIdentityHeader => 'Identity';
|
String get backupIdentityHeader => 'Identity';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupArchiveHeader => 'Contacts, Settings and Messages';
|
String get backupArchiveHeader => 'Contacts & Messages';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupLastBackupDate => 'Last backup';
|
String get backupLastBackupDate => 'Last backup';
|
||||||
|
|
@ -842,7 +845,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupSelectStrongPassword =>
|
String get backupSelectStrongPassword =>
|
||||||
'Choose a secure password. This is required if you want to restore your twonly Backup.';
|
'Select a secure password. It is recommended to generate and store it via your password manager of choice.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get password => 'Password';
|
String get password => 'Password';
|
||||||
|
|
@ -858,7 +861,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
'Password must be at least 10 characters long.';
|
'Password must be at least 10 characters long.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupEnableBackup => 'Activate automatic backup';
|
String get backupEnableBackup => 'Enable Password Backup';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupTwonlySaveNow => 'Save now';
|
String get backupTwonlySaveNow => 'Save now';
|
||||||
|
|
@ -873,6 +876,25 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
String get backupChangePasswordAuthFailed =>
|
String get backupChangePasswordAuthFailed =>
|
||||||
'You can only change your password after you have authenticated!';
|
'You can only change your password after you have authenticated!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupFreeSpaceWithCloud => 'Free Space with Cloud Backup';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupMemoriesNotEnabled => 'Not enabled';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupMemoriesUpgradeRequired => 'Upgrade required';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String todayAt(Object time) {
|
||||||
|
return 'Today at $time';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String yesterdayAt(Object time) {
|
||||||
|
return 'Yesterday at $time';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get twonlySafeRecoverTitle => 'Restore backup';
|
String get twonlySafeRecoverTitle => 'Restore backup';
|
||||||
|
|
||||||
|
|
@ -1946,6 +1968,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get subscriptionPledgeSubtitle => 'Zero ads. Total privacy.';
|
String get subscriptionPledgeSubtitle => 'Zero ads. Total privacy.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get subscriptionManage => 'Manage subscription';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get dragToZoom => 'Drag to Zoom';
|
String get dragToZoom => 'Drag to Zoom';
|
||||||
|
|
||||||
|
|
@ -2104,7 +2129,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
String get avatarCustomizeReset => 'Reset';
|
String get avatarCustomizeReset => 'Reset';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecovery => 'Passwordless Recovery';
|
String get passwordlessRecovery => 'Trusted Friends';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryNotConfigured => 'Not configured';
|
String get passwordlessRecoveryNotConfigured => 'Not configured';
|
||||||
|
|
@ -2170,7 +2195,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryEnableSuccess =>
|
String get passwordlessRecoveryEnableSuccess =>
|
||||||
'Passwordless recovery successfully enabled!';
|
'Trusted Friends successfully set up!';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryEnterPin => 'Please enter a PIN.';
|
String get passwordlessRecoveryEnterPin => 'Please enter a PIN.';
|
||||||
|
|
@ -2179,13 +2204,13 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
String get passwordlessRecoveryEnterEmail => 'Please enter an email address.';
|
String get passwordlessRecoveryEnterEmail => 'Please enter an email address.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryEnableBtn => 'Enable Passwordless Recovery';
|
String get passwordlessRecoveryEnableBtn => 'Enable Trusted Friends';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryRecoverBtn => 'Recover passwordless';
|
String get passwordlessRecoveryRecoverBtn => 'Recover via Trusted Friends';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryModifyBtn => 'Modify Passwordless Recovery';
|
String get passwordlessRecoveryModifyBtn => 'Modify Trusted Friends';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String passwordlessRecoveryStatusEnabled(num count) {
|
String passwordlessRecoveryStatusEnabled(num count) {
|
||||||
|
|
@ -2245,7 +2270,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
String get passwordlessRecoverySelectFriends => 'Select trusted friends';
|
String get passwordlessRecoverySelectFriends => 'Select trusted friends';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get passwordlessRecoveryTrustedFriends => 'Trusted Friends';
|
String get passwordlessRecoveryTrustedFriends => 'Account recovery';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String passwordlessRecoveryDoneBtn(num count) {
|
String passwordlessRecoveryDoneBtn(num count) {
|
||||||
|
|
@ -2354,7 +2379,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
String get recoverPasswordlessRecoverNowBtn => 'Recover now';
|
String get recoverPasswordlessRecoverNowBtn => 'Recover now';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get missingRecoveryContactsCardTitle => 'Recovery Contacts';
|
String get missingRecoveryContactsCardTitle => 'Account Recovery';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get missingRecoveryContactsCardDesc =>
|
String get missingRecoveryContactsCardDesc =>
|
||||||
|
|
@ -2405,7 +2430,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
String get settingsHelpNews => 'News';
|
String get settingsHelpNews => 'News';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsStorageContents => 'Storage contents';
|
String get settingsStorageContents => 'Free up space';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsStorageSortStorage => 'Occupied storage';
|
String get settingsStorageSortStorage => 'Occupied storage';
|
||||||
|
|
@ -2453,4 +2478,123 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsStorageSyncUpToDate => 'All memories are up to date.';
|
String get settingsStorageSyncUpToDate => 'All memories are up to date.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String restoreLostFlames(int count) {
|
||||||
|
return 'Restore your $count lost flames';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settingsShowRestoreFlameTitle => 'Show flame restore warning';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contactLabelsTitle => 'Contact Labels';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contactLabelsSubtitleEmpty => 'No labels selected';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contactLabelsMaxLimit => 'Maximum 3 labels per contact';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get createLabel => 'Create new label';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get editLabel => 'Edit label';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get deleteLabel => 'Delete label';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get deleteLabelConfirmation =>
|
||||||
|
'Are you sure you want to delete this label? It will be removed from all contacts.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelNameHint => 'Label name';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelTextColor => 'Text color';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelBackgroundColor => 'Background color';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get customColor => 'Custom Color';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get hue => 'Hue';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get saturation => 'Saturation';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get brightness => 'Brightness';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settingsAppearancePrimaryColor => 'Primary Color';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeSystemDefault => 'System default';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeLight => 'Light';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeDark => 'Dark';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoverySectionTitle => 'Secure Account Access';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoverySectionDescNone =>
|
||||||
|
'You must select at least one recovery option, as otherwise no one can help you if you lose access to your device.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoverySectionDescSome =>
|
||||||
|
'You can recover your account with the recovery options below. It is recommended to enable both options.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoveryOptionAFriends => 'Via trusted friends';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoveryOptionAMicrocopy =>
|
||||||
|
'Select friends who can help you recover your account.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoveryOptionBPassword => 'Classic Password';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupRecoveryOptionBMicrocopy =>
|
||||||
|
'Set a password for your access.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupCloudSectionTitle => 'Backup Your Data';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupCloudSectionDesc =>
|
||||||
|
'Backup your content so nothing gets lost.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupCloudContactsMessages => 'Contacts & Messages';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupCloudFreeActive => 'Free Active';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupCloudImagesMedia => 'Images & Media';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupCloudProBadge => 'Pro';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memoriesAddingToFavorites => 'Adding to favorites...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memoriesRemovingFromFavorites => 'Removing from favorites...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memoriesDeletingProgress => 'Deleting memories...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memoriesExportingProgress => 'Exporting memories...';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 34c835db2de08af962b39fb79ec11341b8847926
|
Subproject commit 50cc5cb69dd91a5c626534fe4c015e50d2a0a486
|
||||||
|
|
@ -23,7 +23,6 @@ class UserData {
|
||||||
String username;
|
String username;
|
||||||
String displayName;
|
String displayName;
|
||||||
String? avatarSvg;
|
String? avatarSvg;
|
||||||
String? avatarJson;
|
|
||||||
|
|
||||||
@JsonKey(defaultValue: 0)
|
@JsonKey(defaultValue: 0)
|
||||||
int appVersion = 0;
|
int appVersion = 0;
|
||||||
|
|
@ -57,6 +56,12 @@ class UserData {
|
||||||
@JsonKey(defaultValue: ThemeMode.system)
|
@JsonKey(defaultValue: ThemeMode.system)
|
||||||
ThemeMode themeMode = ThemeMode.system;
|
ThemeMode themeMode = ThemeMode.system;
|
||||||
|
|
||||||
|
int? primaryColorValue;
|
||||||
|
|
||||||
|
Color get primaryColor => primaryColorValue != null
|
||||||
|
? Color(primaryColorValue!)
|
||||||
|
: const Color(0xFF57CC99);
|
||||||
|
|
||||||
int? defaultShowTime;
|
int? defaultShowTime;
|
||||||
|
|
||||||
@JsonKey(defaultValue: false)
|
@JsonKey(defaultValue: false)
|
||||||
|
|
@ -93,10 +98,15 @@ class UserData {
|
||||||
@JsonKey(defaultValue: true)
|
@JsonKey(defaultValue: true)
|
||||||
bool typingIndicators = true;
|
bool typingIndicators = true;
|
||||||
|
|
||||||
|
@JsonKey(defaultValue: true)
|
||||||
|
bool showRestoreFlame = true;
|
||||||
|
|
||||||
String? myBestFriendGroupId;
|
String? myBestFriendGroupId;
|
||||||
|
|
||||||
DateTime? signalLastSignedPreKeyUpdated;
|
DateTime? signalLastSignedPreKeyUpdated;
|
||||||
|
|
||||||
|
DateTime? signalLastPqcPreKeysUploaded;
|
||||||
|
|
||||||
@JsonKey(defaultValue: false)
|
@JsonKey(defaultValue: false)
|
||||||
bool allowErrorTrackingViaSentry = false;
|
bool allowErrorTrackingViaSentry = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ UserData _$UserDataFromJson(Map<String, dynamic> json) =>
|
||||||
appVersion: (json['appVersion'] as num?)?.toInt() ?? 0,
|
appVersion: (json['appVersion'] as num?)?.toInt() ?? 0,
|
||||||
)
|
)
|
||||||
..avatarSvg = json['avatarSvg'] as String?
|
..avatarSvg = json['avatarSvg'] as String?
|
||||||
..avatarJson = json['avatarJson'] as String?
|
|
||||||
..avatarCounter = (json['avatarCounter'] as num?)?.toInt() ?? 0
|
..avatarCounter = (json['avatarCounter'] as num?)?.toInt() ?? 0
|
||||||
..isDeveloper = json['isDeveloper'] as bool? ?? false
|
..isDeveloper = json['isDeveloper'] as bool? ?? false
|
||||||
..deviceId = (json['deviceId'] as num?)?.toInt() ?? 0
|
..deviceId = (json['deviceId'] as num?)?.toInt() ?? 0
|
||||||
|
|
@ -33,6 +32,7 @@ UserData _$UserDataFromJson(Map<String, dynamic> json) =>
|
||||||
..themeMode =
|
..themeMode =
|
||||||
$enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode']) ??
|
$enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode']) ??
|
||||||
ThemeMode.system
|
ThemeMode.system
|
||||||
|
..primaryColorValue = (json['primaryColorValue'] as num?)?.toInt()
|
||||||
..defaultShowTime = (json['defaultShowTime'] as num?)?.toInt()
|
..defaultShowTime = (json['defaultShowTime'] as num?)?.toInt()
|
||||||
..requestedAudioPermission =
|
..requestedAudioPermission =
|
||||||
json['requestedAudioPermission'] as bool? ?? false
|
json['requestedAudioPermission'] as bool? ?? false
|
||||||
|
|
@ -60,11 +60,16 @@ UserData _$UserDataFromJson(Map<String, dynamic> json) =>
|
||||||
..autoStoreAllSendUnlimitedMediaFiles =
|
..autoStoreAllSendUnlimitedMediaFiles =
|
||||||
json['autoStoreAllSendUnlimitedMediaFiles'] as bool? ?? false
|
json['autoStoreAllSendUnlimitedMediaFiles'] as bool? ?? false
|
||||||
..typingIndicators = json['typingIndicators'] as bool? ?? true
|
..typingIndicators = json['typingIndicators'] as bool? ?? true
|
||||||
|
..showRestoreFlame = json['showRestoreFlame'] as bool? ?? true
|
||||||
..myBestFriendGroupId = json['myBestFriendGroupId'] as String?
|
..myBestFriendGroupId = json['myBestFriendGroupId'] as String?
|
||||||
..signalLastSignedPreKeyUpdated =
|
..signalLastSignedPreKeyUpdated =
|
||||||
json['signalLastSignedPreKeyUpdated'] == null
|
json['signalLastSignedPreKeyUpdated'] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json['signalLastSignedPreKeyUpdated'] as String)
|
: DateTime.parse(json['signalLastSignedPreKeyUpdated'] as String)
|
||||||
|
..signalLastPqcPreKeysUploaded =
|
||||||
|
json['signalLastPqcPreKeysUploaded'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['signalLastPqcPreKeysUploaded'] as String)
|
||||||
..allowErrorTrackingViaSentry =
|
..allowErrorTrackingViaSentry =
|
||||||
json['allowErrorTrackingViaSentry'] as bool? ?? false
|
json['allowErrorTrackingViaSentry'] as bool? ?? false
|
||||||
..screenLockEnabled = json['screenLockEnabled'] as bool? ?? false
|
..screenLockEnabled = json['screenLockEnabled'] as bool? ?? false
|
||||||
|
|
@ -123,7 +128,6 @@ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
|
||||||
'username': instance.username,
|
'username': instance.username,
|
||||||
'displayName': instance.displayName,
|
'displayName': instance.displayName,
|
||||||
'avatarSvg': instance.avatarSvg,
|
'avatarSvg': instance.avatarSvg,
|
||||||
'avatarJson': instance.avatarJson,
|
|
||||||
'appVersion': instance.appVersion,
|
'appVersion': instance.appVersion,
|
||||||
'avatarCounter': instance.avatarCounter,
|
'avatarCounter': instance.avatarCounter,
|
||||||
'isDeveloper': instance.isDeveloper,
|
'isDeveloper': instance.isDeveloper,
|
||||||
|
|
@ -136,6 +140,7 @@ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
|
||||||
'lastPlanBallance': instance.lastPlanBallance,
|
'lastPlanBallance': instance.lastPlanBallance,
|
||||||
'additionalUserInvites': instance.additionalUserInvites,
|
'additionalUserInvites': instance.additionalUserInvites,
|
||||||
'themeMode': _$ThemeModeEnumMap[instance.themeMode]!,
|
'themeMode': _$ThemeModeEnumMap[instance.themeMode]!,
|
||||||
|
'primaryColorValue': instance.primaryColorValue,
|
||||||
'defaultShowTime': instance.defaultShowTime,
|
'defaultShowTime': instance.defaultShowTime,
|
||||||
'requestedAudioPermission': instance.requestedAudioPermission,
|
'requestedAudioPermission': instance.requestedAudioPermission,
|
||||||
'enableDatabaseLogging': instance.enableDatabaseLogging,
|
'enableDatabaseLogging': instance.enableDatabaseLogging,
|
||||||
|
|
@ -151,9 +156,12 @@ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
|
||||||
'autoStoreAllSendUnlimitedMediaFiles':
|
'autoStoreAllSendUnlimitedMediaFiles':
|
||||||
instance.autoStoreAllSendUnlimitedMediaFiles,
|
instance.autoStoreAllSendUnlimitedMediaFiles,
|
||||||
'typingIndicators': instance.typingIndicators,
|
'typingIndicators': instance.typingIndicators,
|
||||||
|
'showRestoreFlame': instance.showRestoreFlame,
|
||||||
'myBestFriendGroupId': instance.myBestFriendGroupId,
|
'myBestFriendGroupId': instance.myBestFriendGroupId,
|
||||||
'signalLastSignedPreKeyUpdated': instance.signalLastSignedPreKeyUpdated
|
'signalLastSignedPreKeyUpdated': instance.signalLastSignedPreKeyUpdated
|
||||||
?.toIso8601String(),
|
?.toIso8601String(),
|
||||||
|
'signalLastPqcPreKeysUploaded': instance.signalLastPqcPreKeysUploaded
|
||||||
|
?.toIso8601String(),
|
||||||
'allowErrorTrackingViaSentry': instance.allowErrorTrackingViaSentry,
|
'allowErrorTrackingViaSentry': instance.allowErrorTrackingViaSentry,
|
||||||
'screenLockEnabled': instance.screenLockEnabled,
|
'screenLockEnabled': instance.screenLockEnabled,
|
||||||
'isCloudBackupEnabled': instance.isCloudBackupEnabled,
|
'isCloudBackupEnabled': instance.isCloudBackupEnabled,
|
||||||
|
|
|
||||||
|
|
@ -2059,6 +2059,250 @@ class ApplicationData_UpdateSignedPreKey extends $pb.GeneratedMessage {
|
||||||
void clearSignedPrekeySignature() => $_clearField(3);
|
void clearSignedPrekeySignature() => $_clearField(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ApplicationData_PqcPreKey extends $pb.GeneratedMessage {
|
||||||
|
factory ApplicationData_PqcPreKey({
|
||||||
|
$fixnum.Int64? eccPreKeyId,
|
||||||
|
$core.List<$core.int>? eccPreKey,
|
||||||
|
$fixnum.Int64? kyberPreKeyId,
|
||||||
|
$core.List<$core.int>? kyberPreKey,
|
||||||
|
$core.List<$core.int>? kyberPreKeySignature,
|
||||||
|
}) {
|
||||||
|
final result = create();
|
||||||
|
if (eccPreKeyId != null) result.eccPreKeyId = eccPreKeyId;
|
||||||
|
if (eccPreKey != null) result.eccPreKey = eccPreKey;
|
||||||
|
if (kyberPreKeyId != null) result.kyberPreKeyId = kyberPreKeyId;
|
||||||
|
if (kyberPreKey != null) result.kyberPreKey = kyberPreKey;
|
||||||
|
if (kyberPreKeySignature != null)
|
||||||
|
result.kyberPreKeySignature = kyberPreKeySignature;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationData_PqcPreKey._();
|
||||||
|
|
||||||
|
factory ApplicationData_PqcPreKey.fromBuffer($core.List<$core.int> data,
|
||||||
|
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
|
create()..mergeFromBuffer(data, registry);
|
||||||
|
factory ApplicationData_PqcPreKey.fromJson($core.String json,
|
||||||
|
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
|
create()..mergeFromJson(json, registry);
|
||||||
|
|
||||||
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||||
|
_omitMessageNames ? '' : 'ApplicationData.PqcPreKey',
|
||||||
|
package:
|
||||||
|
const $pb.PackageName(_omitMessageNames ? '' : 'client_to_server'),
|
||||||
|
createEmptyInstance: create)
|
||||||
|
..aInt64(1, _omitFieldNames ? '' : 'eccPreKeyId')
|
||||||
|
..a<$core.List<$core.int>>(
|
||||||
|
2, _omitFieldNames ? '' : 'eccPreKey', $pb.PbFieldType.OY)
|
||||||
|
..aInt64(3, _omitFieldNames ? '' : 'kyberPreKeyId')
|
||||||
|
..a<$core.List<$core.int>>(
|
||||||
|
4, _omitFieldNames ? '' : 'kyberPreKey', $pb.PbFieldType.OY)
|
||||||
|
..a<$core.List<$core.int>>(
|
||||||
|
5, _omitFieldNames ? '' : 'kyberPreKeySignature', $pb.PbFieldType.OY)
|
||||||
|
..hasRequiredFields = false;
|
||||||
|
|
||||||
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
ApplicationData_PqcPreKey clone() => deepCopy();
|
||||||
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
ApplicationData_PqcPreKey copyWith(
|
||||||
|
void Function(ApplicationData_PqcPreKey) updates) =>
|
||||||
|
super.copyWith((message) => updates(message as ApplicationData_PqcPreKey))
|
||||||
|
as ApplicationData_PqcPreKey;
|
||||||
|
|
||||||
|
@$core.override
|
||||||
|
$pb.BuilderInfo get info_ => _i;
|
||||||
|
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static ApplicationData_PqcPreKey create() => ApplicationData_PqcPreKey._();
|
||||||
|
@$core.override
|
||||||
|
ApplicationData_PqcPreKey createEmptyInstance() => create();
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static ApplicationData_PqcPreKey getDefault() => _defaultInstance ??=
|
||||||
|
$pb.GeneratedMessage.$_defaultFor<ApplicationData_PqcPreKey>(create);
|
||||||
|
static ApplicationData_PqcPreKey? _defaultInstance;
|
||||||
|
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$fixnum.Int64 get eccPreKeyId => $_getI64(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
set eccPreKeyId($fixnum.Int64 value) => $_setInt64(0, value);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$core.bool hasEccPreKeyId() => $_has(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
void clearEccPreKeyId() => $_clearField(1);
|
||||||
|
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.List<$core.int> get eccPreKey => $_getN(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
set eccPreKey($core.List<$core.int> value) => $_setBytes(1, value);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.bool hasEccPreKey() => $_has(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
void clearEccPreKey() => $_clearField(2);
|
||||||
|
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$fixnum.Int64 get kyberPreKeyId => $_getI64(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
set kyberPreKeyId($fixnum.Int64 value) => $_setInt64(2, value);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$core.bool hasKyberPreKeyId() => $_has(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
void clearKyberPreKeyId() => $_clearField(3);
|
||||||
|
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
$core.List<$core.int> get kyberPreKey => $_getN(3);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
set kyberPreKey($core.List<$core.int> value) => $_setBytes(3, value);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
$core.bool hasKyberPreKey() => $_has(3);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
void clearKyberPreKey() => $_clearField(4);
|
||||||
|
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
$core.List<$core.int> get kyberPreKeySignature => $_getN(4);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
set kyberPreKeySignature($core.List<$core.int> value) => $_setBytes(4, value);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
$core.bool hasKyberPreKeySignature() => $_has(4);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
void clearKyberPreKeySignature() => $_clearField(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApplicationData_UploadPqcPreKeys extends $pb.GeneratedMessage {
|
||||||
|
factory ApplicationData_UploadPqcPreKeys({
|
||||||
|
$fixnum.Int64? eccSignedPrekeyId,
|
||||||
|
$core.List<$core.int>? eccSignedPrekey,
|
||||||
|
$core.List<$core.int>? eccSignedPrekeySignature,
|
||||||
|
$fixnum.Int64? kyberSignedPrekeyId,
|
||||||
|
$core.List<$core.int>? kyberSignedPrekey,
|
||||||
|
$core.List<$core.int>? kyberSignedPrekeySignature,
|
||||||
|
$core.Iterable<ApplicationData_PqcPreKey>? prekeys,
|
||||||
|
}) {
|
||||||
|
final result = create();
|
||||||
|
if (eccSignedPrekeyId != null) result.eccSignedPrekeyId = eccSignedPrekeyId;
|
||||||
|
if (eccSignedPrekey != null) result.eccSignedPrekey = eccSignedPrekey;
|
||||||
|
if (eccSignedPrekeySignature != null)
|
||||||
|
result.eccSignedPrekeySignature = eccSignedPrekeySignature;
|
||||||
|
if (kyberSignedPrekeyId != null)
|
||||||
|
result.kyberSignedPrekeyId = kyberSignedPrekeyId;
|
||||||
|
if (kyberSignedPrekey != null) result.kyberSignedPrekey = kyberSignedPrekey;
|
||||||
|
if (kyberSignedPrekeySignature != null)
|
||||||
|
result.kyberSignedPrekeySignature = kyberSignedPrekeySignature;
|
||||||
|
if (prekeys != null) result.prekeys.addAll(prekeys);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationData_UploadPqcPreKeys._();
|
||||||
|
|
||||||
|
factory ApplicationData_UploadPqcPreKeys.fromBuffer(
|
||||||
|
$core.List<$core.int> data,
|
||||||
|
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
|
create()..mergeFromBuffer(data, registry);
|
||||||
|
factory ApplicationData_UploadPqcPreKeys.fromJson($core.String json,
|
||||||
|
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
|
create()..mergeFromJson(json, registry);
|
||||||
|
|
||||||
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||||
|
_omitMessageNames ? '' : 'ApplicationData.UploadPqcPreKeys',
|
||||||
|
package:
|
||||||
|
const $pb.PackageName(_omitMessageNames ? '' : 'client_to_server'),
|
||||||
|
createEmptyInstance: create)
|
||||||
|
..aInt64(1, _omitFieldNames ? '' : 'eccSignedPrekeyId')
|
||||||
|
..a<$core.List<$core.int>>(
|
||||||
|
2, _omitFieldNames ? '' : 'eccSignedPrekey', $pb.PbFieldType.OY)
|
||||||
|
..a<$core.List<$core.int>>(3,
|
||||||
|
_omitFieldNames ? '' : 'eccSignedPrekeySignature', $pb.PbFieldType.OY)
|
||||||
|
..aInt64(4, _omitFieldNames ? '' : 'kyberSignedPrekeyId')
|
||||||
|
..a<$core.List<$core.int>>(
|
||||||
|
5, _omitFieldNames ? '' : 'kyberSignedPrekey', $pb.PbFieldType.OY)
|
||||||
|
..a<$core.List<$core.int>>(6,
|
||||||
|
_omitFieldNames ? '' : 'kyberSignedPrekeySignature', $pb.PbFieldType.OY)
|
||||||
|
..pPM<ApplicationData_PqcPreKey>(7, _omitFieldNames ? '' : 'prekeys',
|
||||||
|
subBuilder: ApplicationData_PqcPreKey.create)
|
||||||
|
..hasRequiredFields = false;
|
||||||
|
|
||||||
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
ApplicationData_UploadPqcPreKeys clone() => deepCopy();
|
||||||
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
ApplicationData_UploadPqcPreKeys copyWith(
|
||||||
|
void Function(ApplicationData_UploadPqcPreKeys) updates) =>
|
||||||
|
super.copyWith(
|
||||||
|
(message) => updates(message as ApplicationData_UploadPqcPreKeys))
|
||||||
|
as ApplicationData_UploadPqcPreKeys;
|
||||||
|
|
||||||
|
@$core.override
|
||||||
|
$pb.BuilderInfo get info_ => _i;
|
||||||
|
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static ApplicationData_UploadPqcPreKeys create() =>
|
||||||
|
ApplicationData_UploadPqcPreKeys._();
|
||||||
|
@$core.override
|
||||||
|
ApplicationData_UploadPqcPreKeys createEmptyInstance() => create();
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static ApplicationData_UploadPqcPreKeys getDefault() => _defaultInstance ??=
|
||||||
|
$pb.GeneratedMessage.$_defaultFor<ApplicationData_UploadPqcPreKeys>(
|
||||||
|
create);
|
||||||
|
static ApplicationData_UploadPqcPreKeys? _defaultInstance;
|
||||||
|
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$fixnum.Int64 get eccSignedPrekeyId => $_getI64(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
set eccSignedPrekeyId($fixnum.Int64 value) => $_setInt64(0, value);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$core.bool hasEccSignedPrekeyId() => $_has(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
void clearEccSignedPrekeyId() => $_clearField(1);
|
||||||
|
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.List<$core.int> get eccSignedPrekey => $_getN(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
set eccSignedPrekey($core.List<$core.int> value) => $_setBytes(1, value);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.bool hasEccSignedPrekey() => $_has(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
void clearEccSignedPrekey() => $_clearField(2);
|
||||||
|
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$core.List<$core.int> get eccSignedPrekeySignature => $_getN(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
set eccSignedPrekeySignature($core.List<$core.int> value) =>
|
||||||
|
$_setBytes(2, value);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$core.bool hasEccSignedPrekeySignature() => $_has(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
void clearEccSignedPrekeySignature() => $_clearField(3);
|
||||||
|
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
$fixnum.Int64 get kyberSignedPrekeyId => $_getI64(3);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
set kyberSignedPrekeyId($fixnum.Int64 value) => $_setInt64(3, value);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
$core.bool hasKyberSignedPrekeyId() => $_has(3);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
void clearKyberSignedPrekeyId() => $_clearField(4);
|
||||||
|
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
$core.List<$core.int> get kyberSignedPrekey => $_getN(4);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
set kyberSignedPrekey($core.List<$core.int> value) => $_setBytes(4, value);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
$core.bool hasKyberSignedPrekey() => $_has(4);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
void clearKyberSignedPrekey() => $_clearField(5);
|
||||||
|
|
||||||
|
@$pb.TagNumber(6)
|
||||||
|
$core.List<$core.int> get kyberSignedPrekeySignature => $_getN(5);
|
||||||
|
@$pb.TagNumber(6)
|
||||||
|
set kyberSignedPrekeySignature($core.List<$core.int> value) =>
|
||||||
|
$_setBytes(5, value);
|
||||||
|
@$pb.TagNumber(6)
|
||||||
|
$core.bool hasKyberSignedPrekeySignature() => $_has(5);
|
||||||
|
@$pb.TagNumber(6)
|
||||||
|
void clearKyberSignedPrekeySignature() => $_clearField(6);
|
||||||
|
|
||||||
|
@$pb.TagNumber(7)
|
||||||
|
$pb.PbList<ApplicationData_PqcPreKey> get prekeys => $_getList(6);
|
||||||
|
}
|
||||||
|
|
||||||
class ApplicationData_DownloadDone extends $pb.GeneratedMessage {
|
class ApplicationData_DownloadDone extends $pb.GeneratedMessage {
|
||||||
factory ApplicationData_DownloadDone({
|
factory ApplicationData_DownloadDone({
|
||||||
$core.List<$core.int>? downloadToken,
|
$core.List<$core.int>? downloadToken,
|
||||||
|
|
@ -3085,6 +3329,7 @@ enum ApplicationData_ApplicationData {
|
||||||
getMemoriesUsage,
|
getMemoriesUsage,
|
||||||
deleteMemory,
|
deleteMemory,
|
||||||
disableMemoriesBackup,
|
disableMemoriesBackup,
|
||||||
|
uploadPqcPrekeys,
|
||||||
notSet
|
notSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3117,6 +3362,7 @@ class ApplicationData extends $pb.GeneratedMessage {
|
||||||
ApplicationData_GetMemoriesUsage? getMemoriesUsage,
|
ApplicationData_GetMemoriesUsage? getMemoriesUsage,
|
||||||
ApplicationData_DeleteMemory? deleteMemory,
|
ApplicationData_DeleteMemory? deleteMemory,
|
||||||
ApplicationData_DisableMemoriesBackup? disableMemoriesBackup,
|
ApplicationData_DisableMemoriesBackup? disableMemoriesBackup,
|
||||||
|
ApplicationData_UploadPqcPreKeys? uploadPqcPrekeys,
|
||||||
}) {
|
}) {
|
||||||
final result = create();
|
final result = create();
|
||||||
if (textMessage != null) result.textMessage = textMessage;
|
if (textMessage != null) result.textMessage = textMessage;
|
||||||
|
|
@ -3157,6 +3403,7 @@ class ApplicationData extends $pb.GeneratedMessage {
|
||||||
if (deleteMemory != null) result.deleteMemory = deleteMemory;
|
if (deleteMemory != null) result.deleteMemory = deleteMemory;
|
||||||
if (disableMemoriesBackup != null)
|
if (disableMemoriesBackup != null)
|
||||||
result.disableMemoriesBackup = disableMemoriesBackup;
|
result.disableMemoriesBackup = disableMemoriesBackup;
|
||||||
|
if (uploadPqcPrekeys != null) result.uploadPqcPrekeys = uploadPqcPrekeys;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3198,6 +3445,7 @@ class ApplicationData extends $pb.GeneratedMessage {
|
||||||
37: ApplicationData_ApplicationData.getMemoriesUsage,
|
37: ApplicationData_ApplicationData.getMemoriesUsage,
|
||||||
38: ApplicationData_ApplicationData.deleteMemory,
|
38: ApplicationData_ApplicationData.deleteMemory,
|
||||||
39: ApplicationData_ApplicationData.disableMemoriesBackup,
|
39: ApplicationData_ApplicationData.disableMemoriesBackup,
|
||||||
|
40: ApplicationData_ApplicationData.uploadPqcPrekeys,
|
||||||
0: ApplicationData_ApplicationData.notSet
|
0: ApplicationData_ApplicationData.notSet
|
||||||
};
|
};
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||||
|
|
@ -3232,7 +3480,8 @@ class ApplicationData extends $pb.GeneratedMessage {
|
||||||
36,
|
36,
|
||||||
37,
|
37,
|
||||||
38,
|
38,
|
||||||
39
|
39,
|
||||||
|
40
|
||||||
])
|
])
|
||||||
..aOM<ApplicationData_TextMessage>(1, _omitFieldNames ? '' : 'textMessage',
|
..aOM<ApplicationData_TextMessage>(1, _omitFieldNames ? '' : 'textMessage',
|
||||||
protoName: 'textMessage',
|
protoName: 'textMessage',
|
||||||
|
|
@ -3327,6 +3576,9 @@ class ApplicationData extends $pb.GeneratedMessage {
|
||||||
..aOM<ApplicationData_DisableMemoriesBackup>(
|
..aOM<ApplicationData_DisableMemoriesBackup>(
|
||||||
39, _omitFieldNames ? '' : 'disableMemoriesBackup',
|
39, _omitFieldNames ? '' : 'disableMemoriesBackup',
|
||||||
subBuilder: ApplicationData_DisableMemoriesBackup.create)
|
subBuilder: ApplicationData_DisableMemoriesBackup.create)
|
||||||
|
..aOM<ApplicationData_UploadPqcPreKeys>(
|
||||||
|
40, _omitFieldNames ? '' : 'uploadPqcPrekeys',
|
||||||
|
subBuilder: ApplicationData_UploadPqcPreKeys.create)
|
||||||
..hasRequiredFields = false;
|
..hasRequiredFields = false;
|
||||||
|
|
||||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
|
@ -3375,6 +3627,7 @@ class ApplicationData extends $pb.GeneratedMessage {
|
||||||
@$pb.TagNumber(37)
|
@$pb.TagNumber(37)
|
||||||
@$pb.TagNumber(38)
|
@$pb.TagNumber(38)
|
||||||
@$pb.TagNumber(39)
|
@$pb.TagNumber(39)
|
||||||
|
@$pb.TagNumber(40)
|
||||||
ApplicationData_ApplicationData whichApplicationData() =>
|
ApplicationData_ApplicationData whichApplicationData() =>
|
||||||
_ApplicationData_ApplicationDataByTag[$_whichOneof(0)]!;
|
_ApplicationData_ApplicationDataByTag[$_whichOneof(0)]!;
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
|
|
@ -3404,6 +3657,7 @@ class ApplicationData extends $pb.GeneratedMessage {
|
||||||
@$pb.TagNumber(37)
|
@$pb.TagNumber(37)
|
||||||
@$pb.TagNumber(38)
|
@$pb.TagNumber(38)
|
||||||
@$pb.TagNumber(39)
|
@$pb.TagNumber(39)
|
||||||
|
@$pb.TagNumber(40)
|
||||||
void clearApplicationData() => $_clearField($_whichOneof(0));
|
void clearApplicationData() => $_clearField($_whichOneof(0));
|
||||||
|
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
|
|
@ -3737,6 +3991,18 @@ class ApplicationData extends $pb.GeneratedMessage {
|
||||||
@$pb.TagNumber(39)
|
@$pb.TagNumber(39)
|
||||||
ApplicationData_DisableMemoriesBackup ensureDisableMemoriesBackup() =>
|
ApplicationData_DisableMemoriesBackup ensureDisableMemoriesBackup() =>
|
||||||
$_ensure(26);
|
$_ensure(26);
|
||||||
|
|
||||||
|
@$pb.TagNumber(40)
|
||||||
|
ApplicationData_UploadPqcPreKeys get uploadPqcPrekeys => $_getN(27);
|
||||||
|
@$pb.TagNumber(40)
|
||||||
|
set uploadPqcPrekeys(ApplicationData_UploadPqcPreKeys value) =>
|
||||||
|
$_setField(40, value);
|
||||||
|
@$pb.TagNumber(40)
|
||||||
|
$core.bool hasUploadPqcPrekeys() => $_has(27);
|
||||||
|
@$pb.TagNumber(40)
|
||||||
|
void clearUploadPqcPrekeys() => $_clearField(40);
|
||||||
|
@$pb.TagNumber(40)
|
||||||
|
ApplicationData_UploadPqcPreKeys ensureUploadPqcPrekeys() => $_ensure(27);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Response_PreKey extends $pb.GeneratedMessage {
|
class Response_PreKey extends $pb.GeneratedMessage {
|
||||||
|
|
@ -3857,16 +4123,68 @@ class Response_Prekeys extends $pb.GeneratedMessage {
|
||||||
$pb.PbList<Response_PreKey> get prekeys => $_getList(0);
|
$pb.PbList<Response_PreKey> get prekeys => $_getList(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Response_Ok_Ok { none, prekeys, notSet }
|
class Response_PqcPrekeys extends $pb.GeneratedMessage {
|
||||||
|
factory Response_PqcPrekeys({
|
||||||
|
$core.Iterable<ApplicationData_PqcPreKey>? prekeys,
|
||||||
|
}) {
|
||||||
|
final result = create();
|
||||||
|
if (prekeys != null) result.prekeys.addAll(prekeys);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Response_PqcPrekeys._();
|
||||||
|
|
||||||
|
factory Response_PqcPrekeys.fromBuffer($core.List<$core.int> data,
|
||||||
|
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
|
create()..mergeFromBuffer(data, registry);
|
||||||
|
factory Response_PqcPrekeys.fromJson($core.String json,
|
||||||
|
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
|
create()..mergeFromJson(json, registry);
|
||||||
|
|
||||||
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||||
|
_omitMessageNames ? '' : 'Response.PqcPrekeys',
|
||||||
|
package:
|
||||||
|
const $pb.PackageName(_omitMessageNames ? '' : 'client_to_server'),
|
||||||
|
createEmptyInstance: create)
|
||||||
|
..pPM<ApplicationData_PqcPreKey>(1, _omitFieldNames ? '' : 'prekeys',
|
||||||
|
subBuilder: ApplicationData_PqcPreKey.create)
|
||||||
|
..hasRequiredFields = false;
|
||||||
|
|
||||||
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
Response_PqcPrekeys clone() => deepCopy();
|
||||||
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
Response_PqcPrekeys copyWith(void Function(Response_PqcPrekeys) updates) =>
|
||||||
|
super.copyWith((message) => updates(message as Response_PqcPrekeys))
|
||||||
|
as Response_PqcPrekeys;
|
||||||
|
|
||||||
|
@$core.override
|
||||||
|
$pb.BuilderInfo get info_ => _i;
|
||||||
|
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static Response_PqcPrekeys create() => Response_PqcPrekeys._();
|
||||||
|
@$core.override
|
||||||
|
Response_PqcPrekeys createEmptyInstance() => create();
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static Response_PqcPrekeys getDefault() => _defaultInstance ??=
|
||||||
|
$pb.GeneratedMessage.$_defaultFor<Response_PqcPrekeys>(create);
|
||||||
|
static Response_PqcPrekeys? _defaultInstance;
|
||||||
|
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$pb.PbList<ApplicationData_PqcPreKey> get prekeys => $_getList(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Response_Ok_Ok { none, prekeys, prekeysPqc, notSet }
|
||||||
|
|
||||||
class Response_Ok extends $pb.GeneratedMessage {
|
class Response_Ok extends $pb.GeneratedMessage {
|
||||||
factory Response_Ok({
|
factory Response_Ok({
|
||||||
$core.bool? none,
|
$core.bool? none,
|
||||||
Response_Prekeys? prekeys,
|
Response_Prekeys? prekeys,
|
||||||
|
Response_PqcPrekeys? prekeysPqc,
|
||||||
}) {
|
}) {
|
||||||
final result = create();
|
final result = create();
|
||||||
if (none != null) result.none = none;
|
if (none != null) result.none = none;
|
||||||
if (prekeys != null) result.prekeys = prekeys;
|
if (prekeys != null) result.prekeys = prekeys;
|
||||||
|
if (prekeysPqc != null) result.prekeysPqc = prekeysPqc;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3882,6 +4200,7 @@ class Response_Ok extends $pb.GeneratedMessage {
|
||||||
static const $core.Map<$core.int, Response_Ok_Ok> _Response_Ok_OkByTag = {
|
static const $core.Map<$core.int, Response_Ok_Ok> _Response_Ok_OkByTag = {
|
||||||
1: Response_Ok_Ok.none,
|
1: Response_Ok_Ok.none,
|
||||||
2: Response_Ok_Ok.prekeys,
|
2: Response_Ok_Ok.prekeys,
|
||||||
|
3: Response_Ok_Ok.prekeysPqc,
|
||||||
0: Response_Ok_Ok.notSet
|
0: Response_Ok_Ok.notSet
|
||||||
};
|
};
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||||
|
|
@ -3889,10 +4208,12 @@ class Response_Ok extends $pb.GeneratedMessage {
|
||||||
package:
|
package:
|
||||||
const $pb.PackageName(_omitMessageNames ? '' : 'client_to_server'),
|
const $pb.PackageName(_omitMessageNames ? '' : 'client_to_server'),
|
||||||
createEmptyInstance: create)
|
createEmptyInstance: create)
|
||||||
..oo(0, [1, 2])
|
..oo(0, [1, 2, 3])
|
||||||
..aOB(1, _omitFieldNames ? '' : 'None', protoName: 'None')
|
..aOB(1, _omitFieldNames ? '' : 'None', protoName: 'None')
|
||||||
..aOM<Response_Prekeys>(2, _omitFieldNames ? '' : 'prekeys',
|
..aOM<Response_Prekeys>(2, _omitFieldNames ? '' : 'prekeys',
|
||||||
subBuilder: Response_Prekeys.create)
|
subBuilder: Response_Prekeys.create)
|
||||||
|
..aOM<Response_PqcPrekeys>(3, _omitFieldNames ? '' : 'prekeysPqc',
|
||||||
|
subBuilder: Response_PqcPrekeys.create)
|
||||||
..hasRequiredFields = false;
|
..hasRequiredFields = false;
|
||||||
|
|
||||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
|
@ -3916,9 +4237,11 @@ class Response_Ok extends $pb.GeneratedMessage {
|
||||||
|
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
|
@$pb.TagNumber(3)
|
||||||
Response_Ok_Ok whichOk() => _Response_Ok_OkByTag[$_whichOneof(0)]!;
|
Response_Ok_Ok whichOk() => _Response_Ok_OkByTag[$_whichOneof(0)]!;
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
|
@$pb.TagNumber(3)
|
||||||
void clearOk() => $_clearField($_whichOneof(0));
|
void clearOk() => $_clearField($_whichOneof(0));
|
||||||
|
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
|
|
@ -3940,6 +4263,17 @@ class Response_Ok extends $pb.GeneratedMessage {
|
||||||
void clearPrekeys() => $_clearField(2);
|
void clearPrekeys() => $_clearField(2);
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
Response_Prekeys ensurePrekeys() => $_ensure(1);
|
Response_Prekeys ensurePrekeys() => $_ensure(1);
|
||||||
|
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
Response_PqcPrekeys get prekeysPqc => $_getN(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
set prekeysPqc(Response_PqcPrekeys value) => $_setField(3, value);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$core.bool hasPrekeysPqc() => $_has(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
void clearPrekeysPqc() => $_clearField(3);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
Response_PqcPrekeys ensurePrekeysPqc() => $_ensure(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Response_Response { ok, error, notSet }
|
enum Response_Response { ok, error, notSet }
|
||||||
|
|
|
||||||
|
|
@ -724,6 +724,15 @@ const ApplicationData$json = {
|
||||||
'9': 0,
|
'9': 0,
|
||||||
'10': 'disableMemoriesBackup'
|
'10': 'disableMemoriesBackup'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'1': 'upload_pqc_prekeys',
|
||||||
|
'3': 40,
|
||||||
|
'4': 1,
|
||||||
|
'5': 11,
|
||||||
|
'6': '.client_to_server.ApplicationData.UploadPqcPreKeys',
|
||||||
|
'9': 0,
|
||||||
|
'10': 'uploadPqcPrekeys'
|
||||||
|
},
|
||||||
],
|
],
|
||||||
'3': [
|
'3': [
|
||||||
ApplicationData_TextMessage$json,
|
ApplicationData_TextMessage$json,
|
||||||
|
|
@ -737,6 +746,8 @@ const ApplicationData$json = {
|
||||||
ApplicationData_GetPrekeysByUserId$json,
|
ApplicationData_GetPrekeysByUserId$json,
|
||||||
ApplicationData_GetSignedPreKeyByUserId$json,
|
ApplicationData_GetSignedPreKeyByUserId$json,
|
||||||
ApplicationData_UpdateSignedPreKey$json,
|
ApplicationData_UpdateSignedPreKey$json,
|
||||||
|
ApplicationData_PqcPreKey$json,
|
||||||
|
ApplicationData_UploadPqcPreKeys$json,
|
||||||
ApplicationData_DownloadDone$json,
|
ApplicationData_DownloadDone$json,
|
||||||
ApplicationData_ReportUser$json,
|
ApplicationData_ReportUser$json,
|
||||||
ApplicationData_IPAPurchase$json,
|
ApplicationData_IPAPurchase$json,
|
||||||
|
|
@ -868,6 +879,81 @@ const ApplicationData_UpdateSignedPreKey$json = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@$core.Deprecated('Use applicationDataDescriptor instead')
|
||||||
|
const ApplicationData_PqcPreKey$json = {
|
||||||
|
'1': 'PqcPreKey',
|
||||||
|
'2': [
|
||||||
|
{'1': 'ecc_pre_key_id', '3': 1, '4': 1, '5': 3, '10': 'eccPreKeyId'},
|
||||||
|
{'1': 'ecc_pre_key', '3': 2, '4': 1, '5': 12, '10': 'eccPreKey'},
|
||||||
|
{'1': 'kyber_pre_key_id', '3': 3, '4': 1, '5': 3, '10': 'kyberPreKeyId'},
|
||||||
|
{'1': 'kyber_pre_key', '3': 4, '4': 1, '5': 12, '10': 'kyberPreKey'},
|
||||||
|
{
|
||||||
|
'1': 'kyber_pre_key_signature',
|
||||||
|
'3': 5,
|
||||||
|
'4': 1,
|
||||||
|
'5': 12,
|
||||||
|
'10': 'kyberPreKeySignature'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
@$core.Deprecated('Use applicationDataDescriptor instead')
|
||||||
|
const ApplicationData_UploadPqcPreKeys$json = {
|
||||||
|
'1': 'UploadPqcPreKeys',
|
||||||
|
'2': [
|
||||||
|
{
|
||||||
|
'1': 'ecc_signed_prekey_id',
|
||||||
|
'3': 1,
|
||||||
|
'4': 1,
|
||||||
|
'5': 3,
|
||||||
|
'10': 'eccSignedPrekeyId'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'1': 'ecc_signed_prekey',
|
||||||
|
'3': 2,
|
||||||
|
'4': 1,
|
||||||
|
'5': 12,
|
||||||
|
'10': 'eccSignedPrekey'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'1': 'ecc_signed_prekey_signature',
|
||||||
|
'3': 3,
|
||||||
|
'4': 1,
|
||||||
|
'5': 12,
|
||||||
|
'10': 'eccSignedPrekeySignature'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'1': 'kyber_signed_prekey_id',
|
||||||
|
'3': 4,
|
||||||
|
'4': 1,
|
||||||
|
'5': 3,
|
||||||
|
'10': 'kyberSignedPrekeyId'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'1': 'kyber_signed_prekey',
|
||||||
|
'3': 5,
|
||||||
|
'4': 1,
|
||||||
|
'5': 12,
|
||||||
|
'10': 'kyberSignedPrekey'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'1': 'kyber_signed_prekey_signature',
|
||||||
|
'3': 6,
|
||||||
|
'4': 1,
|
||||||
|
'5': 12,
|
||||||
|
'10': 'kyberSignedPrekeySignature'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'1': 'prekeys',
|
||||||
|
'3': 7,
|
||||||
|
'4': 3,
|
||||||
|
'5': 11,
|
||||||
|
'6': '.client_to_server.ApplicationData.PqcPreKey',
|
||||||
|
'10': 'prekeys'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
@$core.Deprecated('Use applicationDataDescriptor instead')
|
@$core.Deprecated('Use applicationDataDescriptor instead')
|
||||||
const ApplicationData_DownloadDone$json = {
|
const ApplicationData_DownloadDone$json = {
|
||||||
'1': 'DownloadDone',
|
'1': 'DownloadDone',
|
||||||
|
|
@ -1073,38 +1159,51 @@ final $typed_data.Uint8List applicationDataDescriptor = $convert.base64Decode(
|
||||||
'CzIuLmNsaWVudF90b19zZXJ2ZXIuQXBwbGljYXRpb25EYXRhLkRlbGV0ZU1lbW9yeUgAUgxkZW'
|
'CzIuLmNsaWVudF90b19zZXJ2ZXIuQXBwbGljYXRpb25EYXRhLkRlbGV0ZU1lbW9yeUgAUgxkZW'
|
||||||
'xldGVNZW1vcnkScQoXZGlzYWJsZV9tZW1vcmllc19iYWNrdXAYJyABKAsyNy5jbGllbnRfdG9f'
|
'xldGVNZW1vcnkScQoXZGlzYWJsZV9tZW1vcmllc19iYWNrdXAYJyABKAsyNy5jbGllbnRfdG9f'
|
||||||
'c2VydmVyLkFwcGxpY2F0aW9uRGF0YS5EaXNhYmxlTWVtb3JpZXNCYWNrdXBIAFIVZGlzYWJsZU'
|
'c2VydmVyLkFwcGxpY2F0aW9uRGF0YS5EaXNhYmxlTWVtb3JpZXNCYWNrdXBIAFIVZGlzYWJsZU'
|
||||||
'1lbW9yaWVzQmFja3VwGmoKC1RleHRNZXNzYWdlEhcKB3VzZXJfaWQYASABKANSBnVzZXJJZBIS'
|
'1lbW9yaWVzQmFja3VwEmIKEnVwbG9hZF9wcWNfcHJla2V5cxgoIAEoCzIyLmNsaWVudF90b19z'
|
||||||
'CgRib2R5GAMgASgMUgRib2R5EiAKCXB1c2hfZGF0YRgEIAEoDEgAUghwdXNoRGF0YYgBAUIMCg'
|
'ZXJ2ZXIuQXBwbGljYXRpb25EYXRhLlVwbG9hZFBxY1ByZUtleXNIAFIQdXBsb2FkUHFjUHJla2'
|
||||||
'pfcHVzaF9kYXRhGi8KEUdldFVzZXJCeVVzZXJuYW1lEhoKCHVzZXJuYW1lGAEgASgJUgh1c2Vy'
|
'V5cxpqCgtUZXh0TWVzc2FnZRIXCgd1c2VyX2lkGAEgASgDUgZ1c2VySWQSEgoEYm9keRgDIAEo'
|
||||||
'bmFtZRosCg5DaGFuZ2VVc2VybmFtZRIaCgh1c2VybmFtZRgBIAEoCVIIdXNlcm5hbWUaNQoUVX'
|
'DFIEYm9keRIgCglwdXNoX2RhdGEYBCABKAxIAFIIcHVzaERhdGGIAQFCDAoKX3B1c2hfZGF0YR'
|
||||||
'BkYXRlR29vZ2xlRmNtVG9rZW4SHQoKZ29vZ2xlX2ZjbRgBIAEoCVIJZ29vZ2xlRmNtGiYKC0dl'
|
'ovChFHZXRVc2VyQnlVc2VybmFtZRIaCgh1c2VybmFtZRgBIAEoCVIIdXNlcm5hbWUaLAoOQ2hh'
|
||||||
'dFVzZXJCeUlkEhcKB3VzZXJfaWQYASABKANSBnVzZXJJZBoTChFHZXRBdmFpbGFibGVQbGFucx'
|
'bmdlVXNlcm5hbWUSGgoIdXNlcm5hbWUYASABKAlSCHVzZXJuYW1lGjUKFFVwZGF0ZUdvb2dsZU'
|
||||||
'oVChNHZXRDdXJyZW50UGxhbkluZm9zGi8KFFJlbW92ZUFkZGl0aW9uYWxVc2VyEhcKB3VzZXJf'
|
'ZjbVRva2VuEh0KCmdvb2dsZV9mY20YASABKAlSCWdvb2dsZUZjbRomCgtHZXRVc2VyQnlJZBIX'
|
||||||
'aWQYASABKANSBnVzZXJJZBotChJHZXRQcmVrZXlzQnlVc2VySWQSFwoHdXNlcl9pZBgBIAEoA1'
|
'Cgd1c2VyX2lkGAEgASgDUgZ1c2VySWQaEwoRR2V0QXZhaWxhYmxlUGxhbnMaFQoTR2V0Q3Vycm'
|
||||||
'IGdXNlcklkGjIKF0dldFNpZ25lZFByZUtleUJ5VXNlcklkEhcKB3VzZXJfaWQYASABKANSBnVz'
|
'VudFBsYW5JbmZvcxovChRSZW1vdmVBZGRpdGlvbmFsVXNlchIXCgd1c2VyX2lkGAEgASgDUgZ1'
|
||||||
'ZXJJZBqbAQoSVXBkYXRlU2lnbmVkUHJlS2V5EigKEHNpZ25lZF9wcmVrZXlfaWQYASABKANSDn'
|
'c2VySWQaLQoSR2V0UHJla2V5c0J5VXNlcklkEhcKB3VzZXJfaWQYASABKANSBnVzZXJJZBoyCh'
|
||||||
'NpZ25lZFByZWtleUlkEiMKDXNpZ25lZF9wcmVrZXkYAiABKAxSDHNpZ25lZFByZWtleRI2Chdz'
|
'dHZXRTaWduZWRQcmVLZXlCeVVzZXJJZBIXCgd1c2VyX2lkGAEgASgDUgZ1c2VySWQamwEKElVw'
|
||||||
'aWduZWRfcHJla2V5X3NpZ25hdHVyZRgDIAEoDFIVc2lnbmVkUHJla2V5U2lnbmF0dXJlGjUKDE'
|
'ZGF0ZVNpZ25lZFByZUtleRIoChBzaWduZWRfcHJla2V5X2lkGAEgASgDUg5zaWduZWRQcmVrZX'
|
||||||
'Rvd25sb2FkRG9uZRIlCg5kb3dubG9hZF90b2tlbhgBIAEoDFINZG93bmxvYWRUb2tlbhpOCgpS'
|
'lJZBIjCg1zaWduZWRfcHJla2V5GAIgASgMUgxzaWduZWRQcmVrZXkSNgoXc2lnbmVkX3ByZWtl'
|
||||||
'ZXBvcnRVc2VyEigKEHJlcG9ydGVkX3VzZXJfaWQYASABKANSDnJlcG9ydGVkVXNlcklkEhYKBn'
|
'eV9zaWduYXR1cmUYAyABKAxSFXNpZ25lZFByZWtleVNpZ25hdHVyZRrUAQoJUHFjUHJlS2V5Ei'
|
||||||
'JlYXNvbhgCIAEoCVIGcmVhc29uGnEKC0lQQVB1cmNoYXNlEh0KCnByb2R1Y3RfaWQYASABKAlS'
|
'MKDmVjY19wcmVfa2V5X2lkGAEgASgDUgtlY2NQcmVLZXlJZBIeCgtlY2NfcHJlX2tleRgCIAEo'
|
||||||
'CXByb2R1Y3RJZBIWCgZzb3VyY2UYAiABKAlSBnNvdXJjZRIrChF2ZXJpZmljYXRpb25fZGF0YR'
|
'DFIJZWNjUHJlS2V5EicKEGt5YmVyX3ByZV9rZXlfaWQYAyABKANSDWt5YmVyUHJlS2V5SWQSIg'
|
||||||
'gDIAEoCVIQdmVyaWZpY2F0aW9uRGF0YRoPCg1JUEFGb3JjZUNoZWNrGg8KDURlbGV0ZUFjY291'
|
'oNa3liZXJfcHJlX2tleRgEIAEoDFILa3liZXJQcmVLZXkSNQoXa3liZXJfcHJlX2tleV9zaWdu'
|
||||||
'bnQaLAoRQWRkQWRkaXRpb25hbFVzZXISFwoHdXNlcl9pZBgBIAEoA1IGdXNlcklkGjAKDVNldE'
|
'YXR1cmUYBSABKAxSFGt5YmVyUHJlS2V5U2lnbmF0dXJlGp0DChBVcGxvYWRQcWNQcmVLZXlzEi'
|
||||||
'xvZ2luVG9rZW4SHwoLbG9naW5fdG9rZW4YASABKAxSCmxvZ2luVG9rZW4ajgEKHFJlZ2lzdGVy'
|
'8KFGVjY19zaWduZWRfcHJla2V5X2lkGAEgASgDUhFlY2NTaWduZWRQcmVrZXlJZBIqChFlY2Nf'
|
||||||
'UGFzc3dvcmRMZXNzUmVjb3ZlcnkSLgoSZW5jcnlwdGVkU2VydmVyS2V5GAEgASgMUhJlbmNyeX'
|
'c2lnbmVkX3ByZWtleRgCIAEoDFIPZWNjU2lnbmVkUHJla2V5Ej0KG2VjY19zaWduZWRfcHJla2'
|
||||||
'B0ZWRTZXJ2ZXJLZXkSKwoOcGluVW5sb2NrVG9rZW4YAiABKAxIAFIOcGluVW5sb2NrVG9rZW6I'
|
'V5X3NpZ25hdHVyZRgDIAEoDFIYZWNjU2lnbmVkUHJla2V5U2lnbmF0dXJlEjMKFmt5YmVyX3Np'
|
||||||
'AQFCEQoPX3BpblVubG9ja1Rva2VuGnAKGFBhc3N3b3JkbGVzc05vdGlmaWNhdGlvbhInCg9ub3'
|
'Z25lZF9wcmVrZXlfaWQYBCABKANSE2t5YmVyU2lnbmVkUHJla2V5SWQSLgoTa3liZXJfc2lnbm'
|
||||||
'RpZmljYXRpb25faWQYASABKAlSDm5vdGlmaWNhdGlvbklkEisKEWVuY3J5cHRlZF9tZXNzYWdl'
|
'VkX3ByZWtleRgFIAEoDFIRa3liZXJTaWduZWRQcmVrZXkSQQoda3liZXJfc2lnbmVkX3ByZWtl'
|
||||||
'GAIgASgMUhBlbmNyeXB0ZWRNZXNzYWdlGmsKFVJlcXVlc3RNZW1vcmllc1VwbG9hZBISCgRzaX'
|
'eV9zaWduYXR1cmUYBiABKAxSGmt5YmVyU2lnbmVkUHJla2V5U2lnbmF0dXJlEkUKB3ByZWtleX'
|
||||||
'plGAEgASgDUgRzaXplEiMKDW9yaWdpbmFsX2RhdGUYAiABKANSDG9yaWdpbmFsRGF0ZRIZCght'
|
'MYByADKAsyKy5jbGllbnRfdG9fc2VydmVyLkFwcGxpY2F0aW9uRGF0YS5QcWNQcmVLZXlSB3By'
|
||||||
'ZWRpYV9pZBgDIAEoCVIHbWVkaWFJZBoyChVDb25maXJtTWVtb3JpZXNVcGxvYWQSGQoIbWVkaW'
|
'ZWtleXMaNQoMRG93bmxvYWREb25lEiUKDmRvd25sb2FkX3Rva2VuGAEgASgMUg1kb3dubG9hZF'
|
||||||
'FfaWQYASABKAlSB21lZGlhSWQaSAoPR2V0TWVtb3JpZXNMaXN0Eh8KC29mZnNldF9kYXRlGAEg'
|
'Rva2VuGk4KClJlcG9ydFVzZXISKAoQcmVwb3J0ZWRfdXNlcl9pZBgBIAEoA1IOcmVwb3J0ZWRV'
|
||||||
'ASgDUgpvZmZzZXREYXRlEhQKBWxpbWl0GAIgASgDUgVsaW1pdBpJCg5HZXRNZW1vcmllc1VybB'
|
'c2VySWQSFgoGcmVhc29uGAIgASgJUgZyZWFzb24acQoLSVBBUHVyY2hhc2USHQoKcHJvZHVjdF'
|
||||||
'IZCghtZWRpYV9pZBgBIAEoCVIHbWVkaWFJZBIcCgl0aHVtYm5haWwYAiABKAhSCXRodW1ibmFp'
|
'9pZBgBIAEoCVIJcHJvZHVjdElkEhYKBnNvdXJjZRgCIAEoCVIGc291cmNlEisKEXZlcmlmaWNh'
|
||||||
'bBoSChBHZXRNZW1vcmllc1VzYWdlGikKDERlbGV0ZU1lbW9yeRIZCghtZWRpYV9pZBgBIAEoCV'
|
'dGlvbl9kYXRhGAMgASgJUhB2ZXJpZmljYXRpb25EYXRhGg8KDUlQQUZvcmNlQ2hlY2saDwoNRG'
|
||||||
'IHbWVkaWFJZBoXChVEaXNhYmxlTWVtb3JpZXNCYWNrdXBCEQoPQXBwbGljYXRpb25EYXRhSgQI'
|
'VsZXRlQWNjb3VudBosChFBZGRBZGRpdGlvbmFsVXNlchIXCgd1c2VyX2lkGAEgASgDUgZ1c2Vy'
|
||||||
'CRAKSgQICxAMSgQIDRASSgQIExAU');
|
'SWQaMAoNU2V0TG9naW5Ub2tlbhIfCgtsb2dpbl90b2tlbhgBIAEoDFIKbG9naW5Ub2tlbhqOAQ'
|
||||||
|
'ocUmVnaXN0ZXJQYXNzd29yZExlc3NSZWNvdmVyeRIuChJlbmNyeXB0ZWRTZXJ2ZXJLZXkYASAB'
|
||||||
|
'KAxSEmVuY3J5cHRlZFNlcnZlcktleRIrCg5waW5VbmxvY2tUb2tlbhgCIAEoDEgAUg5waW5Vbm'
|
||||||
|
'xvY2tUb2tlbogBAUIRCg9fcGluVW5sb2NrVG9rZW4acAoYUGFzc3dvcmRsZXNzTm90aWZpY2F0'
|
||||||
|
'aW9uEicKD25vdGlmaWNhdGlvbl9pZBgBIAEoCVIObm90aWZpY2F0aW9uSWQSKwoRZW5jcnlwdG'
|
||||||
|
'VkX21lc3NhZ2UYAiABKAxSEGVuY3J5cHRlZE1lc3NhZ2UaawoVUmVxdWVzdE1lbW9yaWVzVXBs'
|
||||||
|
'b2FkEhIKBHNpemUYASABKANSBHNpemUSIwoNb3JpZ2luYWxfZGF0ZRgCIAEoA1IMb3JpZ2luYW'
|
||||||
|
'xEYXRlEhkKCG1lZGlhX2lkGAMgASgJUgdtZWRpYUlkGjIKFUNvbmZpcm1NZW1vcmllc1VwbG9h'
|
||||||
|
'ZBIZCghtZWRpYV9pZBgBIAEoCVIHbWVkaWFJZBpICg9HZXRNZW1vcmllc0xpc3QSHwoLb2Zmc2'
|
||||||
|
'V0X2RhdGUYASABKANSCm9mZnNldERhdGUSFAoFbGltaXQYAiABKANSBWxpbWl0GkkKDkdldE1l'
|
||||||
|
'bW9yaWVzVXJsEhkKCG1lZGlhX2lkGAEgASgJUgdtZWRpYUlkEhwKCXRodW1ibmFpbBgCIAEoCF'
|
||||||
|
'IJdGh1bWJuYWlsGhIKEEdldE1lbW9yaWVzVXNhZ2UaKQoMRGVsZXRlTWVtb3J5EhkKCG1lZGlh'
|
||||||
|
'X2lkGAEgASgJUgdtZWRpYUlkGhcKFURpc2FibGVNZW1vcmllc0JhY2t1cEIRCg9BcHBsaWNhdG'
|
||||||
|
'lvbkRhdGFKBAgJEApKBAgLEAxKBAgNEBJKBAgTEBQ=');
|
||||||
|
|
||||||
@$core.Deprecated('Use responseDescriptor instead')
|
@$core.Deprecated('Use responseDescriptor instead')
|
||||||
const Response$json = {
|
const Response$json = {
|
||||||
|
|
@ -1129,7 +1228,12 @@ const Response$json = {
|
||||||
'10': 'error'
|
'10': 'error'
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
'3': [Response_PreKey$json, Response_Prekeys$json, Response_Ok$json],
|
'3': [
|
||||||
|
Response_PreKey$json,
|
||||||
|
Response_Prekeys$json,
|
||||||
|
Response_PqcPrekeys$json,
|
||||||
|
Response_Ok$json
|
||||||
|
],
|
||||||
'8': [
|
'8': [
|
||||||
{'1': 'Response'},
|
{'1': 'Response'},
|
||||||
],
|
],
|
||||||
|
|
@ -1159,6 +1263,21 @@ const Response_Prekeys$json = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@$core.Deprecated('Use responseDescriptor instead')
|
||||||
|
const Response_PqcPrekeys$json = {
|
||||||
|
'1': 'PqcPrekeys',
|
||||||
|
'2': [
|
||||||
|
{
|
||||||
|
'1': 'prekeys',
|
||||||
|
'3': 1,
|
||||||
|
'4': 3,
|
||||||
|
'5': 11,
|
||||||
|
'6': '.client_to_server.ApplicationData.PqcPreKey',
|
||||||
|
'10': 'prekeys'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
@$core.Deprecated('Use responseDescriptor instead')
|
@$core.Deprecated('Use responseDescriptor instead')
|
||||||
const Response_Ok$json = {
|
const Response_Ok$json = {
|
||||||
'1': 'Ok',
|
'1': 'Ok',
|
||||||
|
|
@ -1173,6 +1292,15 @@ const Response_Ok$json = {
|
||||||
'9': 0,
|
'9': 0,
|
||||||
'10': 'prekeys'
|
'10': 'prekeys'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'1': 'prekeys_pqc',
|
||||||
|
'3': 3,
|
||||||
|
'4': 1,
|
||||||
|
'5': 11,
|
||||||
|
'6': '.client_to_server.Response.PqcPrekeys',
|
||||||
|
'9': 0,
|
||||||
|
'10': 'prekeysPqc'
|
||||||
|
},
|
||||||
],
|
],
|
||||||
'8': [
|
'8': [
|
||||||
{'1': 'Ok'},
|
{'1': 'Ok'},
|
||||||
|
|
@ -1185,5 +1313,8 @@ final $typed_data.Uint8List responseDescriptor = $convert.base64Decode(
|
||||||
'ICb2sSKAoFZXJyb3IYAiABKA4yEC5lcnJvci5FcnJvckNvZGVIAFIFZXJyb3IaMAoGUHJlS2V5'
|
'ICb2sSKAoFZXJyb3IYAiABKA4yEC5lcnJvci5FcnJvckNvZGVIAFIFZXJyb3IaMAoGUHJlS2V5'
|
||||||
'Eg4KAmlkGAEgASgDUgJpZBIWCgZwcmVrZXkYAiABKAxSBnByZWtleRpGCgdQcmVrZXlzEjsKB3'
|
'Eg4KAmlkGAEgASgDUgJpZBIWCgZwcmVrZXkYAiABKAxSBnByZWtleRpGCgdQcmVrZXlzEjsKB3'
|
||||||
'ByZWtleXMYASADKAsyIS5jbGllbnRfdG9fc2VydmVyLlJlc3BvbnNlLlByZUtleVIHcHJla2V5'
|
'ByZWtleXMYASADKAsyIS5jbGllbnRfdG9fc2VydmVyLlJlc3BvbnNlLlByZUtleVIHcHJla2V5'
|
||||||
'cxpgCgJPaxIUCgROb25lGAEgASgISABSBE5vbmUSPgoHcHJla2V5cxgCIAEoCzIiLmNsaWVudF'
|
'cxpTCgpQcWNQcmVrZXlzEkUKB3ByZWtleXMYASADKAsyKy5jbGllbnRfdG9fc2VydmVyLkFwcG'
|
||||||
'90b19zZXJ2ZXIuUmVzcG9uc2UuUHJla2V5c0gAUgdwcmVrZXlzQgQKAk9rQgoKCFJlc3BvbnNl');
|
'xpY2F0aW9uRGF0YS5QcWNQcmVLZXlSB3ByZWtleXMaqgEKAk9rEhQKBE5vbmUYASABKAhIAFIE'
|
||||||
|
'Tm9uZRI+CgdwcmVrZXlzGAIgASgLMiIuY2xpZW50X3RvX3NlcnZlci5SZXNwb25zZS5QcmVrZX'
|
||||||
|
'lzSABSB3ByZWtleXMSSAoLcHJla2V5c19wcWMYAyABKAsyJS5jbGllbnRfdG9fc2VydmVyLlJl'
|
||||||
|
'c3BvbnNlLlBxY1ByZWtleXNIAFIKcHJla2V5c1BxY0IECgJPa0IKCghSZXNwb25zZQ==');
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ enum V0_Kind {
|
||||||
requestNewPreKeys,
|
requestNewPreKeys,
|
||||||
error,
|
error,
|
||||||
newMessages,
|
newMessages,
|
||||||
|
requestNewPqcPreKeys,
|
||||||
notSet
|
notSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,6 +107,7 @@ class V0 extends $pb.GeneratedMessage {
|
||||||
$core.bool? requestNewPreKeys,
|
$core.bool? requestNewPreKeys,
|
||||||
$0.ErrorCode? error,
|
$0.ErrorCode? error,
|
||||||
NewMessages? newMessages,
|
NewMessages? newMessages,
|
||||||
|
$core.bool? requestNewPqcPreKeys,
|
||||||
}) {
|
}) {
|
||||||
final result = create();
|
final result = create();
|
||||||
if (seq != null) result.seq = seq;
|
if (seq != null) result.seq = seq;
|
||||||
|
|
@ -114,6 +116,8 @@ class V0 extends $pb.GeneratedMessage {
|
||||||
if (requestNewPreKeys != null) result.requestNewPreKeys = requestNewPreKeys;
|
if (requestNewPreKeys != null) result.requestNewPreKeys = requestNewPreKeys;
|
||||||
if (error != null) result.error = error;
|
if (error != null) result.error = error;
|
||||||
if (newMessages != null) result.newMessages = newMessages;
|
if (newMessages != null) result.newMessages = newMessages;
|
||||||
|
if (requestNewPqcPreKeys != null)
|
||||||
|
result.requestNewPqcPreKeys = requestNewPqcPreKeys;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,6 +136,7 @@ class V0 extends $pb.GeneratedMessage {
|
||||||
4: V0_Kind.requestNewPreKeys,
|
4: V0_Kind.requestNewPreKeys,
|
||||||
6: V0_Kind.error,
|
6: V0_Kind.error,
|
||||||
7: V0_Kind.newMessages,
|
7: V0_Kind.newMessages,
|
||||||
|
8: V0_Kind.requestNewPqcPreKeys,
|
||||||
0: V0_Kind.notSet
|
0: V0_Kind.notSet
|
||||||
};
|
};
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||||
|
|
@ -139,7 +144,7 @@ class V0 extends $pb.GeneratedMessage {
|
||||||
package:
|
package:
|
||||||
const $pb.PackageName(_omitMessageNames ? '' : 'server_to_client'),
|
const $pb.PackageName(_omitMessageNames ? '' : 'server_to_client'),
|
||||||
createEmptyInstance: create)
|
createEmptyInstance: create)
|
||||||
..oo(0, [2, 3, 4, 6, 7])
|
..oo(0, [2, 3, 4, 6, 7, 8])
|
||||||
..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'seq', $pb.PbFieldType.OU6,
|
..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'seq', $pb.PbFieldType.OU6,
|
||||||
defaultOrMaker: $fixnum.Int64.ZERO)
|
defaultOrMaker: $fixnum.Int64.ZERO)
|
||||||
..aOM<Response>(2, _omitFieldNames ? '' : 'response',
|
..aOM<Response>(2, _omitFieldNames ? '' : 'response',
|
||||||
|
|
@ -152,6 +157,8 @@ class V0 extends $pb.GeneratedMessage {
|
||||||
enumValues: $0.ErrorCode.values)
|
enumValues: $0.ErrorCode.values)
|
||||||
..aOM<NewMessages>(7, _omitFieldNames ? '' : 'newMessages',
|
..aOM<NewMessages>(7, _omitFieldNames ? '' : 'newMessages',
|
||||||
protoName: 'newMessages', subBuilder: NewMessages.create)
|
protoName: 'newMessages', subBuilder: NewMessages.create)
|
||||||
|
..aOB(8, _omitFieldNames ? '' : 'RequestNewPqcPreKeys',
|
||||||
|
protoName: 'RequestNewPqcPreKeys')
|
||||||
..hasRequiredFields = false;
|
..hasRequiredFields = false;
|
||||||
|
|
||||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
|
@ -177,12 +184,14 @@ class V0 extends $pb.GeneratedMessage {
|
||||||
@$pb.TagNumber(4)
|
@$pb.TagNumber(4)
|
||||||
@$pb.TagNumber(6)
|
@$pb.TagNumber(6)
|
||||||
@$pb.TagNumber(7)
|
@$pb.TagNumber(7)
|
||||||
|
@$pb.TagNumber(8)
|
||||||
V0_Kind whichKind() => _V0_KindByTag[$_whichOneof(0)]!;
|
V0_Kind whichKind() => _V0_KindByTag[$_whichOneof(0)]!;
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
@$pb.TagNumber(4)
|
@$pb.TagNumber(4)
|
||||||
@$pb.TagNumber(6)
|
@$pb.TagNumber(6)
|
||||||
@$pb.TagNumber(7)
|
@$pb.TagNumber(7)
|
||||||
|
@$pb.TagNumber(8)
|
||||||
void clearKind() => $_clearField($_whichOneof(0));
|
void clearKind() => $_clearField($_whichOneof(0));
|
||||||
|
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
|
|
@ -244,6 +253,15 @@ class V0 extends $pb.GeneratedMessage {
|
||||||
void clearNewMessages() => $_clearField(7);
|
void clearNewMessages() => $_clearField(7);
|
||||||
@$pb.TagNumber(7)
|
@$pb.TagNumber(7)
|
||||||
NewMessages ensureNewMessages() => $_ensure(5);
|
NewMessages ensureNewMessages() => $_ensure(5);
|
||||||
|
|
||||||
|
@$pb.TagNumber(8)
|
||||||
|
$core.bool get requestNewPqcPreKeys => $_getBF(6);
|
||||||
|
@$pb.TagNumber(8)
|
||||||
|
set requestNewPqcPreKeys($core.bool value) => $_setBool(6, value);
|
||||||
|
@$pb.TagNumber(8)
|
||||||
|
$core.bool hasRequestNewPqcPreKeys() => $_has(6);
|
||||||
|
@$pb.TagNumber(8)
|
||||||
|
void clearRequestNewPqcPreKeys() => $_clearField(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
class NewMessage extends $pb.GeneratedMessage {
|
class NewMessage extends $pb.GeneratedMessage {
|
||||||
|
|
@ -830,45 +848,6 @@ class Response_AdditionalAccount extends $pb.GeneratedMessage {
|
||||||
void clearPlanId() => $_clearField(3);
|
void clearPlanId() => $_clearField(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Response_Deprecated extends $pb.GeneratedMessage {
|
|
||||||
factory Response_Deprecated() => create();
|
|
||||||
|
|
||||||
Response_Deprecated._();
|
|
||||||
|
|
||||||
factory Response_Deprecated.fromBuffer($core.List<$core.int> data,
|
|
||||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
|
||||||
create()..mergeFromBuffer(data, registry);
|
|
||||||
factory Response_Deprecated.fromJson($core.String json,
|
|
||||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
|
||||||
create()..mergeFromJson(json, registry);
|
|
||||||
|
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
|
||||||
_omitMessageNames ? '' : 'Response.Deprecated',
|
|
||||||
package:
|
|
||||||
const $pb.PackageName(_omitMessageNames ? '' : 'server_to_client'),
|
|
||||||
createEmptyInstance: create)
|
|
||||||
..hasRequiredFields = false;
|
|
||||||
|
|
||||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
|
||||||
Response_Deprecated clone() => deepCopy();
|
|
||||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
|
||||||
Response_Deprecated copyWith(void Function(Response_Deprecated) updates) =>
|
|
||||||
super.copyWith((message) => updates(message as Response_Deprecated))
|
|
||||||
as Response_Deprecated;
|
|
||||||
|
|
||||||
@$core.override
|
|
||||||
$pb.BuilderInfo get info_ => _i;
|
|
||||||
|
|
||||||
@$core.pragma('dart2js:noInline')
|
|
||||||
static Response_Deprecated create() => Response_Deprecated._();
|
|
||||||
@$core.override
|
|
||||||
Response_Deprecated createEmptyInstance() => create();
|
|
||||||
@$core.pragma('dart2js:noInline')
|
|
||||||
static Response_Deprecated getDefault() => _defaultInstance ??=
|
|
||||||
$pb.GeneratedMessage.$_defaultFor<Response_Deprecated>(create);
|
|
||||||
static Response_Deprecated? _defaultInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Response_Transaction extends $pb.GeneratedMessage {
|
class Response_Transaction extends $pb.GeneratedMessage {
|
||||||
factory Response_Transaction() => create();
|
factory Response_Transaction() => create();
|
||||||
|
|
||||||
|
|
@ -1196,6 +1175,252 @@ class Response_SignedPreKey extends $pb.GeneratedMessage {
|
||||||
void clearSignedPrekeySignature() => $_clearField(3);
|
void clearSignedPrekeySignature() => $_clearField(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Response_PqcPreKey extends $pb.GeneratedMessage {
|
||||||
|
factory Response_PqcPreKey({
|
||||||
|
$fixnum.Int64? eccPreKeyId,
|
||||||
|
$core.List<$core.int>? eccPreKey,
|
||||||
|
$fixnum.Int64? kyberPreKeyId,
|
||||||
|
$core.List<$core.int>? kyberPreKey,
|
||||||
|
$core.List<$core.int>? kyberPreKeySignature,
|
||||||
|
}) {
|
||||||
|
final result = create();
|
||||||
|
if (eccPreKeyId != null) result.eccPreKeyId = eccPreKeyId;
|
||||||
|
if (eccPreKey != null) result.eccPreKey = eccPreKey;
|
||||||
|
if (kyberPreKeyId != null) result.kyberPreKeyId = kyberPreKeyId;
|
||||||
|
if (kyberPreKey != null) result.kyberPreKey = kyberPreKey;
|
||||||
|
if (kyberPreKeySignature != null)
|
||||||
|
result.kyberPreKeySignature = kyberPreKeySignature;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Response_PqcPreKey._();
|
||||||
|
|
||||||
|
factory Response_PqcPreKey.fromBuffer($core.List<$core.int> data,
|
||||||
|
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
|
create()..mergeFromBuffer(data, registry);
|
||||||
|
factory Response_PqcPreKey.fromJson($core.String json,
|
||||||
|
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
|
create()..mergeFromJson(json, registry);
|
||||||
|
|
||||||
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||||
|
_omitMessageNames ? '' : 'Response.PqcPreKey',
|
||||||
|
package:
|
||||||
|
const $pb.PackageName(_omitMessageNames ? '' : 'server_to_client'),
|
||||||
|
createEmptyInstance: create)
|
||||||
|
..aInt64(1, _omitFieldNames ? '' : 'eccPreKeyId')
|
||||||
|
..a<$core.List<$core.int>>(
|
||||||
|
2, _omitFieldNames ? '' : 'eccPreKey', $pb.PbFieldType.OY)
|
||||||
|
..aInt64(3, _omitFieldNames ? '' : 'kyberPreKeyId')
|
||||||
|
..a<$core.List<$core.int>>(
|
||||||
|
4, _omitFieldNames ? '' : 'kyberPreKey', $pb.PbFieldType.OY)
|
||||||
|
..a<$core.List<$core.int>>(
|
||||||
|
5, _omitFieldNames ? '' : 'kyberPreKeySignature', $pb.PbFieldType.OY)
|
||||||
|
..hasRequiredFields = false;
|
||||||
|
|
||||||
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
Response_PqcPreKey clone() => deepCopy();
|
||||||
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
Response_PqcPreKey copyWith(void Function(Response_PqcPreKey) updates) =>
|
||||||
|
super.copyWith((message) => updates(message as Response_PqcPreKey))
|
||||||
|
as Response_PqcPreKey;
|
||||||
|
|
||||||
|
@$core.override
|
||||||
|
$pb.BuilderInfo get info_ => _i;
|
||||||
|
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static Response_PqcPreKey create() => Response_PqcPreKey._();
|
||||||
|
@$core.override
|
||||||
|
Response_PqcPreKey createEmptyInstance() => create();
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static Response_PqcPreKey getDefault() => _defaultInstance ??=
|
||||||
|
$pb.GeneratedMessage.$_defaultFor<Response_PqcPreKey>(create);
|
||||||
|
static Response_PqcPreKey? _defaultInstance;
|
||||||
|
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$fixnum.Int64 get eccPreKeyId => $_getI64(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
set eccPreKeyId($fixnum.Int64 value) => $_setInt64(0, value);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$core.bool hasEccPreKeyId() => $_has(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
void clearEccPreKeyId() => $_clearField(1);
|
||||||
|
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.List<$core.int> get eccPreKey => $_getN(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
set eccPreKey($core.List<$core.int> value) => $_setBytes(1, value);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.bool hasEccPreKey() => $_has(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
void clearEccPreKey() => $_clearField(2);
|
||||||
|
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$fixnum.Int64 get kyberPreKeyId => $_getI64(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
set kyberPreKeyId($fixnum.Int64 value) => $_setInt64(2, value);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$core.bool hasKyberPreKeyId() => $_has(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
void clearKyberPreKeyId() => $_clearField(3);
|
||||||
|
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
$core.List<$core.int> get kyberPreKey => $_getN(3);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
set kyberPreKey($core.List<$core.int> value) => $_setBytes(3, value);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
$core.bool hasKyberPreKey() => $_has(3);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
void clearKyberPreKey() => $_clearField(4);
|
||||||
|
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
$core.List<$core.int> get kyberPreKeySignature => $_getN(4);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
set kyberPreKeySignature($core.List<$core.int> value) => $_setBytes(4, value);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
$core.bool hasKyberPreKeySignature() => $_has(4);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
void clearKyberPreKeySignature() => $_clearField(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Response_PqcBundle extends $pb.GeneratedMessage {
|
||||||
|
factory Response_PqcBundle({
|
||||||
|
$fixnum.Int64? eccSignedPrekeyId,
|
||||||
|
$core.List<$core.int>? eccSignedPrekey,
|
||||||
|
$core.List<$core.int>? eccSignedPrekeySignature,
|
||||||
|
$fixnum.Int64? kyberSignedPrekeyId,
|
||||||
|
$core.List<$core.int>? kyberSignedPrekey,
|
||||||
|
$core.List<$core.int>? kyberSignedPrekeySignature,
|
||||||
|
Response_PqcPreKey? prekey,
|
||||||
|
}) {
|
||||||
|
final result = create();
|
||||||
|
if (eccSignedPrekeyId != null) result.eccSignedPrekeyId = eccSignedPrekeyId;
|
||||||
|
if (eccSignedPrekey != null) result.eccSignedPrekey = eccSignedPrekey;
|
||||||
|
if (eccSignedPrekeySignature != null)
|
||||||
|
result.eccSignedPrekeySignature = eccSignedPrekeySignature;
|
||||||
|
if (kyberSignedPrekeyId != null)
|
||||||
|
result.kyberSignedPrekeyId = kyberSignedPrekeyId;
|
||||||
|
if (kyberSignedPrekey != null) result.kyberSignedPrekey = kyberSignedPrekey;
|
||||||
|
if (kyberSignedPrekeySignature != null)
|
||||||
|
result.kyberSignedPrekeySignature = kyberSignedPrekeySignature;
|
||||||
|
if (prekey != null) result.prekey = prekey;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Response_PqcBundle._();
|
||||||
|
|
||||||
|
factory Response_PqcBundle.fromBuffer($core.List<$core.int> data,
|
||||||
|
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
|
create()..mergeFromBuffer(data, registry);
|
||||||
|
factory Response_PqcBundle.fromJson($core.String json,
|
||||||
|
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
|
create()..mergeFromJson(json, registry);
|
||||||
|
|
||||||
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||||
|
_omitMessageNames ? '' : 'Response.PqcBundle',
|
||||||
|
package:
|
||||||
|
const $pb.PackageName(_omitMessageNames ? '' : 'server_to_client'),
|
||||||
|
createEmptyInstance: create)
|
||||||
|
..aInt64(1, _omitFieldNames ? '' : 'eccSignedPrekeyId')
|
||||||
|
..a<$core.List<$core.int>>(
|
||||||
|
2, _omitFieldNames ? '' : 'eccSignedPrekey', $pb.PbFieldType.OY)
|
||||||
|
..a<$core.List<$core.int>>(3,
|
||||||
|
_omitFieldNames ? '' : 'eccSignedPrekeySignature', $pb.PbFieldType.OY)
|
||||||
|
..aInt64(4, _omitFieldNames ? '' : 'kyberSignedPrekeyId')
|
||||||
|
..a<$core.List<$core.int>>(
|
||||||
|
5, _omitFieldNames ? '' : 'kyberSignedPrekey', $pb.PbFieldType.OY)
|
||||||
|
..a<$core.List<$core.int>>(6,
|
||||||
|
_omitFieldNames ? '' : 'kyberSignedPrekeySignature', $pb.PbFieldType.OY)
|
||||||
|
..aOM<Response_PqcPreKey>(7, _omitFieldNames ? '' : 'prekey',
|
||||||
|
subBuilder: Response_PqcPreKey.create)
|
||||||
|
..hasRequiredFields = false;
|
||||||
|
|
||||||
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
Response_PqcBundle clone() => deepCopy();
|
||||||
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
Response_PqcBundle copyWith(void Function(Response_PqcBundle) updates) =>
|
||||||
|
super.copyWith((message) => updates(message as Response_PqcBundle))
|
||||||
|
as Response_PqcBundle;
|
||||||
|
|
||||||
|
@$core.override
|
||||||
|
$pb.BuilderInfo get info_ => _i;
|
||||||
|
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static Response_PqcBundle create() => Response_PqcBundle._();
|
||||||
|
@$core.override
|
||||||
|
Response_PqcBundle createEmptyInstance() => create();
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static Response_PqcBundle getDefault() => _defaultInstance ??=
|
||||||
|
$pb.GeneratedMessage.$_defaultFor<Response_PqcBundle>(create);
|
||||||
|
static Response_PqcBundle? _defaultInstance;
|
||||||
|
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$fixnum.Int64 get eccSignedPrekeyId => $_getI64(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
set eccSignedPrekeyId($fixnum.Int64 value) => $_setInt64(0, value);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$core.bool hasEccSignedPrekeyId() => $_has(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
void clearEccSignedPrekeyId() => $_clearField(1);
|
||||||
|
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.List<$core.int> get eccSignedPrekey => $_getN(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
set eccSignedPrekey($core.List<$core.int> value) => $_setBytes(1, value);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.bool hasEccSignedPrekey() => $_has(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
void clearEccSignedPrekey() => $_clearField(2);
|
||||||
|
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$core.List<$core.int> get eccSignedPrekeySignature => $_getN(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
set eccSignedPrekeySignature($core.List<$core.int> value) =>
|
||||||
|
$_setBytes(2, value);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$core.bool hasEccSignedPrekeySignature() => $_has(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
void clearEccSignedPrekeySignature() => $_clearField(3);
|
||||||
|
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
$fixnum.Int64 get kyberSignedPrekeyId => $_getI64(3);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
set kyberSignedPrekeyId($fixnum.Int64 value) => $_setInt64(3, value);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
$core.bool hasKyberSignedPrekeyId() => $_has(3);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
void clearKyberSignedPrekeyId() => $_clearField(4);
|
||||||
|
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
$core.List<$core.int> get kyberSignedPrekey => $_getN(4);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
set kyberSignedPrekey($core.List<$core.int> value) => $_setBytes(4, value);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
$core.bool hasKyberSignedPrekey() => $_has(4);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
void clearKyberSignedPrekey() => $_clearField(5);
|
||||||
|
|
||||||
|
@$pb.TagNumber(6)
|
||||||
|
$core.List<$core.int> get kyberSignedPrekeySignature => $_getN(5);
|
||||||
|
@$pb.TagNumber(6)
|
||||||
|
set kyberSignedPrekeySignature($core.List<$core.int> value) =>
|
||||||
|
$_setBytes(5, value);
|
||||||
|
@$pb.TagNumber(6)
|
||||||
|
$core.bool hasKyberSignedPrekeySignature() => $_has(5);
|
||||||
|
@$pb.TagNumber(6)
|
||||||
|
void clearKyberSignedPrekeySignature() => $_clearField(6);
|
||||||
|
|
||||||
|
@$pb.TagNumber(7)
|
||||||
|
Response_PqcPreKey get prekey => $_getN(6);
|
||||||
|
@$pb.TagNumber(7)
|
||||||
|
set prekey(Response_PqcPreKey value) => $_setField(7, value);
|
||||||
|
@$pb.TagNumber(7)
|
||||||
|
$core.bool hasPrekey() => $_has(6);
|
||||||
|
@$pb.TagNumber(7)
|
||||||
|
void clearPrekey() => $_clearField(7);
|
||||||
|
@$pb.TagNumber(7)
|
||||||
|
Response_PqcPreKey ensurePrekey() => $_ensure(6);
|
||||||
|
}
|
||||||
|
|
||||||
class Response_UserData extends $pb.GeneratedMessage {
|
class Response_UserData extends $pb.GeneratedMessage {
|
||||||
factory Response_UserData({
|
factory Response_UserData({
|
||||||
$fixnum.Int64? userId,
|
$fixnum.Int64? userId,
|
||||||
|
|
@ -1206,6 +1431,7 @@ class Response_UserData extends $pb.GeneratedMessage {
|
||||||
$fixnum.Int64? signedPrekeyId,
|
$fixnum.Int64? signedPrekeyId,
|
||||||
$core.List<$core.int>? username,
|
$core.List<$core.int>? username,
|
||||||
$fixnum.Int64? registrationId,
|
$fixnum.Int64? registrationId,
|
||||||
|
Response_PqcBundle? pqcBundle,
|
||||||
}) {
|
}) {
|
||||||
final result = create();
|
final result = create();
|
||||||
if (userId != null) result.userId = userId;
|
if (userId != null) result.userId = userId;
|
||||||
|
|
@ -1217,6 +1443,7 @@ class Response_UserData extends $pb.GeneratedMessage {
|
||||||
if (signedPrekeyId != null) result.signedPrekeyId = signedPrekeyId;
|
if (signedPrekeyId != null) result.signedPrekeyId = signedPrekeyId;
|
||||||
if (username != null) result.username = username;
|
if (username != null) result.username = username;
|
||||||
if (registrationId != null) result.registrationId = registrationId;
|
if (registrationId != null) result.registrationId = registrationId;
|
||||||
|
if (pqcBundle != null) result.pqcBundle = pqcBundle;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1247,6 +1474,8 @@ class Response_UserData extends $pb.GeneratedMessage {
|
||||||
..a<$core.List<$core.int>>(
|
..a<$core.List<$core.int>>(
|
||||||
7, _omitFieldNames ? '' : 'username', $pb.PbFieldType.OY)
|
7, _omitFieldNames ? '' : 'username', $pb.PbFieldType.OY)
|
||||||
..aInt64(8, _omitFieldNames ? '' : 'registrationId')
|
..aInt64(8, _omitFieldNames ? '' : 'registrationId')
|
||||||
|
..aOM<Response_PqcBundle>(9, _omitFieldNames ? '' : 'pqcBundle',
|
||||||
|
subBuilder: Response_PqcBundle.create)
|
||||||
..hasRequiredFields = false;
|
..hasRequiredFields = false;
|
||||||
|
|
||||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
|
@ -1334,6 +1563,17 @@ class Response_UserData extends $pb.GeneratedMessage {
|
||||||
$core.bool hasRegistrationId() => $_has(7);
|
$core.bool hasRegistrationId() => $_has(7);
|
||||||
@$pb.TagNumber(8)
|
@$pb.TagNumber(8)
|
||||||
void clearRegistrationId() => $_clearField(8);
|
void clearRegistrationId() => $_clearField(8);
|
||||||
|
|
||||||
|
@$pb.TagNumber(9)
|
||||||
|
Response_PqcBundle get pqcBundle => $_getN(8);
|
||||||
|
@$pb.TagNumber(9)
|
||||||
|
set pqcBundle(Response_PqcBundle value) => $_setField(9, value);
|
||||||
|
@$pb.TagNumber(9)
|
||||||
|
$core.bool hasPqcBundle() => $_has(8);
|
||||||
|
@$pb.TagNumber(9)
|
||||||
|
void clearPqcBundle() => $_clearField(9);
|
||||||
|
@$pb.TagNumber(9)
|
||||||
|
Response_PqcBundle ensurePqcBundle() => $_ensure(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Response_UploadToken extends $pb.GeneratedMessage {
|
class Response_UploadToken extends $pb.GeneratedMessage {
|
||||||
|
|
@ -2074,11 +2314,9 @@ enum Response_Ok_Ok {
|
||||||
uploadtoken,
|
uploadtoken,
|
||||||
userdata,
|
userdata,
|
||||||
authtoken,
|
authtoken,
|
||||||
deprecated7,
|
|
||||||
authenticated,
|
authenticated,
|
||||||
plans,
|
plans,
|
||||||
planballance,
|
planballance,
|
||||||
deprecated11,
|
|
||||||
addaccountsinvites,
|
addaccountsinvites,
|
||||||
downloadtokens,
|
downloadtokens,
|
||||||
signedprekey,
|
signedprekey,
|
||||||
|
|
@ -2100,11 +2338,9 @@ class Response_Ok extends $pb.GeneratedMessage {
|
||||||
Response_UploadToken? uploadtoken,
|
Response_UploadToken? uploadtoken,
|
||||||
Response_UserData? userdata,
|
Response_UserData? userdata,
|
||||||
$core.List<$core.int>? authtoken,
|
$core.List<$core.int>? authtoken,
|
||||||
Response_Deprecated? deprecated7,
|
|
||||||
Response_Authenticated? authenticated,
|
Response_Authenticated? authenticated,
|
||||||
Response_Plans? plans,
|
Response_Plans? plans,
|
||||||
Response_PlanBallance? planballance,
|
Response_PlanBallance? planballance,
|
||||||
Response_Deprecated? deprecated11,
|
|
||||||
Response_AddAccountsInvites? addaccountsinvites,
|
Response_AddAccountsInvites? addaccountsinvites,
|
||||||
Response_DownloadTokens? downloadtokens,
|
Response_DownloadTokens? downloadtokens,
|
||||||
Response_SignedPreKey? signedprekey,
|
Response_SignedPreKey? signedprekey,
|
||||||
|
|
@ -2123,11 +2359,9 @@ class Response_Ok extends $pb.GeneratedMessage {
|
||||||
if (uploadtoken != null) result.uploadtoken = uploadtoken;
|
if (uploadtoken != null) result.uploadtoken = uploadtoken;
|
||||||
if (userdata != null) result.userdata = userdata;
|
if (userdata != null) result.userdata = userdata;
|
||||||
if (authtoken != null) result.authtoken = authtoken;
|
if (authtoken != null) result.authtoken = authtoken;
|
||||||
if (deprecated7 != null) result.deprecated7 = deprecated7;
|
|
||||||
if (authenticated != null) result.authenticated = authenticated;
|
if (authenticated != null) result.authenticated = authenticated;
|
||||||
if (plans != null) result.plans = plans;
|
if (plans != null) result.plans = plans;
|
||||||
if (planballance != null) result.planballance = planballance;
|
if (planballance != null) result.planballance = planballance;
|
||||||
if (deprecated11 != null) result.deprecated11 = deprecated11;
|
|
||||||
if (addaccountsinvites != null)
|
if (addaccountsinvites != null)
|
||||||
result.addaccountsinvites = addaccountsinvites;
|
result.addaccountsinvites = addaccountsinvites;
|
||||||
if (downloadtokens != null) result.downloadtokens = downloadtokens;
|
if (downloadtokens != null) result.downloadtokens = downloadtokens;
|
||||||
|
|
@ -2162,11 +2396,9 @@ class Response_Ok extends $pb.GeneratedMessage {
|
||||||
4: Response_Ok_Ok.uploadtoken,
|
4: Response_Ok_Ok.uploadtoken,
|
||||||
5: Response_Ok_Ok.userdata,
|
5: Response_Ok_Ok.userdata,
|
||||||
6: Response_Ok_Ok.authtoken,
|
6: Response_Ok_Ok.authtoken,
|
||||||
7: Response_Ok_Ok.deprecated7,
|
|
||||||
8: Response_Ok_Ok.authenticated,
|
8: Response_Ok_Ok.authenticated,
|
||||||
9: Response_Ok_Ok.plans,
|
9: Response_Ok_Ok.plans,
|
||||||
10: Response_Ok_Ok.planballance,
|
10: Response_Ok_Ok.planballance,
|
||||||
11: Response_Ok_Ok.deprecated11,
|
|
||||||
12: Response_Ok_Ok.addaccountsinvites,
|
12: Response_Ok_Ok.addaccountsinvites,
|
||||||
13: Response_Ok_Ok.downloadtokens,
|
13: Response_Ok_Ok.downloadtokens,
|
||||||
14: Response_Ok_Ok.signedprekey,
|
14: Response_Ok_Ok.signedprekey,
|
||||||
|
|
@ -2184,29 +2416,8 @@ class Response_Ok extends $pb.GeneratedMessage {
|
||||||
package:
|
package:
|
||||||
const $pb.PackageName(_omitMessageNames ? '' : 'server_to_client'),
|
const $pb.PackageName(_omitMessageNames ? '' : 'server_to_client'),
|
||||||
createEmptyInstance: create)
|
createEmptyInstance: create)
|
||||||
..oo(0, [
|
..oo(
|
||||||
1,
|
0, [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21])
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4,
|
|
||||||
5,
|
|
||||||
6,
|
|
||||||
7,
|
|
||||||
8,
|
|
||||||
9,
|
|
||||||
10,
|
|
||||||
11,
|
|
||||||
12,
|
|
||||||
13,
|
|
||||||
14,
|
|
||||||
15,
|
|
||||||
16,
|
|
||||||
17,
|
|
||||||
18,
|
|
||||||
19,
|
|
||||||
20,
|
|
||||||
21
|
|
||||||
])
|
|
||||||
..aOB(1, _omitFieldNames ? '' : 'None', protoName: 'None')
|
..aOB(1, _omitFieldNames ? '' : 'None', protoName: 'None')
|
||||||
..aInt64(2, _omitFieldNames ? '' : 'userid')
|
..aInt64(2, _omitFieldNames ? '' : 'userid')
|
||||||
..a<$core.List<$core.int>>(
|
..a<$core.List<$core.int>>(
|
||||||
|
|
@ -2217,16 +2428,12 @@ class Response_Ok extends $pb.GeneratedMessage {
|
||||||
subBuilder: Response_UserData.create)
|
subBuilder: Response_UserData.create)
|
||||||
..a<$core.List<$core.int>>(
|
..a<$core.List<$core.int>>(
|
||||||
6, _omitFieldNames ? '' : 'authtoken', $pb.PbFieldType.OY)
|
6, _omitFieldNames ? '' : 'authtoken', $pb.PbFieldType.OY)
|
||||||
..aOM<Response_Deprecated>(7, _omitFieldNames ? '' : 'deprecated7',
|
|
||||||
protoName: 'deprecated_7', subBuilder: Response_Deprecated.create)
|
|
||||||
..aOM<Response_Authenticated>(8, _omitFieldNames ? '' : 'authenticated',
|
..aOM<Response_Authenticated>(8, _omitFieldNames ? '' : 'authenticated',
|
||||||
subBuilder: Response_Authenticated.create)
|
subBuilder: Response_Authenticated.create)
|
||||||
..aOM<Response_Plans>(9, _omitFieldNames ? '' : 'plans',
|
..aOM<Response_Plans>(9, _omitFieldNames ? '' : 'plans',
|
||||||
subBuilder: Response_Plans.create)
|
subBuilder: Response_Plans.create)
|
||||||
..aOM<Response_PlanBallance>(10, _omitFieldNames ? '' : 'planballance',
|
..aOM<Response_PlanBallance>(10, _omitFieldNames ? '' : 'planballance',
|
||||||
subBuilder: Response_PlanBallance.create)
|
subBuilder: Response_PlanBallance.create)
|
||||||
..aOM<Response_Deprecated>(11, _omitFieldNames ? '' : 'deprecated11',
|
|
||||||
protoName: 'deprecated_11', subBuilder: Response_Deprecated.create)
|
|
||||||
..aOM<Response_AddAccountsInvites>(
|
..aOM<Response_AddAccountsInvites>(
|
||||||
12, _omitFieldNames ? '' : 'addaccountsinvites',
|
12, _omitFieldNames ? '' : 'addaccountsinvites',
|
||||||
subBuilder: Response_AddAccountsInvites.create)
|
subBuilder: Response_AddAccountsInvites.create)
|
||||||
|
|
@ -2279,11 +2486,9 @@ class Response_Ok extends $pb.GeneratedMessage {
|
||||||
@$pb.TagNumber(4)
|
@$pb.TagNumber(4)
|
||||||
@$pb.TagNumber(5)
|
@$pb.TagNumber(5)
|
||||||
@$pb.TagNumber(6)
|
@$pb.TagNumber(6)
|
||||||
@$pb.TagNumber(7)
|
|
||||||
@$pb.TagNumber(8)
|
@$pb.TagNumber(8)
|
||||||
@$pb.TagNumber(9)
|
@$pb.TagNumber(9)
|
||||||
@$pb.TagNumber(10)
|
@$pb.TagNumber(10)
|
||||||
@$pb.TagNumber(11)
|
|
||||||
@$pb.TagNumber(12)
|
@$pb.TagNumber(12)
|
||||||
@$pb.TagNumber(13)
|
@$pb.TagNumber(13)
|
||||||
@$pb.TagNumber(14)
|
@$pb.TagNumber(14)
|
||||||
|
|
@ -2301,11 +2506,9 @@ class Response_Ok extends $pb.GeneratedMessage {
|
||||||
@$pb.TagNumber(4)
|
@$pb.TagNumber(4)
|
||||||
@$pb.TagNumber(5)
|
@$pb.TagNumber(5)
|
||||||
@$pb.TagNumber(6)
|
@$pb.TagNumber(6)
|
||||||
@$pb.TagNumber(7)
|
|
||||||
@$pb.TagNumber(8)
|
@$pb.TagNumber(8)
|
||||||
@$pb.TagNumber(9)
|
@$pb.TagNumber(9)
|
||||||
@$pb.TagNumber(10)
|
@$pb.TagNumber(10)
|
||||||
@$pb.TagNumber(11)
|
|
||||||
@$pb.TagNumber(12)
|
@$pb.TagNumber(12)
|
||||||
@$pb.TagNumber(13)
|
@$pb.TagNumber(13)
|
||||||
@$pb.TagNumber(14)
|
@$pb.TagNumber(14)
|
||||||
|
|
@ -2376,175 +2579,153 @@ class Response_Ok extends $pb.GeneratedMessage {
|
||||||
@$pb.TagNumber(6)
|
@$pb.TagNumber(6)
|
||||||
void clearAuthtoken() => $_clearField(6);
|
void clearAuthtoken() => $_clearField(6);
|
||||||
|
|
||||||
@$pb.TagNumber(7)
|
|
||||||
Response_Deprecated get deprecated7 => $_getN(6);
|
|
||||||
@$pb.TagNumber(7)
|
|
||||||
set deprecated7(Response_Deprecated value) => $_setField(7, value);
|
|
||||||
@$pb.TagNumber(7)
|
|
||||||
$core.bool hasDeprecated7() => $_has(6);
|
|
||||||
@$pb.TagNumber(7)
|
|
||||||
void clearDeprecated7() => $_clearField(7);
|
|
||||||
@$pb.TagNumber(7)
|
|
||||||
Response_Deprecated ensureDeprecated7() => $_ensure(6);
|
|
||||||
|
|
||||||
@$pb.TagNumber(8)
|
@$pb.TagNumber(8)
|
||||||
Response_Authenticated get authenticated => $_getN(7);
|
Response_Authenticated get authenticated => $_getN(6);
|
||||||
@$pb.TagNumber(8)
|
@$pb.TagNumber(8)
|
||||||
set authenticated(Response_Authenticated value) => $_setField(8, value);
|
set authenticated(Response_Authenticated value) => $_setField(8, value);
|
||||||
@$pb.TagNumber(8)
|
@$pb.TagNumber(8)
|
||||||
$core.bool hasAuthenticated() => $_has(7);
|
$core.bool hasAuthenticated() => $_has(6);
|
||||||
@$pb.TagNumber(8)
|
@$pb.TagNumber(8)
|
||||||
void clearAuthenticated() => $_clearField(8);
|
void clearAuthenticated() => $_clearField(8);
|
||||||
@$pb.TagNumber(8)
|
@$pb.TagNumber(8)
|
||||||
Response_Authenticated ensureAuthenticated() => $_ensure(7);
|
Response_Authenticated ensureAuthenticated() => $_ensure(6);
|
||||||
|
|
||||||
@$pb.TagNumber(9)
|
@$pb.TagNumber(9)
|
||||||
Response_Plans get plans => $_getN(8);
|
Response_Plans get plans => $_getN(7);
|
||||||
@$pb.TagNumber(9)
|
@$pb.TagNumber(9)
|
||||||
set plans(Response_Plans value) => $_setField(9, value);
|
set plans(Response_Plans value) => $_setField(9, value);
|
||||||
@$pb.TagNumber(9)
|
@$pb.TagNumber(9)
|
||||||
$core.bool hasPlans() => $_has(8);
|
$core.bool hasPlans() => $_has(7);
|
||||||
@$pb.TagNumber(9)
|
@$pb.TagNumber(9)
|
||||||
void clearPlans() => $_clearField(9);
|
void clearPlans() => $_clearField(9);
|
||||||
@$pb.TagNumber(9)
|
@$pb.TagNumber(9)
|
||||||
Response_Plans ensurePlans() => $_ensure(8);
|
Response_Plans ensurePlans() => $_ensure(7);
|
||||||
|
|
||||||
@$pb.TagNumber(10)
|
@$pb.TagNumber(10)
|
||||||
Response_PlanBallance get planballance => $_getN(9);
|
Response_PlanBallance get planballance => $_getN(8);
|
||||||
@$pb.TagNumber(10)
|
@$pb.TagNumber(10)
|
||||||
set planballance(Response_PlanBallance value) => $_setField(10, value);
|
set planballance(Response_PlanBallance value) => $_setField(10, value);
|
||||||
@$pb.TagNumber(10)
|
@$pb.TagNumber(10)
|
||||||
$core.bool hasPlanballance() => $_has(9);
|
$core.bool hasPlanballance() => $_has(8);
|
||||||
@$pb.TagNumber(10)
|
@$pb.TagNumber(10)
|
||||||
void clearPlanballance() => $_clearField(10);
|
void clearPlanballance() => $_clearField(10);
|
||||||
@$pb.TagNumber(10)
|
@$pb.TagNumber(10)
|
||||||
Response_PlanBallance ensurePlanballance() => $_ensure(9);
|
Response_PlanBallance ensurePlanballance() => $_ensure(8);
|
||||||
|
|
||||||
@$pb.TagNumber(11)
|
|
||||||
Response_Deprecated get deprecated11 => $_getN(10);
|
|
||||||
@$pb.TagNumber(11)
|
|
||||||
set deprecated11(Response_Deprecated value) => $_setField(11, value);
|
|
||||||
@$pb.TagNumber(11)
|
|
||||||
$core.bool hasDeprecated11() => $_has(10);
|
|
||||||
@$pb.TagNumber(11)
|
|
||||||
void clearDeprecated11() => $_clearField(11);
|
|
||||||
@$pb.TagNumber(11)
|
|
||||||
Response_Deprecated ensureDeprecated11() => $_ensure(10);
|
|
||||||
|
|
||||||
@$pb.TagNumber(12)
|
@$pb.TagNumber(12)
|
||||||
Response_AddAccountsInvites get addaccountsinvites => $_getN(11);
|
Response_AddAccountsInvites get addaccountsinvites => $_getN(9);
|
||||||
@$pb.TagNumber(12)
|
@$pb.TagNumber(12)
|
||||||
set addaccountsinvites(Response_AddAccountsInvites value) =>
|
set addaccountsinvites(Response_AddAccountsInvites value) =>
|
||||||
$_setField(12, value);
|
$_setField(12, value);
|
||||||
@$pb.TagNumber(12)
|
@$pb.TagNumber(12)
|
||||||
$core.bool hasAddaccountsinvites() => $_has(11);
|
$core.bool hasAddaccountsinvites() => $_has(9);
|
||||||
@$pb.TagNumber(12)
|
@$pb.TagNumber(12)
|
||||||
void clearAddaccountsinvites() => $_clearField(12);
|
void clearAddaccountsinvites() => $_clearField(12);
|
||||||
@$pb.TagNumber(12)
|
@$pb.TagNumber(12)
|
||||||
Response_AddAccountsInvites ensureAddaccountsinvites() => $_ensure(11);
|
Response_AddAccountsInvites ensureAddaccountsinvites() => $_ensure(9);
|
||||||
|
|
||||||
@$pb.TagNumber(13)
|
@$pb.TagNumber(13)
|
||||||
Response_DownloadTokens get downloadtokens => $_getN(12);
|
Response_DownloadTokens get downloadtokens => $_getN(10);
|
||||||
@$pb.TagNumber(13)
|
@$pb.TagNumber(13)
|
||||||
set downloadtokens(Response_DownloadTokens value) => $_setField(13, value);
|
set downloadtokens(Response_DownloadTokens value) => $_setField(13, value);
|
||||||
@$pb.TagNumber(13)
|
@$pb.TagNumber(13)
|
||||||
$core.bool hasDownloadtokens() => $_has(12);
|
$core.bool hasDownloadtokens() => $_has(10);
|
||||||
@$pb.TagNumber(13)
|
@$pb.TagNumber(13)
|
||||||
void clearDownloadtokens() => $_clearField(13);
|
void clearDownloadtokens() => $_clearField(13);
|
||||||
@$pb.TagNumber(13)
|
@$pb.TagNumber(13)
|
||||||
Response_DownloadTokens ensureDownloadtokens() => $_ensure(12);
|
Response_DownloadTokens ensureDownloadtokens() => $_ensure(10);
|
||||||
|
|
||||||
@$pb.TagNumber(14)
|
@$pb.TagNumber(14)
|
||||||
Response_SignedPreKey get signedprekey => $_getN(13);
|
Response_SignedPreKey get signedprekey => $_getN(11);
|
||||||
@$pb.TagNumber(14)
|
@$pb.TagNumber(14)
|
||||||
set signedprekey(Response_SignedPreKey value) => $_setField(14, value);
|
set signedprekey(Response_SignedPreKey value) => $_setField(14, value);
|
||||||
@$pb.TagNumber(14)
|
@$pb.TagNumber(14)
|
||||||
$core.bool hasSignedprekey() => $_has(13);
|
$core.bool hasSignedprekey() => $_has(11);
|
||||||
@$pb.TagNumber(14)
|
@$pb.TagNumber(14)
|
||||||
void clearSignedprekey() => $_clearField(14);
|
void clearSignedprekey() => $_clearField(14);
|
||||||
@$pb.TagNumber(14)
|
@$pb.TagNumber(14)
|
||||||
Response_SignedPreKey ensureSignedprekey() => $_ensure(13);
|
Response_SignedPreKey ensureSignedprekey() => $_ensure(11);
|
||||||
|
|
||||||
@$pb.TagNumber(15)
|
@$pb.TagNumber(15)
|
||||||
Response_ProofOfWork get proofOfWork => $_getN(14);
|
Response_ProofOfWork get proofOfWork => $_getN(12);
|
||||||
@$pb.TagNumber(15)
|
@$pb.TagNumber(15)
|
||||||
set proofOfWork(Response_ProofOfWork value) => $_setField(15, value);
|
set proofOfWork(Response_ProofOfWork value) => $_setField(15, value);
|
||||||
@$pb.TagNumber(15)
|
@$pb.TagNumber(15)
|
||||||
$core.bool hasProofOfWork() => $_has(14);
|
$core.bool hasProofOfWork() => $_has(12);
|
||||||
@$pb.TagNumber(15)
|
@$pb.TagNumber(15)
|
||||||
void clearProofOfWork() => $_clearField(15);
|
void clearProofOfWork() => $_clearField(15);
|
||||||
@$pb.TagNumber(15)
|
@$pb.TagNumber(15)
|
||||||
Response_ProofOfWork ensureProofOfWork() => $_ensure(14);
|
Response_ProofOfWork ensureProofOfWork() => $_ensure(12);
|
||||||
|
|
||||||
@$pb.TagNumber(16)
|
@$pb.TagNumber(16)
|
||||||
$core.List<$core.int> get passwordlessRecoveryServerKey => $_getN(15);
|
$core.List<$core.int> get passwordlessRecoveryServerKey => $_getN(13);
|
||||||
@$pb.TagNumber(16)
|
@$pb.TagNumber(16)
|
||||||
set passwordlessRecoveryServerKey($core.List<$core.int> value) =>
|
set passwordlessRecoveryServerKey($core.List<$core.int> value) =>
|
||||||
$_setBytes(15, value);
|
$_setBytes(13, value);
|
||||||
@$pb.TagNumber(16)
|
@$pb.TagNumber(16)
|
||||||
$core.bool hasPasswordlessRecoveryServerKey() => $_has(15);
|
$core.bool hasPasswordlessRecoveryServerKey() => $_has(13);
|
||||||
@$pb.TagNumber(16)
|
@$pb.TagNumber(16)
|
||||||
void clearPasswordlessRecoveryServerKey() => $_clearField(16);
|
void clearPasswordlessRecoveryServerKey() => $_clearField(16);
|
||||||
|
|
||||||
@$pb.TagNumber(17)
|
@$pb.TagNumber(17)
|
||||||
Response_PasswordlessNotificationMessages
|
Response_PasswordlessNotificationMessages
|
||||||
get passwordlessNotificationMessages => $_getN(16);
|
get passwordlessNotificationMessages => $_getN(14);
|
||||||
@$pb.TagNumber(17)
|
@$pb.TagNumber(17)
|
||||||
set passwordlessNotificationMessages(
|
set passwordlessNotificationMessages(
|
||||||
Response_PasswordlessNotificationMessages value) =>
|
Response_PasswordlessNotificationMessages value) =>
|
||||||
$_setField(17, value);
|
$_setField(17, value);
|
||||||
@$pb.TagNumber(17)
|
@$pb.TagNumber(17)
|
||||||
$core.bool hasPasswordlessNotificationMessages() => $_has(16);
|
$core.bool hasPasswordlessNotificationMessages() => $_has(14);
|
||||||
@$pb.TagNumber(17)
|
@$pb.TagNumber(17)
|
||||||
void clearPasswordlessNotificationMessages() => $_clearField(17);
|
void clearPasswordlessNotificationMessages() => $_clearField(17);
|
||||||
@$pb.TagNumber(17)
|
@$pb.TagNumber(17)
|
||||||
Response_PasswordlessNotificationMessages
|
Response_PasswordlessNotificationMessages
|
||||||
ensurePasswordlessNotificationMessages() => $_ensure(16);
|
ensurePasswordlessNotificationMessages() => $_ensure(14);
|
||||||
|
|
||||||
@$pb.TagNumber(18)
|
@$pb.TagNumber(18)
|
||||||
Response_MemoriesUploadUrls get memoriesUploadUrls => $_getN(17);
|
Response_MemoriesUploadUrls get memoriesUploadUrls => $_getN(15);
|
||||||
@$pb.TagNumber(18)
|
@$pb.TagNumber(18)
|
||||||
set memoriesUploadUrls(Response_MemoriesUploadUrls value) =>
|
set memoriesUploadUrls(Response_MemoriesUploadUrls value) =>
|
||||||
$_setField(18, value);
|
$_setField(18, value);
|
||||||
@$pb.TagNumber(18)
|
@$pb.TagNumber(18)
|
||||||
$core.bool hasMemoriesUploadUrls() => $_has(17);
|
$core.bool hasMemoriesUploadUrls() => $_has(15);
|
||||||
@$pb.TagNumber(18)
|
@$pb.TagNumber(18)
|
||||||
void clearMemoriesUploadUrls() => $_clearField(18);
|
void clearMemoriesUploadUrls() => $_clearField(18);
|
||||||
@$pb.TagNumber(18)
|
@$pb.TagNumber(18)
|
||||||
Response_MemoriesUploadUrls ensureMemoriesUploadUrls() => $_ensure(17);
|
Response_MemoriesUploadUrls ensureMemoriesUploadUrls() => $_ensure(15);
|
||||||
|
|
||||||
@$pb.TagNumber(19)
|
@$pb.TagNumber(19)
|
||||||
Response_MemoriesList get memoriesList => $_getN(18);
|
Response_MemoriesList get memoriesList => $_getN(16);
|
||||||
@$pb.TagNumber(19)
|
@$pb.TagNumber(19)
|
||||||
set memoriesList(Response_MemoriesList value) => $_setField(19, value);
|
set memoriesList(Response_MemoriesList value) => $_setField(19, value);
|
||||||
@$pb.TagNumber(19)
|
@$pb.TagNumber(19)
|
||||||
$core.bool hasMemoriesList() => $_has(18);
|
$core.bool hasMemoriesList() => $_has(16);
|
||||||
@$pb.TagNumber(19)
|
@$pb.TagNumber(19)
|
||||||
void clearMemoriesList() => $_clearField(19);
|
void clearMemoriesList() => $_clearField(19);
|
||||||
@$pb.TagNumber(19)
|
@$pb.TagNumber(19)
|
||||||
Response_MemoriesList ensureMemoriesList() => $_ensure(18);
|
Response_MemoriesList ensureMemoriesList() => $_ensure(16);
|
||||||
|
|
||||||
@$pb.TagNumber(20)
|
@$pb.TagNumber(20)
|
||||||
Response_MemoriesUrl get memoriesUrl => $_getN(19);
|
Response_MemoriesUrl get memoriesUrl => $_getN(17);
|
||||||
@$pb.TagNumber(20)
|
@$pb.TagNumber(20)
|
||||||
set memoriesUrl(Response_MemoriesUrl value) => $_setField(20, value);
|
set memoriesUrl(Response_MemoriesUrl value) => $_setField(20, value);
|
||||||
@$pb.TagNumber(20)
|
@$pb.TagNumber(20)
|
||||||
$core.bool hasMemoriesUrl() => $_has(19);
|
$core.bool hasMemoriesUrl() => $_has(17);
|
||||||
@$pb.TagNumber(20)
|
@$pb.TagNumber(20)
|
||||||
void clearMemoriesUrl() => $_clearField(20);
|
void clearMemoriesUrl() => $_clearField(20);
|
||||||
@$pb.TagNumber(20)
|
@$pb.TagNumber(20)
|
||||||
Response_MemoriesUrl ensureMemoriesUrl() => $_ensure(19);
|
Response_MemoriesUrl ensureMemoriesUrl() => $_ensure(17);
|
||||||
|
|
||||||
@$pb.TagNumber(21)
|
@$pb.TagNumber(21)
|
||||||
Response_MemoriesUsage get memoriesUsage => $_getN(20);
|
Response_MemoriesUsage get memoriesUsage => $_getN(18);
|
||||||
@$pb.TagNumber(21)
|
@$pb.TagNumber(21)
|
||||||
set memoriesUsage(Response_MemoriesUsage value) => $_setField(21, value);
|
set memoriesUsage(Response_MemoriesUsage value) => $_setField(21, value);
|
||||||
@$pb.TagNumber(21)
|
@$pb.TagNumber(21)
|
||||||
$core.bool hasMemoriesUsage() => $_has(20);
|
$core.bool hasMemoriesUsage() => $_has(18);
|
||||||
@$pb.TagNumber(21)
|
@$pb.TagNumber(21)
|
||||||
void clearMemoriesUsage() => $_clearField(21);
|
void clearMemoriesUsage() => $_clearField(21);
|
||||||
@$pb.TagNumber(21)
|
@$pb.TagNumber(21)
|
||||||
Response_MemoriesUsage ensureMemoriesUsage() => $_ensure(20);
|
Response_MemoriesUsage ensureMemoriesUsage() => $_ensure(18);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Response_Response { ok, error, notSet }
|
enum Response_Response { ok, error, notSet }
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,14 @@ const V0$json = {
|
||||||
'9': 0,
|
'9': 0,
|
||||||
'10': 'RequestNewPreKeys'
|
'10': 'RequestNewPreKeys'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'1': 'RequestNewPqcPreKeys',
|
||||||
|
'3': 8,
|
||||||
|
'4': 1,
|
||||||
|
'5': 8,
|
||||||
|
'9': 0,
|
||||||
|
'10': 'RequestNewPqcPreKeys'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'1': 'error',
|
'1': 'error',
|
||||||
'3': 6,
|
'3': 6,
|
||||||
|
|
@ -100,8 +108,9 @@ final $typed_data.Uint8List v0Descriptor = $convert.base64Decode(
|
||||||
'llbnQuUmVzcG9uc2VIAFIIcmVzcG9uc2USPgoKbmV3TWVzc2FnZRgDIAEoCzIcLnNlcnZlcl90'
|
'llbnQuUmVzcG9uc2VIAFIIcmVzcG9uc2USPgoKbmV3TWVzc2FnZRgDIAEoCzIcLnNlcnZlcl90'
|
||||||
'b19jbGllbnQuTmV3TWVzc2FnZUgAUgpuZXdNZXNzYWdlEkEKC25ld01lc3NhZ2VzGAcgASgLMh'
|
'b19jbGllbnQuTmV3TWVzc2FnZUgAUgpuZXdNZXNzYWdlEkEKC25ld01lc3NhZ2VzGAcgASgLMh'
|
||||||
'0uc2VydmVyX3RvX2NsaWVudC5OZXdNZXNzYWdlc0gAUgtuZXdNZXNzYWdlcxIuChFSZXF1ZXN0'
|
'0uc2VydmVyX3RvX2NsaWVudC5OZXdNZXNzYWdlc0gAUgtuZXdNZXNzYWdlcxIuChFSZXF1ZXN0'
|
||||||
'TmV3UHJlS2V5cxgEIAEoCEgAUhFSZXF1ZXN0TmV3UHJlS2V5cxIoCgVlcnJvchgGIAEoDjIQLm'
|
'TmV3UHJlS2V5cxgEIAEoCEgAUhFSZXF1ZXN0TmV3UHJlS2V5cxI0ChRSZXF1ZXN0TmV3UHFjUH'
|
||||||
'Vycm9yLkVycm9yQ29kZUgAUgVlcnJvckIGCgRLaW5k');
|
'JlS2V5cxgIIAEoCEgAUhRSZXF1ZXN0TmV3UHFjUHJlS2V5cxIoCgVlcnJvchgGIAEoDjIQLmVy'
|
||||||
|
'cm9yLkVycm9yQ29kZUgAUgVlcnJvckIGCgRLaW5k');
|
||||||
|
|
||||||
@$core.Deprecated('Use newMessageDescriptor instead')
|
@$core.Deprecated('Use newMessageDescriptor instead')
|
||||||
const NewMessage$json = {
|
const NewMessage$json = {
|
||||||
|
|
@ -167,11 +176,12 @@ const Response$json = {
|
||||||
Response_AddAccountsInvite$json,
|
Response_AddAccountsInvite$json,
|
||||||
Response_AddAccountsInvites$json,
|
Response_AddAccountsInvites$json,
|
||||||
Response_AdditionalAccount$json,
|
Response_AdditionalAccount$json,
|
||||||
Response_Deprecated$json,
|
|
||||||
Response_Transaction$json,
|
Response_Transaction$json,
|
||||||
Response_PlanBallance$json,
|
Response_PlanBallance$json,
|
||||||
Response_PreKey$json,
|
Response_PreKey$json,
|
||||||
Response_SignedPreKey$json,
|
Response_SignedPreKey$json,
|
||||||
|
Response_PqcPreKey$json,
|
||||||
|
Response_PqcBundle$json,
|
||||||
Response_UserData$json,
|
Response_UserData$json,
|
||||||
Response_UploadToken$json,
|
Response_UploadToken$json,
|
||||||
Response_DownloadTokens$json,
|
Response_DownloadTokens$json,
|
||||||
|
|
@ -306,11 +316,6 @@ const Response_AdditionalAccount$json = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
@$core.Deprecated('Use responseDescriptor instead')
|
|
||||||
const Response_Deprecated$json = {
|
|
||||||
'1': 'Deprecated',
|
|
||||||
};
|
|
||||||
|
|
||||||
@$core.Deprecated('Use responseDescriptor instead')
|
@$core.Deprecated('Use responseDescriptor instead')
|
||||||
const Response_Transaction$json = {
|
const Response_Transaction$json = {
|
||||||
'1': 'Transaction',
|
'1': 'Transaction',
|
||||||
|
|
@ -420,6 +425,86 @@ const Response_SignedPreKey$json = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@$core.Deprecated('Use responseDescriptor instead')
|
||||||
|
const Response_PqcPreKey$json = {
|
||||||
|
'1': 'PqcPreKey',
|
||||||
|
'2': [
|
||||||
|
{'1': 'ecc_pre_key_id', '3': 1, '4': 1, '5': 3, '10': 'eccPreKeyId'},
|
||||||
|
{'1': 'ecc_pre_key', '3': 2, '4': 1, '5': 12, '10': 'eccPreKey'},
|
||||||
|
{'1': 'kyber_pre_key_id', '3': 3, '4': 1, '5': 3, '10': 'kyberPreKeyId'},
|
||||||
|
{'1': 'kyber_pre_key', '3': 4, '4': 1, '5': 12, '10': 'kyberPreKey'},
|
||||||
|
{
|
||||||
|
'1': 'kyber_pre_key_signature',
|
||||||
|
'3': 5,
|
||||||
|
'4': 1,
|
||||||
|
'5': 12,
|
||||||
|
'10': 'kyberPreKeySignature'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
@$core.Deprecated('Use responseDescriptor instead')
|
||||||
|
const Response_PqcBundle$json = {
|
||||||
|
'1': 'PqcBundle',
|
||||||
|
'2': [
|
||||||
|
{
|
||||||
|
'1': 'ecc_signed_prekey_id',
|
||||||
|
'3': 1,
|
||||||
|
'4': 1,
|
||||||
|
'5': 3,
|
||||||
|
'10': 'eccSignedPrekeyId'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'1': 'ecc_signed_prekey',
|
||||||
|
'3': 2,
|
||||||
|
'4': 1,
|
||||||
|
'5': 12,
|
||||||
|
'10': 'eccSignedPrekey'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'1': 'ecc_signed_prekey_signature',
|
||||||
|
'3': 3,
|
||||||
|
'4': 1,
|
||||||
|
'5': 12,
|
||||||
|
'10': 'eccSignedPrekeySignature'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'1': 'kyber_signed_prekey_id',
|
||||||
|
'3': 4,
|
||||||
|
'4': 1,
|
||||||
|
'5': 3,
|
||||||
|
'10': 'kyberSignedPrekeyId'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'1': 'kyber_signed_prekey',
|
||||||
|
'3': 5,
|
||||||
|
'4': 1,
|
||||||
|
'5': 12,
|
||||||
|
'10': 'kyberSignedPrekey'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'1': 'kyber_signed_prekey_signature',
|
||||||
|
'3': 6,
|
||||||
|
'4': 1,
|
||||||
|
'5': 12,
|
||||||
|
'10': 'kyberSignedPrekeySignature'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'1': 'prekey',
|
||||||
|
'3': 7,
|
||||||
|
'4': 1,
|
||||||
|
'5': 11,
|
||||||
|
'6': '.server_to_client.Response.PqcPreKey',
|
||||||
|
'9': 0,
|
||||||
|
'10': 'prekey',
|
||||||
|
'17': true
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'8': [
|
||||||
|
{'1': '_prekey'},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
@$core.Deprecated('Use responseDescriptor instead')
|
@$core.Deprecated('Use responseDescriptor instead')
|
||||||
const Response_UserData$json = {
|
const Response_UserData$json = {
|
||||||
'1': 'UserData',
|
'1': 'UserData',
|
||||||
|
|
@ -487,6 +572,16 @@ const Response_UserData$json = {
|
||||||
'10': 'registrationId',
|
'10': 'registrationId',
|
||||||
'17': true
|
'17': true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'1': 'pqc_bundle',
|
||||||
|
'3': 9,
|
||||||
|
'4': 1,
|
||||||
|
'5': 11,
|
||||||
|
'6': '.server_to_client.Response.PqcBundle',
|
||||||
|
'9': 6,
|
||||||
|
'10': 'pqcBundle',
|
||||||
|
'17': true
|
||||||
|
},
|
||||||
],
|
],
|
||||||
'8': [
|
'8': [
|
||||||
{'1': '_username'},
|
{'1': '_username'},
|
||||||
|
|
@ -495,6 +590,7 @@ const Response_UserData$json = {
|
||||||
{'1': '_signed_prekey_signature'},
|
{'1': '_signed_prekey_signature'},
|
||||||
{'1': '_signed_prekey_id'},
|
{'1': '_signed_prekey_id'},
|
||||||
{'1': '_registration_id'},
|
{'1': '_registration_id'},
|
||||||
|
{'1': '_pqc_bundle'},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -687,15 +783,6 @@ const Response_Ok$json = {
|
||||||
'10': 'userdata'
|
'10': 'userdata'
|
||||||
},
|
},
|
||||||
{'1': 'authtoken', '3': 6, '4': 1, '5': 12, '9': 0, '10': 'authtoken'},
|
{'1': 'authtoken', '3': 6, '4': 1, '5': 12, '9': 0, '10': 'authtoken'},
|
||||||
{
|
|
||||||
'1': 'deprecated_7',
|
|
||||||
'3': 7,
|
|
||||||
'4': 1,
|
|
||||||
'5': 11,
|
|
||||||
'6': '.server_to_client.Response.Deprecated',
|
|
||||||
'9': 0,
|
|
||||||
'10': 'deprecated7'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
'1': 'authenticated',
|
'1': 'authenticated',
|
||||||
'3': 8,
|
'3': 8,
|
||||||
|
|
@ -723,15 +810,6 @@ const Response_Ok$json = {
|
||||||
'9': 0,
|
'9': 0,
|
||||||
'10': 'planballance'
|
'10': 'planballance'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
'1': 'deprecated_11',
|
|
||||||
'3': 11,
|
|
||||||
'4': 1,
|
|
||||||
'5': 11,
|
|
||||||
'6': '.server_to_client.Response.Deprecated',
|
|
||||||
'9': 0,
|
|
||||||
'10': 'deprecated11'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
'1': 'addaccountsinvites',
|
'1': 'addaccountsinvites',
|
||||||
'3': 12,
|
'3': 12,
|
||||||
|
|
@ -825,6 +903,10 @@ const Response_Ok$json = {
|
||||||
'8': [
|
'8': [
|
||||||
{'1': 'Ok'},
|
{'1': 'Ok'},
|
||||||
],
|
],
|
||||||
|
'9': [
|
||||||
|
{'1': 7, '2': 8},
|
||||||
|
{'1': 11, '2': 12},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `Response`. Decode as a `google.protobuf.DescriptorProto`.
|
/// Descriptor for `Response`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
|
|
@ -846,79 +928,89 @@ final $typed_data.Uint8List responseDescriptor = $convert.base64Decode(
|
||||||
'cGxhbklkEh8KC2ludml0ZV9jb2RlGAIgASgJUgppbnZpdGVDb2RlGlwKEkFkZEFjY291bnRzSW'
|
'cGxhbklkEh8KC2ludml0ZV9jb2RlGAIgASgJUgppbnZpdGVDb2RlGlwKEkFkZEFjY291bnRzSW'
|
||||||
'52aXRlcxJGCgdpbnZpdGVzGAEgAygLMiwuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5BZGRB'
|
'52aXRlcxJGCgdpbnZpdGVzGAEgAygLMiwuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5BZGRB'
|
||||||
'Y2NvdW50c0ludml0ZVIHaW52aXRlcxpFChFBZGRpdGlvbmFsQWNjb3VudBIXCgd1c2VyX2lkGA'
|
'Y2NvdW50c0ludml0ZVIHaW52aXRlcxpFChFBZGRpdGlvbmFsQWNjb3VudBIXCgd1c2VyX2lkGA'
|
||||||
'EgASgDUgZ1c2VySWQSFwoHcGxhbl9pZBgDIAEoCVIGcGxhbklkGgwKCkRlcHJlY2F0ZWQaDQoL'
|
'EgASgDUgZ1c2VySWQSFwoHcGxhbl9pZBgDIAEoCVIGcGxhbklkGg0KC1RyYW5zYWN0aW9uGpcF'
|
||||||
'VHJhbnNhY3Rpb24alwUKDFBsYW5CYWxsYW5jZRJACh11c2VkX2RhaWx5X21lZGlhX3VwbG9hZF'
|
'CgxQbGFuQmFsbGFuY2USQAoddXNlZF9kYWlseV9tZWRpYV91cGxvYWRfbGltaXQYASABKANSGX'
|
||||||
'9saW1pdBgBIAEoA1IZdXNlZERhaWx5TWVkaWFVcGxvYWRMaW1pdBI+Chx1c2VkX3VwbG9hZF9t'
|
'VzZWREYWlseU1lZGlhVXBsb2FkTGltaXQSPgocdXNlZF91cGxvYWRfbWVkaWFfc2l6ZV9saW1p'
|
||||||
'ZWRpYV9zaXplX2xpbWl0GAIgASgDUhh1c2VkVXBsb2FkTWVkaWFTaXplTGltaXQSMwoTcGF5bW'
|
'dBgCIAEoA1IYdXNlZFVwbG9hZE1lZGlhU2l6ZUxpbWl0EjMKE3BheW1lbnRfcGVyaW9kX2RheX'
|
||||||
'VudF9wZXJpb2RfZGF5cxgDIAEoA0gAUhFwYXltZW50UGVyaW9kRGF5c4gBARJLCiBsYXN0X3Bh'
|
'MYAyABKANIAFIRcGF5bWVudFBlcmlvZERheXOIAQESSwogbGFzdF9wYXltZW50X2RvbmVfdW5p'
|
||||||
'eW1lbnRfZG9uZV91bml4X3RpbWVzdGFtcBgEIAEoA0gBUhxsYXN0UGF5bWVudERvbmVVbml4VG'
|
'eF90aW1lc3RhbXAYBCABKANIAVIcbGFzdFBheW1lbnREb25lVW5peFRpbWVzdGFtcIgBARJKCg'
|
||||||
'ltZXN0YW1wiAEBEkoKDHRyYW5zYWN0aW9ucxgFIAMoCzImLnNlcnZlcl90b19jbGllbnQuUmVz'
|
'x0cmFuc2FjdGlvbnMYBSADKAsyJi5zZXJ2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLlRyYW5zYWN0'
|
||||||
'cG9uc2UuVHJhbnNhY3Rpb25SDHRyYW5zYWN0aW9ucxJdChNhZGRpdGlvbmFsX2FjY291bnRzGA'
|
'aW9uUgx0cmFuc2FjdGlvbnMSXQoTYWRkaXRpb25hbF9hY2NvdW50cxgGIAMoCzIsLnNlcnZlcl'
|
||||||
'YgAygLMiwuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5BZGRpdGlvbmFsQWNjb3VudFISYWRk'
|
'90b19jbGllbnQuUmVzcG9uc2UuQWRkaXRpb25hbEFjY291bnRSEmFkZGl0aW9uYWxBY2NvdW50'
|
||||||
'aXRpb25hbEFjY291bnRzEiYKDGF1dG9fcmVuZXdhbBgHIAEoCEgCUgthdXRvUmVuZXdhbIgBAR'
|
'cxImCgxhdXRvX3JlbmV3YWwYByABKAhIAlILYXV0b1JlbmV3YWyIAQESQgobYWRkaXRpb25hbF'
|
||||||
'JCChthZGRpdGlvbmFsX2FjY291bnRfb3duZXJfaWQYCCABKANIA1IYYWRkaXRpb25hbEFjY291'
|
'9hY2NvdW50X293bmVyX2lkGAggASgDSANSGGFkZGl0aW9uYWxBY2NvdW50T3duZXJJZIgBAUIW'
|
||||||
'bnRPd25lcklkiAEBQhYKFF9wYXltZW50X3BlcmlvZF9kYXlzQiMKIV9sYXN0X3BheW1lbnRfZG'
|
'ChRfcGF5bWVudF9wZXJpb2RfZGF5c0IjCiFfbGFzdF9wYXltZW50X2RvbmVfdW5peF90aW1lc3'
|
||||||
'9uZV91bml4X3RpbWVzdGFtcEIPCg1fYXV0b19yZW5ld2FsQh4KHF9hZGRpdGlvbmFsX2FjY291'
|
'RhbXBCDwoNX2F1dG9fcmVuZXdhbEIeChxfYWRkaXRpb25hbF9hY2NvdW50X293bmVyX2lkGjAK'
|
||||||
'bnRfb3duZXJfaWQaMAoGUHJlS2V5Eg4KAmlkGAEgASgDUgJpZBIWCgZwcmVrZXkYAiABKAxSBn'
|
'BlByZUtleRIOCgJpZBgBIAEoA1ICaWQSFgoGcHJla2V5GAIgASgMUgZwcmVrZXkalQEKDFNpZ2'
|
||||||
'ByZWtleRqVAQoMU2lnbmVkUHJlS2V5EigKEHNpZ25lZF9wcmVrZXlfaWQYASABKANSDnNpZ25l'
|
'5lZFByZUtleRIoChBzaWduZWRfcHJla2V5X2lkGAEgASgDUg5zaWduZWRQcmVrZXlJZBIjCg1z'
|
||||||
'ZFByZWtleUlkEiMKDXNpZ25lZF9wcmVrZXkYAiABKAxSDHNpZ25lZFByZWtleRI2ChdzaWduZW'
|
'aWduZWRfcHJla2V5GAIgASgMUgxzaWduZWRQcmVrZXkSNgoXc2lnbmVkX3ByZWtleV9zaWduYX'
|
||||||
'RfcHJla2V5X3NpZ25hdHVyZRgDIAEoDFIVc2lnbmVkUHJla2V5U2lnbmF0dXJlGvYDCghVc2Vy'
|
'R1cmUYAyABKAxSFXNpZ25lZFByZWtleVNpZ25hdHVyZRrUAQoJUHFjUHJlS2V5EiMKDmVjY19w'
|
||||||
'RGF0YRIXCgd1c2VyX2lkGAEgASgDUgZ1c2VySWQSOwoHcHJla2V5cxgCIAMoCzIhLnNlcnZlcl'
|
'cmVfa2V5X2lkGAEgASgDUgtlY2NQcmVLZXlJZBIeCgtlY2NfcHJlX2tleRgCIAEoDFIJZWNjUH'
|
||||||
'90b19jbGllbnQuUmVzcG9uc2UuUHJlS2V5UgdwcmVrZXlzEh8KCHVzZXJuYW1lGAcgASgMSABS'
|
'JlS2V5EicKEGt5YmVyX3ByZV9rZXlfaWQYAyABKANSDWt5YmVyUHJlS2V5SWQSIgoNa3liZXJf'
|
||||||
'CHVzZXJuYW1liAEBEjMKE3B1YmxpY19pZGVudGl0eV9rZXkYAyABKAxIAVIRcHVibGljSWRlbn'
|
'cHJlX2tleRgEIAEoDFILa3liZXJQcmVLZXkSNQoXa3liZXJfcHJlX2tleV9zaWduYXR1cmUYBS'
|
||||||
'RpdHlLZXmIAQESKAoNc2lnbmVkX3ByZWtleRgEIAEoDEgCUgxzaWduZWRQcmVrZXmIAQESOwoX'
|
'ABKAxSFGt5YmVyUHJlS2V5U2lnbmF0dXJlGp0DCglQcWNCdW5kbGUSLwoUZWNjX3NpZ25lZF9w'
|
||||||
'c2lnbmVkX3ByZWtleV9zaWduYXR1cmUYBSABKAxIA1IVc2lnbmVkUHJla2V5U2lnbmF0dXJliA'
|
'cmVrZXlfaWQYASABKANSEWVjY1NpZ25lZFByZWtleUlkEioKEWVjY19zaWduZWRfcHJla2V5GA'
|
||||||
'EBEi0KEHNpZ25lZF9wcmVrZXlfaWQYBiABKANIBFIOc2lnbmVkUHJla2V5SWSIAQESLAoPcmVn'
|
'IgASgMUg9lY2NTaWduZWRQcmVrZXkSPQobZWNjX3NpZ25lZF9wcmVrZXlfc2lnbmF0dXJlGAMg'
|
||||||
'aXN0cmF0aW9uX2lkGAggASgDSAVSDnJlZ2lzdHJhdGlvbklkiAEBQgsKCV91c2VybmFtZUIWCh'
|
'ASgMUhhlY2NTaWduZWRQcmVrZXlTaWduYXR1cmUSMwoWa3liZXJfc2lnbmVkX3ByZWtleV9pZB'
|
||||||
'RfcHVibGljX2lkZW50aXR5X2tleUIQCg5fc2lnbmVkX3ByZWtleUIaChhfc2lnbmVkX3ByZWtl'
|
'gEIAEoA1ITa3liZXJTaWduZWRQcmVrZXlJZBIuChNreWJlcl9zaWduZWRfcHJla2V5GAUgASgM'
|
||||||
'eV9zaWduYXR1cmVCEwoRX3NpZ25lZF9wcmVrZXlfaWRCEgoQX3JlZ2lzdHJhdGlvbl9pZBpZCg'
|
'UhFreWJlclNpZ25lZFByZWtleRJBCh1reWJlcl9zaWduZWRfcHJla2V5X3NpZ25hdHVyZRgGIA'
|
||||||
'tVcGxvYWRUb2tlbhIhCgx1cGxvYWRfdG9rZW4YASABKAxSC3VwbG9hZFRva2VuEicKD2Rvd25s'
|
'EoDFIaa3liZXJTaWduZWRQcmVrZXlTaWduYXR1cmUSQQoGcHJla2V5GAcgASgLMiQuc2VydmVy'
|
||||||
'b2FkX3Rva2VucxgCIAMoDFIOZG93bmxvYWRUb2tlbnMaOQoORG93bmxvYWRUb2tlbnMSJwoPZG'
|
'X3RvX2NsaWVudC5SZXNwb25zZS5QcWNQcmVLZXlIAFIGcHJla2V5iAEBQgkKB19wcmVrZXkazw'
|
||||||
'93bmxvYWRfdG9rZW5zGAEgAygMUg5kb3dubG9hZFRva2VucxpFCgtQcm9vZk9mV29yaxIWCgZw'
|
'QKCFVzZXJEYXRhEhcKB3VzZXJfaWQYASABKANSBnVzZXJJZBI7CgdwcmVrZXlzGAIgAygLMiEu'
|
||||||
'cmVmaXgYASABKAlSBnByZWZpeBIeCgpkaWZmaWN1bHR5GAIgASgDUgpkaWZmaWN1bHR5Gl4KH1'
|
'c2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5QcmVLZXlSB3ByZWtleXMSHwoIdXNlcm5hbWUYBy'
|
||||||
'Bhc3N3b3JkbGVzc05vdGlmaWNhdGlvbk1lc3NhZ2USDgoCaWQYASABKANSAmlkEisKEWVuY3J5'
|
'ABKAxIAFIIdXNlcm5hbWWIAQESMwoTcHVibGljX2lkZW50aXR5X2tleRgDIAEoDEgBUhFwdWJs'
|
||||||
'cHRlZF9tZXNzYWdlGAIgASgMUhBlbmNyeXB0ZWRNZXNzYWdlGnoKIFBhc3N3b3JkbGVzc05vdG'
|
'aWNJZGVudGl0eUtleYgBARIoCg1zaWduZWRfcHJla2V5GAQgASgMSAJSDHNpZ25lZFByZWtleY'
|
||||||
'lmaWNhdGlvbk1lc3NhZ2VzElYKCG1lc3NhZ2VzGAEgAygLMjouc2VydmVyX3RvX2NsaWVudC5S'
|
'gBARI7ChdzaWduZWRfcHJla2V5X3NpZ25hdHVyZRgFIAEoDEgDUhVzaWduZWRQcmVrZXlTaWdu'
|
||||||
'ZXNwb25zZS5QYXNzd29yZGxlc3NOb3RpZmljYXRpb25NZXNzYWdlUghtZXNzYWdlcxqqAQoNUH'
|
'YXR1cmWIAQESLQoQc2lnbmVkX3ByZWtleV9pZBgGIAEoA0gEUg5zaWduZWRQcmVrZXlJZIgBAR'
|
||||||
'Jlc2lnbmVkUG9zdBIQCgN1cmwYASABKAlSA3VybBJMCgZmaWVsZHMYAiADKAsyNC5zZXJ2ZXJf'
|
'IsCg9yZWdpc3RyYXRpb25faWQYCCABKANIBVIOcmVnaXN0cmF0aW9uSWSIAQESSAoKcHFjX2J1'
|
||||||
'dG9fY2xpZW50LlJlc3BvbnNlLlByZXNpZ25lZFBvc3QuRmllbGRzRW50cnlSBmZpZWxkcxo5Cg'
|
'bmRsZRgJIAEoCzIkLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuUHFjQnVuZGxlSAZSCXBxY0'
|
||||||
'tGaWVsZHNFbnRyeRIQCgNrZXkYASABKAlSA2tleRIUCgV2YWx1ZRgCIAEoCVIFdmFsdWU6AjgB'
|
'J1bmRsZYgBAUILCglfdXNlcm5hbWVCFgoUX3B1YmxpY19pZGVudGl0eV9rZXlCEAoOX3NpZ25l'
|
||||||
'Gs8BChJNZW1vcmllc1VwbG9hZFVybHMSGQoIbWVkaWFfaWQYASABKAlSB21lZGlhSWQSUwoQdG'
|
'ZF9wcmVrZXlCGgoYX3NpZ25lZF9wcmVrZXlfc2lnbmF0dXJlQhMKEV9zaWduZWRfcHJla2V5X2'
|
||||||
'h1bWJuYWlsX3VwbG9hZBgCIAEoCzIoLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuUHJlc2ln'
|
'lkQhIKEF9yZWdpc3RyYXRpb25faWRCDQoLX3BxY19idW5kbGUaWQoLVXBsb2FkVG9rZW4SIQoM'
|
||||||
'bmVkUG9zdFIPdGh1bWJuYWlsVXBsb2FkEkkKC2Z1bGxfdXBsb2FkGAMgASgLMiguc2VydmVyX3'
|
'dXBsb2FkX3Rva2VuGAEgASgMUgt1cGxvYWRUb2tlbhInCg9kb3dubG9hZF90b2tlbnMYAiADKA'
|
||||||
'RvX2NsaWVudC5SZXNwb25zZS5QcmVzaWduZWRQb3N0UgpmdWxsVXBsb2FkGoEBCglNZWRpYUl0'
|
'xSDmRvd25sb2FkVG9rZW5zGjkKDkRvd25sb2FkVG9rZW5zEicKD2Rvd25sb2FkX3Rva2VucxgB'
|
||||||
'ZW0SGQoIbWVkaWFfaWQYASABKAlSB21lZGlhSWQSIwoNb3JpZ2luYWxfZGF0ZRgCIAEoA1IMb3'
|
'IAMoDFIOZG93bmxvYWRUb2tlbnMaRQoLUHJvb2ZPZldvcmsSFgoGcHJlZml4GAEgASgJUgZwcm'
|
||||||
'JpZ2luYWxEYXRlEjQKFnRodW1ibmFpbF9kb3dubG9hZF91cmwYAyABKAlSFHRodW1ibmFpbERv'
|
'VmaXgSHgoKZGlmZmljdWx0eRgCIAEoA1IKZGlmZmljdWx0eRpeCh9QYXNzd29yZGxlc3NOb3Rp'
|
||||||
'd25sb2FkVXJsGkoKDE1lbW9yaWVzTGlzdBI6CgVpdGVtcxgBIAMoCzIkLnNlcnZlcl90b19jbG'
|
'ZmljYXRpb25NZXNzYWdlEg4KAmlkGAEgASgDUgJpZBIrChFlbmNyeXB0ZWRfbWVzc2FnZRgCIA'
|
||||||
'llbnQuUmVzcG9uc2UuTWVkaWFJdGVtUgVpdGVtcxo5CgtNZW1vcmllc1VybBIqChFmdWxsX2Rv'
|
'EoDFIQZW5jcnlwdGVkTWVzc2FnZRp6CiBQYXNzd29yZGxlc3NOb3RpZmljYXRpb25NZXNzYWdl'
|
||||||
'd25sb2FkX3VybBgBIAEoCVIPZnVsbERvd25sb2FkVXJsGmcKDU1lbW9yaWVzVXNhZ2USGwoJbW'
|
'cxJWCghtZXNzYWdlcxgBIAMoCzI6LnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuUGFzc3dvcm'
|
||||||
'F4X2J5dGVzGAEgASgDUghtYXhCeXRlcxIjCg1jdXJyZW50X2J5dGVzGAIgASgDUgxjdXJyZW50'
|
'RsZXNzTm90aWZpY2F0aW9uTWVzc2FnZVIIbWVzc2FnZXMaqgEKDVByZXNpZ25lZFBvc3QSEAoD'
|
||||||
'Qnl0ZXMSFAoFY291bnQYAyABKANSBWNvdW50GoMMCgJPaxIUCgROb25lGAEgASgISABSBE5vbm'
|
'dXJsGAEgASgJUgN1cmwSTAoGZmllbGRzGAIgAygLMjQuc2VydmVyX3RvX2NsaWVudC5SZXNwb2'
|
||||||
'USGAoGdXNlcmlkGAIgASgDSABSBnVzZXJpZBImCg1hdXRoY2hhbGxlbmdlGAMgASgMSABSDWF1'
|
'5zZS5QcmVzaWduZWRQb3N0LkZpZWxkc0VudHJ5UgZmaWVsZHMaOQoLRmllbGRzRW50cnkSEAoD'
|
||||||
'dGhjaGFsbGVuZ2USSgoLdXBsb2FkdG9rZW4YBCABKAsyJi5zZXJ2ZXJfdG9fY2xpZW50LlJlc3'
|
'a2V5GAEgASgJUgNrZXkSFAoFdmFsdWUYAiABKAlSBXZhbHVlOgI4ARrPAQoSTWVtb3JpZXNVcG'
|
||||||
'BvbnNlLlVwbG9hZFRva2VuSABSC3VwbG9hZHRva2VuEkEKCHVzZXJkYXRhGAUgASgLMiMuc2Vy'
|
'xvYWRVcmxzEhkKCG1lZGlhX2lkGAEgASgJUgdtZWRpYUlkElMKEHRodW1ibmFpbF91cGxvYWQY'
|
||||||
'dmVyX3RvX2NsaWVudC5SZXNwb25zZS5Vc2VyRGF0YUgAUgh1c2VyZGF0YRIeCglhdXRodG9rZW'
|
'AiABKAsyKC5zZXJ2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLlByZXNpZ25lZFBvc3RSD3RodW1ibm'
|
||||||
'4YBiABKAxIAFIJYXV0aHRva2VuEkoKDGRlcHJlY2F0ZWRfNxgHIAEoCzIlLnNlcnZlcl90b19j'
|
'FpbFVwbG9hZBJJCgtmdWxsX3VwbG9hZBgDIAEoCzIoLnNlcnZlcl90b19jbGllbnQuUmVzcG9u'
|
||||||
'bGllbnQuUmVzcG9uc2UuRGVwcmVjYXRlZEgAUgtkZXByZWNhdGVkNxJQCg1hdXRoZW50aWNhdG'
|
'c2UuUHJlc2lnbmVkUG9zdFIKZnVsbFVwbG9hZBqBAQoJTWVkaWFJdGVtEhkKCG1lZGlhX2lkGA'
|
||||||
'VkGAggASgLMiguc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5BdXRoZW50aWNhdGVkSABSDWF1'
|
'EgASgJUgdtZWRpYUlkEiMKDW9yaWdpbmFsX2RhdGUYAiABKANSDG9yaWdpbmFsRGF0ZRI0ChZ0'
|
||||||
'dGhlbnRpY2F0ZWQSOAoFcGxhbnMYCSABKAsyIC5zZXJ2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLl'
|
'aHVtYm5haWxfZG93bmxvYWRfdXJsGAMgASgJUhR0aHVtYm5haWxEb3dubG9hZFVybBpKCgxNZW'
|
||||||
'BsYW5zSABSBXBsYW5zEk0KDHBsYW5iYWxsYW5jZRgKIAEoCzInLnNlcnZlcl90b19jbGllbnQu'
|
'1vcmllc0xpc3QSOgoFaXRlbXMYASADKAsyJC5zZXJ2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLk1l'
|
||||||
'UmVzcG9uc2UuUGxhbkJhbGxhbmNlSABSDHBsYW5iYWxsYW5jZRJMCg1kZXByZWNhdGVkXzExGA'
|
'ZGlhSXRlbVIFaXRlbXMaOQoLTWVtb3JpZXNVcmwSKgoRZnVsbF9kb3dubG9hZF91cmwYASABKA'
|
||||||
'sgASgLMiUuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5EZXByZWNhdGVkSABSDGRlcHJlY2F0'
|
'lSD2Z1bGxEb3dubG9hZFVybBpnCg1NZW1vcmllc1VzYWdlEhsKCW1heF9ieXRlcxgBIAEoA1II'
|
||||||
'ZWQxMRJfChJhZGRhY2NvdW50c2ludml0ZXMYDCABKAsyLS5zZXJ2ZXJfdG9fY2xpZW50LlJlc3'
|
'bWF4Qnl0ZXMSIwoNY3VycmVudF9ieXRlcxgCIAEoA1IMY3VycmVudEJ5dGVzEhQKBWNvdW50GA'
|
||||||
'BvbnNlLkFkZEFjY291bnRzSW52aXRlc0gAUhJhZGRhY2NvdW50c2ludml0ZXMSUwoOZG93bmxv'
|
'MgASgDUgVjb3VudBr1CgoCT2sSFAoETm9uZRgBIAEoCEgAUgROb25lEhgKBnVzZXJpZBgCIAEo'
|
||||||
'YWR0b2tlbnMYDSABKAsyKS5zZXJ2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLkRvd25sb2FkVG9rZW'
|
'A0gAUgZ1c2VyaWQSJgoNYXV0aGNoYWxsZW5nZRgDIAEoDEgAUg1hdXRoY2hhbGxlbmdlEkoKC3'
|
||||||
'5zSABSDmRvd25sb2FkdG9rZW5zEk0KDHNpZ25lZHByZWtleRgOIAEoCzInLnNlcnZlcl90b19j'
|
'VwbG9hZHRva2VuGAQgASgLMiYuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5VcGxvYWRUb2tl'
|
||||||
'bGllbnQuUmVzcG9uc2UuU2lnbmVkUHJlS2V5SABSDHNpZ25lZHByZWtleRJKCgtwcm9vZk9mV2'
|
'bkgAUgt1cGxvYWR0b2tlbhJBCgh1c2VyZGF0YRgFIAEoCzIjLnNlcnZlcl90b19jbGllbnQuUm'
|
||||||
'9yaxgPIAEoCzImLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuUHJvb2ZPZldvcmtIAFILcHJv'
|
'VzcG9uc2UuVXNlckRhdGFIAFIIdXNlcmRhdGESHgoJYXV0aHRva2VuGAYgASgMSABSCWF1dGh0'
|
||||||
'b2ZPZldvcmsSSQogcGFzc3dvcmRsZXNzX3JlY292ZXJ5X3NlcnZlcl9rZXkYECABKAxIAFIdcG'
|
'b2tlbhJQCg1hdXRoZW50aWNhdGVkGAggASgLMiguc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS'
|
||||||
'Fzc3dvcmRsZXNzUmVjb3ZlcnlTZXJ2ZXJLZXkSiwEKInBhc3N3b3JkbGVzc19ub3RpZmljYXRp'
|
'5BdXRoZW50aWNhdGVkSABSDWF1dGhlbnRpY2F0ZWQSOAoFcGxhbnMYCSABKAsyIC5zZXJ2ZXJf'
|
||||||
'b25fbWVzc2FnZXMYESABKAsyOy5zZXJ2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLlBhc3N3b3JkbG'
|
'dG9fY2xpZW50LlJlc3BvbnNlLlBsYW5zSABSBXBsYW5zEk0KDHBsYW5iYWxsYW5jZRgKIAEoCz'
|
||||||
'Vzc05vdGlmaWNhdGlvbk1lc3NhZ2VzSABSIHBhc3N3b3JkbGVzc05vdGlmaWNhdGlvbk1lc3Nh'
|
'InLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuUGxhbkJhbGxhbmNlSABSDHBsYW5iYWxsYW5j'
|
||||||
'Z2VzEmEKFG1lbW9yaWVzX3VwbG9hZF91cmxzGBIgASgLMi0uc2VydmVyX3RvX2NsaWVudC5SZX'
|
'ZRJfChJhZGRhY2NvdW50c2ludml0ZXMYDCABKAsyLS5zZXJ2ZXJfdG9fY2xpZW50LlJlc3Bvbn'
|
||||||
'Nwb25zZS5NZW1vcmllc1VwbG9hZFVybHNIAFISbWVtb3JpZXNVcGxvYWRVcmxzEk4KDW1lbW9y'
|
'NlLkFkZEFjY291bnRzSW52aXRlc0gAUhJhZGRhY2NvdW50c2ludml0ZXMSUwoOZG93bmxvYWR0'
|
||||||
'aWVzX2xpc3QYEyABKAsyJy5zZXJ2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLk1lbW9yaWVzTGlzdE'
|
'b2tlbnMYDSABKAsyKS5zZXJ2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLkRvd25sb2FkVG9rZW5zSA'
|
||||||
'gAUgxtZW1vcmllc0xpc3QSSwoMbWVtb3JpZXNfdXJsGBQgASgLMiYuc2VydmVyX3RvX2NsaWVu'
|
'BSDmRvd25sb2FkdG9rZW5zEk0KDHNpZ25lZHByZWtleRgOIAEoCzInLnNlcnZlcl90b19jbGll'
|
||||||
'dC5SZXNwb25zZS5NZW1vcmllc1VybEgAUgttZW1vcmllc1VybBJRCg5tZW1vcmllc191c2FnZR'
|
'bnQuUmVzcG9uc2UuU2lnbmVkUHJlS2V5SABSDHNpZ25lZHByZWtleRJKCgtwcm9vZk9mV29yax'
|
||||||
'gVIAEoCzIoLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuTWVtb3JpZXNVc2FnZUgAUg1tZW1v'
|
'gPIAEoCzImLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuUHJvb2ZPZldvcmtIAFILcHJvb2ZP'
|
||||||
'cmllc1VzYWdlQgQKAk9rQgoKCFJlc3BvbnNl');
|
'ZldvcmsSSQogcGFzc3dvcmRsZXNzX3JlY292ZXJ5X3NlcnZlcl9rZXkYECABKAxIAFIdcGFzc3'
|
||||||
|
'dvcmRsZXNzUmVjb3ZlcnlTZXJ2ZXJLZXkSiwEKInBhc3N3b3JkbGVzc19ub3RpZmljYXRpb25f'
|
||||||
|
'bWVzc2FnZXMYESABKAsyOy5zZXJ2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLlBhc3N3b3JkbGVzc0'
|
||||||
|
'5vdGlmaWNhdGlvbk1lc3NhZ2VzSABSIHBhc3N3b3JkbGVzc05vdGlmaWNhdGlvbk1lc3NhZ2Vz'
|
||||||
|
'EmEKFG1lbW9yaWVzX3VwbG9hZF91cmxzGBIgASgLMi0uc2VydmVyX3RvX2NsaWVudC5SZXNwb2'
|
||||||
|
'5zZS5NZW1vcmllc1VwbG9hZFVybHNIAFISbWVtb3JpZXNVcGxvYWRVcmxzEk4KDW1lbW9yaWVz'
|
||||||
|
'X2xpc3QYEyABKAsyJy5zZXJ2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLk1lbW9yaWVzTGlzdEgAUg'
|
||||||
|
'xtZW1vcmllc0xpc3QSSwoMbWVtb3JpZXNfdXJsGBQgASgLMiYuc2VydmVyX3RvX2NsaWVudC5S'
|
||||||
|
'ZXNwb25zZS5NZW1vcmllc1VybEgAUgttZW1vcmllc1VybBJRCg5tZW1vcmllc191c2FnZRgVIA'
|
||||||
|
'EoCzIoLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuTWVtb3JpZXNVc2FnZUgAUg1tZW1vcmll'
|
||||||
|
'c1VzYWdlQgQKAk9rSgQIBxAISgQICxAMQgoKCFJlc3BvbnNl');
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ class Message_Type extends $pb.ProtobufEnum {
|
||||||
Message_Type._(3, _omitEnumNames ? '' : 'PREKEY_BUNDLE');
|
Message_Type._(3, _omitEnumNames ? '' : 'PREKEY_BUNDLE');
|
||||||
static const Message_Type TEST_NOTIFICATION =
|
static const Message_Type TEST_NOTIFICATION =
|
||||||
Message_Type._(4, _omitEnumNames ? '' : 'TEST_NOTIFICATION');
|
Message_Type._(4, _omitEnumNames ? '' : 'TEST_NOTIFICATION');
|
||||||
|
static const Message_Type CIPHERTEXT_V2 =
|
||||||
|
Message_Type._(5, _omitEnumNames ? '' : 'CIPHERTEXT_V2');
|
||||||
|
|
||||||
static const $core.List<Message_Type> values = <Message_Type>[
|
static const $core.List<Message_Type> values = <Message_Type>[
|
||||||
SENDER_DELIVERY_RECEIPT,
|
SENDER_DELIVERY_RECEIPT,
|
||||||
|
|
@ -32,10 +34,11 @@ class Message_Type extends $pb.ProtobufEnum {
|
||||||
CIPHERTEXT,
|
CIPHERTEXT,
|
||||||
PREKEY_BUNDLE,
|
PREKEY_BUNDLE,
|
||||||
TEST_NOTIFICATION,
|
TEST_NOTIFICATION,
|
||||||
|
CIPHERTEXT_V2,
|
||||||
];
|
];
|
||||||
|
|
||||||
static final $core.List<Message_Type?> _byValue =
|
static final $core.List<Message_Type?> _byValue =
|
||||||
$pb.ProtobufEnum.$_initByValueList(values, 4);
|
$pb.ProtobufEnum.$_initByValueList(values, 5);
|
||||||
static Message_Type? valueOf($core.int value) =>
|
static Message_Type? valueOf($core.int value) =>
|
||||||
value < 0 || value >= _byValue.length ? null : _byValue[value];
|
value < 0 || value >= _byValue.length ? null : _byValue[value];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ const Message_Type$json = {
|
||||||
{'1': 'CIPHERTEXT', '2': 2},
|
{'1': 'CIPHERTEXT', '2': 2},
|
||||||
{'1': 'PREKEY_BUNDLE', '2': 3},
|
{'1': 'PREKEY_BUNDLE', '2': 3},
|
||||||
{'1': 'TEST_NOTIFICATION', '2': 4},
|
{'1': 'TEST_NOTIFICATION', '2': 4},
|
||||||
|
{'1': 'CIPHERTEXT_V2', '2': 5},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -65,10 +66,10 @@ final $typed_data.Uint8List messageDescriptor = $convert.base64Decode(
|
||||||
'CgdNZXNzYWdlEiEKBHR5cGUYASABKA4yDS5NZXNzYWdlLlR5cGVSBHR5cGUSHQoKcmVjZWlwdF'
|
'CgdNZXNzYWdlEiEKBHR5cGUYASABKA4yDS5NZXNzYWdlLlR5cGVSBHR5cGUSHQoKcmVjZWlwdF'
|
||||||
'9pZBgCIAEoCVIJcmVjZWlwdElkEjAKEWVuY3J5cHRlZF9jb250ZW50GAMgASgMSABSEGVuY3J5'
|
'9pZBgCIAEoCVIJcmVjZWlwdElkEjAKEWVuY3J5cHRlZF9jb250ZW50GAMgASgMSABSEGVuY3J5'
|
||||||
'cHRlZENvbnRlbnSIAQESQwoRcGxhaW50ZXh0X2NvbnRlbnQYBCABKAsyES5QbGFpbnRleHRDb2'
|
'cHRlZENvbnRlbnSIAQESQwoRcGxhaW50ZXh0X2NvbnRlbnQYBCABKAsyES5QbGFpbnRleHRDb2'
|
||||||
'50ZW50SAFSEHBsYWludGV4dENvbnRlbnSIAQEidAoEVHlwZRIbChdTRU5ERVJfREVMSVZFUllf'
|
'50ZW50SAFSEHBsYWludGV4dENvbnRlbnSIAQEihwEKBFR5cGUSGwoXU0VOREVSX0RFTElWRVJZ'
|
||||||
'UkVDRUlQVBAAEhUKEVBMQUlOVEVYVF9DT05URU5UEAESDgoKQ0lQSEVSVEVYVBACEhEKDVBSRU'
|
'X1JFQ0VJUFQQABIVChFQTEFJTlRFWFRfQ09OVEVOVBABEg4KCkNJUEhFUlRFWFQQAhIRCg1QUk'
|
||||||
'tFWV9CVU5ETEUQAxIVChFURVNUX05PVElGSUNBVElPThAEQhQKEl9lbmNyeXB0ZWRfY29udGVu'
|
'VLRVlfQlVORExFEAMSFQoRVEVTVF9OT1RJRklDQVRJT04QBBIRCg1DSVBIRVJURVhUX1YyEAVC'
|
||||||
'dEIUChJfcGxhaW50ZXh0X2NvbnRlbnQ=');
|
'FAoSX2VuY3J5cHRlZF9jb250ZW50QhQKEl9wbGFpbnRleHRfY29udGVudA==');
|
||||||
|
|
||||||
@$core.Deprecated('Use plaintextContentDescriptor instead')
|
@$core.Deprecated('Use plaintextContentDescriptor instead')
|
||||||
const PlaintextContent$json = {
|
const PlaintextContent$json = {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ message Message {
|
||||||
CIPHERTEXT = 2;
|
CIPHERTEXT = 2;
|
||||||
PREKEY_BUNDLE = 3;
|
PREKEY_BUNDLE = 3;
|
||||||
TEST_NOTIFICATION = 4;
|
TEST_NOTIFICATION = 4;
|
||||||
|
CIPHERTEXT_V2 = 5;
|
||||||
}
|
}
|
||||||
Type type = 1;
|
Type type = 1;
|
||||||
string receipt_id = 2;
|
string receipt_id = 2;
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,23 @@ import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/services/user.service.dart';
|
import 'package:twonly/src/services/user.service.dart';
|
||||||
|
import 'package:twonly/src/visual/themes/light.dart';
|
||||||
|
|
||||||
class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
late ThemeMode _themeMode;
|
late ThemeMode _themeMode;
|
||||||
|
late Color _primaryColor;
|
||||||
|
|
||||||
ThemeMode get themeMode => _themeMode;
|
ThemeMode get themeMode => _themeMode;
|
||||||
|
Color get primaryColor => _primaryColor;
|
||||||
|
|
||||||
void loadSettings() {
|
void loadSettings() {
|
||||||
if (userService.isUserCreated) {
|
if (userService.isUserCreated) {
|
||||||
_themeMode = userService.currentUser.themeMode;
|
_themeMode = userService.currentUser.themeMode;
|
||||||
|
_primaryColor = userService.currentUser.primaryColor;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
} else {
|
} else {
|
||||||
_themeMode = ThemeMode.system;
|
_themeMode = ThemeMode.system;
|
||||||
|
_primaryColor = defaultPrimaryColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -28,4 +33,16 @@ class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
|
|
||||||
await UserService.update((u) => u.themeMode = newThemeMode);
|
await UserService.update((u) => u.themeMode = newThemeMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> updatePrimaryColor(Color newColor) async {
|
||||||
|
if (newColor.toARGB32() == _primaryColor.toARGB32()) return;
|
||||||
|
|
||||||
|
_primaryColor = newColor;
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
await UserService.update(
|
||||||
|
(u) => u.primaryColorValue = newColor.toARGB32(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ import 'package:twonly/core/bridge/wrapper/key_manager.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
import 'package:twonly/src/model/protobuf/api/websocket/client_to_server.pb.dart'
|
||||||
|
as client;
|
||||||
import 'package:twonly/src/model/protobuf/api/websocket/client_to_server.pbserver.dart';
|
import 'package:twonly/src/model/protobuf/api/websocket/client_to_server.pbserver.dart';
|
||||||
import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart';
|
import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart';
|
||||||
import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart'
|
import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart'
|
||||||
|
|
@ -297,9 +299,17 @@ class ApiService {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> sendResponse(ClientToServer response) async {
|
Future<bool> sendResponse(ClientToServer response) async {
|
||||||
if (_channel != null) {
|
final channel = _channel;
|
||||||
_channel!.sink.add(response.writeToBuffer());
|
if (channel == null || channel.closeCode != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
channel.sink.add(response.writeToBuffer());
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
Log.warn('Could not send response to server: $e');
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -625,7 +635,13 @@ class ApiService {
|
||||||
|
|
||||||
final signalStore = await getSignalStoreFromIdentity(signalIdentity);
|
final signalStore = await getSignalStoreFromIdentity(signalIdentity);
|
||||||
|
|
||||||
final signedPreKey = (await signalStore.loadSignedPreKeys())[0];
|
final signedPreKeysList = await signalStore.loadSignedPreKeys();
|
||||||
|
if (signedPreKeysList.isEmpty) {
|
||||||
|
throw Exception(
|
||||||
|
'Signal Signed PreKeys list is empty. Database insertion likely failed due to lack of storage space or a corrupted database.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
final signedPreKey = signedPreKeysList[0];
|
||||||
|
|
||||||
final loginToken = await RustKeyManager.getLoginToken();
|
final loginToken = await RustKeyManager.getLoginToken();
|
||||||
|
|
||||||
|
|
@ -992,6 +1008,28 @@ class ApiService {
|
||||||
return sendRequestSync(req);
|
return sendRequestSync(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Result> uploadPqcPreKeys(
|
||||||
|
int eccSignedPreKeyId,
|
||||||
|
Uint8List eccSignedPreKey,
|
||||||
|
Uint8List eccSignedPreKeySignature,
|
||||||
|
int kyberSignedPreKeyId,
|
||||||
|
Uint8List kyberSignedPreKey,
|
||||||
|
Uint8List kyberSignedPreKeySignature,
|
||||||
|
List<client.ApplicationData_PqcPreKey> prekeys,
|
||||||
|
) async {
|
||||||
|
final get = ApplicationData_UploadPqcPreKeys()
|
||||||
|
..eccSignedPrekeyId = Int64(eccSignedPreKeyId)
|
||||||
|
..eccSignedPrekey = eccSignedPreKey
|
||||||
|
..eccSignedPrekeySignature = eccSignedPreKeySignature
|
||||||
|
..kyberSignedPrekeyId = Int64(kyberSignedPreKeyId)
|
||||||
|
..kyberSignedPrekey = kyberSignedPreKey
|
||||||
|
..kyberSignedPrekeySignature = kyberSignedPreKeySignature
|
||||||
|
..prekeys.addAll(prekeys);
|
||||||
|
final appData = ApplicationData()..uploadPqcPrekeys = get;
|
||||||
|
final req = createClientToServerFromApplicationData(appData);
|
||||||
|
return sendRequestSync(req);
|
||||||
|
}
|
||||||
|
|
||||||
Future<Response_PlanBallance?> loadPlanBalance({bool useCache = true}) async {
|
Future<Response_PlanBallance?> loadPlanBalance({bool useCache = true}) async {
|
||||||
final ballance = await getPlanBallance();
|
final ballance = await getPlanBallance();
|
||||||
if (ballance != null) {
|
if (ballance != null) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:fixnum/fixnum.dart';
|
import 'package:fixnum/fixnum.dart';
|
||||||
|
import 'package:twonly/core/bridge/wrapper/signal.dart';
|
||||||
import 'package:twonly/src/model/protobuf/api/websocket/client_to_server.pb.dart'
|
import 'package:twonly/src/model/protobuf/api/websocket/client_to_server.pb.dart'
|
||||||
as client;
|
as client;
|
||||||
import 'package:twonly/src/services/signal/identity.signal.dart';
|
import 'package:twonly/src/services/signal/identity.signal.dart';
|
||||||
|
|
@ -18,3 +19,25 @@ Future<client.Response> handleRequestNewPreKey() async {
|
||||||
final ok = client.Response_Ok()..prekeys = prekeys;
|
final ok = client.Response_Ok()..prekeys = prekeys;
|
||||||
return client.Response()..ok = ok;
|
return client.Response()..ok = ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<client.Response?> handleRequestNewPqcPreKey() async {
|
||||||
|
final pqcKeys = await RustSignal.generatePqcPrekeys();
|
||||||
|
if (pqcKeys.isEmpty) return null;
|
||||||
|
|
||||||
|
final prekeysList = <client.ApplicationData_PqcPreKey>[];
|
||||||
|
for (final pqcKey in pqcKeys) {
|
||||||
|
prekeysList.add(
|
||||||
|
client.ApplicationData_PqcPreKey(
|
||||||
|
eccPreKeyId: Int64(pqcKey.eccPreKeyId),
|
||||||
|
eccPreKey: pqcKey.eccPreKey,
|
||||||
|
kyberPreKeyId: Int64(pqcKey.kyberPreKeyId),
|
||||||
|
kyberPreKey: pqcKey.kyberPreKey,
|
||||||
|
kyberPreKeySignature: pqcKey.kyberPreKeySignature,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final prekeys = client.Response_PqcPrekeys(prekeys: prekeysList);
|
||||||
|
final ok = client.Response_Ok()..prekeysPqc = prekeys;
|
||||||
|
return client.Response()..ok = ok;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -227,11 +227,19 @@ Future<void> finishStartedPreprocessing() async {
|
||||||
mediaFile.mediaId,
|
mediaFile.mediaId,
|
||||||
);
|
);
|
||||||
if (messages.isEmpty) {
|
if (messages.isEmpty) {
|
||||||
|
if (mediaFile.createdAt.isBefore(
|
||||||
|
clock.now().subtract(const Duration(hours: 1)),
|
||||||
|
)) {
|
||||||
Log.info(
|
Log.info(
|
||||||
'Deleted orphaned media file ${mediaFile.mediaId} as no messages reference it.',
|
'Deleted orphaned media file ${mediaFile.mediaId} as no messages reference it.',
|
||||||
);
|
);
|
||||||
MediaFileService(mediaFile).fullMediaRemoval();
|
MediaFileService(mediaFile).fullMediaRemoval();
|
||||||
await twonlyDB.mediaFilesDao.deleteMediaFile(mediaFile.mediaId);
|
await twonlyDB.mediaFilesDao.deleteMediaFile(mediaFile.mediaId);
|
||||||
|
} else {
|
||||||
|
Log.info(
|
||||||
|
'Media file ${mediaFile.mediaId} has no messages, but is too new to be deleted by finishStartedPreprocessing. Skipping.',
|
||||||
|
);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -392,6 +400,7 @@ Future<void> insertMediaFileInMessagesTable(
|
||||||
List<String> groupIds, {
|
List<String> groupIds, {
|
||||||
AdditionalMessageData? additionalData,
|
AdditionalMessageData? additionalData,
|
||||||
}) async {
|
}) async {
|
||||||
|
await twonlyDB.transaction(() async {
|
||||||
await twonlyDB.mediaFilesDao.updateAllMediaFiles(
|
await twonlyDB.mediaFilesDao.updateAllMediaFiles(
|
||||||
const MediaFilesCompanion(
|
const MediaFilesCompanion(
|
||||||
isDraftMedia: Value(false),
|
isDraftMedia: Value(false),
|
||||||
|
|
@ -418,7 +427,10 @@ Future<void> insertMediaFileInMessagesTable(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
await twonlyDB.groupsDao.increaseLastMessageExchange(groupId, clock.now());
|
await twonlyDB.groupsDao.increaseLastMessageExchange(
|
||||||
|
groupId,
|
||||||
|
clock.now(),
|
||||||
|
);
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
Log.info(
|
Log.info(
|
||||||
'Created message ${message.messageId} for media ${message.mediaId}',
|
'Created message ${message.messageId} for media ${message.mediaId}',
|
||||||
|
|
@ -435,6 +447,7 @@ Future<void> insertMediaFileInMessagesTable(
|
||||||
Log.error('Error inserting media upload message in database.');
|
Log.error('Error inserting media upload message in database.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
unawaited(startBackgroundMediaUpload(mediaService));
|
unawaited(startBackgroundMediaUpload(mediaService));
|
||||||
}
|
}
|
||||||
|
|
@ -479,12 +492,20 @@ Future<void> _startBackgroundMediaUploadInternal(
|
||||||
mediaService.mediaFile.mediaId,
|
mediaService.mediaFile.mediaId,
|
||||||
);
|
);
|
||||||
if (messages.isEmpty) {
|
if (messages.isEmpty) {
|
||||||
|
if (mediaService.mediaFile.createdAt.isBefore(
|
||||||
|
clock.now().subtract(const Duration(hours: 1)),
|
||||||
|
)) {
|
||||||
Log.warn(
|
Log.warn(
|
||||||
'Media files ${mediaService.mediaFile.mediaId} has no original, temp, or stored path. Removing it from DB as files are not existent.',
|
'Media files ${mediaService.mediaFile.mediaId} has no original, temp, or stored path. Removing it from DB as files are not existent.',
|
||||||
);
|
);
|
||||||
await twonlyDB.mediaFilesDao.deleteMediaFile(
|
await twonlyDB.mediaFilesDao.deleteMediaFile(
|
||||||
mediaService.mediaFile.mediaId,
|
mediaService.mediaFile.mediaId,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
Log.warn(
|
||||||
|
'Media files ${mediaService.mediaFile.mediaId} has no paths, but is too new to be deleted. Skipping deletion.',
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.warn(
|
Log.warn(
|
||||||
'Media files ${mediaService.mediaFile.mediaId} has no original, temp, or stored path, but messages still reference it. Marking as uploaded to stop retries.',
|
'Media files ${mediaService.mediaFile.mediaId} has no original, temp, or stored path, but messages still reference it. Marking as uploaded to stop retries.',
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ import 'dart:io';
|
||||||
import 'package:clock/clock.dart';
|
import 'package:clock/clock.dart';
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:fixnum/fixnum.dart';
|
import 'package:fixnum/fixnum.dart';
|
||||||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
|
||||||
import 'package:mutex/mutex.dart';
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
|
import 'package:twonly/src/database/tables/contacts.table.dart';
|
||||||
import 'package:twonly/src/database/tables/messages.table.dart';
|
import 'package:twonly/src/database/tables/messages.table.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart';
|
import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart';
|
||||||
|
|
@ -114,22 +114,6 @@ Future<(Uint8List, Uint8List?)?> _tryToSendCompleteMessageInternal({
|
||||||
// ignore: parameter_assignments
|
// ignore: parameter_assignments
|
||||||
receipt = loadedReceipt;
|
receipt = loadedReceipt;
|
||||||
|
|
||||||
if (receipt.retryCount >= 2) {
|
|
||||||
// After two retries, change the receiptId. This addresses a bug where the receiver received the message and marked it as received,
|
|
||||||
// but the app was closed before the message was fully processed. Because the receipt was already stored, subsequent retries were
|
|
||||||
// detected as duplicates and rejected.
|
|
||||||
final oldReceiptId = receipt.receiptId;
|
|
||||||
final updatedReceipt = await twonlyDB.receiptsDao.rotateReceiptId(
|
|
||||||
oldReceiptId,
|
|
||||||
);
|
|
||||||
if (updatedReceipt != null) {
|
|
||||||
Log.info(
|
|
||||||
'Changed receiptId $oldReceiptId to ${updatedReceipt.receiptId} as retryCount is ${receipt.retryCount}',
|
|
||||||
);
|
|
||||||
receipt = updatedReceipt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final contact = await twonlyDB.contactsDao.getContactById(
|
final contact = await twonlyDB.contactsDao.getContactById(
|
||||||
receipt.contactId,
|
receipt.contactId,
|
||||||
);
|
);
|
||||||
|
|
@ -176,11 +160,11 @@ Future<(Uint8List, Uint8List?)?> _tryToSendCompleteMessageInternal({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.type == pb.Message_Type.CIPHERTEXT) {
|
if (message.type == pb.Message_Type.CIPHERTEXT) {
|
||||||
final cipherText = await signalEncryptMessage(
|
final encryptResult = await signalEncryptMessage(
|
||||||
receipt.contactId,
|
receipt.contactId,
|
||||||
Uint8List.fromList(message.encryptedContent),
|
Uint8List.fromList(message.encryptedContent),
|
||||||
);
|
);
|
||||||
if (cipherText == null) {
|
if (encryptResult == null) {
|
||||||
Log.error(
|
Log.error(
|
||||||
'[${receipt.receiptId}] Could not encrypt the message for user ${receipt.contactId}. Aborting and trying again.',
|
'[${receipt.receiptId}] Could not encrypt the message for user ${receipt.contactId}. Aborting and trying again.',
|
||||||
);
|
);
|
||||||
|
|
@ -194,16 +178,31 @@ Future<(Uint8List, Uint8List?)?> _tryToSendCompleteMessageInternal({
|
||||||
await twonlyDB.receiptsDao.deleteReceipt(receipt.receiptId);
|
await twonlyDB.receiptsDao.deleteReceipt(receipt.receiptId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
message.encryptedContent = cipherText.serialize();
|
message
|
||||||
switch (cipherText.getType()) {
|
..encryptedContent = encryptResult.ciphertext
|
||||||
case CiphertextMessage.prekeyType:
|
..type = encryptResult.type;
|
||||||
message.type = pb.Message_Type.PREKEY_BUNDLE;
|
} else if (message.type == pb.Message_Type.CIPHERTEXT_V2) {
|
||||||
case CiphertextMessage.whisperType:
|
final encryptResult = await signalEncryptMessageV2(
|
||||||
message.type = pb.Message_Type.CIPHERTEXT;
|
receipt.contactId,
|
||||||
default:
|
Uint8List.fromList(message.encryptedContent),
|
||||||
Log.error('Invalid ciphertext type: ${cipherText.getType()}.');
|
);
|
||||||
|
if (encryptResult == null) {
|
||||||
|
Log.error(
|
||||||
|
'[${receipt.receiptId}] Could not encrypt the message (V2) for user ${receipt.contactId}. Aborting and trying again.',
|
||||||
|
);
|
||||||
|
if (receipt.messageId != null) {
|
||||||
|
await twonlyDB.messagesDao.handleMessageAckByServer(
|
||||||
|
receipt.contactId,
|
||||||
|
receipt.messageId!,
|
||||||
|
clock.now(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await twonlyDB.receiptsDao.deleteReceipt(receipt.receiptId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
message
|
||||||
|
..encryptedContent = encryptResult.ciphertext
|
||||||
|
..type = encryptResult.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onlyReturnEncryptedData) {
|
if (onlyReturnEncryptedData) {
|
||||||
|
|
@ -482,8 +481,11 @@ Future<(Uint8List, Uint8List?)?> sendCipherText(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final contact = await twonlyDB.contactsDao.getContactById(contactId);
|
||||||
|
final isV2 = contact?.signalVersion == SignalVersion.v2;
|
||||||
|
|
||||||
final response = pb.Message()
|
final response = pb.Message()
|
||||||
..type = pb.Message_Type.CIPHERTEXT
|
..type = isV2 ? pb.Message_Type.CIPHERTEXT_V2 : pb.Message_Type.CIPHERTEXT
|
||||||
..encryptedContent = encryptedContent.writeToBuffer();
|
..encryptedContent = encryptedContent.writeToBuffer();
|
||||||
|
|
||||||
var retryCounter = 0;
|
var retryCounter = 0;
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@ Future<void> handleServerMessage(server.ServerToClient msg) async {
|
||||||
try {
|
try {
|
||||||
if (msg.v0.hasRequestNewPreKeys()) {
|
if (msg.v0.hasRequestNewPreKeys()) {
|
||||||
response = await handleRequestNewPreKey();
|
response = await handleRequestNewPreKey();
|
||||||
|
} else if (msg.v0.hasRequestNewPqcPreKeys()) {
|
||||||
|
response = (await handleRequestNewPqcPreKey()) ?? response;
|
||||||
} else if (msg.v0.hasNewMessage()) {
|
} else if (msg.v0.hasNewMessage()) {
|
||||||
Log.info('Got 1 message from the server.');
|
Log.info('Got 1 message from the server.');
|
||||||
await handleClient2ClientMessage(msg.v0.newMessage);
|
await handleClient2ClientMessage(msg.v0.newMessage);
|
||||||
|
|
@ -78,9 +80,16 @@ Future<void> handleServerMessage(server.ServerToClient msg) async {
|
||||||
..seq = msg.v0.seq
|
..seq = msg.v0.seq
|
||||||
..response = response;
|
..response = response;
|
||||||
|
|
||||||
await apiService.sendResponse(ClientToServer()..v0 = v0);
|
final responseSent = await apiService.sendResponse(ClientToServer()..v0 = v0);
|
||||||
|
if (responseSent) {
|
||||||
|
Log.info(
|
||||||
|
'Successfully queued response for server message ${msg.v0.seq}.',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Log.warn('Could not send response for server message ${msg.v0.seq}.');
|
||||||
|
}
|
||||||
AppState.gotMessageFromServer = true;
|
AppState.gotMessageFromServer = true;
|
||||||
Log.info('All messages from the server proccessed.');
|
Log.info('All messages from the server processed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime lastPushKeyRequest = clock.now().subtract(const Duration(hours: 1));
|
DateTime lastPushKeyRequest = clock.now().subtract(const Duration(hours: 1));
|
||||||
|
|
@ -139,6 +148,43 @@ Future<void> _handleClient2ClientMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await twonlyDB.receiptsDao.isDuplicated(receiptId)) {
|
if (await twonlyDB.receiptsDao.isDuplicated(receiptId)) {
|
||||||
|
if (message.type == Message_Type.SENDER_DELIVERY_RECEIPT) {
|
||||||
|
Log.info(
|
||||||
|
'[$receiptId] Delivery receipt is a duplicate. Skipping receipt response.',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const duplicateReceiptCooldown = Duration(days: 10);
|
||||||
|
final shouldResend = await twonlyDB.receiptsDao.claimDuplicateReceiptResend(
|
||||||
|
receiptId,
|
||||||
|
duplicateReceiptCooldown,
|
||||||
|
);
|
||||||
|
if (!shouldResend) {
|
||||||
|
Log.info(
|
||||||
|
'[$receiptId] Message is a duplicate. Skipping delivery receipt during cooldown.',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.info(
|
||||||
|
'[$receiptId] Message is a duplicate and cooldown elapsed. Sending delivery receipt again.',
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
final response = Message(type: Message_Type.SENDER_DELIVERY_RECEIPT);
|
||||||
|
await twonlyDB.receiptsDao.insertReceipt(
|
||||||
|
ReceiptsCompanion(
|
||||||
|
receiptId: Value(receiptId),
|
||||||
|
contactId: Value(fromUserId),
|
||||||
|
message: Value(response.writeToBuffer()),
|
||||||
|
contactWillSendsReceipt: const Value(false),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
Log.warn('[$receiptId] Error handling duplicate receipt ACK: $e');
|
||||||
|
}
|
||||||
|
await tryToSendCompleteMessage(
|
||||||
|
receiptId: receiptId,
|
||||||
|
blocking: false,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,6 +236,7 @@ Future<void> _handleClient2ClientMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
case Message_Type.CIPHERTEXT:
|
case Message_Type.CIPHERTEXT:
|
||||||
|
case Message_Type.CIPHERTEXT_V2:
|
||||||
case Message_Type.PREKEY_BUNDLE:
|
case Message_Type.PREKEY_BUNDLE:
|
||||||
if (message.hasEncryptedContent()) {
|
if (message.hasEncryptedContent()) {
|
||||||
Value<String>? receiptIdDB;
|
Value<String>? receiptIdDB;
|
||||||
|
|
@ -266,13 +313,14 @@ Future<void> _handleClient2ClientMessage(
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.warn('[$receiptId] Error inserting receipt: $e');
|
Log.warn('[$receiptId] Error inserting receipt: $e');
|
||||||
}
|
}
|
||||||
if (targetReceiptId != null) {
|
|
||||||
|
targetReceiptId ??= receiptIdDB?.value ?? receiptId;
|
||||||
|
|
||||||
await tryToSendCompleteMessage(
|
await tryToSendCompleteMessage(
|
||||||
receiptId: targetReceiptId,
|
receiptId: targetReceiptId,
|
||||||
blocking: false,
|
blocking: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
case Message_Type.TEST_NOTIFICATION:
|
case Message_Type.TEST_NOTIFICATION:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -297,12 +345,23 @@ Future<(EncryptedContent?, PlaintextContent?)> handleEncryptedMessageRaw(
|
||||||
Set<int>? brokenSessionsInCurrentBatch,
|
Set<int>? brokenSessionsInCurrentBatch,
|
||||||
}) async {
|
}) async {
|
||||||
Log.info('[$receiptId] calling signalDecryptMessage');
|
Log.info('[$receiptId] calling signalDecryptMessage');
|
||||||
var (encryptedContent, decryptionErrorType) = await signalDecryptMessage(
|
EncryptedContent? encryptedContent;
|
||||||
|
PlaintextContent_DecryptionErrorMessage_Type? decryptionErrorType;
|
||||||
|
|
||||||
|
if (messageType == Message_Type.CIPHERTEXT_V2) {
|
||||||
|
(encryptedContent, decryptionErrorType) = await signalDecryptMessageV2(
|
||||||
|
fromUserId,
|
||||||
|
encryptedContentRaw,
|
||||||
|
brokenSessionsInCurrentBatch: brokenSessionsInCurrentBatch,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
(encryptedContent, decryptionErrorType) = await signalDecryptMessageV1(
|
||||||
fromUserId,
|
fromUserId,
|
||||||
encryptedContentRaw,
|
encryptedContentRaw,
|
||||||
messageType.value,
|
messageType.value,
|
||||||
brokenSessionsInCurrentBatch: brokenSessionsInCurrentBatch,
|
brokenSessionsInCurrentBatch: brokenSessionsInCurrentBatch,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (encryptedContent == null) {
|
if (encryptedContent == null) {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,12 @@ class Result<T, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime fromTimestamp(Int64 timeStamp) {
|
DateTime fromTimestamp(Int64 timeStamp) {
|
||||||
return DateTime.fromMillisecondsSinceEpoch(timeStamp.toInt());
|
final date = DateTime.fromMillisecondsSinceEpoch(timeStamp.toInt());
|
||||||
|
final now = DateTime.now();
|
||||||
|
if (date.isAfter(now)) {
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
return date;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: strict_raw_type
|
// ignore: strict_raw_type
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,10 @@ Future<bool> initBackgroundExecution() async {
|
||||||
final Mutex _keyValueMutex = Mutex();
|
final Mutex _keyValueMutex = Mutex();
|
||||||
|
|
||||||
// ignore: unreachable_from_main
|
// ignore: unreachable_from_main
|
||||||
Future<void> handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async {
|
Future<bool> backgroundFetch({
|
||||||
|
int? lastExecutionInSecondsLimit = 120,
|
||||||
|
}) async {
|
||||||
|
if (lastExecutionInSecondsLimit != null) {
|
||||||
final shouldBeExecuted = await exclusiveAccess(
|
final shouldBeExecuted = await exclusiveAccess(
|
||||||
lockName: 'periodic_task',
|
lockName: 'periodic_task',
|
||||||
mutex: _keyValueMutex,
|
mutex: _keyValueMutex,
|
||||||
|
|
@ -116,9 +119,10 @@ Future<void> handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!shouldBeExecuted) return;
|
if (!shouldBeExecuted) return false;
|
||||||
|
}
|
||||||
|
|
||||||
Log.info('eu.twonly.periodic_task was called.');
|
Log.info('Periodic task was called.');
|
||||||
AppState.gotMessageFromServer = false;
|
AppState.gotMessageFromServer = false;
|
||||||
|
|
||||||
final stopwatch = Stopwatch()..start();
|
final stopwatch = Stopwatch()..start();
|
||||||
|
|
@ -130,14 +134,16 @@ Future<void> handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async {
|
||||||
|
|
||||||
if (!await apiService.connect()) {
|
if (!await apiService.connect()) {
|
||||||
Log.info('Could not connect to the api. Returning early.');
|
Log.info('Could not connect to the api. Returning early.');
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!apiService.isAuthenticated) {
|
if (!apiService.isAuthenticated) {
|
||||||
Log.info('Api is not authenticated. Returning early.');
|
Log.info('Api is not authenticated. Returning early.');
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var receiveMessage = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (!AppState.gotMessageFromServer) {
|
while (!AppState.gotMessageFromServer) {
|
||||||
if (stopwatch.elapsed.inSeconds >= 15) {
|
if (stopwatch.elapsed.inSeconds >= 15) {
|
||||||
|
|
@ -148,19 +154,22 @@ Future<void> handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AppState.gotMessageFromServer) {
|
if (AppState.gotMessageFromServer) {
|
||||||
|
receiveMessage = true;
|
||||||
Log.info('Received a server message from the server.');
|
Log.info('Received a server message from the server.');
|
||||||
}
|
}
|
||||||
|
|
||||||
await finishStartedPreprocessing();
|
await finishStartedPreprocessing();
|
||||||
|
|
||||||
|
if (lastExecutionInSecondsLimit != null) {
|
||||||
await Future.delayed(const Duration(milliseconds: 2000));
|
await Future.delayed(const Duration(milliseconds: 2000));
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
await apiService.close(() {});
|
await apiService.close(() {});
|
||||||
stopwatch.stop();
|
stopwatch.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.info('eu.twonly.periodic_task finished after ${stopwatch.elapsed}.');
|
Log.info('Periodic task finished after ${stopwatch.elapsed}.');
|
||||||
return;
|
return receiveMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> handleProcessingTask() async {
|
Future<void> handleProcessingTask() async {
|
||||||
|
|
|
||||||
|
|
@ -347,7 +347,7 @@ Future<(int, EncryptedGroupState)?> fetchGroupState(Group group) async {
|
||||||
}
|
}
|
||||||
// the state is now updated and the appended_group_state should be removed on the server, so just call this
|
// the state is now updated and the appended_group_state should be removed on the server, so just call this
|
||||||
// function again, to sync the local database
|
// function again, to sync the local database
|
||||||
return fetchGroupState(group);
|
return await fetchGroupState(group);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error(e);
|
Log.error(e);
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
@ -12,7 +10,6 @@ import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/constants/routes.keys.dart';
|
import 'package:twonly/src/constants/routes.keys.dart';
|
||||||
import 'package:twonly/src/database/tables/contacts.table.dart';
|
import 'package:twonly/src/database/tables/contacts.table.dart';
|
||||||
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||||
import 'package:twonly/src/services/api/mediafiles/upload.api.dart';
|
|
||||||
import 'package:twonly/src/services/passwordless_recovery.service.dart'
|
import 'package:twonly/src/services/passwordless_recovery.service.dart'
|
||||||
show PasswordlessRecoveryService;
|
show PasswordlessRecoveryService;
|
||||||
import 'package:twonly/src/services/signal/session.signal.dart';
|
import 'package:twonly/src/services/signal/session.signal.dart';
|
||||||
|
|
@ -20,7 +17,6 @@ import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/utils/qr.utils.dart';
|
import 'package:twonly/src/utils/qr.utils.dart';
|
||||||
import 'package:twonly/src/visual/components/alert.dialog.dart';
|
import 'package:twonly/src/visual/components/alert.dialog.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/share_image_editor.view.dart';
|
|
||||||
import 'package:twonly/src/visual/views/contact/add_contact_via_qr_link.view.dart';
|
import 'package:twonly/src/visual/views/contact/add_contact_via_qr_link.view.dart';
|
||||||
import 'package:twonly/src/visual/views/contact/add_new_contact.view.dart';
|
import 'package:twonly/src/visual/views/contact/add_new_contact.view.dart';
|
||||||
|
|
||||||
|
|
@ -149,53 +145,20 @@ Future<void> _pubKeysDoNotMatch(BuildContext context, String username) async {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> handleIntentMediaFile(
|
|
||||||
BuildContext context,
|
|
||||||
String filePath,
|
|
||||||
MediaType type,
|
|
||||||
) async {
|
|
||||||
final file = File(filePath);
|
|
||||||
if (!file.existsSync()) {
|
|
||||||
Log.error('The shared intent file does not exits.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final newMediaService = await initializeMediaUpload(
|
|
||||||
type,
|
|
||||||
userService.currentUser.defaultShowTime,
|
|
||||||
);
|
|
||||||
if (newMediaService == null) {
|
|
||||||
Log.error('Could not create new media file for intent shared file');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
file.copySync(newMediaService.originalPath.path);
|
|
||||||
if (!context.mounted) return;
|
|
||||||
|
|
||||||
await Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => ShareImageEditorView(
|
|
||||||
mediaFileService: newMediaService,
|
|
||||||
sharedFromGallery: true,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamSubscription<List<SharedFile>> initIntentStreams(
|
StreamSubscription<List<SharedFile>> initIntentStreams(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
void Function(Uri) onUrlCallBack,
|
void Function(Uri) onUrlCallBack,
|
||||||
|
void Function(String, MediaType) onMediaCallBack,
|
||||||
) {
|
) {
|
||||||
FlutterSharingIntent.instance.getInitialSharing().then((f) {
|
FlutterSharingIntent.instance.getInitialSharing().then((f) {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
handleIntentSharedFile(context, f, onUrlCallBack);
|
handleIntentSharedFile(context, f, onUrlCallBack, onMediaCallBack);
|
||||||
});
|
});
|
||||||
|
|
||||||
return FlutterSharingIntent.instance.getMediaStream().listen(
|
return FlutterSharingIntent.instance.getMediaStream().listen(
|
||||||
(f) {
|
(f) {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
handleIntentSharedFile(context, f, onUrlCallBack);
|
handleIntentSharedFile(context, f, onUrlCallBack, onMediaCallBack);
|
||||||
},
|
},
|
||||||
// ignore: inference_failure_on_untyped_parameter
|
// ignore: inference_failure_on_untyped_parameter
|
||||||
onError: (err) {
|
onError: (err) {
|
||||||
|
|
@ -208,6 +171,7 @@ Future<void> handleIntentSharedFile(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
List<SharedFile> files,
|
List<SharedFile> files,
|
||||||
void Function(Uri) onUrlCallBack,
|
void Function(Uri) onUrlCallBack,
|
||||||
|
void Function(String, MediaType) onMediaCallBack,
|
||||||
) async {
|
) async {
|
||||||
for (final file in files) {
|
for (final file in files) {
|
||||||
if (file.value == null) {
|
if (file.value == null) {
|
||||||
|
|
@ -231,9 +195,9 @@ Future<void> handleIntentSharedFile(
|
||||||
if (file.value!.endsWith('.gif')) {
|
if (file.value!.endsWith('.gif')) {
|
||||||
type = MediaType.gif;
|
type = MediaType.gif;
|
||||||
}
|
}
|
||||||
await handleIntentMediaFile(context, file.value!, type);
|
onMediaCallBack(file.value!, type);
|
||||||
case SharedMediaType.VIDEO:
|
case SharedMediaType.VIDEO:
|
||||||
await handleIntentMediaFile(context, file.value!, MediaType.video);
|
onMediaCallBack(file.value!, MediaType.video);
|
||||||
// ignore: no_default_cases
|
// ignore: no_default_cases
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -323,10 +323,12 @@ class MediaFileService {
|
||||||
name: mediaFile.mediaId,
|
name: mediaFile.mediaId,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await saveImageToGallery(
|
unawaited(
|
||||||
storedPath.readAsBytesSync(),
|
saveImageToGallery(
|
||||||
|
await storedPath.readAsBytes(),
|
||||||
createdAt: mediaFile.createdAt,
|
createdAt: mediaFile.createdAt,
|
||||||
name: mediaFile.mediaId,
|
name: mediaFile.mediaId,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:cryptography_flutter_plus/cryptography_flutter_plus.dart';
|
import 'package:cryptography_flutter_plus/cryptography_flutter_plus.dart';
|
||||||
import 'package:cryptography_plus/cryptography_plus.dart';
|
import 'package:cryptography_plus/cryptography_plus.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
|
|
@ -100,6 +102,7 @@ Future<void> showLocalPushNotification(
|
||||||
PushUser pushUser,
|
PushUser pushUser,
|
||||||
PushNotification pushNotification, {
|
PushNotification pushNotification, {
|
||||||
String? groupId,
|
String? groupId,
|
||||||
|
String? titleSuffix,
|
||||||
}) async {
|
}) async {
|
||||||
String? title;
|
String? title;
|
||||||
String? body;
|
String? body;
|
||||||
|
|
@ -125,7 +128,9 @@ Future<void> showLocalPushNotification(
|
||||||
if (targetGroupId != null) {
|
if (targetGroupId != null) {
|
||||||
try {
|
try {
|
||||||
final currentUri = routerProvider.routerDelegate.currentConfiguration.uri;
|
final currentUri = routerProvider.routerDelegate.currentConfiguration.uri;
|
||||||
if (currentUri.path.contains(targetGroupId)) {
|
final isResumed =
|
||||||
|
WidgetsBinding.instance.lifecycleState == AppLifecycleState.resumed;
|
||||||
|
if (isResumed && currentUri.path.contains(targetGroupId)) {
|
||||||
Log.info(
|
Log.info(
|
||||||
'Suppressing local push notification because chat with group $targetGroupId is currently open.',
|
'Suppressing local push notification because chat with group $targetGroupId is currently open.',
|
||||||
);
|
);
|
||||||
|
|
@ -137,6 +142,10 @@ Future<void> showLocalPushNotification(
|
||||||
}
|
}
|
||||||
|
|
||||||
title = pushUser.displayName;
|
title = pushUser.displayName;
|
||||||
|
if (titleSuffix != null && titleSuffix.isNotEmpty) {
|
||||||
|
title = '$title $titleSuffix';
|
||||||
|
}
|
||||||
|
|
||||||
body = getPushNotificationText(pushNotification);
|
body = getPushNotificationText(pushNotification);
|
||||||
if (body == '') {
|
if (body == '') {
|
||||||
Log.error('No push notification type defined!');
|
Log.error('No push notification type defined!');
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||||
|
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
if (isInitialized) {
|
if (isInitialized) {
|
||||||
await handlePeriodicTask(lastExecutionInSecondsLimit: 10);
|
await backgroundFetch(lastExecutionInSecondsLimit: 3);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// make sure every thing run...
|
// make sure every thing run...
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/constants/secure_storage.keys.dart';
|
import 'package:twonly/src/constants/secure_storage.keys.dart';
|
||||||
|
import 'package:twonly/src/services/background/callback_dispatcher.background.dart';
|
||||||
import 'package:twonly/src/services/notifications/background.notifications.dart';
|
import 'package:twonly/src/services/notifications/background.notifications.dart';
|
||||||
import 'package:twonly/src/services/notifications/fcm.background.dart';
|
import 'package:twonly/src/services/notifications/fcm.background.dart';
|
||||||
import 'package:twonly/src/services/user.service.dart';
|
import 'package:twonly/src/services/user.service.dart';
|
||||||
|
|
@ -144,6 +145,7 @@ class FcmNotificationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> handleRemoteMessage(RemoteMessage message) async {
|
static Future<void> handleRemoteMessage(RemoteMessage message) async {
|
||||||
|
Log.info('handleRemoteMessage received message: ${message.messageId}');
|
||||||
await _updateLastFcmMessageTimestamp();
|
await _updateLastFcmMessageTimestamp();
|
||||||
if (!Platform.isAndroid) {
|
if (!Platform.isAndroid) {
|
||||||
Log.error('Got message in Dart while on iOS');
|
Log.error('Got message in Dart while on iOS');
|
||||||
|
|
@ -155,6 +157,24 @@ class FcmNotificationService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In scenarios like Android Doze Mode or aggressive background restrictions, the OS may kill
|
||||||
|
// or heavily restrict network access, preventing the WebSocket from connecting in time.
|
||||||
|
// By parsing the FCM data payload offline, we can instantly display the notification, which also
|
||||||
|
// prevents FCM from penalizing/downgrading the app's data message priority for failing to show a notification.
|
||||||
|
// This is just a workarround until the new Rust decryption is enrolled fully.
|
||||||
|
final pushDataString = message.data['push_data'] as String?;
|
||||||
|
if (pushDataString != null) {
|
||||||
|
if (apiService.isConnected) {
|
||||||
|
Log.info('Got FCM message, but API is connected...');
|
||||||
|
} else {
|
||||||
|
Log.info('Trying to connect to the API in the background.');
|
||||||
|
|
||||||
|
if (await backgroundFetch()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (message.notification != null || message.data['title'] != null) {
|
if (message.notification != null || message.data['title'] != null) {
|
||||||
final title =
|
final title =
|
||||||
message.notification?.title ?? message.data['title'] as String? ?? '';
|
message.notification?.title ?? message.data['title'] as String? ?? '';
|
||||||
|
|
|
||||||
|
|
@ -202,11 +202,11 @@ class PasswordlessRecoveryService {
|
||||||
case SecondFactorType.pin:
|
case SecondFactorType.pin:
|
||||||
|
|
||||||
// The pin seed - never shared with the server - ensures that the server is unable to brute-force real user's pin
|
// The pin seed - never shared with the server - ensures that the server is unable to brute-force real user's pin
|
||||||
config.serverKeyProtection = getRandomUint8List(32);
|
config
|
||||||
|
..serverKeyProtection = getRandomUint8List(32)
|
||||||
// As the pin is heavily protected against brute-forcing e.g. will be deleted by the server after 10 tries, the
|
// As the pin is heavily protected against brute-forcing e.g. will be deleted by the server after 10 tries, the
|
||||||
// unlock token is required to prevent a malicious user (except the trusted friends) to trigger this deletion.
|
// unlock token is required to prevent a malicious user (except the trusted friends) to trigger this deletion.
|
||||||
config.pinUnlockToken = getRandomUint8List(32);
|
..pinUnlockToken = getRandomUint8List(32);
|
||||||
|
|
||||||
// Brute-force protection for the user's pin:
|
// Brute-force protection for the user's pin:
|
||||||
// - Server: Does not know the seed.
|
// - Server: Does not know the seed.
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,48 @@ import 'dart:typed_data';
|
||||||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
||||||
// ignore: implementation_imports
|
// ignore: implementation_imports
|
||||||
import 'package:libsignal_protocol_dart/src/invalid_message_exception.dart';
|
import 'package:libsignal_protocol_dart/src/invalid_message_exception.dart';
|
||||||
import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart';
|
import 'package:twonly/core/bridge/wrapper/signal.dart';
|
||||||
|
import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart'
|
||||||
|
as pb;
|
||||||
import 'package:twonly/src/services/api/messages.api.dart';
|
import 'package:twonly/src/services/api/messages.api.dart';
|
||||||
import 'package:twonly/src/services/signal/protocol_state.signal.dart';
|
import 'package:twonly/src/services/signal/protocol_state.signal.dart';
|
||||||
import 'package:twonly/src/services/signal/session.signal.dart';
|
import 'package:twonly/src/services/signal/session.signal.dart';
|
||||||
import 'package:twonly/src/services/signal/utils.signal.dart';
|
import 'package:twonly/src/services/signal/utils.signal.dart';
|
||||||
import 'package:twonly/src/utils/log.dart';
|
import 'package:twonly/src/utils/log.dart';
|
||||||
|
|
||||||
Future<CiphertextMessage?> signalEncryptMessage(
|
class SignalEncryptResult {
|
||||||
|
SignalEncryptResult(this.ciphertext, this.type);
|
||||||
|
final Uint8List ciphertext;
|
||||||
|
final pb.Message_Type type;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<SignalEncryptResult?> signalEncryptMessage(
|
||||||
int target,
|
int target,
|
||||||
Uint8List plaintextContent,
|
Uint8List plaintextContent,
|
||||||
) async {
|
) async {
|
||||||
return lockingSignalProtocol.protect<CiphertextMessage?>(() async {
|
return lockingSignalProtocol.protect<SignalEncryptResult?>(() async {
|
||||||
return _signalEncryptMessage(target, plaintextContent);
|
return _signalEncryptMessageV1(target, plaintextContent);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<CiphertextMessage?> _signalEncryptMessage(
|
Future<SignalEncryptResult?> signalEncryptMessageV2(
|
||||||
|
int target,
|
||||||
|
Uint8List plaintextContent,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
final res = await RustSignal.encrypt(
|
||||||
|
name: target.toString(),
|
||||||
|
deviceId: 1,
|
||||||
|
plaintext: plaintextContent,
|
||||||
|
);
|
||||||
|
return SignalEncryptResult(res, pb.Message_Type.CIPHERTEXT_V2);
|
||||||
|
} catch (e) {
|
||||||
|
Log.error('Could not encrypt message (V2) for target $target: $e');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<SignalEncryptResult?> _signalEncryptMessageV1(
|
||||||
int target,
|
int target,
|
||||||
Uint8List plaintextContent,
|
Uint8List plaintextContent,
|
||||||
) async {
|
) async {
|
||||||
|
|
@ -27,29 +52,97 @@ Future<CiphertextMessage?> _signalEncryptMessage(
|
||||||
final signalStore = (await getSignalStore())!;
|
final signalStore = (await getSignalStore())!;
|
||||||
final address = getSignalAddress(target);
|
final address = getSignalAddress(target);
|
||||||
final session = SessionCipher.fromStore(signalStore, address);
|
final session = SessionCipher.fromStore(signalStore, address);
|
||||||
return await session.encrypt(plaintextContent);
|
final cipherText = await session.encrypt(plaintextContent);
|
||||||
|
|
||||||
|
pb.Message_Type type;
|
||||||
|
switch (cipherText.getType()) {
|
||||||
|
case CiphertextMessage.prekeyType:
|
||||||
|
type = pb.Message_Type.PREKEY_BUNDLE;
|
||||||
|
case CiphertextMessage.whisperType:
|
||||||
|
type = pb.Message_Type.CIPHERTEXT;
|
||||||
|
default:
|
||||||
|
Log.error('Invalid ciphertext type: ${cipherText.getType()}.');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SignalEncryptResult(cipherText.serialize(), type);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error('Could not encrypt message for target $target: $e');
|
Log.error('Could not encrypt message (V1) for target $target: $e');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<(EncryptedContent?, PlaintextContent_DecryptionErrorMessage_Type?)>
|
Future<(pb.EncryptedContent?, pb.PlaintextContent_DecryptionErrorMessage_Type?)>
|
||||||
signalDecryptMessage(
|
signalDecryptMessageV2(
|
||||||
int fromUserId,
|
int fromUserId,
|
||||||
Uint8List encryptedContentRaw,
|
Uint8List encryptedContentRaw, {
|
||||||
int type, {
|
|
||||||
Set<int>? brokenSessionsInCurrentBatch,
|
Set<int>? brokenSessionsInCurrentBatch,
|
||||||
}) async {
|
}) async {
|
||||||
// Hold the lock only for the cryptographic operation, not for network I/O
|
Log.info('Acquiring lockingSignalProtocol for $fromUserId (V2)');
|
||||||
Log.info('Acquiring lockingSignalProtocol for $fromUserId');
|
|
||||||
final (
|
final (
|
||||||
decryptedContent,
|
decryptedContent,
|
||||||
errorType,
|
errorType,
|
||||||
needsResync,
|
needsResync,
|
||||||
) = await lockingSignalProtocol.protect(() async {
|
) = await lockingSignalProtocol.protect(() async {
|
||||||
Log.info('Lock acquired for $fromUserId');
|
Log.info('Lock acquired for $fromUserId (V2)');
|
||||||
try {
|
try {
|
||||||
|
final plaintext = await RustSignal.decrypt(
|
||||||
|
name: fromUserId.toString(),
|
||||||
|
deviceId: 1,
|
||||||
|
ciphertext: encryptedContentRaw,
|
||||||
|
);
|
||||||
|
recordResyncAttempt(fromUserId, success: true);
|
||||||
|
return (pb.EncryptedContent.fromBuffer(plaintext), null, false);
|
||||||
|
} catch (e) {
|
||||||
|
Log.error('Could not decrypt message (V2) from $fromUserId: $e');
|
||||||
|
return (
|
||||||
|
null,
|
||||||
|
pb.PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN,
|
||||||
|
true, // Needs resync on failure
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Log.info('Released lockingSignalProtocol for $fromUserId (V2)');
|
||||||
|
|
||||||
|
if (needsResync) {
|
||||||
|
brokenSessionsInCurrentBatch?.add(fromUserId);
|
||||||
|
if (shouldAttemptResync(fromUserId)) {
|
||||||
|
if (await handleSessionResync(fromUserId)) {
|
||||||
|
recordResyncAttempt(fromUserId, success: false);
|
||||||
|
await sendCipherText(
|
||||||
|
fromUserId,
|
||||||
|
pb.EncryptedContent(
|
||||||
|
errorMessages: pb.EncryptedContent_ErrorMessages(
|
||||||
|
type: pb.EncryptedContent_ErrorMessages_Type.SESSION_OUT_OF_SYNC,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (decryptedContent, errorType);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<(pb.EncryptedContent?, pb.PlaintextContent_DecryptionErrorMessage_Type?)>
|
||||||
|
signalDecryptMessageV1(
|
||||||
|
int fromUserId,
|
||||||
|
Uint8List encryptedContentRaw,
|
||||||
|
int type, {
|
||||||
|
Set<int>? brokenSessionsInCurrentBatch,
|
||||||
|
}) async {
|
||||||
|
Log.info('Acquiring lockingSignalProtocol for $fromUserId (V1)');
|
||||||
|
final (
|
||||||
|
decryptedContent,
|
||||||
|
errorType,
|
||||||
|
needsResync,
|
||||||
|
) = await lockingSignalProtocol.protect(() async {
|
||||||
|
Log.info('Lock acquired for $fromUserId (V1)');
|
||||||
|
try {
|
||||||
|
// Yield execution to the event loop to prevent UI freezing during bulk decryption
|
||||||
|
await Future.delayed(Duration.zero);
|
||||||
|
|
||||||
final session = SessionCipher.fromStore(
|
final session = SessionCipher.fromStore(
|
||||||
(await getSignalStore())!,
|
(await getSignalStore())!,
|
||||||
getSignalAddress(fromUserId),
|
getSignalAddress(fromUserId),
|
||||||
|
|
@ -70,18 +163,18 @@ signalDecryptMessage(
|
||||||
Log.error('Unknown Message Decryption Type: $type');
|
Log.error('Unknown Message Decryption Type: $type');
|
||||||
return (
|
return (
|
||||||
null,
|
null,
|
||||||
PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN,
|
pb.PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
recordResyncAttempt(fromUserId, success: true);
|
recordResyncAttempt(fromUserId, success: true);
|
||||||
return (EncryptedContent.fromBuffer(plaintext), null, false);
|
return (pb.EncryptedContent.fromBuffer(plaintext), null, false);
|
||||||
} on InvalidKeyIdException catch (e) {
|
} on InvalidKeyIdException catch (e) {
|
||||||
Log.warn(e);
|
Log.warn(e);
|
||||||
return (
|
return (
|
||||||
null,
|
null,
|
||||||
PlaintextContent_DecryptionErrorMessage_Type.PREKEY_UNKNOWN,
|
pb.PlaintextContent_DecryptionErrorMessage_Type.PREKEY_UNKNOWN,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
} on DuplicateMessageException catch (e) {
|
} on DuplicateMessageException catch (e) {
|
||||||
|
|
@ -91,27 +184,27 @@ signalDecryptMessage(
|
||||||
Log.info(e);
|
Log.info(e);
|
||||||
return (
|
return (
|
||||||
null,
|
null,
|
||||||
PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN,
|
pb.PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
} on InvalidMessageException catch (e) {
|
} on InvalidMessageException catch (e) {
|
||||||
Log.warn(e);
|
Log.warn(e);
|
||||||
return (
|
return (
|
||||||
null,
|
null,
|
||||||
PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN,
|
pb.PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error(e);
|
Log.error(e);
|
||||||
return (
|
return (
|
||||||
null,
|
null,
|
||||||
PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN,
|
pb.PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Log.info('Released lockingSignalProtocol for $fromUserId');
|
Log.info('Released lockingSignalProtocol for $fromUserId (V1)');
|
||||||
|
|
||||||
// Handle session resync OUTSIDE the lock to avoid holding it during
|
// Handle session resync OUTSIDE the lock to avoid holding it during
|
||||||
// network round-trips (which can block for up to 60 seconds)
|
// network round-trips (which can block for up to 60 seconds)
|
||||||
|
|
@ -127,9 +220,9 @@ signalDecryptMessage(
|
||||||
// session
|
// session
|
||||||
await sendCipherText(
|
await sendCipherText(
|
||||||
fromUserId,
|
fromUserId,
|
||||||
EncryptedContent(
|
pb.EncryptedContent(
|
||||||
errorMessages: EncryptedContent_ErrorMessages(
|
errorMessages: pb.EncryptedContent_ErrorMessages(
|
||||||
type: EncryptedContent_ErrorMessages_Type.SESSION_OUT_OF_SYNC,
|
type: pb.EncryptedContent_ErrorMessages_Type.SESSION_OUT_OF_SYNC,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:clock/clock.dart';
|
import 'package:clock/clock.dart';
|
||||||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
||||||
import 'package:twonly/core/bridge/wrapper/key_manager.dart';
|
import 'package:twonly/core/bridge/wrapper/key_manager.dart';
|
||||||
|
import 'package:twonly/core/bridge/wrapper/signal.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/database/signal/signal_signed_pre_key_store.dart';
|
import 'package:twonly/src/database/signal/signal_signed_pre_key_store.dart';
|
||||||
import 'package:twonly/src/model/json/signal_identity.model.dart';
|
import 'package:twonly/src/model/json/signal_identity.model.dart';
|
||||||
|
|
@ -13,26 +15,20 @@ import 'package:twonly/src/utils/log.dart';
|
||||||
|
|
||||||
class SignalIdentityService {
|
class SignalIdentityService {
|
||||||
static Future<void> onAuthenticated() async {
|
static Future<void> onAuthenticated() async {
|
||||||
if (userService.currentUser.signalLastSignedPreKeyUpdated != null) {
|
final now = clock.now();
|
||||||
final fortyEightHoursAgo = clock.now().subtract(
|
final fortyEightHoursAgo = now.subtract(const Duration(hours: 48));
|
||||||
const Duration(hours: 48),
|
final oneWeekAgo = now.subtract(const Duration(days: 7));
|
||||||
);
|
|
||||||
final isYoungerThan48Hours =
|
if (userService.currentUser.signalLastSignedPreKeyUpdated == null ||
|
||||||
(userService.currentUser.signalLastSignedPreKeyUpdated!).isAfter(
|
!userService.currentUser.signalLastSignedPreKeyUpdated!.isAfter(
|
||||||
fortyEightHoursAgo,
|
fortyEightHoursAgo,
|
||||||
);
|
)) {
|
||||||
if (isYoungerThan48Hours) {
|
|
||||||
// The key does live for 48 hours then it expires and a new key is generated.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final signedPreKey = await _getNewSignalSignedPreKey();
|
final signedPreKey = await _getNewSignalSignedPreKey();
|
||||||
if (signedPreKey == null) {
|
if (signedPreKey == null) {
|
||||||
Log.error('could not generate a new signed pre key!');
|
Log.error('could not generate a new signed pre key!');
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
await UserService.update((user) {
|
await UserService.update((user) {
|
||||||
user.signalLastSignedPreKeyUpdated = clock.now();
|
user.signalLastSignedPreKeyUpdated = now;
|
||||||
});
|
});
|
||||||
final res = await apiService.updateSignedPreKey(
|
final res = await apiService.updateSignedPreKey(
|
||||||
signedPreKey.id,
|
signedPreKey.id,
|
||||||
|
|
@ -50,6 +46,34 @@ class SignalIdentityService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (userService.currentUser.signalLastPqcPreKeysUploaded == null ||
|
||||||
|
!userService.currentUser.signalLastPqcPreKeysUploaded!.isAfter(
|
||||||
|
oneWeekAgo,
|
||||||
|
)) {
|
||||||
|
final bundle = await RustSignal.generateBundle();
|
||||||
|
|
||||||
|
final pqcRes = await apiService.uploadPqcPreKeys(
|
||||||
|
bundle.signedPreKeyId,
|
||||||
|
bundle.signedPreKeyPublic,
|
||||||
|
bundle.signedPreKeySignature,
|
||||||
|
bundle.kyberPreKeyId,
|
||||||
|
bundle.kyberPreKeyPublic,
|
||||||
|
bundle.kyberPreKeySignature,
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pqcRes.isError) {
|
||||||
|
Log.warn('could not update the pqc signed pre key: ${pqcRes.error}');
|
||||||
|
} else {
|
||||||
|
Log.info('updated pqc signed pre key');
|
||||||
|
await UserService.update((user) {
|
||||||
|
user.signalLastPqcPreKeysUploaded = now;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<PreKeyRecord>> signalGetPreKeys() async {
|
Future<List<PreKeyRecord>> signalGetPreKeys() async {
|
||||||
return lockingSignalProtocol.protect(() async {
|
return lockingSignalProtocol.protect(() async {
|
||||||
final start = userService.currentUser.currentPreKeyIndexStart;
|
final start = userService.currentUser.currentPreKeyIndexStart;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:drift/drift.dart' as drift;
|
||||||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
||||||
|
import 'package:twonly/core/bridge/wrapper/signal.dart';
|
||||||
|
import 'package:twonly/core/signal/engine.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
|
import 'package:twonly/src/database/tables/contacts.table.dart';
|
||||||
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart';
|
import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart';
|
||||||
import 'package:twonly/src/services/signal/consts.signal.dart';
|
import 'package:twonly/src/services/signal/consts.signal.dart';
|
||||||
import 'package:twonly/src/services/signal/protocol_state.signal.dart';
|
import 'package:twonly/src/services/signal/protocol_state.signal.dart';
|
||||||
|
|
@ -15,6 +20,106 @@ Future<bool> processSignalUserData(Response_UserData userData) async {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _processSignalUserData(Response_UserData userData) async {
|
Future<bool> _processSignalUserData(Response_UserData userData) async {
|
||||||
|
if (userData.hasPqcBundle()) {
|
||||||
|
return _processSignalUserDataV2(userData);
|
||||||
|
}
|
||||||
|
return _processSignalUserDataV1(userData);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _processSignalUserDataV2(Response_UserData userData) async {
|
||||||
|
try {
|
||||||
|
final tempIdentityKey = IdentityKey(
|
||||||
|
Curve.decodePoint(
|
||||||
|
DjbECPublicKey(
|
||||||
|
Uint8List.fromList(userData.publicIdentityKey),
|
||||||
|
).serialize(),
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final signalStore = await getSignalStore();
|
||||||
|
if (signalStore != null) {
|
||||||
|
final existingIdentity = await signalStore.getIdentity(
|
||||||
|
SignalProtocolAddress(userData.userId.toString(), defaultDeviceId),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingIdentity != null && existingIdentity != tempIdentityKey) {
|
||||||
|
Log.error(
|
||||||
|
'Identity key mismatch for contact ${userData.userId}! Existing V1 key does not match the incoming V2 identity key.',
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int? tempEccPreKeyId;
|
||||||
|
Uint8List? tempEccPreKeyPublic;
|
||||||
|
if (userData.pqcBundle.hasPrekey()) {
|
||||||
|
tempEccPreKeyId = userData.pqcBundle.prekey.eccPreKeyId.toInt();
|
||||||
|
tempEccPreKeyPublic = Uint8List.fromList(
|
||||||
|
userData.pqcBundle.prekey.eccPreKey,
|
||||||
|
);
|
||||||
|
} else if (userData.prekeys.isNotEmpty) {
|
||||||
|
tempEccPreKeyId = userData.prekeys.first.id.toInt();
|
||||||
|
tempEccPreKeyPublic = Curve.decodePoint(
|
||||||
|
DjbECPublicKey(
|
||||||
|
Uint8List.fromList(userData.prekeys.first.prekey),
|
||||||
|
).serialize(),
|
||||||
|
1,
|
||||||
|
).serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
final tempKyberPreKeyId = userData.pqcBundle.hasPrekey()
|
||||||
|
? userData.pqcBundle.prekey.kyberPreKeyId.toInt()
|
||||||
|
: userData.pqcBundle.kyberSignedPrekeyId.toInt();
|
||||||
|
final tempKyberPreKeyPublic = userData.pqcBundle.hasPrekey()
|
||||||
|
? Uint8List.fromList(userData.pqcBundle.prekey.kyberPreKey)
|
||||||
|
: Uint8List.fromList(userData.pqcBundle.kyberSignedPrekey);
|
||||||
|
final tempKyberPreKeySignature = userData.pqcBundle.hasPrekey()
|
||||||
|
? Uint8List.fromList(userData.pqcBundle.prekey.kyberPreKeySignature)
|
||||||
|
: Uint8List.fromList(userData.pqcBundle.kyberSignedPrekeySignature);
|
||||||
|
|
||||||
|
final rustBundle = FrbPreKeyBundle(
|
||||||
|
registrationId: userData.registrationId.toInt(),
|
||||||
|
deviceId: 1,
|
||||||
|
preKeyId: tempEccPreKeyId,
|
||||||
|
preKeyPublic: tempEccPreKeyPublic,
|
||||||
|
signedPreKeyId: userData.pqcBundle.eccSignedPrekeyId.toInt(),
|
||||||
|
signedPreKeyPublic: Uint8List.fromList(
|
||||||
|
userData.pqcBundle.eccSignedPrekey,
|
||||||
|
),
|
||||||
|
signedPreKeySignature: Uint8List.fromList(
|
||||||
|
userData.pqcBundle.eccSignedPrekeySignature,
|
||||||
|
),
|
||||||
|
identityKey: tempIdentityKey.publicKey.serialize(),
|
||||||
|
kyberPreKeyId: tempKyberPreKeyId,
|
||||||
|
kyberPreKeyPublic: tempKyberPreKeyPublic,
|
||||||
|
kyberPreKeySignature: tempKyberPreKeySignature,
|
||||||
|
);
|
||||||
|
|
||||||
|
await RustSignal.processPrekeyBundle(
|
||||||
|
name: userData.userId.toString(),
|
||||||
|
deviceId: 1,
|
||||||
|
bundle: rustBundle,
|
||||||
|
);
|
||||||
|
|
||||||
|
final contact = await twonlyDB.contactsDao.getContactById(
|
||||||
|
userData.userId.toInt(),
|
||||||
|
);
|
||||||
|
if (contact != null && contact.signalVersion != SignalVersion.v2) {
|
||||||
|
await twonlyDB.contactsDao.updateContact(
|
||||||
|
contact.userId,
|
||||||
|
const ContactsCompanion(signalVersion: drift.Value(SignalVersion.v2)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
Log.error('could not process pqc bundle: $e');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _processSignalUserDataV1(Response_UserData userData) async {
|
||||||
final SignalProtocolStore? signalStore = await getSignalStore();
|
final SignalProtocolStore? signalStore = await getSignalStore();
|
||||||
|
|
||||||
if (signalStore == null) {
|
if (signalStore == null) {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/utils/log.dart';
|
import 'package:twonly/src/utils/log.dart';
|
||||||
|
|
@ -114,11 +115,14 @@ File currentUserAvatarFile(int avatarCounter) {
|
||||||
return File('${avatarsDirectory.path}/user_$avatarCounter.png');
|
return File('${avatarsDirectory.path}/user_$avatarCounter.png');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final _avatarMutex = Mutex();
|
||||||
|
|
||||||
Future<String?> getUserAvatar() async {
|
Future<String?> getUserAvatar() async {
|
||||||
if (userService.currentUser.avatarSvg == null) {
|
if (userService.currentUser.avatarSvg == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return _avatarMutex.protect(() async {
|
||||||
final avatarCounter = userService.currentUser.avatarCounter;
|
final avatarCounter = userService.currentUser.avatarCounter;
|
||||||
final file = currentUserAvatarFile(avatarCounter);
|
final file = currentUserAvatarFile(avatarCounter);
|
||||||
if (file.existsSync()) {
|
if (file.existsSync()) {
|
||||||
|
|
@ -135,8 +139,9 @@ Future<String?> getUserAvatar() async {
|
||||||
final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
|
final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
|
||||||
final pngBytes = byteData!.buffer.asUint8List();
|
final pngBytes = byteData!.buffer.asUint8List();
|
||||||
|
|
||||||
await file.writeAsBytes(pngBytes);
|
await file.writeAsBytes(pngBytes, flush: true);
|
||||||
pictureInfo.picture.dispose();
|
pictureInfo.picture.dispose();
|
||||||
|
|
||||||
return file.path;
|
return file.path;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:isolate';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:clock/clock.dart';
|
import 'package:clock/clock.dart';
|
||||||
|
|
@ -6,7 +7,6 @@ import 'package:convert/convert.dart';
|
||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
|
||||||
import 'package:gal/gal.dart';
|
import 'package:gal/gal.dart';
|
||||||
import 'package:image/image.dart' as img;
|
import 'package:image/image.dart' as img;
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
@ -44,6 +44,7 @@ Future<String?> saveImageToGallery(
|
||||||
|
|
||||||
if (createdAt != null) {
|
if (createdAt != null) {
|
||||||
try {
|
try {
|
||||||
|
bytesToProcess = await Isolate.run(() {
|
||||||
final image = img.decodeImage(imageBytes);
|
final image = img.decodeImage(imageBytes);
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
final formattedDate = DateFormat(
|
final formattedDate = DateFormat(
|
||||||
|
|
@ -59,26 +60,25 @@ Future<String?> saveImageToGallery(
|
||||||
formattedDate,
|
formattedDate,
|
||||||
); // DateTimeDigitized
|
); // DateTimeDigitized
|
||||||
|
|
||||||
bytesToProcess = img.encodeJpg(image);
|
return img.encodeJpg(image);
|
||||||
}
|
}
|
||||||
|
return imageBytes;
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error(e);
|
Log.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final jpgImages = await FlutterImageCompress.compressWithList(
|
|
||||||
// ignore: avoid_redundant_argument_values
|
|
||||||
format: CompressFormat.jpeg,
|
|
||||||
bytesToProcess,
|
|
||||||
quality: 100,
|
|
||||||
keepExif: true,
|
|
||||||
);
|
|
||||||
final hasAccess = await Gal.hasAccess(toAlbum: true);
|
final hasAccess = await Gal.hasAccess(toAlbum: true);
|
||||||
if (!hasAccess) {
|
if (!hasAccess) {
|
||||||
await Gal.requestAccess(toAlbum: true);
|
await Gal.requestAccess(toAlbum: true);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await Gal.putImageBytes(jpgImages, album: 'twonly', name: name ?? 'image');
|
await Gal.putImageBytes(
|
||||||
|
bytesToProcess,
|
||||||
|
album: 'twonly',
|
||||||
|
name: name ?? 'image',
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
} on GalException catch (e) {
|
} on GalException catch (e) {
|
||||||
Log.error(e);
|
Log.error(e);
|
||||||
|
|
@ -210,6 +210,10 @@ Future<bool> authenticateUser(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Catch unexpected platform exceptions (e.g. PlatformException) that
|
||||||
|
// would otherwise propagate and leave callers in a broken state.
|
||||||
|
Log.error('Unexpected authentication error: $e');
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -260,6 +264,28 @@ String formatDateTime(BuildContext context, DateTime? dateTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String formatRelativeDateTime(BuildContext context, DateTime? dateTime) {
|
||||||
|
if (dateTime == null) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
final now = clock.now();
|
||||||
|
final today = DateTime(now.year, now.month, now.day);
|
||||||
|
final yesterday = today.subtract(const Duration(days: 1));
|
||||||
|
final dateDay = DateTime(dateTime.year, dateTime.month, dateTime.day);
|
||||||
|
|
||||||
|
final time = DateFormat.Hm(
|
||||||
|
Localizations.localeOf(context).toLanguageTag(),
|
||||||
|
).format(dateTime);
|
||||||
|
|
||||||
|
if (dateDay == today) {
|
||||||
|
return context.lang.todayAt(time);
|
||||||
|
} else if (dateDay == yesterday) {
|
||||||
|
return context.lang.yesterdayAt(time);
|
||||||
|
} else {
|
||||||
|
return formatDateTime(context, dateTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String formatBytes(int bytes) {
|
String formatBytes(int bytes) {
|
||||||
if (bytes <= 0) return '0 Bytes';
|
if (bytes <= 0) return '0 Bytes';
|
||||||
const units = <String>['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
const units = <String>['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,27 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:twonly/locator.dart';
|
||||||
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/utils/secure_storage.dart';
|
import 'package:twonly/src/utils/secure_storage.dart';
|
||||||
|
|
||||||
Future<bool> deleteLocalUserData() async {
|
Future<bool> deleteLocalUserData() async {
|
||||||
|
await twonlyDB.close();
|
||||||
|
// Wait for the background drift isolate to potentially shut down
|
||||||
|
await Future.delayed(const Duration(milliseconds: 200));
|
||||||
|
|
||||||
|
// Remove port mappings to prevent connecting to an old, detached isolate that holds a deleted DB file.
|
||||||
|
IsolateNameServer.removePortNameMapping('drift-db/twonly');
|
||||||
|
IsolateNameServer.removePortNameMapping('drift-db/twonly/control');
|
||||||
|
|
||||||
final appDir = await getApplicationSupportDirectory();
|
final appDir = await getApplicationSupportDirectory();
|
||||||
if (appDir.existsSync()) {
|
if (appDir.existsSync()) {
|
||||||
appDir.deleteSync(recursive: true);
|
appDir.deleteSync(recursive: true);
|
||||||
}
|
}
|
||||||
await SecureStorage.instance.deleteAll();
|
await SecureStorage.instance.deleteAll();
|
||||||
|
locator
|
||||||
|
..unregister<TwonlyDB>()
|
||||||
|
..registerLazySingleton<TwonlyDB>(TwonlyDB.new);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
148
lib/src/visual/components/cached_network_image.dart
Normal file
148
lib/src/visual/components/cached_network_image.dart
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:crypto/crypto.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
class CachedNetworkImage extends StatefulWidget {
|
||||||
|
const CachedNetworkImage({
|
||||||
|
required this.imageUrl,
|
||||||
|
super.key,
|
||||||
|
this.width,
|
||||||
|
this.height,
|
||||||
|
this.fit,
|
||||||
|
this.placeholder,
|
||||||
|
this.errorWidget,
|
||||||
|
});
|
||||||
|
final String imageUrl;
|
||||||
|
final double? width;
|
||||||
|
final double? height;
|
||||||
|
final BoxFit? fit;
|
||||||
|
final Widget Function(BuildContext, String)? placeholder;
|
||||||
|
final Widget Function(BuildContext, String, dynamic)? errorWidget;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CachedNetworkImage> createState() => _CachedNetworkImageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CachedNetworkImageState extends State<CachedNetworkImage> {
|
||||||
|
File? _imageFile;
|
||||||
|
bool _isLoading = true;
|
||||||
|
dynamic _error;
|
||||||
|
static bool _hasCleanedUp = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_loadImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(CachedNetworkImage oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (oldWidget.imageUrl != widget.imageUrl) {
|
||||||
|
_loadImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadImage() async {
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() {
|
||||||
|
_isLoading = true;
|
||||||
|
_error = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
final cacheDir = await getTemporaryDirectory();
|
||||||
|
final urlHash = md5.convert(utf8.encode(widget.imageUrl)).toString();
|
||||||
|
final file = File('${cacheDir.path}/custom_cached_image_$urlHash');
|
||||||
|
|
||||||
|
if (!_hasCleanedUp) {
|
||||||
|
_hasCleanedUp = true;
|
||||||
|
unawaited(_cleanupOldFiles(cacheDir)); // Run asynchronously
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.existsSync()) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_imageFile = file;
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final client = HttpClient();
|
||||||
|
final request = await client.getUrl(Uri.parse(widget.imageUrl));
|
||||||
|
final response = await request.close();
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
await response.pipe(file.openWrite());
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_imageFile = file;
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load image: ${response.statusCode}');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_error = e;
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _cleanupOldFiles(Directory cacheDir) async {
|
||||||
|
try {
|
||||||
|
final files = cacheDir.listSync();
|
||||||
|
final now = DateTime.now();
|
||||||
|
for (final f in files) {
|
||||||
|
if (f is File && f.path.contains('custom_cached_image_')) {
|
||||||
|
final stat = f.statSync();
|
||||||
|
if (now.difference(stat.modified).inDays >= 7) {
|
||||||
|
await f.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// Ignore cleanup errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (_isLoading) {
|
||||||
|
if (widget.placeholder != null) {
|
||||||
|
return widget.placeholder!(context, widget.imageUrl);
|
||||||
|
}
|
||||||
|
return SizedBox(width: widget.width, height: widget.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_error != null || _imageFile == null) {
|
||||||
|
if (widget.errorWidget != null) {
|
||||||
|
return widget.errorWidget!(context, widget.imageUrl, _error);
|
||||||
|
}
|
||||||
|
return SizedBox(width: widget.width, height: widget.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Image.file(
|
||||||
|
_imageFile!,
|
||||||
|
width: widget.width,
|
||||||
|
height: widget.height,
|
||||||
|
fit: widget.fit,
|
||||||
|
errorBuilder: (context, error, stackTrace) {
|
||||||
|
if (widget.errorWidget != null) {
|
||||||
|
return widget.errorWidget!(context, widget.imageUrl, error);
|
||||||
|
}
|
||||||
|
return SizedBox(width: widget.width, height: widget.height);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
144
lib/src/visual/components/contact_labels.comp.dart
Normal file
144
lib/src/visual/components/contact_labels.comp.dart
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:twonly/locator.dart';
|
||||||
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
|
||||||
|
class ContactLabels extends StatefulWidget {
|
||||||
|
const ContactLabels({
|
||||||
|
required this.contactId,
|
||||||
|
this.fontSize = 8,
|
||||||
|
this.padding = const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||||
|
this.emptyText,
|
||||||
|
this.showEmptyText = false,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final int contactId;
|
||||||
|
final double fontSize;
|
||||||
|
final EdgeInsetsGeometry padding;
|
||||||
|
final String? emptyText;
|
||||||
|
final bool showEmptyText;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ContactLabels> createState() => _ContactLabelsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ContactLabelsState extends State<ContactLabels> {
|
||||||
|
List<Label> _labels = [];
|
||||||
|
late StreamSubscription<List<Label>> _sub;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_sub = twonlyDB.labelsDao.watchContactLabels(widget.contactId).listen((
|
||||||
|
labels,
|
||||||
|
) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_labels = labels;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_sub.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (_labels.isEmpty) {
|
||||||
|
if (!widget.showEmptyText && widget.emptyText == null) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
return Text(
|
||||||
|
widget.emptyText ?? context.lang.contactLabelsSubtitleEmpty,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: widget.fontSize,
|
||||||
|
color: Theme.of(context).disabledColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Wrap(
|
||||||
|
spacing: 4,
|
||||||
|
runSpacing: 2,
|
||||||
|
children: _labels.map((label) {
|
||||||
|
final bgColor = Color(label.backgroundColor);
|
||||||
|
final textColor = Color(label.textColor);
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
padding: widget.padding,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: bgColor,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
label.name,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: widget.fontSize,
|
||||||
|
color: textColor,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget? buildContactLabelsSubtitle({
|
||||||
|
required int contactId,
|
||||||
|
required List<Label> labels,
|
||||||
|
Widget? additionalSubtitle,
|
||||||
|
}) {
|
||||||
|
if (additionalSubtitle != null) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
additionalSubtitle,
|
||||||
|
if (labels.isNotEmpty)
|
||||||
|
ContactLabels(contactId: contactId),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labels.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ContactLabels(contactId: contactId);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ContactLabelsSubtitleBuilder extends StatelessWidget {
|
||||||
|
const ContactLabelsSubtitleBuilder({
|
||||||
|
required this.contactId,
|
||||||
|
required this.builder,
|
||||||
|
this.additionalSubtitle,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final int contactId;
|
||||||
|
final Widget? additionalSubtitle;
|
||||||
|
final Widget Function(BuildContext context, Widget? subtitleWidget) builder;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return StreamBuilder<List<Label>>(
|
||||||
|
stream: twonlyDB.labelsDao.watchContactLabels(contactId),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final labels = snapshot.data ?? [];
|
||||||
|
final subtitle = buildContactLabelsSubtitle(
|
||||||
|
contactId: contactId,
|
||||||
|
labels: labels,
|
||||||
|
additionalSubtitle: additionalSubtitle,
|
||||||
|
);
|
||||||
|
return builder(context, subtitle);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,6 @@ import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/constants/routes.keys.dart';
|
import 'package:twonly/src/constants/routes.keys.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/visual/components/notification_badge.comp.dart';
|
import 'package:twonly/src/visual/components/notification_badge.comp.dart';
|
||||||
import 'package:twonly/src/visual/themes/light.dart';
|
|
||||||
|
|
||||||
class ContactRequestBadgeComp extends StatelessWidget {
|
class ContactRequestBadgeComp extends StatelessWidget {
|
||||||
const ContactRequestBadgeComp({super.key});
|
const ContactRequestBadgeComp({super.key});
|
||||||
|
|
@ -26,8 +25,8 @@ class ContactRequestBadgeComp extends StatelessWidget {
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 40,
|
height: 40,
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: primaryColor,
|
color: context.color.primary,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
114
lib/src/visual/components/custom_color_picker_dialog.comp.dart
Normal file
114
lib/src/visual/components/custom_color_picker_dialog.comp.dart
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
import 'package:twonly/src/visual/elements/my_button.element.dart';
|
||||||
|
|
||||||
|
class CustomColorPickerDialog extends StatefulWidget {
|
||||||
|
const CustomColorPickerDialog({
|
||||||
|
required this.initialColor,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Color initialColor;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CustomColorPickerDialog> createState() => _CustomColorPickerDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomColorPickerDialogState extends State<CustomColorPickerDialog> {
|
||||||
|
late HSVColor _hsvColor;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_hsvColor = HSVColor.fromColor(widget.initialColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final currentColor = _hsvColor.toColor();
|
||||||
|
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(context.lang.customColor),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Color preview box
|
||||||
|
Center(
|
||||||
|
child: Container(
|
||||||
|
width: 80,
|
||||||
|
height: 80,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: currentColor,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withValues(alpha: 0.15),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: const Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
// Hue Slider
|
||||||
|
Text(context.lang.hue, style: const TextStyle(fontWeight: FontWeight.w600)),
|
||||||
|
Slider(
|
||||||
|
value: _hsvColor.hue,
|
||||||
|
max: 360,
|
||||||
|
activeColor: HSVColor.fromAHSV(1, _hsvColor.hue, 1, 1).toColor(),
|
||||||
|
onChanged: (val) {
|
||||||
|
setState(() {
|
||||||
|
_hsvColor = _hsvColor.withHue(val);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// Saturation Slider
|
||||||
|
Text(context.lang.saturation, style: const TextStyle(fontWeight: FontWeight.w600)),
|
||||||
|
Slider(
|
||||||
|
value: _hsvColor.saturation,
|
||||||
|
onChanged: (val) {
|
||||||
|
setState(() {
|
||||||
|
_hsvColor = _hsvColor.withSaturation(val);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// Brightness / Value Slider
|
||||||
|
Text(context.lang.brightness, style: const TextStyle(fontWeight: FontWeight.w600)),
|
||||||
|
Slider(
|
||||||
|
value: _hsvColor.value,
|
||||||
|
onChanged: (val) {
|
||||||
|
setState(() {
|
||||||
|
_hsvColor = _hsvColor.withValue(val);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: MyButton(
|
||||||
|
variant: MyButtonVariant.text,
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: Text(context.lang.cancel),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: MyButton(
|
||||||
|
variant: MyButtonVariant.primaryMiddle,
|
||||||
|
onPressed: () => Navigator.of(context).pop(currentColor.toARGB32()),
|
||||||
|
child: Text(context.lang.ok),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
328
lib/src/visual/components/label_editor_bottom_sheet.comp.dart
Normal file
328
lib/src/visual/components/label_editor_bottom_sheet.comp.dart
Normal file
|
|
@ -0,0 +1,328 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
import 'package:twonly/src/visual/components/custom_color_picker_dialog.comp.dart';
|
||||||
|
import 'package:twonly/src/visual/elements/my_button.element.dart';
|
||||||
|
|
||||||
|
class LabelEditorBottomSheet extends StatefulWidget {
|
||||||
|
const LabelEditorBottomSheet({
|
||||||
|
this.label,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Label? label;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LabelEditorBottomSheet> createState() => _LabelEditorBottomSheetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LabelEditorBottomSheetState extends State<LabelEditorBottomSheet> {
|
||||||
|
late TextEditingController _nameController;
|
||||||
|
late int _selectedBgColor;
|
||||||
|
late int _selectedTextColor;
|
||||||
|
|
||||||
|
static const List<int> defaultBgColors = [
|
||||||
|
0xFFE57373, // Red
|
||||||
|
0xFFF06292, // Pink
|
||||||
|
0xFFBA68C8, // Purple
|
||||||
|
0xFF7986CB, // Indigo
|
||||||
|
0xFF64B5F6, // Blue
|
||||||
|
0xFF4DD0E1, // Cyan
|
||||||
|
0xFF4DB6AC, // Teal
|
||||||
|
0xFF81C784, // Green
|
||||||
|
0xFFFFB74D, // Amber
|
||||||
|
0xFFFF8A65, // Deep Orange
|
||||||
|
0xFF90A4AE, // Blue Grey
|
||||||
|
0xFF424242, // Dark Grey
|
||||||
|
];
|
||||||
|
|
||||||
|
static const List<int> defaultTextColors = [
|
||||||
|
0xFFFFFFFF, // White
|
||||||
|
0xFF121212, // Dark/Black
|
||||||
|
0xFF1B263B, // Deep Navy
|
||||||
|
0xFF8B0000, // Dark Red
|
||||||
|
0xFF004D40, // Dark Teal
|
||||||
|
0xFF4A148C, // Dark Purple
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_nameController = TextEditingController(text: widget.label?.name ?? '');
|
||||||
|
_selectedBgColor = widget.label?.backgroundColor ?? defaultBgColors[4];
|
||||||
|
_selectedTextColor = widget.label?.textColor ?? defaultTextColors[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_nameController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _pickCustomColor({required bool isBgColor}) async {
|
||||||
|
final initial = isBgColor ? Color(_selectedBgColor) : Color(_selectedTextColor);
|
||||||
|
final pickedColorInt = await showDialog<int>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => CustomColorPickerDialog(initialColor: initial),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pickedColorInt != null && mounted) {
|
||||||
|
setState(() {
|
||||||
|
if (isBgColor) {
|
||||||
|
_selectedBgColor = pickedColorInt;
|
||||||
|
} else {
|
||||||
|
_selectedTextColor = pickedColorInt;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final isEditing = widget.label != null;
|
||||||
|
final bottomInset = MediaQuery.of(context).viewInsets.bottom;
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: bottomInset),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).scaffoldBackgroundColor,
|
||||||
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
// Drag indicator handle
|
||||||
|
Center(
|
||||||
|
child: Container(
|
||||||
|
width: 40,
|
||||||
|
height: 4,
|
||||||
|
margin: const EdgeInsets.only(bottom: 16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey.shade400,
|
||||||
|
borderRadius: BorderRadius.circular(2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
isEditing ? context.lang.editLabel : context.lang.createLabel,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
// Interactive Inline Label Badge
|
||||||
|
Center(
|
||||||
|
child: IntrinsicWidth(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(minWidth: 100, maxWidth: 200),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Color(_selectedBgColor),
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 2),
|
||||||
|
child: TextField(
|
||||||
|
controller: _nameController,
|
||||||
|
autofocus: true,
|
||||||
|
maxLength: 8,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
textCapitalization: TextCapitalization.words,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Color(_selectedTextColor),
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: context.lang.labelNameHint,
|
||||||
|
hintStyle: TextStyle(
|
||||||
|
color: Color(_selectedTextColor).withValues(alpha: 0.6),
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
border: InputBorder.none,
|
||||||
|
isDense: true,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 4, vertical: 6),
|
||||||
|
counterText: '',
|
||||||
|
),
|
||||||
|
onChanged: (_) => setState(() {}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
// Background Color Section
|
||||||
|
Text(
|
||||||
|
context.lang.labelBackgroundColor,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Wrap(
|
||||||
|
alignment: WrapAlignment.center,
|
||||||
|
spacing: 10,
|
||||||
|
runSpacing: 10,
|
||||||
|
children: [
|
||||||
|
...defaultBgColors.map((colorValue) {
|
||||||
|
final selected = _selectedBgColor == colorValue;
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_selectedBgColor = colorValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Color(colorValue),
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: selected
|
||||||
|
? Icon(
|
||||||
|
Icons.check,
|
||||||
|
size: 18,
|
||||||
|
color: Color(colorValue).computeLuminance() > 0.5
|
||||||
|
? Colors.black
|
||||||
|
: Colors.white,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
// Custom Color Picker Button
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => _pickCustomColor(isBgColor: true),
|
||||||
|
child: Container(
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
gradient: SweepGradient(
|
||||||
|
colors: [
|
||||||
|
Colors.red,
|
||||||
|
Colors.yellow,
|
||||||
|
Colors.green,
|
||||||
|
Colors.cyan,
|
||||||
|
Colors.blue,
|
||||||
|
Colors.purple,
|
||||||
|
Colors.red,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.colorize,
|
||||||
|
size: 18,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
// Text Color Section
|
||||||
|
Text(
|
||||||
|
context.lang.labelTextColor,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Wrap(
|
||||||
|
alignment: WrapAlignment.center,
|
||||||
|
spacing: 10,
|
||||||
|
runSpacing: 10,
|
||||||
|
children: [
|
||||||
|
...defaultTextColors.map((colorValue) {
|
||||||
|
final selected = _selectedTextColor == colorValue;
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_selectedTextColor = colorValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Color(colorValue),
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: selected
|
||||||
|
? Icon(
|
||||||
|
Icons.check,
|
||||||
|
size: 18,
|
||||||
|
color: Color(colorValue).computeLuminance() > 0.5
|
||||||
|
? Colors.black
|
||||||
|
: Colors.white,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
// Custom Color Picker Button for Text
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => _pickCustomColor(isBgColor: false),
|
||||||
|
child: Container(
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
gradient: SweepGradient(
|
||||||
|
colors: [
|
||||||
|
Colors.red,
|
||||||
|
Colors.yellow,
|
||||||
|
Colors.green,
|
||||||
|
Colors.cyan,
|
||||||
|
Colors.blue,
|
||||||
|
Colors.purple,
|
||||||
|
Colors.red,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.colorize,
|
||||||
|
size: 18,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: MyButton(
|
||||||
|
variant: MyButtonVariant.text,
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: Text(context.lang.cancel),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: MyButton(
|
||||||
|
variant: MyButtonVariant.primaryMiddle,
|
||||||
|
onPressed: () {
|
||||||
|
final name = _nameController.text.trim();
|
||||||
|
if (name.isNotEmpty) {
|
||||||
|
Navigator.of(context).pop({
|
||||||
|
'name': name,
|
||||||
|
'backgroundColor': _selectedBgColor,
|
||||||
|
'textColor': _selectedTextColor,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text(context.lang.ok),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:twonly/src/visual/themes/light.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
|
||||||
class SelectableThumbnailComp extends StatelessWidget {
|
class SelectableThumbnailComp extends StatelessWidget {
|
||||||
const SelectableThumbnailComp({
|
const SelectableThumbnailComp({
|
||||||
|
|
@ -19,7 +19,7 @@ class SelectableThumbnailComp extends StatelessWidget {
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isSelected ? primaryColor : Colors.transparent,
|
color: isSelected ? context.color.primary : Colors.transparent,
|
||||||
boxShadow: const [
|
boxShadow: const [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black12,
|
color: Colors.black12,
|
||||||
|
|
@ -49,7 +49,7 @@ class SelectableThumbnailComp extends StatelessWidget {
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(2),
|
padding: const EdgeInsets.all(2),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isSelected ? primaryColor : Colors.black38,
|
color: isSelected ? context.color.primary : Colors.black38,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/visual/components/profile_qr_code.comp.dart';
|
import 'package:twonly/src/visual/components/profile_qr_code.comp.dart';
|
||||||
import 'package:twonly/src/visual/elements/my_button.element.dart';
|
import 'package:twonly/src/visual/elements/my_button.element.dart';
|
||||||
import 'package:twonly/src/visual/elements/svg_icon.element.dart';
|
import 'package:twonly/src/visual/elements/svg_icon.element.dart';
|
||||||
import 'package:twonly/src/visual/themes/light.dart';
|
|
||||||
|
|
||||||
const colorVerificationBadgeYellow = Color.fromARGB(255, 0, 182, 238);
|
const colorVerificationBadgeYellow = Color.fromARGB(255, 0, 182, 238);
|
||||||
|
|
||||||
|
|
@ -90,7 +89,7 @@ class VerificationBadgeInfo extends StatelessWidget {
|
||||||
context,
|
context,
|
||||||
icon: const SvgIcon(assetPath: SvgIcons.verifiedGreen, size: 40),
|
icon: const SvgIcon(assetPath: SvgIcons.verifiedGreen, size: 40),
|
||||||
description: context.lang.verificationBadgeGreenDesc,
|
description: context.lang.verificationBadgeGreenDesc,
|
||||||
boldTextColor: primaryColor,
|
boldTextColor: context.color.primary,
|
||||||
onTap: () => context.push(
|
onTap: () => context.push(
|
||||||
Routes.cameraQRScanner,
|
Routes.cameraQRScanner,
|
||||||
extra: {
|
extra: {
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ class VerificationSuccessAnimationState
|
||||||
'<svg viewBox="0 0 640 640"><path d="$_path2" fill="white"/></svg>';
|
'<svg viewBox="0 0 640 640"><path d="$_path2" fill="white"/></svg>';
|
||||||
|
|
||||||
static const _grey = Color(0xFF8E9AAF);
|
static const _grey = Color(0xFF8E9AAF);
|
||||||
static const Color _green = primaryColor;
|
static const Color _green = defaultPrimaryColor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ class BetterText extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// Regular expression to find URLs and domains
|
// Regular expression to find URLs and domains
|
||||||
final urlRegExp = RegExp(
|
final urlRegExp = RegExp(
|
||||||
r'(?:(?:https?://|www\.)[^\s]+|(?:[a-zA-Z0-9-]+\.[a-zA-Z]{2,}))',
|
r'''(?:(?:https?://|www\.)(?:[^\s()<>]+|\([^\s()<>]+\))+(?:\([^\s()<>]+\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))|(?:(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,})''',
|
||||||
caseSensitive: false,
|
caseSensitive: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/visual/elements/reactive_tap_feedback.element.dart';
|
import 'package:twonly/src/visual/elements/reactive_tap_feedback.element.dart';
|
||||||
import 'package:twonly/src/visual/themes/light.dart';
|
|
||||||
|
|
||||||
enum MyButtonVariant {
|
enum MyButtonVariant {
|
||||||
primary,
|
primary,
|
||||||
|
|
@ -49,7 +48,7 @@ class _MyButtonState extends State<MyButton> {
|
||||||
switch (widget.variant) {
|
switch (widget.variant) {
|
||||||
case MyButtonVariant.primary:
|
case MyButtonVariant.primary:
|
||||||
buttonStyle = FilledButton.styleFrom(
|
buttonStyle = FilledButton.styleFrom(
|
||||||
backgroundColor: primaryColor,
|
backgroundColor: context.color.primary,
|
||||||
foregroundColor: Colors.black87,
|
foregroundColor: Colors.black87,
|
||||||
disabledBackgroundColor: disabledBgColor,
|
disabledBackgroundColor: disabledBgColor,
|
||||||
disabledForegroundColor: disabledFgColor,
|
disabledForegroundColor: disabledFgColor,
|
||||||
|
|
@ -96,7 +95,7 @@ class _MyButtonState extends State<MyButton> {
|
||||||
);
|
);
|
||||||
case MyButtonVariant.primaryMiddle:
|
case MyButtonVariant.primaryMiddle:
|
||||||
buttonStyle = FilledButton.styleFrom(
|
buttonStyle = FilledButton.styleFrom(
|
||||||
backgroundColor: primaryColor,
|
backgroundColor: context.color.primary,
|
||||||
foregroundColor: Colors.black87,
|
foregroundColor: Colors.black87,
|
||||||
disabledBackgroundColor: disabledBgColor,
|
disabledBackgroundColor: disabledBgColor,
|
||||||
disabledForegroundColor: disabledFgColor,
|
disabledForegroundColor: disabledFgColor,
|
||||||
|
|
@ -115,7 +114,7 @@ class _MyButtonState extends State<MyButton> {
|
||||||
);
|
);
|
||||||
case MyButtonVariant.primaryDense:
|
case MyButtonVariant.primaryDense:
|
||||||
buttonStyle = FilledButton.styleFrom(
|
buttonStyle = FilledButton.styleFrom(
|
||||||
backgroundColor: primaryColor,
|
backgroundColor: context.color.primary,
|
||||||
foregroundColor: Colors.black87,
|
foregroundColor: Colors.black87,
|
||||||
disabledBackgroundColor: disabledBgColor,
|
disabledBackgroundColor: disabledBgColor,
|
||||||
disabledForegroundColor: disabledFgColor,
|
disabledForegroundColor: disabledFgColor,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/visual/elements/reactive_tap_feedback.element.dart';
|
import 'package:twonly/src/visual/elements/reactive_tap_feedback.element.dart';
|
||||||
import 'package:twonly/src/visual/themes/light.dart';
|
|
||||||
|
|
||||||
enum MyIconButtonVariant {
|
enum MyIconButtonVariant {
|
||||||
primary,
|
primary,
|
||||||
|
|
@ -43,7 +42,7 @@ class _MyIconButtonState extends State<MyIconButton> {
|
||||||
late final Color fgColor;
|
late final Color fgColor;
|
||||||
|
|
||||||
if (widget.variant == MyIconButtonVariant.primary) {
|
if (widget.variant == MyIconButtonVariant.primary) {
|
||||||
bgColor = primaryColor;
|
bgColor = context.color.primary;
|
||||||
fgColor = Colors.black87;
|
fgColor = Colors.black87;
|
||||||
} else {
|
} else {
|
||||||
bgColor = isDark ? Colors.grey[800]! : Colors.grey[200]!;
|
bgColor = isDark ? Colors.grey[800]! : Colors.grey[200]!;
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,7 @@ class _VideoPlayerFileHelperState extends State<VideoPlayerFileHelper> {
|
||||||
super.initState();
|
super.initState();
|
||||||
_controller = VideoPlayerController.file(
|
_controller = VideoPlayerController.file(
|
||||||
widget.videoPath,
|
widget.videoPath,
|
||||||
videoPlayerOptions: VideoPlayerOptions(
|
videoPlayerOptions: VideoPlayerOptions(),
|
||||||
mixWithOthers: true,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
unawaited(
|
unawaited(
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:twonly/src/visual/themes/light.dart';
|
||||||
|
|
||||||
final ThemeData darkTheme = () {
|
ThemeData getDarkTheme([Color primary = defaultPrimaryColor]) {
|
||||||
final base = ThemeData.dark().copyWith(
|
final base = ThemeData.dark().copyWith(
|
||||||
colorScheme: ColorScheme.fromSeed(
|
colorScheme: ColorScheme.fromSeed(
|
||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
seedColor: const Color(0xFF57CC99),
|
seedColor: primary,
|
||||||
|
primary: primary,
|
||||||
surface: const Color.fromARGB(255, 20, 18, 23),
|
surface: const Color.fromARGB(255, 20, 18, 23),
|
||||||
surfaceContainer: const Color.fromARGB(255, 45, 41, 54),
|
surfaceContainer: const Color.fromARGB(255, 45, 41, 54),
|
||||||
surfaceContainerLow: const Color.fromARGB(255, 38, 34, 45),
|
surfaceContainerLow: const Color.fromARGB(255, 38, 34, 45),
|
||||||
|
|
@ -21,4 +23,6 @@ final ThemeData darkTheme = () {
|
||||||
fontFamilyFallback: Platform.isAndroid ? const ['NotoColorEmoji'] : null,
|
fontFamilyFallback: Platform.isAndroid ? const ['NotoColorEmoji'] : null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}();
|
}
|
||||||
|
|
||||||
|
final ThemeData darkTheme = getDarkTheme();
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,13 @@ import 'dart:io';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
|
||||||
const primaryColor = Color(0xFF57CC99);
|
const defaultPrimaryColor = Color(0xFF57CC99);
|
||||||
|
|
||||||
final ThemeData lightTheme = () {
|
ThemeData getLightTheme([Color primary = defaultPrimaryColor]) {
|
||||||
final base = ThemeData(
|
final base = ThemeData(
|
||||||
colorScheme: ColorScheme.fromSeed(
|
colorScheme: ColorScheme.fromSeed(
|
||||||
seedColor: primaryColor,
|
seedColor: primary,
|
||||||
|
primary: primary,
|
||||||
),
|
),
|
||||||
inputDecorationTheme: const InputDecorationTheme(
|
inputDecorationTheme: const InputDecorationTheme(
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
|
|
@ -19,10 +20,12 @@ final ThemeData lightTheme = () {
|
||||||
fontFamilyFallback: Platform.isAndroid ? const ['NotoColorEmoji'] : null,
|
fontFamilyFallback: Platform.isAndroid ? const ['NotoColorEmoji'] : null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}();
|
}
|
||||||
|
|
||||||
|
final ThemeData lightTheme = getLightTheme();
|
||||||
|
|
||||||
final ButtonStyle primaryColorButtonStyle = FilledButton.styleFrom(
|
final ButtonStyle primaryColorButtonStyle = FilledButton.styleFrom(
|
||||||
backgroundColor: primaryColor,
|
backgroundColor: defaultPrimaryColor,
|
||||||
foregroundColor: Colors.black87,
|
foregroundColor: Colors.black87,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@ class CameraScannedOverlay extends StatelessWidget {
|
||||||
width: 150,
|
width: 150,
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
if (mainController.scannedUrl != null)
|
if (mainController.scannedUrl != null &&
|
||||||
|
mainController.scannedUrl!.isNotEmpty)
|
||||||
_buildScannedUrlTile(context, mainController.scannedUrl!),
|
_buildScannedUrlTile(context, mainController.scannedUrl!),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
super.initState();
|
super.initState();
|
||||||
initVolumeControl();
|
initVolumeControl();
|
||||||
initAsync();
|
initAsync();
|
||||||
|
_checkAndInitCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -176,12 +177,26 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
if (oldWidget.isVisible != widget.isVisible) {
|
if (oldWidget.isVisible != widget.isVisible) {
|
||||||
if (widget.isVisible) {
|
if (widget.isVisible) {
|
||||||
initVolumeControl();
|
initVolumeControl();
|
||||||
|
_checkAndInitCamera();
|
||||||
} else {
|
} else {
|
||||||
_deInitVolumeControl();
|
_deInitVolumeControl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _checkAndInitCamera() {
|
||||||
|
if (widget.isVisible &&
|
||||||
|
mc.cameraController == null &&
|
||||||
|
!mc.initCameraStarted) {
|
||||||
|
unawaited(
|
||||||
|
mc.selectCamera(
|
||||||
|
mc.selectedCameraDetails.cameraId,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_videoRecordingTimer?.cancel();
|
_videoRecordingTimer?.cancel();
|
||||||
|
|
@ -686,6 +701,13 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (mc.selectedCameraDetails.cameraId >= AppEnvironment.cameras.length ||
|
if (mc.selectedCameraDetails.cameraId >= AppEnvironment.cameras.length ||
|
||||||
mc.cameraController == null) {
|
mc.cameraController == null) {
|
||||||
|
if (widget.isVisible &&
|
||||||
|
!mc.initCameraStarted &&
|
||||||
|
!mc.isSharePreviewIsShown) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_checkAndInitCamera();
|
||||||
|
});
|
||||||
|
}
|
||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
return StreamBuilder(
|
return StreamBuilder(
|
||||||
|
|
@ -758,10 +780,18 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
mc.sharedLinkForPreview != null &&
|
mc.sharedLinkForPreview != null &&
|
||||||
mc.sharedLinkForPreview!.shouldGeneratePreview &&
|
mc.sharedLinkForPreview!.shouldGeneratePreview &&
|
||||||
!mc.isVideoRecording)
|
!mc.isVideoRecording)
|
||||||
ShowTitleText(
|
Positioned(
|
||||||
title: mc.sharedLinkForPreview!.url.host,
|
top: 50,
|
||||||
desc: 'Link',
|
left: 0,
|
||||||
isLink: true,
|
right: 0,
|
||||||
|
child: Center(
|
||||||
|
child: Chip(
|
||||||
|
label: Text(mc.sharedLinkForPreview!.url.host),
|
||||||
|
onDeleted: () {
|
||||||
|
mc.setSharedLinkForPreview(null);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (!mc.isSharePreviewIsShown &&
|
if (!mc.isSharePreviewIsShown &&
|
||||||
!mc.isVideoRecording &&
|
!mc.isVideoRecording &&
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ class MainCameraController {
|
||||||
}
|
}
|
||||||
|
|
||||||
void onImageSend() {
|
void onImageSend() {
|
||||||
scannedUrl = '';
|
scannedUrl = null;
|
||||||
setState?.call();
|
setState?.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,6 +155,7 @@ class MainCameraController {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error('Error querying available cameras: $e');
|
Log.error('Error querying available cameras: $e');
|
||||||
initCameraStarted = false;
|
initCameraStarted = false;
|
||||||
|
setState?.call();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,6 +165,7 @@ class MainCameraController {
|
||||||
'Trying to select a non existing camera $cameraId >= ${AppEnvironment.cameras.length}',
|
'Trying to select a non existing camera $cameraId >= ${AppEnvironment.cameras.length}',
|
||||||
);
|
);
|
||||||
initCameraStarted = false;
|
initCameraStarted = false;
|
||||||
|
setState?.call();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,7 +194,7 @@ class MainCameraController {
|
||||||
final hasMic = await micPermissionFuture;
|
final hasMic = await micPermissionFuture;
|
||||||
if (sessionId != _cameraSessionId) return;
|
if (sessionId != _cameraSessionId) return;
|
||||||
|
|
||||||
final controller = CameraController(
|
var controller = CameraController(
|
||||||
AppEnvironment.cameras[cameraId],
|
AppEnvironment.cameras[cameraId],
|
||||||
ResolutionPreset.high,
|
ResolutionPreset.high,
|
||||||
enableAudio: hasMic,
|
enableAudio: hasMic,
|
||||||
|
|
@ -204,7 +206,23 @@ class MainCameraController {
|
||||||
var assignedToGlobal = false;
|
var assignedToGlobal = false;
|
||||||
try {
|
try {
|
||||||
_initializeFuture = controller.initialize();
|
_initializeFuture = controller.initialize();
|
||||||
|
try {
|
||||||
await _initializeFuture;
|
await _initializeFuture;
|
||||||
|
} on CameraException catch (e) {
|
||||||
|
// If specific image format is unsupported on this hardware, fallback to default format
|
||||||
|
Log.warn(
|
||||||
|
'Initial camera format initialization failed ($e), trying fallback format...',
|
||||||
|
);
|
||||||
|
await controller.dispose();
|
||||||
|
controller = CameraController(
|
||||||
|
AppEnvironment.cameras[cameraId],
|
||||||
|
ResolutionPreset.high,
|
||||||
|
enableAudio: hasMic,
|
||||||
|
);
|
||||||
|
_initializeFuture = controller.initialize();
|
||||||
|
await _initializeFuture;
|
||||||
|
}
|
||||||
|
|
||||||
if (sessionId != _cameraSessionId) {
|
if (sessionId != _cameraSessionId) {
|
||||||
unawaited(controller.dispose());
|
unawaited(controller.dispose());
|
||||||
return;
|
return;
|
||||||
|
|
@ -256,6 +274,7 @@ class MainCameraController {
|
||||||
unawaited(controller.dispose());
|
unawaited(controller.dispose());
|
||||||
}
|
}
|
||||||
initCameraStarted = false;
|
initCameraStarted = false;
|
||||||
|
setState?.call();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -91,10 +91,10 @@ class SaveToGalleryButtonState extends State<SaveToGalleryButton> {
|
||||||
valueColor: AlwaysStoppedAnimation(Colors.white),
|
valueColor: AlwaysStoppedAnimation(Colors.white),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
else if (_imageSaved)
|
||||||
|
const Icon(Icons.check, size: 14)
|
||||||
else
|
else
|
||||||
_imageSaved
|
const FaIcon(FontAwesomeIcons.floppyDisk, size: 14),
|
||||||
? const Icon(Icons.check, size: 14)
|
|
||||||
: const FaIcon(FontAwesomeIcons.floppyDisk, size: 14),
|
|
||||||
if (widget.displayButtonLabel) const SizedBox(width: 10),
|
if (widget.displayButtonLabel) const SizedBox(width: 10),
|
||||||
if (widget.displayButtonLabel)
|
if (widget.displayButtonLabel)
|
||||||
Text(
|
Text(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/services/key_verification.service.dart';
|
import 'package:twonly/src/services/key_verification.service.dart';
|
||||||
|
|
@ -8,6 +10,7 @@ import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/main_camera_controller.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/main_camera_controller.dart';
|
||||||
|
import 'package:twonly/src/visual/views/camera/share_image_editor_components/action_button.dart';
|
||||||
|
|
||||||
class QrCodeScannerView extends StatefulWidget {
|
class QrCodeScannerView extends StatefulWidget {
|
||||||
const QrCodeScannerView({
|
const QrCodeScannerView({
|
||||||
|
|
@ -41,6 +44,7 @@ class QrCodeScannerViewState extends State<QrCodeScannerView> {
|
||||||
}
|
}
|
||||||
Permission.camera.isGranted.then((hasPermission) {
|
Permission.camera.isGranted.then((hasPermission) {
|
||||||
if (hasPermission && mounted) {
|
if (hasPermission && mounted) {
|
||||||
|
AppState.hasCameraPermissions = true;
|
||||||
unawaited(_mainCameraController.selectCamera(0, true));
|
unawaited(_mainCameraController.selectCamera(0, true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -100,6 +104,17 @@ class QrCodeScannerViewState extends State<QrCodeScannerView> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// Always-visible back button so the user can exit regardless of
|
||||||
|
// camera state (e.g. during init or after init failure).
|
||||||
|
Positioned(
|
||||||
|
left: 5,
|
||||||
|
top: MediaQuery.paddingOf(context).top + 10,
|
||||||
|
child: ActionButton(
|
||||||
|
FontAwesomeIcons.xmark,
|
||||||
|
tooltipText: context.lang.close,
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/main_camera_controller.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/main_camera_controller.dart';
|
||||||
|
import 'package:twonly/src/visual/views/camera/share_image_editor_components/action_button.dart';
|
||||||
|
|
||||||
class CameraSendToView extends StatefulWidget {
|
class CameraSendToView extends StatefulWidget {
|
||||||
const CameraSendToView(this.sendToGroup, {super.key});
|
const CameraSendToView(this.sendToGroup, {super.key});
|
||||||
|
|
@ -24,6 +28,7 @@ class CameraSendToViewState extends State<CameraSendToView> {
|
||||||
};
|
};
|
||||||
Permission.camera.isGranted.then((hasPermission) {
|
Permission.camera.isGranted.then((hasPermission) {
|
||||||
if (hasPermission && mounted) {
|
if (hasPermission && mounted) {
|
||||||
|
AppState.hasCameraPermissions = true;
|
||||||
unawaited(_mainCameraController.selectCamera(0, true));
|
unawaited(_mainCameraController.selectCamera(0, true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -58,6 +63,17 @@ class CameraSendToViewState extends State<CameraSendToView> {
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// Always-visible back button so the user can exit regardless of
|
||||||
|
// camera state (e.g. during init or after init failure).
|
||||||
|
Positioned(
|
||||||
|
left: 5,
|
||||||
|
top: MediaQuery.paddingOf(context).top + 10,
|
||||||
|
child: ActionButton(
|
||||||
|
FontAwesomeIcons.xmark,
|
||||||
|
tooltipText: context.lang.close,
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -310,10 +310,12 @@ class _ShareImageView extends State<ShareImageView> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// in case mediaStoreFutureReady is ready, the image is stored in the originalPath
|
// in case mediaStoreFutureReady is ready, the image is stored in the originalPath
|
||||||
await insertMediaFileInMessagesTable(
|
unawaited(
|
||||||
|
insertMediaFileInMessagesTable(
|
||||||
widget.mediaFileService,
|
widget.mediaFileService,
|
||||||
widget.selectedGroupIds.toList(),
|
widget.selectedGroupIds.toList(),
|
||||||
additionalData: widget.additionalData,
|
additionalData: widget.additionalData,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
|
|
|
||||||
|
|
@ -116,9 +116,7 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
});
|
});
|
||||||
videoController = VideoPlayerController.file(
|
videoController = VideoPlayerController.file(
|
||||||
mediaService.originalPath,
|
mediaService.originalPath,
|
||||||
videoPlayerOptions: VideoPlayerOptions(
|
videoPlayerOptions: VideoPlayerOptions(),
|
||||||
mixWithOthers: true,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
videoController?.setLooping(true);
|
videoController?.setLooping(true);
|
||||||
videoController
|
videoController
|
||||||
|
|
@ -127,7 +125,7 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
await videoController!.play();
|
await videoController!.play();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
})
|
})
|
||||||
// ignore: argument_type_not_assignable_to_error_handler, invalid_return_type_for_catch_error
|
// ignore: argument_type_not_assignable_to_error_handler
|
||||||
.catchError(Log.error);
|
.catchError(Log.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -359,11 +357,12 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
context.lang.dialogAskDeleteMediaFilePopTitle,
|
context.lang.dialogAskDeleteMediaFilePopTitle,
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
FilledButton(
|
MyButton(
|
||||||
child: Text(context.lang.dialogAskDeleteMediaFilePopDelete),
|
variant: MyButtonVariant.primaryMiddle,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context, true);
|
Navigator.pop(context, true);
|
||||||
},
|
},
|
||||||
|
child: Text(context.lang.dialogAskDeleteMediaFilePopDelete),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text(context.lang.cancel),
|
child: Text(context.lang.cancel),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:twonly/src/visual/components/cached_network_image.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/share_image_editor_components/layers/filter.layer.dart';
|
import 'package:twonly/src/visual/views/camera/share_image_editor_components/layers/filter.layer.dart';
|
||||||
|
|
||||||
class ImageFilter extends StatelessWidget {
|
class ImageFilter extends StatelessWidget {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
import 'package:twonly/src/visual/components/cached_network_image.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/share_image_editor_components/layers/link_preview/parser/base.dart';
|
import 'package:twonly/src/visual/views/camera/share_image_editor_components/layers/link_preview/parser/base.dart';
|
||||||
|
|
||||||
class CustomLinkCard extends StatelessWidget {
|
class CustomLinkCard extends StatelessWidget {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
|
import 'package:twonly/src/visual/components/cached_network_image.dart';
|
||||||
import 'package:twonly/src/visual/loader/three_rotating_dots.loader.dart';
|
import 'package:twonly/src/visual/loader/three_rotating_dots.loader.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/share_image_editor_components/layers/link_preview/parser/base.dart';
|
import 'package:twonly/src/visual/views/camera/share_image_editor_components/layers/link_preview/parser/base.dart';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
|
import 'package:twonly/src/visual/components/cached_network_image.dart';
|
||||||
// Assuming the same Metadata import structure
|
// Assuming the same Metadata import structure
|
||||||
import 'package:twonly/src/visual/views/camera/share_image_editor_components/layers/link_preview/parser/base.dart';
|
import 'package:twonly/src/visual/views/camera/share_image_editor_components/layers/link_preview/parser/base.dart';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
|
import 'package:twonly/src/visual/components/cached_network_image.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/share_image_editor_components/layers/link_preview/parser/base.dart';
|
import 'package:twonly/src/visual/views/camera/share_image_editor_components/layers/link_preview/parser/base.dart';
|
||||||
|
|
||||||
class YouTubePostCard extends StatelessWidget {
|
class YouTubePostCard extends StatelessWidget {
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ class _ArchivedChatsViewState extends State<ArchivedChatsView> {
|
||||||
body: ListView(
|
body: ListView(
|
||||||
children: _groupsArchived.map((group) {
|
children: _groupsArchived.map((group) {
|
||||||
return GroupListItemComp(
|
return GroupListItemComp(
|
||||||
|
key: ValueKey(group.groupId),
|
||||||
group: group,
|
group: group,
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/visual/components/avatar_icon.comp.dart';
|
import 'package:twonly/src/visual/components/avatar_icon.comp.dart';
|
||||||
import 'package:twonly/src/visual/components/connection_status.comp.dart';
|
import 'package:twonly/src/visual/components/connection_status.comp.dart';
|
||||||
import 'package:twonly/src/visual/components/notification_badge.comp.dart';
|
import 'package:twonly/src/visual/components/notification_badge.comp.dart';
|
||||||
import 'package:twonly/src/visual/themes/light.dart';
|
|
||||||
import 'package:twonly/src/visual/views/chats/chat_list_components/empty_chat_list.comp.dart';
|
import 'package:twonly/src/visual/views/chats/chat_list_components/empty_chat_list.comp.dart';
|
||||||
import 'package:twonly/src/visual/views/chats/chat_list_components/group_list_item.comp.dart';
|
import 'package:twonly/src/visual/views/chats/chat_list_components/group_list_item.comp.dart';
|
||||||
import 'package:twonly/src/visual/views/chats/chat_list_components/news_btn.comp.dart';
|
import 'package:twonly/src/visual/views/chats/chat_list_components/news_btn.comp.dart';
|
||||||
|
|
@ -196,8 +195,8 @@ class _ChatListViewState extends State<ChatListView> with AutomaticKeepAliveClie
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 40,
|
height: 40,
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: primaryColor,
|
color: context.color.primary,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -329,7 +328,7 @@ class _ChatListViewState extends State<ChatListView> with AutomaticKeepAliveClie
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
heroTag: 'new_chat_fab',
|
heroTag: 'new_chat_fab',
|
||||||
elevation: 2,
|
elevation: 2,
|
||||||
backgroundColor: primaryColor,
|
backgroundColor: context.color.primary,
|
||||||
foregroundColor: Colors.black87,
|
foregroundColor: Colors.black87,
|
||||||
onPressed: () => context.push(Routes.chatsStartNewChat),
|
onPressed: () => context.push(Routes.chatsStartNewChat),
|
||||||
child: const FaIcon(
|
child: const FaIcon(
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,13 @@ import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/constants/routes.keys.dart';
|
import 'package:twonly/src/constants/routes.keys.dart';
|
||||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
|
||||||
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||||
import 'package:twonly/src/database/tables/messages.table.dart';
|
import 'package:twonly/src/database/tables/messages.table.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/services/api/mediafiles/download.api.dart';
|
import 'package:twonly/src/services/api/mediafiles/download.api.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/visual/components/avatar_icon.comp.dart';
|
import 'package:twonly/src/visual/components/avatar_icon.comp.dart';
|
||||||
|
import 'package:twonly/src/visual/components/contact_labels.comp.dart';
|
||||||
import 'package:twonly/src/visual/components/flame_counter.comp.dart';
|
import 'package:twonly/src/visual/components/flame_counter.comp.dart';
|
||||||
import 'package:twonly/src/visual/components/verification_badge.comp.dart';
|
import 'package:twonly/src/visual/components/verification_badge.comp.dart';
|
||||||
import 'package:twonly/src/visual/context_menu/group.context_menu.dart';
|
import 'package:twonly/src/visual/context_menu/group.context_menu.dart';
|
||||||
|
|
@ -42,6 +42,8 @@ class _UserListItem extends State<GroupListItemComp> {
|
||||||
StreamSubscription<Message?>? _lastMessageStream;
|
StreamSubscription<Message?>? _lastMessageStream;
|
||||||
StreamSubscription<Reaction?>? _lastReactionStream;
|
StreamSubscription<Reaction?>? _lastReactionStream;
|
||||||
StreamSubscription<List<MediaFile>>? _lastMediaFilesStream;
|
StreamSubscription<List<MediaFile>>? _lastMediaFilesStream;
|
||||||
|
Contact? _directContact;
|
||||||
|
StreamSubscription<List<Contact>>? _directContactStream;
|
||||||
|
|
||||||
List<Message> _previewMessages = [];
|
List<Message> _previewMessages = [];
|
||||||
final List<MediaFile> _previewMediaFiles = [];
|
final List<MediaFile> _previewMediaFiles = [];
|
||||||
|
|
@ -60,6 +62,7 @@ class _UserListItem extends State<GroupListItemComp> {
|
||||||
_lastReactionStream?.cancel();
|
_lastReactionStream?.cancel();
|
||||||
_lastMessageStream?.cancel();
|
_lastMessageStream?.cancel();
|
||||||
_lastMediaFilesStream?.cancel();
|
_lastMediaFilesStream?.cancel();
|
||||||
|
_directContactStream?.cancel();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,6 +105,19 @@ class _UserListItem extends State<GroupListItemComp> {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (widget.group.isDirectChat) {
|
||||||
|
_directContactStream = twonlyDB.groupsDao
|
||||||
|
.watchGroupContact(widget.group.groupId)
|
||||||
|
.listen((contacts) {
|
||||||
|
if (!mounted) return;
|
||||||
|
if (contacts.isNotEmpty) {
|
||||||
|
setState(() {
|
||||||
|
_directContact = contacts.first;
|
||||||
|
_receiverDeletedAccount = _directContact!.accountDeleted;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
final groupContacts = await twonlyDB.groupsDao.getGroupContact(
|
final groupContacts = await twonlyDB.groupsDao.getGroupContact(
|
||||||
widget.group.groupId,
|
widget.group.groupId,
|
||||||
);
|
);
|
||||||
|
|
@ -110,6 +126,7 @@ class _UserListItem extends State<GroupListItemComp> {
|
||||||
_receiverDeletedAccount = groupContacts.first.accountDeleted;
|
_receiverDeletedAccount = groupContacts.first.accountDeleted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _updateState(
|
void _updateState(
|
||||||
Message? newLastMessage,
|
Message? newLastMessage,
|
||||||
|
|
@ -239,8 +256,12 @@ class _UserListItem extends State<GroupListItemComp> {
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Row(
|
title: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Flexible(
|
||||||
substringBy(widget.group.groupName, 30),
|
child: Text(
|
||||||
|
widget.group.groupName,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 3),
|
const SizedBox(width: 3),
|
||||||
VerificationBadgeComp(
|
VerificationBadgeComp(
|
||||||
|
|
@ -249,6 +270,18 @@ class _UserListItem extends State<GroupListItemComp> {
|
||||||
clickable: false,
|
clickable: false,
|
||||||
size: 12,
|
size: 12,
|
||||||
),
|
),
|
||||||
|
if (widget.group.isDirectChat && _directContact != null) ...[
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Flexible(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
physics: const BouncingScrollPhysics(),
|
||||||
|
child: ContactLabels(
|
||||||
|
contactId: _directContact!.userId,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
subtitle: _receiverDeletedAccount
|
subtitle: _receiverDeletedAccount
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:clock/clock.dart';
|
import 'package:clock/clock.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:twonly/locator.dart';
|
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
|
||||||
|
|
@ -42,12 +41,12 @@ class _LastMessageTimeCompState extends State<LastMessageTimeComp> {
|
||||||
_actionSubscription = null;
|
_actionSubscription = null;
|
||||||
|
|
||||||
if (widget.message != null) {
|
if (widget.message != null) {
|
||||||
_actionSubscription = twonlyDB.messagesDao
|
if (widget.message!.senderId == null) {
|
||||||
.watchLastMessageAction(widget.message!.messageId)
|
targetTime = widget.message!.openedAt ?? widget.message!.createdAt;
|
||||||
.listen((lastAction) {
|
} else {
|
||||||
targetTime = lastAction?.actionAt ?? widget.message!.createdAt;
|
targetTime = widget.message!.createdAt;
|
||||||
|
}
|
||||||
_updateSeconds();
|
_updateSeconds();
|
||||||
});
|
|
||||||
} else if (widget.dateTime != null) {
|
} else if (widget.dateTime != null) {
|
||||||
targetTime = widget.dateTime;
|
targetTime = widget.dateTime;
|
||||||
_updateSeconds();
|
_updateSeconds();
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/constants/routes.keys.dart';
|
import 'package:twonly/src/constants/routes.keys.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/visual/components/notification_badge.comp.dart';
|
import 'package:twonly/src/visual/components/notification_badge.comp.dart';
|
||||||
import 'package:twonly/src/visual/themes/light.dart';
|
|
||||||
|
|
||||||
class NewsIconButtonComp extends StatelessWidget {
|
class NewsIconButtonComp extends StatelessWidget {
|
||||||
const NewsIconButtonComp({super.key});
|
const NewsIconButtonComp({super.key});
|
||||||
|
|
@ -23,7 +22,7 @@ class NewsIconButtonComp extends StatelessWidget {
|
||||||
builder: (context, count, child) {
|
builder: (context, count, child) {
|
||||||
return NotificationBadgeComp(
|
return NotificationBadgeComp(
|
||||||
count: count.toString(),
|
count: count.toString(),
|
||||||
backgroundColor: primaryColor,
|
backgroundColor: context.color.primary,
|
||||||
textColor: Colors.black87,
|
textColor: Colors.black87,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: () => context.push(Routes.settingsHelpNews),
|
onPressed: () => context.push(Routes.settingsHelpNews),
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue