Skip to content

Commit

Permalink
Merge pull request #12059 from nextcloud/nmc/emailShareViaContactBook
Browse files Browse the repository at this point in the history
Share screen email selection from contact book
  • Loading branch information
AndyScherzinger authored Nov 21, 2023
2 parents dcdd79e + 8cc428a commit 6756b4d
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 22 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*
* Copyright (C) 2018 Andy Scherzinger
* Copyright (C) 2020 Chris Narkiewicz <[email protected]>
* 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
Expand All @@ -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;
Expand All @@ -46,6 +52,7 @@
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;
Expand All @@ -61,13 +68,16 @@
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;
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;
Expand Down Expand Up @@ -167,6 +177,8 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
file.isEncrypted()));
binding.sharesList.setLayoutManager(new LinearLayoutManager(getContext()));

binding.pickContactEmailBtn.setOnClickListener(v -> checkContactPermission());

setupView();

return view;
Expand Down Expand Up @@ -208,6 +220,7 @@ private void setupView() {
} 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);
}
}
Expand Down Expand Up @@ -460,6 +473,52 @@ public void refreshSharesFromDB() {
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) {
Expand Down Expand Up @@ -546,6 +605,38 @@ public void onQuickPermissionChanged(OCShare share, int permission) {
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);
Expand Down
26 changes: 26 additions & 0 deletions app/src/main/res/drawable/ic_contact_book.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!--
@author Google LLC
Copyright (C) 2023 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#666666"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,0L4,0v2h16L20,0zM4,24h16v-2L4,22v2zM20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM12,6.75c1.24,0 2.25,1.01 2.25,2.25s-1.01,2.25 -2.25,2.25S9.75,10.24 9.75,9 10.76,6.75 12,6.75zM17,17L7,17v-1.5c0,-1.67 3.33,-2.5 5,-2.5s5,0.83 5,2.5L17,17z" />
</vector>
57 changes: 36 additions & 21 deletions app/src/main/res/layout/file_details_sharing_fragment.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<?xml version="1.0" encoding="utf-8"?><!--
Nextcloud Android client application
@author TSI-mc
Copyright (C) 2018 Andy Scherzinger
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
Expand Down Expand Up @@ -29,94 +32,106 @@
android:id="@+id/search_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="@dimen/standard_padding"
android:paddingEnd="@dimen/zero">

<ImageView
android:id="@+id/searchViewIcon"
android:layout_height="@dimen/user_icon_size"
android:layout_width="@dimen/user_icon_size"
android:padding="@dimen/standard_half_padding"
android:contentDescription="@string/avatar"
android:layout_height="@dimen/user_icon_size"
android:layout_gravity="center_vertical"
android:contentDescription="@string/avatar"
android:padding="@dimen/standard_half_padding"
android:src="@drawable/ic_search_grey" />

<androidx.appcompat.widget.SearchView
android:id="@+id/searchView"
style="@style/ownCloud.SearchView"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/zero"
android:layout_marginEnd="@dimen/standard_quarter_margin"
android:layout_weight="1"
android:hint="@string/share_search"
app:searchIcon="@null" />

<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/pick_contact_email_btn"
android:layout_width="@dimen/minimum_size_for_touchable_area"
android:layout_height="@dimen/minimum_size_for_touchable_area"
android:layout_gravity="center_vertical"
android:padding="12dp"
android:layout_marginEnd="@dimen/standard_quarter_margin"
android:src="@drawable/ic_contact_book" />

</LinearLayout>

<LinearLayout
android:id="@+id/shared_with_you_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/standard_half_margin"
android:layout_width="match_parent"
android:orientation="horizontal"
android:paddingLeft="@dimen/standard_padding"
android:paddingRight="@dimen/standard_padding"
android:paddingTop="@dimen/standard_padding">
android:paddingTop="@dimen/standard_padding"
android:paddingRight="@dimen/standard_padding">

<ImageView
android:contentDescription="@string/avatar"
android:id="@+id/shared_with_you_avatar"
android:layout_height="@dimen/user_icon_size"
android:layout_width="@dimen/user_icon_size"
android:layout_height="@dimen/user_icon_size"
android:contentDescription="@string/avatar"
android:src="@drawable/ic_user" />

<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/standard_padding"
android:paddingRight="@dimen/standard_padding"
android:paddingTop="@dimen/standard_half_padding">
android:paddingTop="@dimen/standard_half_padding"
android:paddingRight="@dimen/standard_padding">

<TextView
android:id="@+id/shared_with_you_username"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/shared_with_you_by"
android:textSize="@dimen/two_line_primary_text_size" />

<LinearLayout
android:id="@+id/shared_with_you_note_container"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingTop="@dimen/standard_half_padding"
tools:ignore="UseCompoundDrawables">

<ImageView
android:contentDescription="@string/note_icon_hint"
android:layout_height="16dp"
android:layout_width="16dp"
android:layout_height="16dp"
android:contentDescription="@string/note_icon_hint"
android:src="@drawable/file_text" />

<TextView
android:id="@+id/shared_with_you_note"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_width="0dp"
android:paddingEnd="@dimen/standard_half_padding"
android:paddingStart="@dimen/standard_half_padding"
android:paddingEnd="@dimen/standard_half_padding"
android:textSize="16sp" />
</LinearLayout>

</LinearLayout>
</LinearLayout>

<androidx.recyclerview.widget.RecyclerView
android:divider="@drawable/divider"
android:dividerHeight="1dp"
android:id="@+id/sharesList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="match_parent" />
android:divider="@drawable/divider"
android:dividerHeight="1dp"
tools:listitem="@layout/file_details_share_link_share_item" />

</LinearLayout>
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@
<string name="actionbar_calendar_contacts_restore">Restore contacts &amp; calendar</string>
<string name="contacts_backup_button">Back up now</string>
<string name="contactlist_no_permission">No permission given, nothing imported.</string>
<string name="contact_no_permission">Contact permission is required.</string>
<string name="restore_backup">Restore backup</string>
<string name="contacts_preferences_no_file_found">No file found</string>
<string name="contacts_preferences_something_strange_happened">Could not find your last backup!</string>
Expand Down Expand Up @@ -939,6 +940,7 @@
<string name="link_share_file_drop">File drop (upload only)</string>
<string name="could_not_retrieve_shares">Could not retrieve shares</string>
<string name="failed_update_ui">Failed to update UI</string>
<string name="email_pick_failed">Failed to pick email address.</string>
<string name="remote">(remote)</string>
<string name="set_status">Set status</string>
<string name="online_status">Online status</string>
Expand Down

0 comments on commit 6756b4d

Please sign in to comment.