mirror of
https://github.com/nextcloud/android.git
synced 2024-12-22 00:34:31 +03:00
Merge remote-tracking branch 'origin/master' into dev
This commit is contained in:
commit
9755f912f7
17 changed files with 609 additions and 566 deletions
|
@ -1,4 +1,4 @@
|
||||||
FROM ubuntu:noble@sha256:e3f92abc0967a6c19d0dfa2d55838833e947b9d74edbcb0113e48535ad4be12a
|
FROM ubuntu:noble@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ENV ANDROID_HOME=/usr/lib/android-sdk
|
ENV ANDROID_HOME=/usr/lib/android-sdk
|
||||||
|
|
20
.drone.yml
20
.drone.yml
|
@ -36,7 +36,7 @@ services:
|
||||||
image: ghcr.io/nextcloud/continuous-integration-shallow-server:latest # also change in updateScreenshots.sh
|
image: ghcr.io/nextcloud/continuous-integration-shallow-server:latest # also change in updateScreenshots.sh
|
||||||
environment:
|
environment:
|
||||||
EVAL: true
|
EVAL: true
|
||||||
SERVER_VERSION: 'stable27'
|
SERVER_VERSION: 'stable29'
|
||||||
commands:
|
commands:
|
||||||
- BRANCH="$SERVER_VERSION" /usr/local/bin/initnc.sh
|
- BRANCH="$SERVER_VERSION" /usr/local/bin/initnc.sh
|
||||||
- echo 127.0.0.1 server >> /etc/hosts
|
- echo 127.0.0.1 server >> /etc/hosts
|
||||||
|
@ -48,13 +48,13 @@ services:
|
||||||
- su www-data -c "php /var/www/html/occ group:add users"
|
- su www-data -c "php /var/www/html/occ group:add users"
|
||||||
- su www-data -c "php /var/www/html/occ group:adduser users user1"
|
- su www-data -c "php /var/www/html/occ group:adduser users user1"
|
||||||
- su www-data -c "php /var/www/html/occ group:adduser users user2"
|
- su www-data -c "php /var/www/html/occ group:adduser users user2"
|
||||||
- su www-data -c "git clone -b $SERVER_VERSION https://github.com/nextcloud/activity.git /var/www/html/apps/activity/"
|
- su www-data -c "git clone --depth 1 -b $SERVER_VERSION https://github.com/nextcloud/activity.git /var/www/html/apps/activity/"
|
||||||
- su www-data -c "php /var/www/html/occ app:enable activity"
|
- su www-data -c "php /var/www/html/occ app:enable activity"
|
||||||
- su www-data -c "git clone -b $SERVER_VERSION https://github.com/nextcloud/text.git /var/www/html/apps/text/"
|
- su www-data -c "git clone --depth 1 -b $SERVER_VERSION https://github.com/nextcloud/text.git /var/www/html/apps/text/"
|
||||||
- su www-data -c "php /var/www/html/occ app:enable text"
|
- su www-data -c "php /var/www/html/occ app:enable text"
|
||||||
- su www-data -c "git clone -b $SERVER_VERSION https://github.com/nextcloud/end_to_end_encryption.git /var/www/html/apps/end_to_end_encryption/"
|
- su www-data -c "git clone --depth 1 -b $SERVER_VERSION https://github.com/nextcloud/end_to_end_encryption.git /var/www/html/apps/end_to_end_encryption/"
|
||||||
- su www-data -c "php /var/www/html/occ app:enable end_to_end_encryption"
|
- su www-data -c "php /var/www/html/occ app:enable end_to_end_encryption"
|
||||||
- su www-data -c "git clone -b $SERVER_VERSION https://github.com/nextcloud/photos.git /var/www/html/apps/photos/"
|
- su www-data -c "git clone --depth 1 -b $SERVER_VERSION https://github.com/nextcloud/photos.git /var/www/html/apps/photos/"
|
||||||
- su www-data -c "cd /var/www/html/apps/photos; composer install"
|
- su www-data -c "cd /var/www/html/apps/photos; composer install"
|
||||||
- su www-data -c "php /var/www/html/occ app:enable -f photos"
|
- su www-data -c "php /var/www/html/occ app:enable -f photos"
|
||||||
- /usr/local/bin/run.sh
|
- /usr/local/bin/run.sh
|
||||||
|
@ -106,13 +106,13 @@ services:
|
||||||
- su www-data -c "php /var/www/html/occ group:add users"
|
- su www-data -c "php /var/www/html/occ group:add users"
|
||||||
- su www-data -c "php /var/www/html/occ group:adduser users user1"
|
- su www-data -c "php /var/www/html/occ group:adduser users user1"
|
||||||
- su www-data -c "php /var/www/html/occ group:adduser users user2"
|
- su www-data -c "php /var/www/html/occ group:adduser users user2"
|
||||||
- su www-data -c "git clone -b master https://github.com/nextcloud/activity.git /var/www/html/apps/activity/"
|
- su www-data -c "git clone --depth 1 -b master https://github.com/nextcloud/activity.git /var/www/html/apps/activity/"
|
||||||
- su www-data -c "php /var/www/html/occ app:enable activity"
|
- su www-data -c "php /var/www/html/occ app:enable activity"
|
||||||
- su www-data -c "git clone -b main https://github.com/nextcloud/text.git /var/www/html/apps/text/"
|
- su www-data -c "git clone --depth 1 -b main https://github.com/nextcloud/text.git /var/www/html/apps/text/"
|
||||||
- su www-data -c "php /var/www/html/occ app:enable text"
|
- su www-data -c "php /var/www/html/occ app:enable text"
|
||||||
- su www-data -c "git clone -b master https://github.com/nextcloud/end_to_end_encryption/ /var/www/html/apps/end_to_end_encryption/"
|
- su www-data -c "git clone --depth 1 -b master https://github.com/nextcloud/end_to_end_encryption/ /var/www/html/apps/end_to_end_encryption/"
|
||||||
- su www-data -c "php /var/www/html/occ app:enable end_to_end_encryption"
|
- su www-data -c "php /var/www/html/occ app:enable end_to_end_encryption"
|
||||||
- su www-data -c "git clone https://github.com/nextcloud/photos.git /var/www/html/apps/photos/"
|
- su www-data -c "git clone --depth 1 https://github.com/nextcloud/photos.git /var/www/html/apps/photos/"
|
||||||
- su www-data -c "cd /var/www/html/apps/photos; composer install"
|
- su www-data -c "cd /var/www/html/apps/photos; composer install"
|
||||||
- su www-data -c "php /var/www/html/occ app:enable -f photos"
|
- su www-data -c "php /var/www/html/occ app:enable -f photos"
|
||||||
- /usr/local/bin/run.sh
|
- /usr/local/bin/run.sh
|
||||||
|
@ -183,6 +183,6 @@ name: GIT_TOKEN
|
||||||
data: XIoa9IYq+xQ+N5iln8dlpWv0jV6ROr7HuE24ioUr4uQ8m8SjyH0yognWYLYLqnbTKrFWlFZiEMQTH/sZiWjRFvV1iL0=
|
data: XIoa9IYq+xQ+N5iln8dlpWv0jV6ROr7HuE24ioUr4uQ8m8SjyH0yognWYLYLqnbTKrFWlFZiEMQTH/sZiWjRFvV1iL0=
|
||||||
---
|
---
|
||||||
kind: signature
|
kind: signature
|
||||||
hmac: 5d64f2d46fc49a1e7dad823b7ac9c0ee3762a748ab025782a20292887607d831
|
hmac: a659f1f06a609743077c77b6a07a369e55db67adbd8343fc027ac1c9473d1a43
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
4
.github/workflows/screenShotTest.yml
vendored
4
.github/workflows/screenShotTest.yml
vendored
|
@ -56,7 +56,7 @@ jobs:
|
||||||
|
|
||||||
- name: create AVD and generate snapshot for caching
|
- name: create AVD and generate snapshot for caching
|
||||||
if: steps.avd-cache.outputs.cache-hit != 'true'
|
if: steps.avd-cache.outputs.cache-hit != 'true'
|
||||||
uses: reactivecircus/android-emulator-runner@6b0df4b0efb23bb0ec63d881db79aefbc976e4b2 # v2.30.1
|
uses: reactivecircus/android-emulator-runner@77986be26589807b8ebab3fde7bbf5c60dabec32 # v2.31.0
|
||||||
with:
|
with:
|
||||||
api-level: ${{ matrix.api-level }}
|
api-level: ${{ matrix.api-level }}
|
||||||
force-avd-creation: false
|
force-avd-creation: false
|
||||||
|
@ -84,7 +84,7 @@ jobs:
|
||||||
- name: Run screenshot tests
|
- name: Run screenshot tests
|
||||||
env:
|
env:
|
||||||
SHOT_TEST: "true"
|
SHOT_TEST: "true"
|
||||||
uses: reactivecircus/android-emulator-runner@6b0df4b0efb23bb0ec63d881db79aefbc976e4b2 # v2.30.1
|
uses: reactivecircus/android-emulator-runner@77986be26589807b8ebab3fde7bbf5c60dabec32 # v2.31.0
|
||||||
with:
|
with:
|
||||||
api-level: ${{ matrix.api-level }}
|
api-level: ${{ matrix.api-level }}
|
||||||
force-avd-creation: false
|
force-avd-creation: false
|
||||||
|
|
2
.github/workflows/unit-tests.yml
vendored
2
.github/workflows/unit-tests.yml
vendored
|
@ -33,7 +33,7 @@ jobs:
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
run: scripts/deleteOldComments.sh "test" "Unit" ${{github.event.number}}
|
run: scripts/deleteOldComments.sh "test" "Unit" ${{github.event.number}}
|
||||||
- name: Run unit tests with coverage
|
- name: Run unit tests with coverage
|
||||||
uses: gradle/gradle-build-action@4c39dd82cd5e1ec7c6fa0173bb41b4b6bb3b86ff # v3.3.2
|
uses: gradle/gradle-build-action@66535aaf56f831b35e3a8481c9c99b665b84dd45 # v3.4.2
|
||||||
with:
|
with:
|
||||||
arguments: jacocoTestGplayDebugUnitTest
|
arguments: jacocoTestGplayDebugUnitTest
|
||||||
- name: Upload failing results
|
- name: Upload failing results
|
||||||
|
|
|
@ -16,7 +16,7 @@ import org.gradle.internal.jvm.Jvm
|
||||||
buildscript {
|
buildscript {
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "com.android.tools.build:gradle:$androidPluginVersion"
|
classpath "com.android.tools.build:gradle:$androidPluginVersion"
|
||||||
classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.16'
|
classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.18'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.6"
|
classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.6"
|
||||||
classpath "commons-httpclient:commons-httpclient:3.1@jar" // remove after entire switch to lib v2
|
classpath "commons-httpclient:commons-httpclient:3.1@jar" // remove after entire switch to lib v2
|
||||||
|
|
|
@ -227,7 +227,7 @@ class ChooseAccountDialogFragment :
|
||||||
|
|
||||||
binding.currentAccount.status.let {
|
binding.currentAccount.status.let {
|
||||||
if (newStatus.message.isNullOrBlank()) {
|
if (newStatus.message.isNullOrBlank()) {
|
||||||
it.text = ""
|
it.text = getString(R.string.empty)
|
||||||
it.visibility = View.GONE
|
it.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
it.text = newStatus.message
|
it.text = newStatus.message
|
||||||
|
|
|
@ -188,7 +188,7 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
|
||||||
passCodeDigits?.set(passCodeIndex - 1, "")
|
passCodeDigits?.set(passCodeIndex - 1, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
passCodeEditTexts[passCodeIndex - 1]?.setText("")
|
passCodeEditTexts[passCodeIndex - 1]?.setText(R.string.empty)
|
||||||
|
|
||||||
changed = false
|
changed = false
|
||||||
} else if (!changed) {
|
} else if (!changed) {
|
||||||
|
|
|
@ -92,7 +92,7 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList
|
||||||
val view: View = binding.root
|
val view: View = binding.root
|
||||||
|
|
||||||
// Setup layout
|
// Setup layout
|
||||||
binding.userInput.setText("")
|
binding.userInput.setText(R.string.empty)
|
||||||
viewThemeUtils?.material?.colorTextInputLayout(binding.userInputContainer)
|
viewThemeUtils?.material?.colorTextInputLayout(binding.userInputContainer)
|
||||||
|
|
||||||
val parentFolder = requireArguments().getParcelableArgument(ARG_PARENT_FOLDER, OCFile::class.java)
|
val parentFolder = requireArguments().getParcelableArgument(ARG_PARENT_FOLDER, OCFile::class.java)
|
||||||
|
|
|
@ -112,7 +112,7 @@ class SharePasswordDialogFragment : DialogFragment(), Injectable {
|
||||||
binding = PasswordDialogBinding.inflate(inflater, null, false)
|
binding = PasswordDialogBinding.inflate(inflater, null, false)
|
||||||
|
|
||||||
// Setup layout
|
// Setup layout
|
||||||
binding?.sharePassword?.setText("")
|
binding?.sharePassword?.setText(R.string.empty)
|
||||||
viewThemeUtils?.material?.colorTextInputLayout(binding!!.sharePasswordContainer)
|
viewThemeUtils?.material?.colorTextInputLayout(binding!!.sharePasswordContainer)
|
||||||
|
|
||||||
val neutralButtonTextId: Int
|
val neutralButtonTextId: Int
|
||||||
|
|
|
@ -402,7 +402,7 @@ class FileDetailsSharingProcessFragment :
|
||||||
binding.noteText.setText(share?.note)
|
binding.noteText.setText(share?.note)
|
||||||
} else {
|
} else {
|
||||||
binding.shareProcessBtnNext.text = requireContext().resources.getString(R.string.send_share)
|
binding.shareProcessBtnNext.text = requireContext().resources.getString(R.string.send_share)
|
||||||
binding.noteText.setText("")
|
binding.noteText.setText(R.string.empty)
|
||||||
}
|
}
|
||||||
shareProcessStep = SCREEN_TYPE_NOTE
|
shareProcessStep = SCREEN_TYPE_NOTE
|
||||||
}
|
}
|
||||||
|
@ -447,7 +447,7 @@ class FileDetailsSharingProcessFragment :
|
||||||
private fun showChangeNameInput(isChecked: Boolean) {
|
private fun showChangeNameInput(isChecked: Boolean) {
|
||||||
binding.shareProcessChangeNameContainer.visibility = if (isChecked) View.VISIBLE else View.GONE
|
binding.shareProcessChangeNameContainer.visibility = if (isChecked) View.VISIBLE else View.GONE
|
||||||
if (!isChecked) {
|
if (!isChecked) {
|
||||||
binding.shareProcessChangeName.setText("")
|
binding.shareProcessChangeName.setText(R.string.empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +474,7 @@ class FileDetailsSharingProcessFragment :
|
||||||
// reset the expiration date if switch is unchecked
|
// reset the expiration date if switch is unchecked
|
||||||
if (!isChecked) {
|
if (!isChecked) {
|
||||||
chosenExpDateInMills = -1
|
chosenExpDateInMills = -1
|
||||||
binding.shareProcessSelectExpDate.text = ""
|
binding.shareProcessSelectExpDate.text = getString(R.string.empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,7 +483,7 @@ class FileDetailsSharingProcessFragment :
|
||||||
|
|
||||||
// reset the password if switch is unchecked
|
// reset the password if switch is unchecked
|
||||||
if (!isChecked) {
|
if (!isChecked) {
|
||||||
binding.shareProcessEnterPassword.setText("")
|
binding.shareProcessEnterPassword.setText(R.string.empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,536 +0,0 @@
|
||||||
/*
|
|
||||||
* Nextcloud - Android Client
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: 2020-2024 Andy Scherzinger <info@andy-scherzinger.de>
|
|
||||||
* SPDX-FileCopyrightText: 2023 Alper Ozturk <alper.ozturk@nextcloud.com>
|
|
||||||
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
|
||||||
* SPDX-FileCopyrightText: 2019 Tobias Kaminsky <tobias@kaminsky.me>
|
|
||||||
* SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
|
||||||
* SPDX-FileCopyrightText: 2016 ownCloud Inc.
|
|
||||||
* SPDX-FileCopyrightText: 2015 María Asensio Valverde <masensio@solidgear.es>
|
|
||||||
* SPDX-FileCopyrightText: 2013 David A. Velasco <dvelasco@solidgear.es>
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only)
|
|
||||||
*/
|
|
||||||
package com.owncloud.android.ui.preview;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
import com.nextcloud.client.account.User;
|
|
||||||
import com.nextcloud.client.di.Injectable;
|
|
||||||
import com.nextcloud.client.editimage.EditImageActivity;
|
|
||||||
import com.nextcloud.client.jobs.download.FileDownloadHelper;
|
|
||||||
import com.nextcloud.client.jobs.download.FileDownloadWorker;
|
|
||||||
import com.nextcloud.client.jobs.upload.FileUploadWorker;
|
|
||||||
import com.nextcloud.client.preferences.AppPreferences;
|
|
||||||
import com.nextcloud.model.WorkerState;
|
|
||||||
import com.nextcloud.model.WorkerStateLiveData;
|
|
||||||
import com.nextcloud.utils.extensions.IntentExtensionsKt;
|
|
||||||
import com.owncloud.android.MainApp;
|
|
||||||
import com.owncloud.android.R;
|
|
||||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
|
||||||
import com.owncloud.android.datamodel.OCFile;
|
|
||||||
import com.owncloud.android.datamodel.VirtualFolderType;
|
|
||||||
import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
|
||||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
|
||||||
import com.owncloud.android.operations.RemoveFileOperation;
|
|
||||||
import com.owncloud.android.operations.SynchronizeFileOperation;
|
|
||||||
import com.owncloud.android.ui.activity.FileActivity;
|
|
||||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
|
||||||
import com.owncloud.android.ui.fragment.FileFragment;
|
|
||||||
import com.owncloud.android.ui.fragment.GalleryFragment;
|
|
||||||
import com.owncloud.android.ui.fragment.OCFileListFragment;
|
|
||||||
import com.owncloud.android.utils.MimeTypeUtil;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.appcompat.app.ActionBar;
|
|
||||||
import androidx.drawerlayout.widget.DrawerLayout;
|
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|
||||||
import androidx.viewpager2.widget.ViewPager2;
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds a swiping gallery where image files contained in an Nextcloud directory are shown.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
|
|
||||||
public class PreviewImageActivity extends FileActivity implements
|
|
||||||
FileFragment.ContainerActivity,
|
|
||||||
OnRemoteOperationListener,
|
|
||||||
Injectable {
|
|
||||||
|
|
||||||
public static final String TAG = PreviewImageActivity.class.getSimpleName();
|
|
||||||
public static final String EXTRA_VIRTUAL_TYPE = "EXTRA_VIRTUAL_TYPE";
|
|
||||||
private static final String KEY_WAITING_FOR_BINDER = "WAITING_FOR_BINDER";
|
|
||||||
private static final String KEY_SYSTEM_VISIBLE = "TRUE";
|
|
||||||
|
|
||||||
private OCFile livePhotoFile;
|
|
||||||
private ViewPager2 viewPager;
|
|
||||||
private PreviewImagePagerAdapter previewImagePagerAdapter;
|
|
||||||
private int savedPosition;
|
|
||||||
private boolean hasSavedPosition;
|
|
||||||
private boolean requestWaitingForBinder;
|
|
||||||
private DownloadFinishReceiver downloadFinishReceiver;
|
|
||||||
private View fullScreenAnchorView;
|
|
||||||
private boolean isDownloadWorkStarted = false;
|
|
||||||
|
|
||||||
@Inject AppPreferences preferences;
|
|
||||||
@Inject LocalBroadcastManager localBroadcastManager;
|
|
||||||
|
|
||||||
private ActionBar actionBar;
|
|
||||||
|
|
||||||
public static Intent previewFileIntent(Context context, User user, OCFile file) {
|
|
||||||
final Intent intent = new Intent(context, PreviewImageActivity.class);
|
|
||||||
intent.putExtra(FileActivity.EXTRA_FILE, file);
|
|
||||||
intent.putExtra(FileActivity.EXTRA_USER, user);
|
|
||||||
return intent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
actionBar = getSupportActionBar();
|
|
||||||
|
|
||||||
if (savedInstanceState != null && !savedInstanceState.getBoolean(KEY_SYSTEM_VISIBLE, true) &&
|
|
||||||
actionBar != null) {
|
|
||||||
actionBar.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
setContentView(R.layout.preview_image_activity);
|
|
||||||
|
|
||||||
livePhotoFile = IntentExtensionsKt.getParcelableArgument(getIntent(), EXTRA_LIVE_PHOTO_FILE, OCFile.class);
|
|
||||||
|
|
||||||
// Navigation Drawer
|
|
||||||
setupDrawer();
|
|
||||||
|
|
||||||
// ActionBar
|
|
||||||
OCFile chosenFile = IntentExtensionsKt.getParcelableArgument(getIntent(), FileActivity.EXTRA_FILE, OCFile.class);
|
|
||||||
updateActionBarTitleAndHomeButton(chosenFile);
|
|
||||||
|
|
||||||
if (actionBar != null) {
|
|
||||||
viewThemeUtils.files.setWhiteBackButton(this, actionBar);
|
|
||||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
fullScreenAnchorView = getWindow().getDecorView();
|
|
||||||
// to keep our UI controls visibility in line with system bars visibility
|
|
||||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
|
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
|
||||||
requestWaitingForBinder = savedInstanceState.getBoolean(KEY_WAITING_FOR_BINDER);
|
|
||||||
} else {
|
|
||||||
requestWaitingForBinder = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
observeWorkerState();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void toggleActionBarVisibility(boolean hide) {
|
|
||||||
if (actionBar == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hide) {
|
|
||||||
actionBar.hide();
|
|
||||||
} else {
|
|
||||||
actionBar.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initViewPager(User user) {
|
|
||||||
// virtual folder
|
|
||||||
final Serializable virtualFolderType = IntentExtensionsKt.getSerializableArgument(getIntent(), EXTRA_VIRTUAL_TYPE, Serializable.class);
|
|
||||||
if (virtualFolderType != null && virtualFolderType != VirtualFolderType.NONE) {
|
|
||||||
VirtualFolderType type = (VirtualFolderType) virtualFolderType;
|
|
||||||
|
|
||||||
previewImagePagerAdapter = new PreviewImagePagerAdapter(this,
|
|
||||||
type,
|
|
||||||
user,
|
|
||||||
getStorageManager());
|
|
||||||
} else {
|
|
||||||
// get parent from path
|
|
||||||
OCFile parentFolder = getStorageManager().getFileById(getFile().getParentId());
|
|
||||||
|
|
||||||
if (parentFolder == null) {
|
|
||||||
// should not be necessary
|
|
||||||
parentFolder = getStorageManager().getFileByEncryptedRemotePath(OCFile.ROOT_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
previewImagePagerAdapter = new PreviewImagePagerAdapter(
|
|
||||||
this,
|
|
||||||
livePhotoFile,
|
|
||||||
parentFolder,
|
|
||||||
user,
|
|
||||||
getStorageManager(),
|
|
||||||
MainApp.isOnlyOnDevice(),
|
|
||||||
preferences
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
viewPager = findViewById(R.id.fragmentPager);
|
|
||||||
|
|
||||||
int position = hasSavedPosition ? savedPosition : previewImagePagerAdapter.getFilePosition(getFile());
|
|
||||||
position = Math.max(position, 0);
|
|
||||||
|
|
||||||
viewPager.setAdapter(previewImagePagerAdapter);
|
|
||||||
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
|
||||||
@Override
|
|
||||||
public void onPageSelected(int position) {
|
|
||||||
selectPage(position);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
viewPager.setCurrentItem(position, false);
|
|
||||||
|
|
||||||
if (position == 0 && !getFile().isDown()) {
|
|
||||||
// this is necessary because mViewPager.setCurrentItem(0) just after setting the
|
|
||||||
// adapter does not result in a call to #onPageSelected(0)
|
|
||||||
requestWaitingForBinder = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
sendRefreshSearchEventBroadcast();
|
|
||||||
super.onBackPressed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
if (item.getItemId() == android.R.id.home) {
|
|
||||||
sendRefreshSearchEventBroadcast();
|
|
||||||
|
|
||||||
if (isDrawerOpen()) {
|
|
||||||
closeDrawer();
|
|
||||||
} else {
|
|
||||||
backToDisplayActivity();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendRefreshSearchEventBroadcast() {
|
|
||||||
Intent intent = new Intent(GalleryFragment.REFRESH_SEARCH_EVENT_RECEIVER);
|
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
Optional<User> optionalUser = getUser();
|
|
||||||
if (optionalUser.isPresent()) {
|
|
||||||
OCFile file = getFile();
|
|
||||||
/// Validate handled file (first image to preview)
|
|
||||||
if (file == null) {
|
|
||||||
throw new IllegalStateException("Instanced with a NULL OCFile");
|
|
||||||
}
|
|
||||||
if (!MimeTypeUtil.isImage(file)) {
|
|
||||||
throw new IllegalArgumentException("Non-image file passed as argument");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update file according to DB file, if it is possible
|
|
||||||
if (file.getFileId() > FileDataStorageManager.ROOT_PARENT_ID) {
|
|
||||||
file = getStorageManager().getFileById(file.getFileId());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file != null) {
|
|
||||||
/// Refresh the activity according to the Account and OCFile set
|
|
||||||
setFile(file); // reset after getting it fresh from storageManager
|
|
||||||
updateActionBarTitle(getFile().getFileName());
|
|
||||||
//if (!stateWasRecovered) {
|
|
||||||
initViewPager(optionalUser.get());
|
|
||||||
//}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// handled file not in the current Account
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
outState.putBoolean(KEY_WAITING_FOR_BINDER, requestWaitingForBinder);
|
|
||||||
outState.putBoolean(KEY_SYSTEM_VISIBLE, isSystemUIVisible());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
|
|
||||||
super.onRemoteOperationFinish(operation, result);
|
|
||||||
|
|
||||||
if (operation instanceof RemoveFileOperation) {
|
|
||||||
int deletePosition = viewPager.getCurrentItem();
|
|
||||||
int nextPosition = deletePosition > 0 ? deletePosition - 1 : 0;
|
|
||||||
|
|
||||||
if (previewImagePagerAdapter.getItemCount() <= 1) {
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
viewPager.setCurrentItem(nextPosition, true);
|
|
||||||
previewImagePagerAdapter.delete(deletePosition);
|
|
||||||
} else if (operation instanceof SynchronizeFileOperation) {
|
|
||||||
onSynchronizeFileOperationFinish(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onSynchronizeFileOperationFinish(RemoteOperationResult result) {
|
|
||||||
if (result.isSuccess()) {
|
|
||||||
supportInvalidateOptionsMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void observeWorkerState() {
|
|
||||||
WorkerStateLiveData.Companion.instance().observe(this, state -> {
|
|
||||||
if (state instanceof WorkerState.Download) {
|
|
||||||
Log_OC.d(TAG, "Download worker started");
|
|
||||||
isDownloadWorkStarted = true;
|
|
||||||
|
|
||||||
if (requestWaitingForBinder) {
|
|
||||||
requestWaitingForBinder = false;
|
|
||||||
Log_OC.d(TAG, "Simulating reselection of current page after connection " +
|
|
||||||
"of download binder");
|
|
||||||
selectPage(viewPager.getCurrentItem());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log_OC.d(TAG, "Download worker stopped");
|
|
||||||
isDownloadWorkStarted = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStop() {
|
|
||||||
super.onStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
downloadFinishReceiver = new DownloadFinishReceiver();
|
|
||||||
IntentFilter downloadIntentFilter = new IntentFilter(FileDownloadWorker.Companion.getDownloadFinishMessage());
|
|
||||||
localBroadcastManager.registerReceiver(downloadFinishReceiver, downloadIntentFilter);
|
|
||||||
|
|
||||||
UploadFinishReceiver uploadFinishReceiver = new UploadFinishReceiver();
|
|
||||||
IntentFilter uploadIntentFilter = new IntentFilter(FileUploadWorker.Companion.getUploadFinishMessage());
|
|
||||||
localBroadcastManager.registerReceiver(uploadFinishReceiver, uploadIntentFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostResume() {
|
|
||||||
super.onPostResume();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
if (downloadFinishReceiver != null){
|
|
||||||
localBroadcastManager.unregisterReceiver(downloadFinishReceiver);
|
|
||||||
downloadFinishReceiver = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void backToDisplayActivity() {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressFBWarnings("DLS")
|
|
||||||
@Override
|
|
||||||
public void showDetails(OCFile file) {
|
|
||||||
final Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class);
|
|
||||||
showDetailsIntent.setAction(FileDisplayActivity.ACTION_DETAILS);
|
|
||||||
showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, file);
|
|
||||||
showDetailsIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
startActivity(showDetailsIntent);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showDetails(OCFile file, int activeTab) {
|
|
||||||
showDetails(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestForDownload(OCFile file) {
|
|
||||||
requestForDownload(file, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestForDownload(OCFile file, String downloadBehaviour) {
|
|
||||||
final User user = getUser().orElseThrow(RuntimeException::new);
|
|
||||||
FileDownloadHelper.Companion.instance().downloadFileIfNotStartedBefore(user, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method will be invoked when a new page becomes selected. Animation is not necessarily
|
|
||||||
* complete.
|
|
||||||
*
|
|
||||||
* @param position Position index of the new selected page
|
|
||||||
*/
|
|
||||||
public void selectPage(int position) {
|
|
||||||
savedPosition = position;
|
|
||||||
hasSavedPosition = true;
|
|
||||||
|
|
||||||
OCFile currentFile = previewImagePagerAdapter.getFileAt(position);
|
|
||||||
|
|
||||||
if (!isDownloadWorkStarted) {
|
|
||||||
requestWaitingForBinder = true;
|
|
||||||
} else {
|
|
||||||
if (currentFile != null) {
|
|
||||||
if (currentFile.isEncrypted() && !currentFile.isDown() &&
|
|
||||||
!previewImagePagerAdapter.pendingErrorAt(position)) {
|
|
||||||
requestForDownload(currentFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call to reset image zoom to initial state
|
|
||||||
// ((PreviewImagePagerAdapter) mViewPager.getAdapter()).resetZoom();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentFile != null) {
|
|
||||||
updateActionBarTitle(currentFile.getFileName());
|
|
||||||
setDrawerIndicatorEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateActionBarTitle(String title) {
|
|
||||||
if (getSupportActionBar() != null) {
|
|
||||||
getSupportActionBar().setTitle(title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class waiting for broadcast events from the {@link FileDownloadWorker} service.
|
|
||||||
* <p>
|
|
||||||
* Updates the UI when a download is started or finished, provided that it is relevant for the
|
|
||||||
* folder displayed in the gallery.
|
|
||||||
*/
|
|
||||||
private class DownloadFinishReceiver extends BroadcastReceiver {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
previewNewImage(intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class UploadFinishReceiver extends BroadcastReceiver {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
previewNewImage(intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void previewNewImage(Intent intent) {
|
|
||||||
String accountName = intent.getStringExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME);
|
|
||||||
String downloadedRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_REMOTE_PATH);
|
|
||||||
String downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR);
|
|
||||||
|
|
||||||
if (getAccount().name.equals(accountName) && downloadedRemotePath != null) {
|
|
||||||
OCFile file = getStorageManager().getFileByEncryptedRemotePath(downloadedRemotePath);
|
|
||||||
boolean downloadWasFine = intent.getBooleanExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, false);
|
|
||||||
|
|
||||||
if (EditImageActivity.OPEN_IMAGE_EDITOR.equals(downloadBehaviour)) {
|
|
||||||
startImageEditor(file);
|
|
||||||
} else {
|
|
||||||
int position = previewImagePagerAdapter.getFilePosition(file);
|
|
||||||
if (position >= 0) {
|
|
||||||
if (downloadWasFine) {
|
|
||||||
previewImagePagerAdapter.updateFile(position, file);
|
|
||||||
} else {
|
|
||||||
previewImagePagerAdapter.updateWithDownloadError(position);
|
|
||||||
}
|
|
||||||
previewImagePagerAdapter.notifyItemChanged(position);
|
|
||||||
} else if (downloadWasFine) {
|
|
||||||
Optional<User> user = getUser();
|
|
||||||
|
|
||||||
if (user.isPresent()) {
|
|
||||||
initViewPager(user.get());
|
|
||||||
int newPosition = previewImagePagerAdapter.getFilePosition(file);
|
|
||||||
if (newPosition >= 0) {
|
|
||||||
viewPager.setCurrentItem(newPosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSystemUIVisible() {
|
|
||||||
return getSupportActionBar() == null || getSupportActionBar().isShowing();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void toggleFullScreen() {
|
|
||||||
boolean visible = (fullScreenAnchorView.getSystemUiVisibility()
|
|
||||||
& View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
|
|
||||||
|
|
||||||
if (visible) {
|
|
||||||
hideSystemUI(fullScreenAnchorView);
|
|
||||||
} else {
|
|
||||||
showSystemUI(fullScreenAnchorView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startImageEditor(OCFile file) {
|
|
||||||
if (file.isDown()) {
|
|
||||||
Intent editImageIntent = new Intent(this, EditImageActivity.class);
|
|
||||||
editImageIntent.putExtra(EditImageActivity.EXTRA_FILE, file);
|
|
||||||
startActivity(editImageIntent);
|
|
||||||
} else {
|
|
||||||
requestForDownload(file, EditImageActivity.OPEN_IMAGE_EDITOR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBrowsedDownTo(OCFile folder) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
|
||||||
private void hideSystemUI(View anchorView) {
|
|
||||||
anchorView.setSystemUiVisibility(
|
|
||||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hides NAVIGATION BAR; Android >= 4.0
|
|
||||||
| View.SYSTEM_UI_FLAG_FULLSCREEN // hides STATUS BAR; Android >= 4.1
|
|
||||||
| View.SYSTEM_UI_FLAG_IMMERSIVE // stays interactive; Android >= 4.4
|
|
||||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE // draw full window; Android >= 4.1
|
|
||||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN // draw full window; Android >= 4.1
|
|
||||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION // draw full window; Android >= 4.1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
|
||||||
private void showSystemUI(View anchorView) {
|
|
||||||
anchorView.setSystemUiVisibility(
|
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE // draw full window; Android >= 4.1
|
|
||||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN // draw full window; Android >= 4.1
|
|
||||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION // draw full window; Android >= 4.
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,527 @@
|
||||||
|
/*
|
||||||
|
* Nextcloud - Android Client
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2020-2024 Andy Scherzinger <info@andy-scherzinger.de>
|
||||||
|
* SPDX-FileCopyrightText: 2023 Alper Ozturk <alper.ozturk@nextcloud.com>
|
||||||
|
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
||||||
|
* SPDX-FileCopyrightText: 2019 Tobias Kaminsky <tobias@kaminsky.me>
|
||||||
|
* SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||||
|
* SPDX-FileCopyrightText: 2016 ownCloud Inc.
|
||||||
|
* SPDX-FileCopyrightText: 2015 María Asensio Valverde <masensio@solidgear.es>
|
||||||
|
* SPDX-FileCopyrightText: 2013 David A. Velasco <dvelasco@solidgear.es>
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only)
|
||||||
|
*/
|
||||||
|
package com.owncloud.android.ui.preview
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.WindowInsets
|
||||||
|
import android.view.WindowInsetsController
|
||||||
|
import androidx.appcompat.app.ActionBar
|
||||||
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
|
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
||||||
|
import com.nextcloud.client.account.User
|
||||||
|
import com.nextcloud.client.di.Injectable
|
||||||
|
import com.nextcloud.client.editimage.EditImageActivity
|
||||||
|
import com.nextcloud.client.jobs.download.FileDownloadHelper
|
||||||
|
import com.nextcloud.client.jobs.download.FileDownloadWorker
|
||||||
|
import com.nextcloud.client.jobs.download.FileDownloadWorker.Companion.getDownloadFinishMessage
|
||||||
|
import com.nextcloud.client.jobs.upload.FileUploadWorker.Companion.getUploadFinishMessage
|
||||||
|
import com.nextcloud.client.preferences.AppPreferences
|
||||||
|
import com.nextcloud.model.WorkerState
|
||||||
|
import com.nextcloud.model.WorkerStateLiveData
|
||||||
|
import com.nextcloud.utils.extensions.getParcelableArgument
|
||||||
|
import com.nextcloud.utils.extensions.getSerializableArgument
|
||||||
|
import com.owncloud.android.MainApp
|
||||||
|
import com.owncloud.android.R
|
||||||
|
import com.owncloud.android.datamodel.FileDataStorageManager
|
||||||
|
import com.owncloud.android.datamodel.OCFile
|
||||||
|
import com.owncloud.android.datamodel.VirtualFolderType
|
||||||
|
import com.owncloud.android.lib.common.operations.OnRemoteOperationListener
|
||||||
|
import com.owncloud.android.lib.common.operations.RemoteOperation
|
||||||
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||||
|
import com.owncloud.android.lib.common.utils.Log_OC
|
||||||
|
import com.owncloud.android.operations.RemoveFileOperation
|
||||||
|
import com.owncloud.android.operations.SynchronizeFileOperation
|
||||||
|
import com.owncloud.android.ui.activity.FileActivity
|
||||||
|
import com.owncloud.android.ui.activity.FileDisplayActivity
|
||||||
|
import com.owncloud.android.ui.fragment.FileFragment
|
||||||
|
import com.owncloud.android.ui.fragment.GalleryFragment
|
||||||
|
import com.owncloud.android.ui.fragment.OCFileListFragment
|
||||||
|
import com.owncloud.android.utils.MimeTypeUtil
|
||||||
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
|
||||||
|
import java.io.Serializable
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds a swiping gallery where image files contained in an Nextcloud directory are shown.
|
||||||
|
*/
|
||||||
|
class PreviewImageActivity : FileActivity(), FileFragment.ContainerActivity, OnRemoteOperationListener, Injectable {
|
||||||
|
private var livePhotoFile: OCFile? = null
|
||||||
|
private var viewPager: ViewPager2? = null
|
||||||
|
private var previewImagePagerAdapter: PreviewImagePagerAdapter? = null
|
||||||
|
private var savedPosition = 0
|
||||||
|
private var hasSavedPosition = false
|
||||||
|
private var requestWaitingForBinder = false
|
||||||
|
private var downloadFinishReceiver: DownloadFinishReceiver? = null
|
||||||
|
private var fullScreenAnchorView: View? = null
|
||||||
|
private var isDownloadWorkStarted = false
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var preferences: AppPreferences
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var localBroadcastManager: LocalBroadcastManager
|
||||||
|
|
||||||
|
private var actionBar: ActionBar? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
actionBar = supportActionBar
|
||||||
|
|
||||||
|
if (savedInstanceState != null && !savedInstanceState.getBoolean(
|
||||||
|
KEY_SYSTEM_VISIBLE,
|
||||||
|
true
|
||||||
|
) && actionBar != null
|
||||||
|
) {
|
||||||
|
actionBar?.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
setContentView(R.layout.preview_image_activity)
|
||||||
|
|
||||||
|
livePhotoFile = intent.getParcelableArgument(EXTRA_LIVE_PHOTO_FILE, OCFile::class.java)
|
||||||
|
|
||||||
|
setupDrawer()
|
||||||
|
|
||||||
|
val chosenFile = intent.getParcelableArgument(EXTRA_FILE, OCFile::class.java)
|
||||||
|
updateActionBarTitleAndHomeButton(chosenFile)
|
||||||
|
|
||||||
|
if (actionBar != null) {
|
||||||
|
viewThemeUtils.files.setWhiteBackButton(this, actionBar!!)
|
||||||
|
actionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fullScreenAnchorView = window.decorView
|
||||||
|
// to keep our UI controls visibility in line with system bars visibility
|
||||||
|
setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||||
|
|
||||||
|
requestWaitingForBinder = savedInstanceState?.getBoolean(KEY_WAITING_FOR_BINDER) ?: false
|
||||||
|
|
||||||
|
observeWorkerState()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleActionBarVisibility(hide: Boolean) {
|
||||||
|
if (actionBar == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hide) {
|
||||||
|
actionBar?.hide()
|
||||||
|
} else {
|
||||||
|
actionBar?.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initViewPager(user: User) {
|
||||||
|
val virtualFolderType = intent.getSerializableArgument(EXTRA_VIRTUAL_TYPE, Serializable::class.java)
|
||||||
|
if (virtualFolderType != null && virtualFolderType !== VirtualFolderType.NONE) {
|
||||||
|
val type = virtualFolderType as VirtualFolderType
|
||||||
|
|
||||||
|
previewImagePagerAdapter = PreviewImagePagerAdapter(
|
||||||
|
this,
|
||||||
|
type,
|
||||||
|
user,
|
||||||
|
storageManager
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// get parent from path
|
||||||
|
var parentFolder = storageManager.getFileById(file.parentId)
|
||||||
|
|
||||||
|
if (parentFolder == null) {
|
||||||
|
// should not be necessary
|
||||||
|
parentFolder = storageManager.getFileByEncryptedRemotePath(OCFile.ROOT_PATH)
|
||||||
|
}
|
||||||
|
|
||||||
|
previewImagePagerAdapter = PreviewImagePagerAdapter(
|
||||||
|
this,
|
||||||
|
livePhotoFile,
|
||||||
|
parentFolder,
|
||||||
|
user,
|
||||||
|
storageManager,
|
||||||
|
MainApp.isOnlyOnDevice(),
|
||||||
|
preferences
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewPager = findViewById(R.id.fragmentPager)
|
||||||
|
|
||||||
|
var position = if (hasSavedPosition) savedPosition else previewImagePagerAdapter?.getFilePosition(file)
|
||||||
|
position = position?.toDouble()?.let { max(it, 0.0).toInt() }
|
||||||
|
|
||||||
|
viewPager?.setAdapter(previewImagePagerAdapter)
|
||||||
|
viewPager?.registerOnPageChangeCallback(object : OnPageChangeCallback() {
|
||||||
|
override fun onPageSelected(position: Int) {
|
||||||
|
selectPage(position)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (position != null) {
|
||||||
|
viewPager?.setCurrentItem(position, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position == 0 && !file.isDown) {
|
||||||
|
// this is necessary because mViewPager.setCurrentItem(0) just after setting the
|
||||||
|
// adapter does not result in a call to #onPageSelected(0)
|
||||||
|
requestWaitingForBinder = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
sendRefreshSearchEventBroadcast()
|
||||||
|
super.onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (item.itemId != android.R.id.home) {
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendRefreshSearchEventBroadcast()
|
||||||
|
|
||||||
|
if (isDrawerOpen) {
|
||||||
|
closeDrawer()
|
||||||
|
} else {
|
||||||
|
backToDisplayActivity()
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendRefreshSearchEventBroadcast() {
|
||||||
|
val intent = Intent(GalleryFragment.REFRESH_SEARCH_EVENT_RECEIVER)
|
||||||
|
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
val optionalUser = user
|
||||||
|
if (optionalUser.isPresent) {
|
||||||
|
var file: OCFile? = file ?: throw IllegalStateException("Instanced with a NULL OCFile")
|
||||||
|
// / Validate handled file (first image to preview)
|
||||||
|
require(MimeTypeUtil.isImage(file)) { "Non-image file passed as argument" }
|
||||||
|
|
||||||
|
// Update file according to DB file, if it is possible
|
||||||
|
if (file!!.fileId > FileDataStorageManager.ROOT_PARENT_ID) {
|
||||||
|
file = storageManager.getFileById(file.fileId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file != null) {
|
||||||
|
// / Refresh the activity according to the Account and OCFile set
|
||||||
|
setFile(file) // reset after getting it fresh from storageManager
|
||||||
|
updateActionBarTitle(getFile().fileName)
|
||||||
|
// if (!stateWasRecovered) {
|
||||||
|
initViewPager(optionalUser.get())
|
||||||
|
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
// handled file not in the current Account
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
outState.putBoolean(KEY_WAITING_FOR_BINDER, requestWaitingForBinder)
|
||||||
|
outState.putBoolean(KEY_SYSTEM_VISIBLE, isSystemUIVisible)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoteOperationFinish(operation: RemoteOperation<*>?, result: RemoteOperationResult<*>) {
|
||||||
|
super.onRemoteOperationFinish(operation, result)
|
||||||
|
|
||||||
|
if (operation is RemoveFileOperation) {
|
||||||
|
val deletePosition = viewPager?.currentItem ?: return
|
||||||
|
val nextPosition = if (deletePosition > 0) deletePosition - 1 else 0
|
||||||
|
|
||||||
|
previewImagePagerAdapter?.let {
|
||||||
|
if (it.itemCount <= 1) {
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewPager?.setCurrentItem(nextPosition, true)
|
||||||
|
previewImagePagerAdapter?.delete(deletePosition)
|
||||||
|
} else if (operation is SynchronizeFileOperation) {
|
||||||
|
onSynchronizeFileOperationFinish(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onSynchronizeFileOperationFinish(result: RemoteOperationResult<*>) {
|
||||||
|
if (result.isSuccess) {
|
||||||
|
supportInvalidateOptionsMenu()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeWorkerState() {
|
||||||
|
WorkerStateLiveData.instance().observe(this) { state: WorkerState? ->
|
||||||
|
if (state is WorkerState.Download) {
|
||||||
|
Log_OC.d(TAG, "Download worker started")
|
||||||
|
isDownloadWorkStarted = true
|
||||||
|
|
||||||
|
if (requestWaitingForBinder) {
|
||||||
|
requestWaitingForBinder = false
|
||||||
|
Log_OC.d(
|
||||||
|
TAG,
|
||||||
|
"Simulating reselection of current page after connection " +
|
||||||
|
"of download binder"
|
||||||
|
)
|
||||||
|
selectPage(viewPager?.currentItem)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log_OC.d(TAG, "Download worker stopped")
|
||||||
|
isDownloadWorkStarted = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
downloadFinishReceiver = DownloadFinishReceiver()
|
||||||
|
val downloadIntentFilter = IntentFilter(getDownloadFinishMessage())
|
||||||
|
localBroadcastManager.registerReceiver(downloadFinishReceiver!!, downloadIntentFilter)
|
||||||
|
|
||||||
|
val uploadFinishReceiver = UploadFinishReceiver()
|
||||||
|
val uploadIntentFilter = IntentFilter(getUploadFinishMessage())
|
||||||
|
localBroadcastManager.registerReceiver(uploadFinishReceiver, uploadIntentFilter)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun onPause() {
|
||||||
|
if (downloadFinishReceiver != null) {
|
||||||
|
localBroadcastManager.unregisterReceiver(downloadFinishReceiver!!)
|
||||||
|
downloadFinishReceiver = null
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onPause()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun backToDisplayActivity() {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressFBWarnings("DLS")
|
||||||
|
override fun showDetails(file: OCFile) {
|
||||||
|
val intent = Intent(this, FileDisplayActivity::class.java).apply {
|
||||||
|
setAction(FileDisplayActivity.ACTION_DETAILS)
|
||||||
|
putExtra(EXTRA_FILE, file)
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
|
}
|
||||||
|
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showDetails(file: OCFile, activeTab: Int) {
|
||||||
|
showDetails(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun requestForDownload(file: OCFile?, downloadBehaviour: String? = null) {
|
||||||
|
if (file == null) return
|
||||||
|
val user = user.orElseThrow { RuntimeException() }
|
||||||
|
FileDownloadHelper.instance().downloadFileIfNotStartedBefore(user, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will be invoked when a new page becomes selected. Animation is not necessarily
|
||||||
|
* complete.
|
||||||
|
*
|
||||||
|
* @param position Position index of the new selected page
|
||||||
|
*/
|
||||||
|
fun selectPage(position: Int?) {
|
||||||
|
if (position == null) return
|
||||||
|
savedPosition = position
|
||||||
|
hasSavedPosition = true
|
||||||
|
|
||||||
|
val currentFile = previewImagePagerAdapter?.getFileAt(position)
|
||||||
|
|
||||||
|
if (!isDownloadWorkStarted) {
|
||||||
|
requestWaitingForBinder = true
|
||||||
|
} else {
|
||||||
|
if (currentFile != null) {
|
||||||
|
if (currentFile.isEncrypted && !currentFile.isDown &&
|
||||||
|
previewImagePagerAdapter?.pendingErrorAt(position) == false
|
||||||
|
) {
|
||||||
|
requestForDownload(currentFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call to reset image zoom to initial state
|
||||||
|
// ((PreviewImagePagerAdapter) mViewPager.getAdapter()).resetZoom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentFile != null) {
|
||||||
|
updateActionBarTitle(currentFile.fileName)
|
||||||
|
setDrawerIndicatorEnabled(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateActionBarTitle(title: String?) {
|
||||||
|
supportActionBar?.title = title
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class waiting for broadcast events from the [FileDownloadWorker] service.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Updates the UI when a download is started or finished, provided that it is relevant for the
|
||||||
|
* folder displayed in the gallery.
|
||||||
|
*/
|
||||||
|
private inner class DownloadFinishReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
previewNewImage(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class UploadFinishReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
previewNewImage(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NestedBlockDepth", "ReturnCount")
|
||||||
|
private fun previewNewImage(intent: Intent) {
|
||||||
|
val accountName = intent.getStringExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME)
|
||||||
|
val downloadedRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_REMOTE_PATH)
|
||||||
|
val downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR)
|
||||||
|
|
||||||
|
if (account.name != accountName || downloadedRemotePath == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val file = storageManager.getFileByEncryptedRemotePath(downloadedRemotePath)
|
||||||
|
val downloadWasFine = intent.getBooleanExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, false)
|
||||||
|
|
||||||
|
if (EditImageActivity.OPEN_IMAGE_EDITOR == downloadBehaviour) {
|
||||||
|
startImageEditor(file)
|
||||||
|
} else {
|
||||||
|
val position = previewImagePagerAdapter?.getFilePosition(file) ?: return
|
||||||
|
|
||||||
|
if (position >= 0) {
|
||||||
|
if (downloadWasFine) {
|
||||||
|
previewImagePagerAdapter?.updateFile(position, file)
|
||||||
|
} else {
|
||||||
|
previewImagePagerAdapter?.updateWithDownloadError(position)
|
||||||
|
}
|
||||||
|
previewImagePagerAdapter?.notifyItemChanged(position)
|
||||||
|
} else if (downloadWasFine) {
|
||||||
|
val user = user
|
||||||
|
|
||||||
|
if (user.isPresent) {
|
||||||
|
initViewPager(user.get())
|
||||||
|
val newPosition = previewImagePagerAdapter?.getFilePosition(file) ?: return
|
||||||
|
if (newPosition >= 0) {
|
||||||
|
viewPager?.currentItem = newPosition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val isSystemUIVisible: Boolean
|
||||||
|
get() = supportActionBar == null || supportActionBar?.isShowing == true
|
||||||
|
|
||||||
|
fun toggleFullScreen() {
|
||||||
|
if (fullScreenAnchorView == null) return
|
||||||
|
val visible = (
|
||||||
|
fullScreenAnchorView!!.systemUiVisibility
|
||||||
|
and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||||
|
) == 0
|
||||||
|
|
||||||
|
if (visible) {
|
||||||
|
hideSystemUI(fullScreenAnchorView!!)
|
||||||
|
} else {
|
||||||
|
showSystemUI(fullScreenAnchorView!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startImageEditor(file: OCFile) {
|
||||||
|
if (file.isDown) {
|
||||||
|
val editImageIntent = Intent(this, EditImageActivity::class.java)
|
||||||
|
editImageIntent.putExtra(EditImageActivity.EXTRA_FILE, file)
|
||||||
|
startActivity(editImageIntent)
|
||||||
|
} else {
|
||||||
|
requestForDownload(file, EditImageActivity.OPEN_IMAGE_EDITOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBrowsedDownTo(folder: OCFile) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTransferStateChanged(file: OCFile, downloading: Boolean, uploading: Boolean) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hideSystemUI(anchorView: View) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
window.insetsController?.let { controller ->
|
||||||
|
controller.hide(WindowInsets.Type.systemBars())
|
||||||
|
controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
anchorView.systemUiVisibility = (
|
||||||
|
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hides NAVIGATION BAR; Android >= 4.0
|
||||||
|
or View.SYSTEM_UI_FLAG_FULLSCREEN // hides STATUS BAR; Android >= 4.1
|
||||||
|
or View.SYSTEM_UI_FLAG_IMMERSIVE // stays interactive; Android >= 4.4
|
||||||
|
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE // draw full window; Android >= 4.1
|
||||||
|
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN // draw full window; Android >= 4.1
|
||||||
|
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showSystemUI(anchorView: View) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
window.insetsController?.let { controller ->
|
||||||
|
controller.show(WindowInsets.Type.systemBars())
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_DEFAULT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
anchorView.systemUiVisibility = (
|
||||||
|
View.SYSTEM_UI_FLAG_LAYOUT_STABLE // draw full window; Android >= 4.1
|
||||||
|
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN // draw full window; Android >= 4.1
|
||||||
|
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val TAG: String = PreviewImageActivity::class.java.simpleName
|
||||||
|
const val EXTRA_VIRTUAL_TYPE: String = "EXTRA_VIRTUAL_TYPE"
|
||||||
|
private const val KEY_WAITING_FOR_BINDER = "WAITING_FOR_BINDER"
|
||||||
|
private const val KEY_SYSTEM_VISIBLE = "TRUE"
|
||||||
|
|
||||||
|
fun previewFileIntent(context: Context?, user: User?, file: OCFile?): Intent {
|
||||||
|
return Intent(context, PreviewImageActivity::class.java).apply {
|
||||||
|
putExtra(EXTRA_FILE, file)
|
||||||
|
putExtra(EXTRA_USER, user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
androidLibraryVersion ="451cddeba122ff4d17dc8f88feb2fd7589f77567"
|
androidLibraryVersion ="451cddeba122ff4d17dc8f88feb2fd7589f77567"
|
||||||
androidPluginVersion = '8.4.0'
|
androidPluginVersion = '8.5.0'
|
||||||
androidxMediaVersion = '1.3.1'
|
androidxMediaVersion = '1.3.1'
|
||||||
androidxTestVersion = "1.5.0"
|
androidxTestVersion = "1.5.0"
|
||||||
appCompatVersion = '1.7.0'
|
appCompatVersion = '1.7.0'
|
||||||
|
|
|
@ -4457,6 +4457,43 @@ HBhD37R+PsUfSEPep+pmyBlX2nrKxxoRNsl5KWNiQw==
|
||||||
=Phg6
|
=Phg6
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
pub 1669C4BB543E0445
|
||||||
|
uid Emily Johnston <epmjohnston@google.com>
|
||||||
|
|
||||||
|
sub 5F6BA89D4B0869B9
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: BCPG v1.68
|
||||||
|
|
||||||
|
mQGNBF3TQCcBDAD177B+Btl8XBEkBQ5jFSezFrpEl4arwCEa7htCp6T3h55HvYwz
|
||||||
|
P7Y9zWYXfhAC8XJlPQJYpqaQiiYtdlmOrOS4wbp5Lr+z/0XpFlJFzdKglxKYcdfP
|
||||||
|
ntnGyoj7Dz03v+SitL9Ct1YZmOGz6onlifXsCTkWraSJTqR6/y2dL0Beu7dLZp94
|
||||||
|
fgf+FAfr77bwGhUhOh0pPI6ZK2VwNMiQN92jS/RYb6i7QjzO654ALTBR6R2sqx26
|
||||||
|
C0NNsTUZ1WawPreT/rmR4vux1pvgbC8DcXqdptVb+iQPymnysEr69J0f7YC579+7
|
||||||
|
itFIh6efV75W9nDqp9QB/1G808oYx1rglUstOCI0axSgSNyazbInW9qOI58rLQ4v
|
||||||
|
wnCSTWvesVNq+uO6aVrfpXIO3uUTI3t4mpBZgVYZ+g30BlCPRx52YofvQzYbbk9d
|
||||||
|
wCMUDQAzKGJi+mazkgBhcz+neEuNUlR/0fBMObzb7cAT4gGo/sSzYVNN5oT3u/Mi
|
||||||
|
J4hfzYUTFMsJBp0AEQEAAbQnRW1pbHkgSm9obnN0b24gPGVwbWpvaG5zdG9uQGdv
|
||||||
|
b2dsZS5jb20+uQGNBF3TQCcBDADJ17PQ4z5UVGBVUefEkTXeVlGX4oc+vUOVn8Z9
|
||||||
|
B34sQkFmgsORuwm+/1rGthrMatro1Jka4UXSxYFMCt6XBz4/OdJbquxs6D85iuda
|
||||||
|
Id9aozCOJypkfprp+ez2PK7pWeOq6DQ/lqqNGyoHxA703wshI38sNcKRcypn/vf1
|
||||||
|
VJlO3ZjfLCVDQw4+yNrdWiwklb4QS0xwjK9Bw9m8g6HiQGil8V/kL9Avpa76rGqa
|
||||||
|
P9YnkTo7NQG0cwEbpcxNUrkO7fFKjTOMTmfPkh5pHAHVS+FsrCsxhRs6Eb6u/qes
|
||||||
|
tHjpYj6qtMJ5V7oXeUI3OZ9nAPctSxoNVn6f0otsaatoBwcJNNhO/6ZIFH7NlgYQ
|
||||||
|
NN3a5Pz6NrU13+zMGbsxYzlL4/nVwhdn/kHPQ2tl4e2R79da7ModAjeafimikA3n
|
||||||
|
GZj1Zvo1iXKLfguM+U90kTrPKSxcJqwgV4QvrO9Z9llRTzhdBmrFePFhlxN3JdpS
|
||||||
|
KYXFInq6JwncmOAeIDhNYYcVXhcAEQEAAYkBvAQYAQoAJhYhBHYVrVYUTfI3b0nZ
|
||||||
|
ixZpxLtUPgRFBQJd00AnAhsMBQkDwmcAAAoJEBZpxLtUPgRF32gMAJoI+6dvnT7G
|
||||||
|
OJB4S0HAB2qhizmQ5MWiO7QE1HKQ6ShylihJfAIMnAMlLPhorr1ITZXaNMFO+rWN
|
||||||
|
O76BdsBxAkd0rKIIjMTU5r1HuS+XCGFzitffkJ2TgQ2K4vKnSgEpCsBilgCJzdJe
|
||||||
|
vrYoCAudkZAaeBcT0fsTtQDnWHUJSkyWro0ovaaPF5tJzMkFZQBlaNyb+DmWPyNt
|
||||||
|
5TP6iORnmeLNE0OajrUawFUcLUITdutn2t/PRE9LBDSlewE9Gabv79z8ZGAw7jPK
|
||||||
|
x/p+ePpIj6J05TM0BR9KLrk3avMIK+eKwcvm+nCyYA1jKr7c9E4bg+6sRbc6igvV
|
||||||
|
L4QeKzjeGll3vjifmghVXVKVBOW1fk10cMNKaTEkGng8OfLhJDQDXuNz4m8/pMA/
|
||||||
|
wyGfH3HBGSx+F3GZUb00kU0HbxV2Vt0QlyjwT9vJfVGQ4Y+GhnMF6qErtdX8cBIW
|
||||||
|
FJXLEW77wWHN+QpRD6BShYZDvUA2mtO0zlB8reU+VCxgnFfm66DkUg==
|
||||||
|
=jYDe
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
pub 16F71868F1D3A389
|
pub 16F71868F1D3A389
|
||||||
uid Lukhnos Liu <lukhnos@lukhnos.org>
|
uid Lukhnos Liu <lukhnos@lukhnos.org>
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,6 @@
|
||||||
<trust group="com.fasterxml.jackson" name="jackson-base" version="2.14.2" reason="no keys available, no pom artifact to create a checksum"/>
|
<trust group="com.fasterxml.jackson" name="jackson-base" version="2.14.2" reason="no keys available, no pom artifact to create a checksum"/>
|
||||||
<trust file=".*-sources[.]jar" regex="true"/>
|
<trust file=".*-sources[.]jar" regex="true"/>
|
||||||
</trusted-artifacts>
|
</trusted-artifacts>
|
||||||
<ignored-keys>
|
|
||||||
<ignored-key id="1669C4BB543E0445" reason="Key couldn't be downloaded from any key server"/>
|
|
||||||
</ignored-keys>
|
|
||||||
<trusted-keys>
|
<trusted-keys>
|
||||||
<trusted-key id="015479E1055341431B4545AB72475FD306B9CAB7" group="com.googlecode.javaewah" name="JavaEWAH" version="1.2.3"/>
|
<trusted-key id="015479E1055341431B4545AB72475FD306B9CAB7" group="com.googlecode.javaewah" name="JavaEWAH" version="1.2.3"/>
|
||||||
<trusted-key id="042B29E928995B9DB963C636C7CA19B7B620D787" group="com.github.stephenc.jcip" name="jcip-annotations" version="1.0-1"/>
|
<trusted-key id="042B29E928995B9DB963C636C7CA19B7B620D787" group="com.github.stephenc.jcip" name="jcip-annotations" version="1.0-1"/>
|
||||||
|
@ -81,7 +78,10 @@
|
||||||
<trusted-key id="2E52CCA3842FA13C188F1DB50B45DDD344B5FFD1" group="tools.fastlane" name="screengrab" version="2.1.1"/>
|
<trusted-key id="2E52CCA3842FA13C188F1DB50B45DDD344B5FFD1" group="tools.fastlane" name="screengrab" version="2.1.1"/>
|
||||||
<trusted-key id="2E8191ADD82E5C6ABD8E24D802499A5DAEC7ADA9" group="^com[.]twelvemonkeys($|([.].*))" regex="true"/>
|
<trusted-key id="2E8191ADD82E5C6ABD8E24D802499A5DAEC7ADA9" group="^com[.]twelvemonkeys($|([.].*))" regex="true"/>
|
||||||
<trusted-key id="2E92113263FC31C74CCBAAB20E91C2DE43B72BB1" group="org.ec4j.core"/>
|
<trusted-key id="2E92113263FC31C74CCBAAB20E91C2DE43B72BB1" group="org.ec4j.core"/>
|
||||||
<trusted-key id="3051D45031E13516A6E8FAFF280D66A55F5316C5" group="org.bitbucket.b_c" name="jose4j" version="0.7.0"/>
|
<trusted-key id="3051D45031E13516A6E8FAFF280D66A55F5316C5">
|
||||||
|
<trusting group="org.bitbucket.b_c" name="jose4j" version="0.7.0"/>
|
||||||
|
<trusting group="org.bitbucket.b_c" name="jose4j" version="0.9.5"/>
|
||||||
|
</trusted-key>
|
||||||
<trusted-key id="31BAE2E51D95E0F8AD9B7BCC40A3C4432BD7308C" group="com.googlecode.juniversalchardet" name="juniversalchardet" version="1.0.3"/>
|
<trusted-key id="31BAE2E51D95E0F8AD9B7BCC40A3C4432BD7308C" group="com.googlecode.juniversalchardet" name="juniversalchardet" version="1.0.3"/>
|
||||||
<trusted-key id="3241A3ABA33FF6F69B75E2DDEC9458EED5C5AB12" group="id.zelory" name="compressor" version="3.0.1"/>
|
<trusted-key id="3241A3ABA33FF6F69B75E2DDEC9458EED5C5AB12" group="id.zelory" name="compressor" version="3.0.1"/>
|
||||||
<trusted-key id="324E460B9DB8F4515F3EAED9930C5B1EA41B1AA1" group="com.beust" name="jcommander" version="1.48"/>
|
<trusted-key id="324E460B9DB8F4515F3EAED9930C5B1EA41B1AA1" group="com.beust" name="jcommander" version="1.48"/>
|
||||||
|
@ -241,11 +241,13 @@
|
||||||
<trusting group="androidx.annotation"/>
|
<trusting group="androidx.annotation"/>
|
||||||
<trusting group="androidx.appcompat"/>
|
<trusting group="androidx.appcompat"/>
|
||||||
<trusting group="androidx.core"/>
|
<trusting group="androidx.core"/>
|
||||||
|
<trusting group="androidx.databinding"/>
|
||||||
<trusting group="androidx.fragment"/>
|
<trusting group="androidx.fragment"/>
|
||||||
<trusting group="androidx.lifecycle"/>
|
<trusting group="androidx.lifecycle"/>
|
||||||
<trusting group="androidx.transition" name="transition" version="1.5.0"/>
|
<trusting group="androidx.transition" name="transition" version="1.5.0"/>
|
||||||
<trusting group="androidx.webkit" name="webkit" version="1.11.0"/>
|
<trusting group="androidx.webkit" name="webkit" version="1.11.0"/>
|
||||||
<trusting group="^androidx[.]compose($|([.].*))" regex="true"/>
|
<trusting group="^androidx[.]compose($|([.].*))" regex="true"/>
|
||||||
|
<trusting group="^com[.]android($|([.].*))" regex="true"/>
|
||||||
</trusted-key>
|
</trusted-key>
|
||||||
<trusted-key id="A6D6C97108B8585F91B158748671A8DF71296252" group="^com[.]squareup($|([.].*))" regex="true"/>
|
<trusted-key id="A6D6C97108B8585F91B158748671A8DF71296252" group="^com[.]squareup($|([.].*))" regex="true"/>
|
||||||
<trusted-key id="A7892505CF1A58076453E52D7999BEFBA1039E8B" group="net.bytebuddy"/>
|
<trusted-key id="A7892505CF1A58076453E52D7999BEFBA1039E8B" group="net.bytebuddy"/>
|
||||||
|
@ -1146,6 +1148,11 @@
|
||||||
<sha256 value="b037fdfb267dc0141ab9f4e4e85daf87b175cf311248d54b501b58ec42345315" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
<sha256 value="b037fdfb267dc0141ab9f4e4e85daf87b175cf311248d54b501b58ec42345315" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.core" name="core-ktx" version="1.6.0">
|
||||||
|
<artifact name="core-ktx-1.6.0.module">
|
||||||
|
<sha256 value="e937bf22c0da28e872300fc6b96029b83ff75aa8d0ab1ec039aae3d8af6513dd" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.core" name="core-ktx" version="1.8.0">
|
<component group="androidx.core" name="core-ktx" version="1.8.0">
|
||||||
<artifact name="core-ktx-1.8.0.module">
|
<artifact name="core-ktx-1.8.0.module">
|
||||||
<sha256 value="a91bc3e02f209f643dd8275345a9e3003ce20d64fc0760eccf479c1709842f72" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
<sha256 value="a91bc3e02f209f643dd8275345a9e3003ce20d64fc0760eccf479c1709842f72" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||||
|
@ -3941,6 +3948,14 @@
|
||||||
<sha256 value="745894f1d15599871b1c3a6cc09f0da03268f1373ce937ce35942b933d6518e6" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
<sha256 value="745894f1d15599871b1c3a6cc09f0da03268f1373ce937ce35942b933d6518e6" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="com.android.tools.build" name="bundletool" version="1.16.0">
|
||||||
|
<artifact name="bundletool-1.16.0.jar">
|
||||||
|
<sha256 value="1ea2bf5274bbac7a3bb5618521d2fa11fb04e900e33a8a646029ec6332fc08c8" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="bundletool-1.16.0.pom">
|
||||||
|
<sha256 value="f2e8aad4455a42372462d5e18a26973d67571179a6757f3825f227e91af2f2db" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="com.android.tools.build" name="gradle" version="8.2.2">
|
<component group="com.android.tools.build" name="gradle" version="8.2.2">
|
||||||
<artifact name="gradle-8.2.2.jar">
|
<artifact name="gradle-8.2.2.jar">
|
||||||
<sha256 value="ca50f47cd13d347de7c89ecb2bd06487b03a88687c46c2b776bc0a9323958955" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
<sha256 value="ca50f47cd13d347de7c89ecb2bd06487b03a88687c46c2b776bc0a9323958955" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
2
gradlew
vendored
2
gradlew
vendored
|
@ -55,7 +55,7 @@
|
||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
|
Loading…
Reference in a new issue