mirror of
https://github.com/M66B/FairEmail.git
synced 2026-04-05 00:23:09 +02:00
Added pinning of contacts
This commit is contained in:
@@ -42,6 +42,8 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.core.content.pm.ShortcutInfoCompat;
|
||||
import androidx.core.content.pm.ShortcutManagerCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.LifecycleObserver;
|
||||
@@ -235,7 +237,9 @@ public class AdapterContact extends RecyclerView.Adapter<AdapterContact.ViewHold
|
||||
popupMenu.getMenu().add(Menu.NONE, R.string.title_advanced_never_favorite, 1, R.string.title_advanced_never_favorite);
|
||||
if (share.resolveActivity(context.getPackageManager()) != null)
|
||||
popupMenu.getMenu().add(Menu.NONE, R.string.title_share, 2, R.string.title_share);
|
||||
popupMenu.getMenu().add(Menu.NONE, R.string.title_delete, 3, R.string.title_delete);
|
||||
if (ShortcutManagerCompat.isRequestPinShortcutSupported(context))
|
||||
popupMenu.getMenu().add(Menu.NONE, R.string.title_pin, 3, R.string.title_pin);
|
||||
popupMenu.getMenu().add(Menu.NONE, R.string.title_delete, 4, R.string.title_delete);
|
||||
|
||||
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
@@ -247,6 +251,9 @@ public class AdapterContact extends RecyclerView.Adapter<AdapterContact.ViewHold
|
||||
case R.string.title_share:
|
||||
onActionShare();
|
||||
return true;
|
||||
case R.string.title_pin:
|
||||
onActionPin();
|
||||
return true;
|
||||
case R.string.title_delete:
|
||||
onActionDelete();
|
||||
return true;
|
||||
@@ -290,6 +297,11 @@ public class AdapterContact extends RecyclerView.Adapter<AdapterContact.ViewHold
|
||||
}
|
||||
}
|
||||
|
||||
private void onActionPin() {
|
||||
ShortcutInfoCompat.Builder builder = Shortcuts.getShortcut(context, contact);
|
||||
ShortcutManagerCompat.requestPinShortcut(context, builder.build(), null);
|
||||
}
|
||||
|
||||
private void onActionDelete() {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("id", contact.id);
|
||||
|
||||
@@ -114,6 +114,8 @@ import androidx.constraintlayout.helper.widget.Flow;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.constraintlayout.widget.Group;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.core.content.pm.ShortcutInfoCompat;
|
||||
import androidx.core.content.pm.ShortcutManagerCompat;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
@@ -212,6 +214,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||
private int colorSeparator;
|
||||
|
||||
private boolean hasWebView;
|
||||
private boolean pin;
|
||||
private boolean contacts;
|
||||
private float textSize;
|
||||
|
||||
@@ -359,6 +362,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||
|
||||
private ImageButton ibSearchContact;
|
||||
private ImageButton ibNotifyContact;
|
||||
private ImageButton ibPinContact;
|
||||
private ImageButton ibAddContact;
|
||||
|
||||
private TextView tvSubmitterTitle;
|
||||
@@ -529,6 +533,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||
|
||||
ibSearchContact = vsBody.findViewById(R.id.ibSearchContact);
|
||||
ibNotifyContact = vsBody.findViewById(R.id.ibNotifyContact);
|
||||
ibPinContact = vsBody.findViewById(R.id.ibPinContact);
|
||||
ibAddContact = vsBody.findViewById(R.id.ibAddContact);
|
||||
|
||||
tvSubmitterTitle = vsBody.findViewById(R.id.tvSubmitterTitle);
|
||||
@@ -670,6 +675,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||
ibExpanderAddress.setOnClickListener(this);
|
||||
ibSearchContact.setOnClickListener(this);
|
||||
ibNotifyContact.setOnClickListener(this);
|
||||
ibPinContact.setOnClickListener(this);
|
||||
ibAddContact.setOnClickListener(this);
|
||||
|
||||
btnSaveAttachments.setOnClickListener(this);
|
||||
@@ -743,6 +749,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||
ibExpanderAddress.setOnClickListener(null);
|
||||
ibSearchContact.setOnClickListener(null);
|
||||
ibNotifyContact.setOnClickListener(null);
|
||||
ibPinContact.setOnClickListener(null);
|
||||
ibAddContact.setOnClickListener(null);
|
||||
|
||||
btnSaveAttachments.setOnClickListener(null);
|
||||
@@ -1141,6 +1148,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||
|
||||
ibSearchContact.setVisibility(View.GONE);
|
||||
ibNotifyContact.setVisibility(View.GONE);
|
||||
ibPinContact.setVisibility(View.GONE);
|
||||
ibAddContact.setVisibility(View.GONE);
|
||||
|
||||
tvSubmitterTitle.setVisibility(View.GONE);
|
||||
@@ -1350,6 +1358,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||
|
||||
ibSearchContact.setVisibility(show_addresses && (hasFrom || hasTo) ? View.VISIBLE : View.GONE);
|
||||
ibNotifyContact.setVisibility(show_addresses && hasChannel && hasFrom ? View.VISIBLE : View.GONE);
|
||||
ibPinContact.setVisibility(show_addresses && pin && hasFrom ? View.VISIBLE : View.GONE);
|
||||
ibAddContact.setVisibility(show_addresses && contacts && hasFrom ? View.VISIBLE : View.GONE);
|
||||
|
||||
tvSubmitterTitle.setVisibility(show_addresses && !TextUtils.isEmpty(submitter) ? View.VISIBLE : View.GONE);
|
||||
@@ -2541,6 +2550,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||
onSearchContact(message);
|
||||
else if (view.getId() == R.id.ibNotifyContact)
|
||||
onNotifyContact(message);
|
||||
else if (view.getId() == R.id.ibPinContact)
|
||||
onPinContact(message);
|
||||
else if (view.getId() == R.id.ibAddContact)
|
||||
onAddContact(message);
|
||||
else if (viewType == ViewType.THREAD) {
|
||||
@@ -2929,7 +2940,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||
final NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
final String channelId = message.getNotificationChannelId();
|
||||
|
||||
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, powner, ibAddContact);
|
||||
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, powner, ibNotifyContact);
|
||||
NotificationChannel channel = nm.getNotificationChannel(channelId);
|
||||
if (channel == null)
|
||||
popupMenu.getMenu().add(Menu.NONE, R.string.title_create_channel, 1, R.string.title_create_channel);
|
||||
@@ -2994,6 +3005,12 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||
popupMenu.show();
|
||||
}
|
||||
|
||||
private void onPinContact(TupleMessageEx message) {
|
||||
ShortcutInfoCompat.Builder builder =
|
||||
Shortcuts.getShortcut(context, (InternetAddress) message.from[0]);
|
||||
ShortcutManagerCompat.requestPinShortcut(context, builder.build(), null);
|
||||
}
|
||||
|
||||
private void onAddContact(TupleMessageEx message) {
|
||||
for (Address address : message.from) {
|
||||
InternetAddress ia = (InternetAddress) address;
|
||||
@@ -4401,6 +4418,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||
this.colorSeparator = Helper.resolveColor(context, R.attr.colorSeparator);
|
||||
|
||||
this.hasWebView = Helper.hasWebView(context);
|
||||
this.pin = ShortcutManagerCompat.isRequestPinShortcutSupported(context);
|
||||
this.contacts = Helper.hasPermission(context, Manifest.permission.READ_CONTACTS);
|
||||
this.textSize = Helper.getTextSize(context, zoom);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ package eu.faircode.email;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
@@ -32,6 +33,7 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.ContactsContract;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.core.app.Person;
|
||||
@@ -41,6 +43,8 @@ import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -48,6 +52,8 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.mail.internet.InternetAddress;
|
||||
|
||||
class Shortcuts {
|
||||
private static final int MAX_SHORTCUTS = 4;
|
||||
|
||||
@@ -87,48 +93,10 @@ class Shortcuts {
|
||||
if (emails.contains(email))
|
||||
continue;
|
||||
emails.add(email);
|
||||
|
||||
EntityLog.log(context, "Shortcut email=" + email);
|
||||
|
||||
Intent intent = new Intent(context, ActivityMain.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
intent.setAction(Intent.ACTION_SEND);
|
||||
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
intent.setData(Uri.parse("mailto:" + email));
|
||||
|
||||
IconCompat icon = null;
|
||||
if (avatar != null &&
|
||||
Helper.hasPermission(context, Manifest.permission.READ_CONTACTS)) {
|
||||
// Create icon from bitmap because launcher might not have contacts permission
|
||||
InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(
|
||||
context.getContentResolver(), Uri.parse(avatar));
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(is);
|
||||
if (bitmap != null)
|
||||
icon = IconCompat.createWithBitmap(bitmap);
|
||||
}
|
||||
if (icon == null)
|
||||
icon = IconCompat.createWithResource(context, R.drawable.ic_shortcut_email);
|
||||
|
||||
Set<String> categories = new HashSet<>(Arrays.asList("eu.faircode.email.TEXT_SHARE_TARGET"));
|
||||
|
||||
String id = (name == null ? email : "\"" + name + "\" <" + email + ">");
|
||||
ShortcutInfoCompat.Builder builder = new ShortcutInfoCompat.Builder(context, id)
|
||||
.setIcon(icon)
|
||||
.setRank(shortcuts.size() + 1)
|
||||
.setShortLabel(name == null ? email : name)
|
||||
.setLongLabel(name == null ? email : name)
|
||||
.setCategories(categories)
|
||||
.setIntent(intent);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
Person.Builder person = new Person.Builder()
|
||||
.setIcon(icon)
|
||||
.setName(name == null ? email : name)
|
||||
.setImportant(true);
|
||||
if (avatar != null)
|
||||
person.setUri(avatar);
|
||||
builder.setPerson(person.build());
|
||||
}
|
||||
|
||||
ShortcutInfoCompat.Builder builder = getShortcut(context, email, name, avatar);
|
||||
builder.setRank(shortcuts.size() + 1);
|
||||
shortcuts.add(builder.build());
|
||||
}
|
||||
}
|
||||
@@ -149,4 +117,94 @@ class Shortcuts {
|
||||
}
|
||||
}.execute(context, owner, new Bundle(), "shortcuts:update");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static ShortcutInfoCompat.Builder getShortcut(Context context, InternetAddress address) {
|
||||
String name = address.getPersonal();
|
||||
String email = address.getAddress();
|
||||
|
||||
Uri lookupUri = null;
|
||||
boolean contacts = Helper.hasPermission(context, Manifest.permission.READ_CONTACTS);
|
||||
if (contacts) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
try (Cursor cursor = resolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,
|
||||
new String[]{
|
||||
ContactsContract.CommonDataKinds.Photo.CONTACT_ID,
|
||||
ContactsContract.Contacts.LOOKUP_KEY,
|
||||
ContactsContract.Contacts.DISPLAY_NAME
|
||||
},
|
||||
ContactsContract.CommonDataKinds.Email.ADDRESS + " = ?",
|
||||
new String[]{email}, null)) {
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
int colContactId = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Photo.CONTACT_ID);
|
||||
int colLookupKey = cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
|
||||
int colDisplayName = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
|
||||
|
||||
long contactId = cursor.getLong(colContactId);
|
||||
String lookupKey = cursor.getString(colLookupKey);
|
||||
String displayName = cursor.getString(colDisplayName);
|
||||
|
||||
lookupUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
|
||||
if (!TextUtils.isEmpty(displayName))
|
||||
name = displayName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return getShortcut(context, email, name, lookupUri);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static ShortcutInfoCompat.Builder getShortcut(Context context, EntityContact contact) {
|
||||
return getShortcut(context, contact.email, contact.name, contact.avatar);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ShortcutInfoCompat.Builder getShortcut(Context context, String email, String name, String avatar) {
|
||||
return getShortcut(context, email, name, avatar == null ? null : Uri.parse(avatar));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ShortcutInfoCompat.Builder getShortcut(Context context, String email, String name, Uri avatar) {
|
||||
Intent intent = new Intent(context, ActivityMain.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
intent.setAction(Intent.ACTION_SEND);
|
||||
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
intent.setData(Uri.parse("mailto:" + email));
|
||||
|
||||
IconCompat icon = null;
|
||||
if (avatar != null &&
|
||||
Helper.hasPermission(context, Manifest.permission.READ_CONTACTS)) {
|
||||
// Create icon from bitmap because launcher might not have contacts permission
|
||||
InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(
|
||||
context.getContentResolver(), avatar);
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(is);
|
||||
if (bitmap != null)
|
||||
icon = IconCompat.createWithBitmap(bitmap);
|
||||
}
|
||||
if (icon == null)
|
||||
icon = IconCompat.createWithResource(context, R.drawable.ic_shortcut_email);
|
||||
|
||||
Set<String> categories = new HashSet<>(Arrays.asList("eu.faircode.email.TEXT_SHARE_TARGET"));
|
||||
|
||||
String id = (name == null ? email : "\"" + name + "\" <" + email + ">");
|
||||
ShortcutInfoCompat.Builder builder = new ShortcutInfoCompat.Builder(context, id)
|
||||
.setIcon(icon)
|
||||
.setShortLabel(name == null ? email : name)
|
||||
.setLongLabel(name == null ? email : name)
|
||||
.setCategories(categories)
|
||||
.setIntent(intent);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
Person.Builder person = new Person.Builder()
|
||||
.setIcon(icon)
|
||||
.setName(name == null ? email : name)
|
||||
.setImportant(true);
|
||||
if (avatar != null)
|
||||
person.setUri(avatar.toString());
|
||||
builder.setPerson(person.build());
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user