Commit graph

340 commits

Author SHA1 Message Date
Nikita Epifanov
746882587b Translated using Weblate (Russian)
Currently translated at 100.0% (112 of 112 strings)

Translated using Weblate (Russian)

Currently translated at 98.2% (110 of 112 strings)

Co-authored-by: Nikita Epifanov <nikgreens@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/ru/
Translation: CalyxOS/Seedvault
2020-11-26 00:49:04 +05:30
Torsten Grote
c885499faf
Remove string that isn't needed anymore and change one 2020-11-25 08:41:46 -03:00
Torsten Grote
14f6e5ad93
Adapt main screen to new design 2020-11-18 17:14:24 -03:00
Torsten Grote
020a50533c
exclude apps from backup: react also when only switch is tapped
Fixes #83
2020-11-18 17:05:26 -03:00
Torsten Grote
b1a0c1b2e2
Group app status list into three sections
* important system apps
* user apps
* apps not allowing backup
2020-11-18 16:35:45 -03:00
Torsten Grote
7694eb3cf9 Move to different versioning scheme and show version in About dialog 2020-10-29 20:50:53 +05:30
Torsten Grote
81cd67217b Show backup status of select system apps 2020-10-29 20:23:01 +05:30
Torsten Grote
2cde417c8c
Add config option to re-install apps with feature modules only on same device
There is a possibility that incompatible APK splits make a an app crash when starting after re-installing it.
With that config option each OEM can decide with they want to take this risk or not.
2020-10-22 08:00:55 -03:00
Torsten Grote
a833df2165
Show dialog explaining auto-restore after a restore failed due to not all apps being installed 2020-10-22 08:00:54 -03:00
Torsten Grote
d6cb34c211 Allow the user to manually re-install apps before data restore starts
When one or more apps fail to install, the user is shown a dialog explaining that we need the apps installed in order for restore to work.
After the dialog is dismissed, the list of apps is resorted so failed apps are at the top. They are made clickable and the user is brought to an app store to re-install them.
2020-10-13 18:32:04 +05:30
Torsten Grote
9830d2db95 Show different app state messages for backup and restore 2020-10-13 18:32:04 +05:30
Torsten Grote
741e5ef1a0 Fix storage chooser title if the translation is long 2020-10-08 19:27:51 +05:30
Torsten Grote
948cd597d8 Show proper transport labels for OS transport selection
If an AOSP-based ROM allows the user to choose a backup transport, these labels will be shown.
2020-10-08 19:27:51 +05:30
Torsten Grote
53937bda2f Auto-format code style of all files to match official style
This also adds a note to the README
and the Android Studio coding style files.
2020-10-07 19:44:05 +05:30
Torsten Grote
55909ce305 Fix lint issues with translations and ignore missing translations
as weblate doesn't seem to have a way to only import completed
translations.
2020-10-07 19:01:39 +05:30
Torsten Grote
57f404281c Fix lint warnings 2020-10-07 19:01:39 +05:30
Torsten Grote
25695d72b8 Fix storage selection screen (icon color and available bytes) 2020-10-07 19:01:39 +05:30
Chirayu Desai
680ad8b7db Fix translations manually, replacing &lt;&gt; by <>
* Previous attempt via weblate failed, let's just do it here this way
2020-09-25 20:05:15 +05:30
Hosted Weblate
7af61ac92d Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/
Translation: CalyxOS/Seedvault
2020-09-25 20:05:15 +05:30
Chirayu Desai
ddc13516d3 Translated using Weblate (French)
Currently translated at 80.3% (90 of 112 strings)

Translated using Weblate (Icelandic)

Currently translated at 81.8% (90 of 110 strings)

Translated using Weblate (Spanish (American))

Currently translated at 80.9% (89 of 110 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 78.1% (86 of 110 strings)

Translated using Weblate (French)

Currently translated at 81.8% (90 of 110 strings)

Co-authored-by: Chirayu Desai <chirayudesai1@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/es_US/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/fr/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/is/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/nb_NO/
Translation: CalyxOS/Seedvault
2020-09-25 20:05:15 +05:30
ssantos
d1e4cdb137 Translated using Weblate (Portuguese)
Currently translated at 100.0% (110 of 110 strings)

Co-authored-by: ssantos <ssantos@web.de>
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/pt/
Translation: CalyxOS/Seedvault
2020-09-25 20:05:15 +05:30
Milo Ivir
688753d55f Translated using Weblate (Croatian)
Currently translated at 100.0% (110 of 110 strings)

Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/hr/
Translation: CalyxOS/Seedvault
2020-09-25 20:05:15 +05:30
Michael Bestas
4dbb73aaaf Translated using Weblate (Greek)
Currently translated at 100.0% (110 of 110 strings)

Co-authored-by: Michael Bestas <mkbestas@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/el/
Translation: CalyxOS/Seedvault
2020-09-25 20:05:15 +05:30
H
1aef02e1ed Translated using Weblate (Spanish)
Currently translated at 99.0% (109 of 110 strings)

Co-authored-by: H <joaquinfc@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/es/
Translation: CalyxOS/Seedvault
2020-09-25 20:05:15 +05:30
Nikita Epifanov
a0c70293aa Translated using Weblate (Russian)
Currently translated at 100.0% (110 of 110 strings)

Co-authored-by: Nikita Epifanov <nikgreens@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/ru/
Translation: CalyxOS/Seedvault
2020-09-25 20:05:15 +05:30
Samuel Carvalho de Araújo
fc35acadb9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (110 of 110 strings)

Co-authored-by: Samuel Carvalho de Araújo <samuelnegro12345@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/pt_BR/
Translation: CalyxOS/Seedvault
2020-09-25 20:05:15 +05:30
Hosted Weblate
f636831f9e Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 79.6% (86 of 108 strings)

Translated using Weblate (Spanish)

Currently translated at 99.0% (107 of 108 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 72.2% (78 of 108 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 14.8% (16 of 108 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 94.4% (102 of 108 strings)

Translated using Weblate (Russian)

Currently translated at 7.4% (8 of 108 strings)

Translated using Weblate (Russian)

Currently translated at 6.4% (7 of 108 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 3.7% (4 of 108 strings)

Translated using Weblate (German)

Currently translated at 70.3% (76 of 108 strings)

Translated using Weblate (Icelandic)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Spanish (American))

Currently translated at 97.2% (105 of 108 strings)

Translated using Weblate (Spanish)

Currently translated at 34.2% (37 of 108 strings)

Translated using Weblate (Italian)

Currently translated at 60.1% (65 of 108 strings)

Translated using Weblate (Italian)

Currently translated at 38.8% (42 of 108 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 94.4% (102 of 108 strings)

Translated using Weblate (German)

Currently translated at 10.1% (11 of 108 strings)

Translated using Weblate (French)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (French)

Currently translated at 65.7% (71 of 108 strings)

Added translation using Weblate (Dutch)

Added translation using Weblate (Zulu)

Added translation using Weblate (Chinese (Traditional, Hong Kong))

Added translation using Weblate (Chinese (Traditional))

Added translation using Weblate (Chinese (Simplified))

Added translation using Weblate (Vietnamese)

Added translation using Weblate (Uzbek)

Added translation using Weblate (Urdu)

Added translation using Weblate (Ukrainian)

Added translation using Weblate (Turkish)

Added translation using Weblate (Tagalog)

Added translation using Weblate (Thai)

Added translation using Weblate (Telugu)

Added translation using Weblate (Tamil)

Added translation using Weblate (Swahili)

Added translation using Weblate (Swedish)

Added translation using Weblate (Serbian (latin))

Added translation using Weblate (Serbian)

Added translation using Weblate (Albanian)

Added translation using Weblate (Slovenian)

Added translation using Weblate (Slovak)

Added translation using Weblate (Sinhala)

Added translation using Weblate (Romanian)

Added translation using Weblate (Portuguese (Portugal))

Added translation using Weblate (Portuguese (Brazil))

Added translation using Weblate (Portuguese)

Added translation using Weblate (Polish)

Added translation using Weblate (Punjabi)

Added translation using Weblate (Odia)

Added translation using Weblate (Nepali)

Added translation using Weblate (Burmese)

Added translation using Weblate (Malay)

Added translation using Weblate (Marathi)

Added translation using Weblate (Mongolian)

Added translation using Weblate (Malayalam)

Added translation using Weblate (Macedonian)

Added translation using Weblate (Latvian)

Added translation using Weblate (Lithuanian)

Added translation using Weblate (Lao)

Added translation using Weblate (Kyrgyz)

Added translation using Weblate (Korean)

Added translation using Weblate (Kannada)

Added translation using Weblate (Central Khmer)

Added translation using Weblate (Kazakh)

Added translation using Weblate (Georgian)

Added translation using Weblate (Japanese)

Added translation using Weblate (Icelandic)

Added translation using Weblate (Indonesian)

Added translation using Weblate (Armenian)

Added translation using Weblate (Hungarian)

Added translation using Weblate (Croatian)

Added translation using Weblate (Galician)

Added translation using Weblate (French (Canada))

Added translation using Weblate (Finnish)

Added translation using Weblate (Persian)

Added translation using Weblate (Basque)

Added translation using Weblate (Estonian)

Added translation using Weblate (English (India))

Added translation using Weblate (English (United Kingdom))

Added translation using Weblate (English (Canada))

Added translation using Weblate (English (Australia))

Added translation using Weblate (Danish)

Added translation using Weblate (Czech)

Added translation using Weblate (Catalan)

Added translation using Weblate (Bosnian)

Added translation using Weblate (Bengali)

Added translation using Weblate (Bulgarian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Assamese)

Added translation using Weblate (Amharic)

Added translation using Weblate (Afrikaans)

Added translation using Weblate (Spanish (American))

Added translation using Weblate (Spanish)

Added translation using Weblate (Arabic)

Added translation using Weblate (Italian)

Added translation using Weblate (Hebrew)

Added translation using Weblate (Norwegian Bokmål)

Added translation using Weblate (Hindi)

Added translation using Weblate (Russian)

Added translation using Weblate (German)

Added translation using Weblate (Gujarati)

Added translation using Weblate (French)

Translated using Weblate (Greek)

Currently translated at 29.6% (32 of 108 strings)

Added translation using Weblate (Greek)

Co-authored-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Catherine Pierattini <catherine.pierattini@gmail.com>
Co-authored-by: CatieC <catie@calyxinstitute.org>
Co-authored-by: Chirayu Desai <chirayudesai1@gmail.com>
Co-authored-by: Daniel <dan.ef1999@gmail.com>
Co-authored-by: H <joaquinfc@protonmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Meili Huang <meilihuang1216@gmail.com>
Co-authored-by: Michael Bestas <mkbestas@gmail.com>
Co-authored-by: Mordur Aslaugarson <mordur@1984.is>
Co-authored-by: Nikita Epifanov <nikgreens@protonmail.com>
Co-authored-by: Robin Kunze <robinkunze@outlook.com>
Co-authored-by: Samuel Carvalho de Araújo <samuelnegro12345@gmail.com>
Co-authored-by: Santiago Cruz <scruz4@tuta.io>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/de/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/el/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/es/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/es_US/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/fr/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/is/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/it/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/ru/
Translate-URL: https://hosted.weblate.org/projects/calyxos/seedvault/zh_Hans/
Translation: CalyxOS/Seedvault
2020-09-25 20:05:15 +05:30
Torsten Grote
e3406613a6 Always show Nextcloud as an option, offer to install or set up account
Outside of SetupWizard restore, we don't offer to set up an account,
because we don't know if one already exists and the app was locked with
a passcode.
2020-09-25 06:05:47 +05:30
Torsten Grote
7f4761816e Show a different text for stopped apps in app backups status page 2020-09-25 05:55:40 +05:30
Torsten Grote
77550a9860 Treat stopped apps different from opt-out apps
Apps that have FLAG_STOPPED will not get backed up, just like apps
without flag ALLOW_BACKUP will not get backed up.
In the UI both cases are shown the same way: app does not allow backup
This can be confusing for the user as it is not true for stopped apps.
Therefore, this commit introduces a new stopped state for apps,
so we can differentiate between both cases.
2020-09-25 05:55:40 +05:30
Torsten Grote
1cdc2be930 Don't let the user start a new backup when one is already in progress 2020-09-11 19:04:38 +05:30
Torsten Grote
80187c8c70 Show percentages in progress notification and x of n status at the end
Fine-grained progress reporting causes apps to show up twice which is
confusing. Also @pm@ metadata and opt-out APKs are too much detail for
normal users. So we decided to only show a percentage in the progress
notification.

When the backup finished, the app now shows "x of n apps backed up"
which is more positive when the previous negative message of how many
apps were not backed up.

Some further minor tweets were done to app counting to report proper
totals.
2020-09-11 19:04:38 +05:30
Torsten Grote
983f917391 Let backup notification report more fine-grained progress
This adds @pm@ record backup and APK backup of opt-out apps to the
progress reporting since these two operations are slow when using a
cloud storage SAF backend.
2020-09-11 19:04:38 +05:30
Torsten Grote
91daa8e051 Fix icon color of storage locations (Nextcloud icon got tinted) 2020-09-11 19:04:38 +05:30
Michael Bestas
46cd13a55c String improvements
* Don't use camel case, following AOSP applications
* Set app name and Nextcloud as untranslatable
2020-09-11 19:04:38 +05:30
Torsten Grote
324da2a9e9
Allow the user to exclude apps from backup
Closes #70
2020-01-20 11:58:38 -03:00
Torsten Grote
c92b9a3606
Credit Glenn Sorrentino on About page 2020-01-20 10:01:44 -03:00
Torsten Grote
5d38f061d9
Make some app status list tweaks suggested by our designer Glenn 2020-01-20 09:53:51 -03:00
Torsten Grote
fcf17fe23a
Show list of apps and their backup status 2020-01-18 16:38:55 -03:00
Torsten Grote
6ed522bfb7
Show one single progress bar in the notification
Also don't show individual package results,
but a single dismissible status notification in the end.

Closes #59, #61
2020-01-14 15:18:16 -03:00
Torsten Grote
2bcf82d607
Show heads-up notification when auto-restore fails due to removed storage 2020-01-14 10:17:38 -03:00
Torsten Grote
43184f4d23
Add note to auto-restore setting in case removable storage is used
This warns the user that auto-restore will only work when their storage
is plugged in.
2020-01-14 10:17:37 -03:00
Torsten Grote
22be36e2a7
When an app could not be restored, show the likely reason for it 2020-01-14 10:11:17 -03:00
Torsten Grote
3f73119b52
Show restore data progress bar and improve readability of log messages 2020-01-14 07:45:40 -03:00
Torsten Grote
7b27242625
Show apps that we could not restore data for 2020-01-14 07:45:39 -03:00
Torsten Grote
2f352fe828
Show list of packages that we could restore data for 2020-01-14 07:45:39 -03:00
Torsten Grote
96a4642f4f
Show list of re-installed apps and let the user review it before restoring data 2020-01-14 07:45:38 -03:00
Torsten Grote
f562857514
Expose APK backup feature as a setting, so the user can disable it
The user might not want to have their apps copied to the storage,
because it is very slow or for other reasons.
2020-01-14 07:45:38 -03:00
Torsten Grote
7605762631
Re-install backed-up APKs before restoring from backup 2020-01-14 07:45:37 -03:00
Torsten Grote
bbc8bdfaa5
Allow the user to leave the recovery code input if called from setup wizard 2019-12-11 13:48:00 -03:00
Torsten Grote
791f68300d
Allow to setup NextCloud account during restore
This is especially useful when restore is only allowed during
SetupWizard and the backup was stored on a NextCloud account.
2019-12-11 13:48:00 -03:00
Steve Soltys
cf86c57760
Merge pull request #52 from grote/about-page
Add About page
2019-12-07 15:13:01 -05:00
Torsten Grote
88a250ff5c
Use separate dev config and document existing config
Attention: This also changes the action to launch restore activity
2019-12-06 12:33:50 -03:00
Torsten Grote
49ce4b393f
Add a configurable white-list for backup storage 2019-12-06 12:21:49 -03:00
Torsten Grote
3093e3a789
Add About DialogFragment reachable from main overflow menu 2019-12-06 09:31:48 -03:00
Steve Soltys
32f558faf1 Rebrand application as 'Seedvault' 2019-10-28 21:57:47 -04:00
Torsten Grote
c9a29810fc
Remove unused code and resources 2019-09-25 11:04:24 -03:00
Torsten Grote
08018fcc9b
Do not allow manual backup/restore operations when removable storage is not available 2019-09-23 10:10:28 -03:00
Torsten Grote
007dd7759d
Save the time of the last backup and only do automatic flash drive backups once a day
This commit also turns SettingsManager into a class, so we can mock
and later also inject it.
2019-09-23 10:10:27 -03:00
Torsten Grote
b0386c8b66
Start backup automatically when flash drive used for backup is plugged in 2019-09-23 10:10:26 -03:00
Torsten Grote
8adb94c6c9
Explicitly tint storage root icons for system dark theme 2019-09-19 07:54:28 -03:00
Torsten Grote
0e5f9cff0f
Remove the progress bar for restore operation as progress reporting is bugyy
This also adds an additional warning when the user is using ejectable storage
2019-09-18 09:26:32 -03:00
Torsten Grote
55d92aec39
Adapt UI and text to the different use-cases (backup vs. restore) 2019-09-17 15:48:59 -03:00
Torsten Grote
10ad6d6b2d
Improve error message when no backups could be found for restore 2019-09-17 12:14:53 -03:00
Torsten Grote
54ad762eb1
Save more information about current storage location
Show storage name in settings
2019-09-17 12:14:53 -03:00
Torsten Grote
c6f83647b2
Show recovery code from top to bottom instead of from left to right
This way it is easier to enter it.
2019-09-17 12:14:53 -03:00
Torsten Grote
4efaa08881
Show notification right away when requesting manual backup 2019-09-17 12:14:53 -03:00
Torsten Grote
6d8178f6b1
Use the MANAGE_DOCUMENTS permission to show possible storage locations
This also auto-grants the needed Uri permission,
so the user does not need to go through the OS folder selection activity.
2019-09-17 12:14:51 -03:00
Torsten Grote
9cede639f3
When restoring, ask for location first and then restore code
This also checks if there's a backup at the chosen location
and requires the user to select another once,
if we can not find a backup.
2019-09-11 17:26:03 -03:00
Torsten Grote
044ef01ba1
Do not generate new 12-word code when restoring
Also allow auto-completion when entering the 12-word code.
This makes testing and entering the code easier
and does not compromise security as the word list is public anyway.
2019-09-10 13:35:58 -03:00
Torsten Grote
1a7fdfa59a
Implement restoring of backup and show progress in UI
Note that the progress view is not exact as the progress reporting of
AOSP seems to be buggy.
2019-09-10 13:35:58 -03:00
Torsten Grote
491789e8e0
Add a RestoreActivity that lists available RestoreSets (backups)
and allows the user to select one to get restored.
2019-09-10 13:35:57 -03:00
Torsten Grote
c714a4e7e1
Show error notification when backup fails
The implementation is rudimentary for now.
E.g. The notification is only shown when a device init fails
which seems to be triggered after the first failure.
2019-09-02 17:07:21 -03:00
Torsten Grote
2685f2b48a
Don't show rejected packages (usually 0 size) as failed
Also change notification ID to not collide with Nextcloud's ID.
2019-09-02 09:47:52 -03:00
Torsten Grote
2ce625ac87
Huge refactoring of backup transport
* to get rid of global state
* to have a testable architecture
* to allow for authenticated encryption
* to have a backup format version
* to potentially allow for other storage plugins
2019-09-02 09:47:49 -03:00
Torsten Grote
87b25aa4ec
Re-implement manual backup run and show notification during manual backups 2019-07-09 10:41:58 +02:00
Torsten Grote
4c79d41963
Show Backup Location screen before letting user choose backup folder
This screen can also be reached by tapping the previously inactive backup location setting.
2019-07-09 10:25:30 +02:00
Torsten Grote
66c0919eb5
Let user write down recovery code on first start 2019-07-08 13:21:32 +02:00
Torsten Grote
b983414295
Add custom settings UI 2019-07-03 12:46:55 +02:00
Torsten Grote
2f2fba8305
Pre-select all packages and give option to unselect all 2019-06-14 16:33:04 -03:00
Torsten Grote
540147470d
Allow the user to schedule full background backups 2019-06-11 09:28:03 -03:00
Torsten Grote
b8e9e60666 Add a button to change the backup storage location 2019-06-04 16:54:46 -04:00
Torsten Grote
2434fe30f4
Several small nitpicks and fixes 2019-06-04 09:04:25 -03:00
Steve Soltys
03c92efc24 Add initialization message to loading popup window 2019-02-22 01:05:55 -05:00
Steve Soltys
023750be6e Add loading popup when fetching packages for backup or restore 2019-02-21 22:41:54 -05:00
Steve Soltys
656b7702e0 Allow user to select all packages during backup and restore 2019-02-11 22:07:57 -05:00
Steve Soltys
09c8aad237 Update launcher icon 2018-12-15 03:41:50 -05:00
Steve Soltys
e8720189f3 Add experimental support for standalone builds 2018-11-07 22:04:37 -05:00
Steve Soltys
072e9a1b02 Remove Gradle as build system
This application must be compiled with the operating system, so Gradle is unnecessary.
2017-11-08 23:56:49 -05:00
Steve Soltys
2497a94e4c Initial commit 2017-09-21 00:30:28 -04:00