Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2020-11-05 21:44:04 +0300
committerStefan Niedermann <info@niedermann.it>2020-11-05 21:44:04 +0300
commitee8171ceb74b85f07c6ee0092b5d566102b8a5a7 (patch)
tree9557701ba4900b77df87f53634d3bb4df8684884 /app/src/main
parent9f442181a8f1b405283b55df128ed4fa9dc6b42e (diff)
Display attachments in a dialog to give the user a chance to cancel the upload
Signed-off-by: Stefan Niedermann <info@niedermann.it>
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/assignee/CardAssigneeDialog.java9
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java81
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/AbstractCursorPickerAdapter.java13
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/AbstractPickerAdapter.java2
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/ContactAdapter.java7
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/ContactItemViewHolder.java10
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileAdapter.java7
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileAdapterLegacy.java9
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileItemViewHolder.java9
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryAdapter.java9
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryItemViewHolder.java11
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/previewdialog/PreviewDialog.java102
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/previewdialog/PreviewDialogViewModel.java50
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterUserAdapter.java4
-rw-r--r--app/src/main/res/layout/dialog_preview.xml (renamed from app/src/main/res/layout/dialog_assignee.xml)2
-rw-r--r--app/src/main/res/layout/item_filter_user.xml2
-rw-r--r--app/src/main/res/layout/item_picker_user.xml2
-rw-r--r--app/src/main/res/values/strings.xml1
18 files changed, 265 insertions, 65 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/assignee/CardAssigneeDialog.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/assignee/CardAssigneeDialog.java
index 74c89d830..34d2eb3f3 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/assignee/CardAssigneeDialog.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/assignee/CardAssigneeDialog.java
@@ -19,7 +19,7 @@ import com.bumptech.glide.Glide;
import java.io.Serializable;
import it.niedermann.nextcloud.deck.R;
-import it.niedermann.nextcloud.deck.databinding.DialogAssigneeBinding;
+import it.niedermann.nextcloud.deck.databinding.DialogPreviewBinding;
import it.niedermann.nextcloud.deck.model.User;
import it.niedermann.nextcloud.deck.ui.branding.BrandedDeleteAlertDialogBuilder;
import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment;
@@ -27,10 +27,11 @@ import it.niedermann.nextcloud.deck.ui.card.EditCardViewModel;
import static it.niedermann.nextcloud.deck.DeckApplication.isDarkTheme;
+@Deprecated
public class CardAssigneeDialog extends BrandedDialogFragment {
private static final String KEY_USER = "user";
- private DialogAssigneeBinding binding;
+ private DialogPreviewBinding binding;
private EditCardViewModel viewModel;
@Nullable
@@ -63,7 +64,7 @@ public class CardAssigneeDialog extends BrandedDialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- binding = DialogAssigneeBinding.inflate(LayoutInflater.from(requireContext()));
+ binding = DialogPreviewBinding.inflate(LayoutInflater.from(requireContext()));
viewModel = new ViewModelProvider(requireActivity()).get(EditCardViewModel.class);
AlertDialog.Builder dialogBuilder = new BrandedDeleteAlertDialogBuilder(requireContext());
@@ -95,7 +96,7 @@ public class CardAssigneeDialog extends BrandedDialogFragment {
.placeholder(circularProgressDrawable)
.error(R.drawable.ic_person_grey600_24dp)
.into(binding.avatar));
- binding.displayName.setText(user.getDisplayname());
+ binding.title.setText(user.getDisplayname());
}
@Override
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java
index b137b1b7f..24b94ebde 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java
@@ -55,6 +55,8 @@ import it.niedermann.nextcloud.deck.ui.card.attachments.picker.ContactAdapter;
import it.niedermann.nextcloud.deck.ui.card.attachments.picker.FileAdapter;
import it.niedermann.nextcloud.deck.ui.card.attachments.picker.FileAdapterLegacy;
import it.niedermann.nextcloud.deck.ui.card.attachments.picker.GalleryAdapter;
+import it.niedermann.nextcloud.deck.ui.card.attachments.previewdialog.PreviewDialog;
+import it.niedermann.nextcloud.deck.ui.card.attachments.previewdialog.PreviewDialogViewModel;
import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment;
import it.niedermann.nextcloud.deck.ui.takephoto.TakePhotoActivity;
import it.niedermann.nextcloud.deck.util.VCardUtil;
@@ -84,7 +86,8 @@ import static java.net.HttpURLConnection.HTTP_CONFLICT;
public class CardAttachmentsFragment extends BrandedFragment implements AttachmentDeletedListener, AttachmentClickedListener {
private FragmentCardEditTabAttachmentsBinding binding;
- private EditCardViewModel viewModel;
+ private EditCardViewModel editViewModel;
+ private PreviewDialogViewModel previewViewModel;
private BottomSheetBehavior<LinearLayout> mBottomSheetBehaviour;
private static final int REQUEST_CODE_PICK_FILE = 1;
@@ -115,7 +118,8 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
Bundle savedInstanceState) {
binding = FragmentCardEditTabAttachmentsBinding.inflate(inflater, container, false);
- viewModel = new ViewModelProvider(requireActivity()).get(EditCardViewModel.class);
+ editViewModel = new ViewModelProvider(requireActivity()).get(EditCardViewModel.class);
+ previewViewModel = new ViewModelProvider(requireActivity()).get(PreviewDialogViewModel.class);
binding.bottomNavigation.setOnNavigationItemSelectedListener(item -> {
if (item.getItemId() == R.id.gallery) {
showGalleryPicker();
@@ -129,7 +133,7 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
// This might be a zombie fragment with an empty EditCardViewModel after Android killed the activity (but not the fragment instance
// See https://github.com/stefan-niedermann/nextcloud-deck/issues/478
- if (viewModel.getFullCard() == null) {
+ if (editViewModel.getFullCard() == null) {
DeckLog.logError(new IllegalStateException("Cannot populate " + CardAttachmentsFragment.class.getSimpleName() + " because viewModel.getFullCard() is null"));
return binding.getRoot();
}
@@ -139,8 +143,8 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
getChildFragmentManager(),
requireActivity().getMenuInflater(),
this,
- viewModel.getAccount(),
- viewModel.getFullCard().getLocalId());
+ editViewModel.getAccount(),
+ editViewModel.getFullCard().getLocalId());
binding.attachmentsList.setAdapter(adapter);
adapter.isEmpty().observe(getViewLifecycleOwner(), (isEmpty) -> {
@@ -198,7 +202,7 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
}
});
binding.attachmentsList.setLayoutManager(glm);
- if (!viewModel.isCreateMode()) {
+ if (!editViewModel.isCreateMode()) {
// https://android-developers.googleblog.com/2018/02/continuous-shared-element-transitions.html?m=1
// https://github.com/android/animation-samples/blob/master/GridToPager/app/src/main/java/com/google/samples/gridtopager/fragment/ImagePagerFragment.java
setExitSharedElementCallback(new SharedElementCallback() {
@@ -211,10 +215,10 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
}
}
});
- adapter.setAttachments(viewModel.getFullCard().getAttachments(), viewModel.getFullCard().getId());
+ adapter.setAttachments(editViewModel.getFullCard().getAttachments(), editViewModel.getFullCard().getId());
}
- if (viewModel.canEdit()) {
+ if (editViewModel.canEdit()) {
binding.fab.setOnClickListener(v -> {
if (SDK_INT < LOLLIPOP) {
openNativeFilePicker();
@@ -293,7 +297,15 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
requestPermissions(new String[]{READ_EXTERNAL_STORAGE, CAMERA}, REQUEST_CODE_PICK_GALLERY_PERMISSION);
} else {
unbindPickerAdapter();
- pickerAdapter = new GalleryAdapter(requireContext(), uri -> onActivityResult(REQUEST_CODE_PICK_FILE, RESULT_OK, new Intent().setData(uri)), this::openNativeCameraPicker, getViewLifecycleOwner());
+ pickerAdapter = new GalleryAdapter(requireContext(), (uri, pair) -> {
+ previewViewModel.prepareDialog(pair.first, pair.second);
+ PreviewDialog.newInstance().show(getChildFragmentManager(), PreviewDialog.class.getSimpleName());
+ observeOnce(previewViewModel.getResult(), getViewLifecycleOwner(), (submitPositive) -> {
+ if (submitPositive) {
+ onActivityResult(REQUEST_CODE_PICK_FILE, RESULT_OK, new Intent().setData(uri));
+ }
+ });
+ }, this::openNativeCameraPicker, getViewLifecycleOwner());
binding.pickerRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 3));
binding.pickerRecyclerView.setAdapter(pickerAdapter);
}
@@ -306,7 +318,15 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_CODE_PICK_CONTACT_PICKER_PERMISSION);
} else {
unbindPickerAdapter();
- pickerAdapter = new ContactAdapter(requireContext(), uri -> onActivityResult(REQUEST_CODE_PICK_CONTACT, RESULT_OK, new Intent().setData(uri)), this::openNativeContactPicker);
+ pickerAdapter = new ContactAdapter(requireContext(), (uri, pair) -> {
+ previewViewModel.prepareDialog(pair.first, pair.second);
+ PreviewDialog.newInstance().show(getChildFragmentManager(), PreviewDialog.class.getSimpleName());
+ observeOnce(previewViewModel.getResult(), getViewLifecycleOwner(), (submitPositive) -> {
+ if (submitPositive) {
+ onActivityResult(REQUEST_CODE_PICK_CONTACT, RESULT_OK, new Intent().setData(uri));
+ }
+ });
+ }, this::openNativeContactPicker);
binding.pickerRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
binding.pickerRecyclerView.setAdapter(pickerAdapter);
}
@@ -324,7 +344,15 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
// // TODO Only usable with Scoped Storage
// pickerAdapter = new FileAdapter(requireContext(), uri -> onActivityResult(REQUEST_CODE_PICK_FILE, RESULT_OK, new Intent().setData(uri)), this::openNativeFilePicker);
// } else {
- pickerAdapter = new FileAdapterLegacy(requireContext(), uri -> onActivityResult(REQUEST_CODE_PICK_FILE, RESULT_OK, new Intent().setData(uri)), this::openNativeFilePicker);
+ pickerAdapter = new FileAdapterLegacy(requireContext(), (uri, pair) -> {
+ previewViewModel.prepareDialog(pair.first, pair.second);
+ PreviewDialog.newInstance().show(getChildFragmentManager(), PreviewDialog.class.getSimpleName());
+ observeOnce(previewViewModel.getResult(), getViewLifecycleOwner(), (submitPositive) -> {
+ if (submitPositive) {
+ onActivityResult(REQUEST_CODE_PICK_FILE, RESULT_OK, new Intent().setData(uri));
+ }
+ });
+ }, this::openNativeFilePicker);
// }
binding.pickerRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
binding.pickerRecyclerView.setAdapter(pickerAdapter);
@@ -337,7 +365,7 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
if (SDK_INT >= LOLLIPOP) {
startActivityForResult(TakePhotoActivity.createIntent(requireContext()), REQUEST_CODE_PICK_CAMERA);
} else {
- ExceptionDialogFragment.newInstance(new UnsupportedOperationException("This feature requires Android 5"), viewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
+ ExceptionDialogFragment.newInstance(new UnsupportedOperationException("This feature requires Android 5"), editViewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
}
}
@@ -388,7 +416,7 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
: requireContext().getContentResolver().getType(sourceUri));
mBottomSheetBehaviour.setState(STATE_HIDDEN);
} catch (Exception e) {
- ExceptionDialogFragment.newInstance(e, viewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
+ ExceptionDialogFragment.newInstance(e, editViewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
}
}
break;
@@ -416,15 +444,14 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
case ContentResolver.SCHEME_CONTENT:
case ContentResolver.SCHEME_FILE: {
DeckLog.verbose("--- found content URL " + sourceUri.getPath());
- final File fileToUpload = copyContentUriToTempFile(requireContext(), sourceUri, viewModel.getAccount().getId(), viewModel.getFullCard().getLocalId());
- for (Attachment existingAttachment : viewModel.getFullCard().getAttachments()) {
+ final File fileToUpload = copyContentUriToTempFile(requireContext(), sourceUri, editViewModel.getAccount().getId(), editViewModel.getFullCard().getLocalId());
+ for (Attachment existingAttachment : editViewModel.getFullCard().getAttachments()) {
final String existingPath = existingAttachment.getLocalPath();
if (existingPath != null && existingPath.equals(fileToUpload.getAbsolutePath())) {
BrandedSnackbar.make(binding.coordinatorLayout, R.string.attachment_already_exists, Snackbar.LENGTH_LONG).show();
return;
}
}
-
final Instant now = Instant.now();
final Attachment a = new Attachment();
a.setMimetype(mimeType);
@@ -436,24 +463,24 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
a.setLastModifiedLocal(now);
a.setCreatedAt(now);
a.setStatusEnum(DBStatus.LOCAL_EDITED);
- viewModel.getFullCard().getAttachments().add(0, a);
+ editViewModel.getFullCard().getAttachments().add(0, a);
adapter.addAttachment(a);
- if (!viewModel.isCreateMode()) {
- WrappedLiveData<Attachment> liveData = syncManager.addAttachmentToCard(viewModel.getAccount().getId(), viewModel.getFullCard().getLocalId(), a.getMimetype(), fileToUpload);
+ if (!editViewModel.isCreateMode()) {
+ WrappedLiveData<Attachment> liveData = syncManager.addAttachmentToCard(editViewModel.getAccount().getId(), editViewModel.getFullCard().getLocalId(), a.getMimetype(), fileToUpload);
observeOnce(liveData, getViewLifecycleOwner(), (next) -> {
if (liveData.hasError()) {
Throwable t = liveData.getError();
if (t instanceof NextcloudHttpRequestFailedException && ((NextcloudHttpRequestFailedException) t).getStatusCode() == HTTP_CONFLICT) {
// https://github.com/stefan-niedermann/nextcloud-deck/issues/534
- viewModel.getFullCard().getAttachments().remove(a);
+ editViewModel.getFullCard().getAttachments().remove(a);
adapter.removeAttachment(a);
BrandedSnackbar.make(binding.coordinatorLayout, R.string.attachment_already_exists, Snackbar.LENGTH_LONG).show();
} else {
- ExceptionDialogFragment.newInstance(new UploadAttachmentFailedException("Unknown URI scheme", t), viewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
+ ExceptionDialogFragment.newInstance(new UploadAttachmentFailedException("Unknown URI scheme", t), editViewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
}
} else {
- viewModel.getFullCard().getAttachments().remove(a);
- viewModel.getFullCard().getAttachments().add(0, next);
+ editViewModel.getFullCard().getAttachments().remove(a);
+ editViewModel.getFullCard().getAttachments().add(0, next);
adapter.replaceAttachment(a, next);
}
});
@@ -503,12 +530,12 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
@Override
public void onAttachmentDeleted(Attachment attachment) {
adapter.removeAttachment(attachment);
- viewModel.getFullCard().getAttachments().remove(attachment);
- if (!viewModel.isCreateMode() && attachment.getLocalId() != null) {
- final WrappedLiveData<Void> deleteLiveData = syncManager.deleteAttachmentOfCard(viewModel.getAccount().getId(), viewModel.getFullCard().getLocalId(), attachment.getLocalId());
+ editViewModel.getFullCard().getAttachments().remove(attachment);
+ if (!editViewModel.isCreateMode() && attachment.getLocalId() != null) {
+ final WrappedLiveData<Void> deleteLiveData = syncManager.deleteAttachmentOfCard(editViewModel.getAccount().getId(), editViewModel.getFullCard().getLocalId(), attachment.getLocalId());
observeOnce(deleteLiveData, this, (next) -> {
if (deleteLiveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(deleteLiveData.getError())) {
- ExceptionDialogFragment.newInstance(deleteLiveData.getError(), viewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
+ ExceptionDialogFragment.newInstance(deleteLiveData.getError(), editViewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
}
});
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/AbstractCursorPickerAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/AbstractCursorPickerAdapter.java
index 73058c757..743e3382e 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/AbstractCursorPickerAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/AbstractCursorPickerAdapter.java
@@ -5,13 +5,16 @@ import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
+import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
+import com.bumptech.glide.RequestBuilder;
+
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
import static android.database.Cursor.FIELD_TYPE_INTEGER;
import static android.database.Cursor.FIELD_TYPE_NULL;
@@ -29,7 +32,7 @@ public abstract class AbstractCursorPickerAdapter<T extends RecyclerView.ViewHol
protected final int columnIndex;
private final int columnIndexType;
@NonNull
- protected final Consumer<Uri> onSelect;
+ protected final BiConsumer<Uri, Pair<String, RequestBuilder<?>>> onSelect;
@NonNull
protected final Runnable openNativePicker;
@NonNull
@@ -44,15 +47,15 @@ public abstract class AbstractCursorPickerAdapter<T extends RecyclerView.ViewHol
@NonNull
protected final ExecutorService bindExecutor = Executors.newFixedThreadPool(1);
- public AbstractCursorPickerAdapter(@NonNull Context context, @NonNull Consumer<Uri> onSelect, @NonNull Runnable openNativePicker, Uri subject, String idColumn, String sortOrder) {
+ public AbstractCursorPickerAdapter(@NonNull Context context, @NonNull BiConsumer<Uri, Pair<String, RequestBuilder<?>>> onSelect, @NonNull Runnable openNativePicker, Uri subject, String idColumn, String sortOrder) {
this(context, onSelect, openNativePicker, subject, idColumn, new String[]{idColumn}, sortOrder);
}
- public AbstractCursorPickerAdapter(@NonNull Context context, @NonNull Consumer<Uri> onSelect, @NonNull Runnable openNativePicker, Uri subject, String idColumn, String[] requestedColumns, String sortOrder) {
+ public AbstractCursorPickerAdapter(@NonNull Context context, @NonNull BiConsumer<Uri, Pair<String, RequestBuilder<?>>> onSelect, @NonNull Runnable openNativePicker, Uri subject, String idColumn, String[] requestedColumns, String sortOrder) {
this(context, onSelect, openNativePicker, idColumn, requireNonNull(context.getContentResolver().query(subject, requestedColumns, null, null, sortOrder)));
}
- public AbstractCursorPickerAdapter(@NonNull Context context, @NonNull Consumer<Uri> onSelect, @NonNull Runnable openNativePicker, String idColumn, @NonNull Cursor cursor) {
+ public AbstractCursorPickerAdapter(@NonNull Context context, @NonNull BiConsumer<Uri, Pair<String, RequestBuilder<?>>> onSelect, @NonNull Runnable openNativePicker, String idColumn, @NonNull Cursor cursor) {
this.contentResolver = context.getContentResolver();
this.onSelect = onSelect;
this.openNativePicker = openNativePicker;
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/AbstractPickerAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/AbstractPickerAdapter.java
index d04065aa4..a17794841 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/AbstractPickerAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/AbstractPickerAdapter.java
@@ -18,4 +18,4 @@ public abstract class AbstractPickerAdapter<T extends RecyclerView.ViewHolder> e
* Call this method when the {@link AbstractPickerAdapter} is no longer need to free resources.
*/
public abstract void onDestroy();
-}
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/ContactAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/ContactAdapter.java
index 874127103..e334cc492 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/ContactAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/ContactAdapter.java
@@ -9,15 +9,18 @@ import android.os.Handler;
import android.os.Looper;
import android.provider.ContactsContract;
import android.text.TextUtils;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
+import com.bumptech.glide.RequestBuilder;
+
import java.io.IOException;
import java.io.InputStream;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
import it.niedermann.nextcloud.deck.databinding.ItemPickerNativeBinding;
import it.niedermann.nextcloud.deck.databinding.ItemPickerUserBinding;
@@ -37,7 +40,7 @@ public class ContactAdapter extends AbstractCursorPickerAdapter<RecyclerView.Vie
private final int lookupKeyColumnIndex;
private final int displayNameColumnIndex;
- public ContactAdapter(@NonNull Context context, @NonNull Consumer<Uri> onSelect, @NonNull Runnable onSelectPicker) {
+ public ContactAdapter(@NonNull Context context, @NonNull BiConsumer<Uri, Pair<String, RequestBuilder<?>>> onSelect, @NonNull Runnable onSelectPicker) {
super(context, onSelect, onSelectPicker, CONTENT_URI, _ID, new String[]{_ID, LOOKUP_KEY, DISPLAY_NAME}, SORT_KEY_PRIMARY);
lookupKeyColumnIndex = cursor.getColumnIndex(LOOKUP_KEY);
displayNameColumnIndex = cursor.getColumnIndex(DISPLAY_NAME);
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/ContactItemViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/ContactItemViewHolder.java
index b8d52a1d3..f403fed21 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/ContactItemViewHolder.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/ContactItemViewHolder.java
@@ -4,15 +4,17 @@ import android.graphics.Bitmap;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.text.TextUtils;
+import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
+import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.request.RequestOptions;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.ItemPickerUserBinding;
@@ -30,9 +32,9 @@ public class ContactItemViewHolder extends RecyclerView.ViewHolder {
this.binding = binding;
}
- public void bind(@NonNull Uri uri, @Nullable Bitmap image, @NonNull String displayName, @Nullable String contactInformation, @NonNull Consumer<Uri> onSelect) {
- itemView.setOnClickListener((v) -> onSelect.accept(uri));
- binding.displayName.setText(displayName);
+ public void bind(@NonNull Uri uri, @Nullable Bitmap image, @NonNull String displayName, @Nullable String contactInformation, @NonNull BiConsumer<Uri, Pair<String, RequestBuilder<?>>> onSelect) {
+ itemView.setOnClickListener((v) -> onSelect.accept(uri, new Pair<>(displayName, image == null ? null : Glide.with(itemView.getContext()).load(image))));
+ binding.title.setText(displayName);
binding.contactInformation.setText(contactInformation);
if (image == null) {
binding.initials.setVisibility(VISIBLE);
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileAdapter.java
index 47dd3f7a3..46633df6c 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileAdapter.java
@@ -6,6 +6,7 @@ import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.provider.MediaStore;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -13,7 +14,9 @@ import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.recyclerview.widget.RecyclerView;
-import java.util.function.Consumer;
+import com.bumptech.glide.RequestBuilder;
+
+import java.util.function.BiConsumer;
import it.niedermann.nextcloud.deck.databinding.ItemAttachmentDefaultBinding;
import it.niedermann.nextcloud.deck.databinding.ItemPickerNativeBinding;
@@ -35,7 +38,7 @@ public class FileAdapter extends AbstractCursorPickerAdapter<RecyclerView.ViewHo
private final int modifiedColumnIndex;
private final int mimeTypeColumnIndex;
- private FileAdapter(@NonNull Context context, @NonNull Consumer<Uri> onSelect, @NonNull Runnable onSelectPicker) {
+ private FileAdapter(@NonNull Context context, @NonNull BiConsumer<Uri, Pair<String, RequestBuilder<?>>> onSelect, @NonNull Runnable onSelectPicker) {
super(context, onSelect, onSelectPicker, _ID, requireNonNull(context.getContentResolver().query(EXTERNAL_CONTENT_URI, new String[]{_ID, TITLE, SIZE, DATE_MODIFIED, MIME_TYPE}, null, null, DATE_ADDED + " DESC")));
displayNameColumnIndex = cursor.getColumnIndex(TITLE);
sizeColumnIndex = cursor.getColumnIndex(SIZE);
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileAdapterLegacy.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileAdapterLegacy.java
index a338e9d75..5688ab15b 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileAdapterLegacy.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileAdapterLegacy.java
@@ -3,16 +3,19 @@ package it.niedermann.nextcloud.deck.ui.card.attachments.picker;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
+import com.bumptech.glide.RequestBuilder;
+
import java.io.File;
import java.util.Arrays;
import java.util.List;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
import it.niedermann.nextcloud.deck.databinding.ItemAttachmentDefaultBinding;
import it.niedermann.nextcloud.deck.databinding.ItemPickerNativeBinding;
@@ -31,11 +34,11 @@ public class FileAdapterLegacy extends AbstractPickerAdapter<RecyclerView.ViewHo
@NonNull
private final List<File> files;
@NonNull
- protected final Consumer<Uri> onSelect;
+ protected final BiConsumer<Uri, Pair<String, RequestBuilder<?>>> onSelect;
@NonNull
protected final Runnable openNativePicker;
- public FileAdapterLegacy(@NonNull Context context, @NonNull Consumer<Uri> onSelect, @NonNull Runnable openNativePicker) {
+ public FileAdapterLegacy(@NonNull Context context, @NonNull BiConsumer<Uri, Pair<String, RequestBuilder<?>>> onSelect, @NonNull Runnable openNativePicker) {
// TODO run in separate thread?
this.context = context;
this.onSelect = onSelect;
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileItemViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileItemViewHolder.java
index 50733dfbe..f7d64aca8 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileItemViewHolder.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/FileItemViewHolder.java
@@ -1,12 +1,15 @@
package it.niedermann.nextcloud.deck.ui.card.attachments.picker;
import android.net.Uri;
+import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
-import java.util.function.Consumer;
+import com.bumptech.glide.RequestBuilder;
+
+import java.util.function.BiConsumer;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.ItemAttachmentDefaultBinding;
@@ -24,8 +27,8 @@ public class FileItemViewHolder extends RecyclerView.ViewHolder {
this.binding = binding;
}
- public void bind(@NonNull Uri uri, @NonNull String name, String mimeType, long size, long modified, @Nullable Consumer<Uri> onSelect) {
- itemView.setOnClickListener(onSelect == null ? null : (v) -> onSelect.accept(uri));
+ public void bind(@NonNull Uri uri, @NonNull String name, String mimeType, long size, long modified, @Nullable BiConsumer<Uri, Pair<String, RequestBuilder<?>>> onSelect) {
+ itemView.setOnClickListener(onSelect == null ? null : (v) -> onSelect.accept(uri, new Pair<>(name, null)));
binding.filename.setText(name);
binding.filesize.setText(formatFileSize(binding.filesize.getContext(), size));
binding.modified.setText(getRelativeDateTimeString(binding.modified.getContext(), modified));
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryAdapter.java
index 0be85d9e5..7f5c254c3 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryAdapter.java
@@ -8,6 +8,7 @@ import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.provider.MediaStore;
+import android.util.Pair;
import android.util.Size;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -16,8 +17,10 @@ import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;
import androidx.recyclerview.widget.RecyclerView;
+import com.bumptech.glide.RequestBuilder;
+
import java.io.IOException;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
import it.niedermann.nextcloud.deck.databinding.ItemAttachmentImageBinding;
import it.niedermann.nextcloud.deck.databinding.ItemPhotoPreviewBinding;
@@ -37,7 +40,7 @@ public class GalleryAdapter extends AbstractCursorPickerAdapter<RecyclerView.Vie
? MediaStore.Images.Media.DATE_TAKEN
: MediaStore.Images.Media.DATE_ADDED;
- public GalleryAdapter(@NonNull Context context, @NonNull Consumer<Uri> onSelect, @NonNull Runnable openNativePicker, @NonNull LifecycleOwner lifecycleOwner) {
+ public GalleryAdapter(@NonNull Context context, @NonNull BiConsumer<Uri, Pair<String, RequestBuilder<?>>> onSelect, @NonNull Runnable openNativePicker, @NonNull LifecycleOwner lifecycleOwner) {
super(context, onSelect, openNativePicker, EXTERNAL_CONTENT_URI, _ID, sortOrder + " DESC");
this.lifecycleOwner = lifecycleOwner;
notifyItemRangeInserted(0, getItemCount());
@@ -90,7 +93,7 @@ public class GalleryAdapter extends AbstractCursorPickerAdapter<RecyclerView.Vie
@Override
public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
- if(holder instanceof GalleryPhotoPreviewItemViewHolder) {
+ if (holder instanceof GalleryPhotoPreviewItemViewHolder) {
((GalleryPhotoPreviewItemViewHolder) holder).unbind();
}
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryItemViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryItemViewHolder.java
index d83876f0e..346fca9c3 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryItemViewHolder.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryItemViewHolder.java
@@ -2,23 +2,22 @@ package it.niedermann.nextcloud.deck.ui.card.attachments.picker;
import android.graphics.Bitmap;
import android.net.Uri;
+import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
+import com.bumptech.glide.RequestBuilder;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.ItemAttachmentImageBinding;
public class GalleryItemViewHolder extends RecyclerView.ViewHolder {
- private final ExecutorService executor = Executors.newCachedThreadPool();
private final ItemAttachmentImageBinding binding;
public GalleryItemViewHolder(@NonNull ItemAttachmentImageBinding binding) {
@@ -26,8 +25,8 @@ public class GalleryItemViewHolder extends RecyclerView.ViewHolder {
this.binding = binding;
}
- public void bind(@NonNull Uri uri, @Nullable Bitmap image, @NonNull Consumer<Uri> onSelect) {
- itemView.setOnClickListener((v) -> onSelect.accept(uri));
+ public void bind(@NonNull Uri uri, @Nullable Bitmap image, @NonNull BiConsumer<Uri, Pair<String, RequestBuilder<?>>> onSelect) {
+ itemView.setOnClickListener((v) -> onSelect.accept(uri, new Pair<>(null, Glide.with(itemView.getContext()).load(image))));
Glide.with(itemView.getContext())
.load(image)
.placeholder(R.drawable.ic_image_grey600_24dp)
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/previewdialog/PreviewDialog.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/previewdialog/PreviewDialog.java
new file mode 100644
index 000000000..8ebdf1b50
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/previewdialog/PreviewDialog.java
@@ -0,0 +1,102 @@
+package it.niedermann.nextcloud.deck.ui.card.attachments.previewdialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.swiperefreshlayout.widget.CircularProgressDrawable;
+
+import com.bumptech.glide.RequestBuilder;
+
+import it.niedermann.nextcloud.deck.R;
+import it.niedermann.nextcloud.deck.databinding.DialogPreviewBinding;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment;
+
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+import static it.niedermann.nextcloud.deck.DeckApplication.isDarkTheme;
+
+public class PreviewDialog extends BrandedDialogFragment {
+
+ private DialogPreviewBinding binding;
+ private PreviewDialogViewModel viewModel;
+ private LiveData<RequestBuilder<?>> imageBuilder$;
+ private LiveData<String> title$;
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ viewModel = new ViewModelProvider(requireActivity()).get(PreviewDialogViewModel.class);
+ binding = DialogPreviewBinding.inflate(LayoutInflater.from(requireContext()));
+
+ final Context context = requireContext();
+
+ this.imageBuilder$ = this.viewModel.getImageBuilder();
+ this.imageBuilder$.observe(requireActivity(), builder -> {
+ if (builder == null) {
+ binding.avatar.setVisibility(GONE);
+ } else {
+ final CircularProgressDrawable circularProgressDrawable = new CircularProgressDrawable(context);
+ circularProgressDrawable.setStrokeWidth(5f);
+ circularProgressDrawable.setCenterRadius(30f);
+ circularProgressDrawable.setColorSchemeColors(isDarkTheme(context) ? Color.LTGRAY : Color.DKGRAY);
+ circularProgressDrawable.start();
+ binding.avatar.setVisibility(VISIBLE);
+ binding.avatar.post(() -> builder
+ .placeholder(circularProgressDrawable)
+ .into(binding.avatar));
+ }
+ });
+ this.title$ = this.viewModel.getTitle();
+ this.title$.observe(requireActivity(), title -> {
+ if (TextUtils.isEmpty(title)) {
+ binding.title.setVisibility(GONE);
+ } else {
+ binding.title.setVisibility(VISIBLE);
+ binding.title.setText(title);
+ }
+ });
+
+ return new BrandedAlertDialogBuilder(requireContext())
+ .setPositiveButton(R.string.simple_attach, (d, w) -> {
+ viewModel.setResult(true);
+ dismiss();
+ })
+ .setNeutralButton(R.string.simple_close, (d, w) -> {
+ viewModel.setResult(false);
+ dismiss();
+ })
+ .setView(binding.getRoot())
+ .create();
+ }
+
+ @Override
+ public void onCancel(@NonNull DialogInterface dialog) {
+ viewModel.setResult(false);
+ super.onCancel(dialog);
+ }
+
+ @Override
+ public void applyBrand(int mainColor) {
+ }
+
+ @Override
+ public void onDestroy() {
+ this.imageBuilder$.removeObservers(requireActivity());
+ this.title$.removeObservers(requireActivity());
+ super.onDestroy();
+ }
+
+ public static DialogFragment newInstance() {
+ return new PreviewDialog();
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/previewdialog/PreviewDialogViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/previewdialog/PreviewDialogViewModel.java
new file mode 100644
index 000000000..8ee8a0e08
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/previewdialog/PreviewDialogViewModel.java
@@ -0,0 +1,50 @@
+package it.niedermann.nextcloud.deck.ui.card.attachments.previewdialog;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+
+import com.bumptech.glide.RequestBuilder;
+
+import static androidx.lifecycle.Transformations.distinctUntilChanged;
+
+public class PreviewDialogViewModel extends ViewModel {
+
+ @NonNull
+ private final MutableLiveData<String> title$ = new MutableLiveData<>();
+ @NonNull
+ private final MutableLiveData<RequestBuilder<?>> imageBuilder$ = new MutableLiveData<>();
+ private MutableLiveData<Boolean> result$ = new MutableLiveData<>();
+
+ /**
+ * Call this before observing {@link #getResult()} to prepare the {@link PreviewDialog}.
+ */
+ public void prepareDialog(@Nullable String title, @Nullable RequestBuilder<?> imageBuilder) {
+ this.result$ = new MutableLiveData<>();
+ this.title$.setValue(title);
+ this.imageBuilder$.setValue(imageBuilder);
+ }
+
+ /**
+ * This will be a new instance after each call of {@link #prepareDialog(String, RequestBuilder)}.
+ *
+ * @return {@link Boolean#TRUE} if a positive action has been submitted, {@link Boolean#FALSE} if the dialog has been canceled.
+ */
+ public LiveData<Boolean> getResult() {
+ return this.result$;
+ }
+
+ protected LiveData<String> getTitle() {
+ return distinctUntilChanged(this.title$);
+ }
+
+ protected LiveData<RequestBuilder<?>> getImageBuilder() {
+ return distinctUntilChanged(this.imageBuilder$);
+ }
+
+ protected void setResult(boolean submittedPositive) {
+ result$.setValue(submittedPositive);
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterUserAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterUserAdapter.java
index 82230060c..4b75b985f 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterUserAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterUserAdapter.java
@@ -84,14 +84,14 @@ public class FilterUserAdapter extends RecyclerView.Adapter<FilterUserAdapter.Us
}
void bind(@NonNull final User user) {
- binding.displayName.setText(user.getDisplayname());
+ binding.title.setText(user.getDisplayname());
ViewUtil.addAvatar(binding.avatar, account.getUrl(), user.getUid(), avatarSize, R.drawable.ic_person_grey600_24dp);
itemView.setSelected(selectedUsers.contains(user));
bindClickListener(user);
}
public void bindNotAssigned() {
- binding.displayName.setText(itemView.getContext().getString(R.string.simple_unassigned));
+ binding.title.setText(itemView.getContext().getString(R.string.simple_unassigned));
Glide.with(itemView.getContext())
.load(R.drawable.ic_baseline_block_24)
.into(binding.avatar);
diff --git a/app/src/main/res/layout/dialog_assignee.xml b/app/src/main/res/layout/dialog_preview.xml
index 6f7157286..5ab35d63e 100644
--- a/app/src/main/res/layout/dialog_assignee.xml
+++ b/app/src/main/res/layout/dialog_preview.xml
@@ -15,7 +15,7 @@
<TextView
android:padding="?dialogPreferredPadding"
- android:id="@+id/displayName"
+ android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceHeadline1"
diff --git a/app/src/main/res/layout/item_filter_user.xml b/app/src/main/res/layout/item_filter_user.xml
index 2c29bf5ad..0aced6dc2 100644
--- a/app/src/main/res/layout/item_filter_user.xml
+++ b/app/src/main/res/layout/item_filter_user.xml
@@ -31,7 +31,7 @@
</FrameLayout>
<TextView
- android:id="@+id/displayName"
+ android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
diff --git a/app/src/main/res/layout/item_picker_user.xml b/app/src/main/res/layout/item_picker_user.xml
index 4418bf461..f9a17508e 100644
--- a/app/src/main/res/layout/item_picker_user.xml
+++ b/app/src/main/res/layout/item_picker_user.xml
@@ -41,7 +41,7 @@
android:orientation="vertical">
<TextView
- android:id="@+id/displayName"
+ android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4d27bbae4..d6d9470fe 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -326,4 +326,5 @@
<string name="downloads">Downloads</string>
<string name="files">Files</string>
<string name="gallery">Gallery</string>
+ <string name="simple_attach">attach</string>
</resources>