|
@@ -7,7 +7,7 @@
|
|
|
*
|
|
|
* Copyright (C) 2018 Andy Scherzinger
|
|
|
* Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
|
|
|
- * Copyright (C) 2020 TSI-mc
|
|
|
+ * Copyright (C) 2023 TSI-mc
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
|
@@ -25,11 +25,17 @@
|
|
|
|
|
|
package com.owncloud.android.ui.fragment;
|
|
|
|
|
|
+import android.Manifest;
|
|
|
import android.accounts.AccountManager;
|
|
|
+import android.app.Activity;
|
|
|
import android.app.SearchManager;
|
|
|
import android.content.Context;
|
|
|
+import android.content.Intent;
|
|
|
+import android.database.Cursor;
|
|
|
import android.graphics.drawable.Drawable;
|
|
|
+import android.net.Uri;
|
|
|
import android.os.Bundle;
|
|
|
+import android.provider.ContactsContract;
|
|
|
import android.text.InputType;
|
|
|
import android.text.TextUtils;
|
|
|
import android.view.LayoutInflater;
|
|
@@ -46,6 +52,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager;
|
|
|
import com.owncloud.android.datamodel.OCFile;
|
|
|
import com.owncloud.android.lib.common.OwnCloudAccount;
|
|
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
|
|
+import com.owncloud.android.lib.common.utils.Log_OC;
|
|
|
import com.owncloud.android.lib.resources.shares.OCShare;
|
|
|
import com.owncloud.android.lib.resources.shares.ShareType;
|
|
|
import com.owncloud.android.lib.resources.status.NextcloudVersion;
|
|
@@ -61,6 +68,7 @@ import com.owncloud.android.ui.fragment.util.FileDetailSharingFragmentHelper;
|
|
|
import com.owncloud.android.ui.helpers.FileOperationsHelper;
|
|
|
import com.owncloud.android.utils.ClipboardUtil;
|
|
|
import com.owncloud.android.utils.DisplayUtils;
|
|
|
+import com.owncloud.android.utils.PermissionUtil;
|
|
|
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
@@ -68,6 +76,8 @@ import java.util.List;
|
|
|
|
|
|
import javax.inject.Inject;
|
|
|
|
|
|
+import androidx.activity.result.ActivityResultLauncher;
|
|
|
+import androidx.activity.result.contract.ActivityResultContracts;
|
|
|
import androidx.annotation.NonNull;
|
|
|
import androidx.annotation.Nullable;
|
|
|
import androidx.annotation.VisibleForTesting;
|
|
@@ -81,7 +91,6 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
|
|
|
|
|
private static final String ARG_FILE = "FILE";
|
|
|
private static final String ARG_USER = "USER";
|
|
|
- public static final int PERMISSION_EDITING_ALLOWED = 17;
|
|
|
|
|
|
private OCFile file;
|
|
|
private User user;
|
|
@@ -118,8 +127,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
|
|
} else {
|
|
|
Bundle arguments = getArguments();
|
|
|
if (arguments != null) {
|
|
|
- file = getArguments().getParcelable(ARG_FILE);
|
|
|
- user = getArguments().getParcelable(ARG_USER);
|
|
|
+ file = arguments.getParcelable(ARG_FILE);
|
|
|
+ user = arguments.getParcelable(ARG_USER);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -149,12 +158,11 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
|
|
@Override
|
|
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
|
binding = FileDetailsSharingFragmentBinding.inflate(inflater, container, false);
|
|
|
- View view = binding.getRoot();
|
|
|
|
|
|
fileOperationsHelper = fileActivity.getFileOperationsHelper();
|
|
|
fileDataStorageManager = fileActivity.getStorageManager();
|
|
|
|
|
|
- AccountManager accountManager = AccountManager.get(getContext());
|
|
|
+ AccountManager accountManager = AccountManager.get(requireContext());
|
|
|
String userId = accountManager.getUserData(user.toPlatformAccount(),
|
|
|
com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
|
|
|
|
|
@@ -165,11 +173,14 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
|
|
user,
|
|
|
viewThemeUtils,
|
|
|
file.isEncrypted()));
|
|
|
- binding.sharesList.setLayoutManager(new LinearLayoutManager(getContext()));
|
|
|
+
|
|
|
+ binding.sharesList.setLayoutManager(new LinearLayoutManager(requireContext()));
|
|
|
+
|
|
|
+ binding.pickContactEmailBtn.setOnClickListener(v -> checkContactPermission());
|
|
|
|
|
|
setupView();
|
|
|
|
|
|
- return view;
|
|
|
+ return binding.getRoot();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -208,6 +219,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
|
|
} else {
|
|
|
binding.searchView.setQueryHint(getResources().getString(R.string.reshare_not_allowed));
|
|
|
binding.searchView.setInputType(InputType.TYPE_NULL);
|
|
|
+ binding.pickContactEmailBtn.setVisibility(View.GONE);
|
|
|
disableSearchView(binding.searchView);
|
|
|
}
|
|
|
}
|
|
@@ -216,9 +228,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
|
|
private void disableSearchView(View view) {
|
|
|
view.setEnabled(false);
|
|
|
|
|
|
- if (view instanceof ViewGroup) {
|
|
|
- ViewGroup viewGroup = (ViewGroup) view;
|
|
|
-
|
|
|
+ if (view instanceof ViewGroup viewGroup) {
|
|
|
for (int i = 0; i < viewGroup.getChildCount(); i++) {
|
|
|
disableSearchView(viewGroup.getChildAt(i));
|
|
|
}
|
|
@@ -302,7 +312,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
|
|
if (TextUtils.isEmpty(share.getShareLink())) {
|
|
|
fileOperationsHelper.getFileWithLink(file, viewThemeUtils);
|
|
|
} else {
|
|
|
- ClipboardUtil.copyToClipboard(getActivity(), share.getShareLink());
|
|
|
+ ClipboardUtil.copyToClipboard(requireActivity(), share.getShareLink());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -460,6 +470,52 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
|
|
adapter.addShares(publicShares);
|
|
|
}
|
|
|
|
|
|
+ private void checkContactPermission() {
|
|
|
+ if (PermissionUtil.checkSelfPermission(requireActivity(), Manifest.permission.READ_CONTACTS)) {
|
|
|
+ pickContactEmail();
|
|
|
+ } else {
|
|
|
+ requestContactPermissionLauncher.launch(Manifest.permission.READ_CONTACTS);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void pickContactEmail() {
|
|
|
+ Intent intent = new Intent(Intent.ACTION_PICK);
|
|
|
+ intent.setDataAndType(ContactsContract.Contacts.CONTENT_URI, ContactsContract.CommonDataKinds.Email.CONTENT_TYPE);
|
|
|
+ onContactSelectionResultLauncher.launch(intent);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleContactResult(@NonNull Uri contactUri) {
|
|
|
+ // Define the projection to get all email addresses.
|
|
|
+ String[] projection = {ContactsContract.CommonDataKinds.Email.ADDRESS};
|
|
|
+
|
|
|
+ Cursor cursor = fileActivity.getContentResolver().query(contactUri, projection, null, null, null);
|
|
|
+
|
|
|
+ if (cursor != null) {
|
|
|
+ if (cursor.moveToFirst()) {
|
|
|
+ // The contact has only one email address, use it.
|
|
|
+ int columnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS);
|
|
|
+ if (columnIndex != -1) {
|
|
|
+ // Use the email address as needed.
|
|
|
+ // email variable contains the selected contact's email address.
|
|
|
+ String email = cursor.getString(columnIndex);
|
|
|
+ binding.searchView.post(() -> {
|
|
|
+ binding.searchView.setQuery(email, false);
|
|
|
+ binding.searchView.requestFocus();
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ DisplayUtils.showSnackMessage(binding.getRoot(), R.string.email_pick_failed);
|
|
|
+ Log_OC.e(FileDetailSharingFragment.class.getSimpleName(), "Failed to pick email address.");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ DisplayUtils.showSnackMessage(binding.getRoot(), R.string.email_pick_failed);
|
|
|
+ Log_OC.e(FileDetailSharingFragment.class.getSimpleName(), "Failed to pick email address as no Email found.");
|
|
|
+ }
|
|
|
+ cursor.close();
|
|
|
+ } else {
|
|
|
+ DisplayUtils.showSnackMessage(binding.getRoot(), R.string.email_pick_failed);
|
|
|
+ Log_OC.e(FileDetailSharingFragment.class.getSimpleName(), "Failed to pick email address as Cursor is null.");
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
private boolean containsNoNewPublicShare(List<OCShare> shares) {
|
|
|
for (OCShare share : shares) {
|
|
@@ -496,7 +552,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
|
|
|
|
|
@VisibleForTesting
|
|
|
public void search(String query) {
|
|
|
- SearchView searchView = getView().findViewById(R.id.searchView);
|
|
|
+ SearchView searchView = requireView().findViewById(R.id.searchView);
|
|
|
searchView.setQuery(query, true);
|
|
|
}
|
|
|
|
|
@@ -546,6 +602,38 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
|
|
fileOperationsHelper.setPermissionsToShare(share, permission);
|
|
|
}
|
|
|
|
|
|
+ //launcher for contact permission
|
|
|
+ private final ActivityResultLauncher<String> requestContactPermissionLauncher =
|
|
|
+ registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
|
|
|
+ if (isGranted) {
|
|
|
+ pickContactEmail();
|
|
|
+ } else {
|
|
|
+ DisplayUtils.showSnackMessage(binding.getRoot(), R.string.contact_no_permission);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ //launcher to handle contact selection
|
|
|
+ private final ActivityResultLauncher<Intent> onContactSelectionResultLauncher =
|
|
|
+ registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
|
|
|
+ result -> {
|
|
|
+ if (result.getResultCode() == Activity.RESULT_OK) {
|
|
|
+ Intent intent = result.getData();
|
|
|
+ if (intent == null) {
|
|
|
+ DisplayUtils.showSnackMessage(binding.getRoot(), R.string.email_pick_failed);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Uri contactUri = intent.getData();
|
|
|
+ if (contactUri == null) {
|
|
|
+ DisplayUtils.showSnackMessage(binding.getRoot(), R.string.email_pick_failed);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ handleContactResult(contactUri);
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
public interface OnEditShareListener {
|
|
|
void editExistingShare(OCShare share, int screenTypePermission, boolean isReshareShown,
|
|
|
boolean isExpiryDateShown);
|