mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-10 14:24:05 +01:00
add ability to "share to" files to nextcloud talk app
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
74f6f91dc9
commit
36fdd6d82b
@ -63,6 +63,7 @@
|
||||
android:name="android.permission.USE_CREDENTIALS"
|
||||
android:maxSdkVersion="22" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
@ -96,6 +97,18 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="*/*" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="*/*" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
@ -307,9 +307,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
|
||||
handleActionFromContact(intent)
|
||||
|
||||
if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
|
||||
if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
|
||||
router!!.pushController(
|
||||
|
@ -26,6 +26,7 @@ import android.app.Activity.RESULT_OK
|
||||
import android.content.ClipData
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.PorterDuff
|
||||
@ -263,6 +264,8 @@ class ChatController(args: Bundle) :
|
||||
var pastPreconditionFailed = false
|
||||
var futurePreconditionFailed = false
|
||||
|
||||
val filesToUpload: MutableList<String> = ArrayList()
|
||||
|
||||
init {
|
||||
setHasOptionsMenu(true)
|
||||
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||
@ -683,27 +686,27 @@ class ChatController(args: Bundle) :
|
||||
if (resultCode == RESULT_OK) {
|
||||
try {
|
||||
checkNotNull(intent)
|
||||
val files: MutableList<String> = ArrayList()
|
||||
filesToUpload.clear()
|
||||
intent.clipData?.let {
|
||||
for (index in 0 until it.itemCount) {
|
||||
files.add(it.getItemAt(index).uri.toString())
|
||||
filesToUpload.add(it.getItemAt(index).uri.toString())
|
||||
}
|
||||
} ?: run {
|
||||
checkNotNull(intent.data)
|
||||
intent.data.let {
|
||||
files.add(intent.data.toString())
|
||||
filesToUpload.add(intent.data.toString())
|
||||
}
|
||||
}
|
||||
require(files.isNotEmpty())
|
||||
require(filesToUpload.isNotEmpty())
|
||||
|
||||
val filenamesWithLinebreaks = StringBuilder("\n")
|
||||
|
||||
for (file in files) {
|
||||
for (file in filesToUpload) {
|
||||
val filename = UriUtils.getFileName(Uri.parse(file), context)
|
||||
filenamesWithLinebreaks.append(filename).append("\n")
|
||||
}
|
||||
|
||||
val confirmationQuestion = when (files.size) {
|
||||
val confirmationQuestion = when (filesToUpload.size) {
|
||||
1 -> context?.resources?.getString(R.string.nc_upload_confirm_send_single)?.let {
|
||||
String.format(it, title)
|
||||
}
|
||||
@ -717,11 +720,11 @@ class ChatController(args: Bundle) :
|
||||
.setTitle(confirmationQuestion)
|
||||
.setMessage(filenamesWithLinebreaks.toString())
|
||||
.setPositiveButton(R.string.nc_yes) { v ->
|
||||
uploadFiles(files)
|
||||
Toast.makeText(
|
||||
context, context?.resources?.getString(R.string.nc_upload_in_progess),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
if (UploadAndShareFilesWorker.isStoragePermissionGranted(context!!)) {
|
||||
uploadFiles(filesToUpload)
|
||||
} else {
|
||||
UploadAndShareFilesWorker.requestStoragePermission(this)
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.nc_no) {}
|
||||
.show()
|
||||
@ -738,6 +741,15 @@ class ChatController(args: Bundle) :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
if (requestCode == UploadAndShareFilesWorker.REQUEST_PERMISSION && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
Log.d(ConversationsListController.TAG, "upload starting after permissions were granted")
|
||||
uploadFiles(filesToUpload)
|
||||
} else {
|
||||
Toast.makeText(context, context?.getString(R.string.read_storage_no_permission), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun uploadFiles(files: MutableList<String>) {
|
||||
try {
|
||||
require(files.isNotEmpty())
|
||||
@ -750,6 +762,11 @@ class ChatController(args: Bundle) :
|
||||
.setInputData(data)
|
||||
.build()
|
||||
WorkManager.getInstance().enqueue(uploadWorker)
|
||||
|
||||
Toast.makeText(
|
||||
context, context?.getString(R.string.nc_upload_in_progess),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Toast.makeText(context, context?.resources?.getString(R.string.nc_upload_failed), Toast.LENGTH_LONG).show()
|
||||
Log.e(javaClass.simpleName, "Something went wrong when trying to upload file", e)
|
||||
|
@ -26,7 +26,10 @@ import android.animation.AnimatorInflater;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.SearchManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@ -42,6 +45,7 @@ import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
@ -54,6 +58,7 @@ import com.facebook.imagepipeline.core.ImagePipeline;
|
||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
|
||||
import com.facebook.imagepipeline.image.CloseableImage;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.kennyc.bottomsheet.BottomSheet;
|
||||
@ -73,6 +78,7 @@ import com.nextcloud.talk.interfaces.ConversationMenuInterface;
|
||||
import com.nextcloud.talk.jobs.AccountRemovalWorker;
|
||||
import com.nextcloud.talk.jobs.ContactAddressBookWorker;
|
||||
import com.nextcloud.talk.jobs.DeleteConversationWorker;
|
||||
import com.nextcloud.talk.jobs.UploadAndShareFilesWorker;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation;
|
||||
import com.nextcloud.talk.models.json.participants.Participant;
|
||||
@ -81,6 +87,7 @@ import com.nextcloud.talk.utils.ApiUtils;
|
||||
import com.nextcloud.talk.utils.ConductorRemapping;
|
||||
import com.nextcloud.talk.utils.DisplayUtils;
|
||||
import com.nextcloud.talk.utils.KeyboardUtils;
|
||||
import com.nextcloud.talk.utils.UriUtils;
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
||||
import com.nextcloud.talk.utils.database.user.UserUtils;
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences;
|
||||
@ -91,11 +98,13 @@ import org.apache.commons.lang3.builder.CompareToBuilder;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@ -128,7 +137,7 @@ public class ConversationsListController extends BaseController implements Searc
|
||||
FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemLongClickListener, FastScroller
|
||||
.OnScrollStateChangeListener, ConversationMenuInterface {
|
||||
|
||||
public static final String TAG = "ConversationsListController";
|
||||
public static final String TAG = "ConvListController";
|
||||
public static final int ID_DELETE_CONVERSATION_DIALOG = 0;
|
||||
private static final String KEY_SEARCH_QUERY = "ContactsController.searchQuery";
|
||||
@Inject
|
||||
@ -187,6 +196,12 @@ public class ConversationsListController extends BaseController implements Searc
|
||||
|
||||
private Bundle conversationMenuBundle = null;
|
||||
|
||||
private boolean showShareToScreen = false;
|
||||
private boolean shareToScreenWasShown = false;
|
||||
|
||||
private ArrayList<String> filesToShare;
|
||||
private Conversation selectedConversation;
|
||||
|
||||
public ConversationsListController() {
|
||||
super();
|
||||
setHasOptionsMenu(true);
|
||||
@ -262,7 +277,6 @@ public class ConversationsListController extends BaseController implements Searc
|
||||
if (!eventBus.isRegistered(this)) {
|
||||
eventBus.register(this);
|
||||
}
|
||||
|
||||
currentUser = userUtils.getCurrentUser();
|
||||
|
||||
if (currentUser != null) {
|
||||
@ -322,73 +336,88 @@ public class ConversationsListController extends BaseController implements Searc
|
||||
|
||||
searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
|
||||
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
showShareToScreen = !shareToScreenWasShown && hasActivityActionSendIntent();
|
||||
|
||||
searchItem.setVisible(callItems.size() > 0);
|
||||
if (adapter.hasFilter()) {
|
||||
showSearchView(activity, searchView, searchItem);
|
||||
searchView.setQuery(adapter.getFilter(String.class), false);
|
||||
}
|
||||
if (showShareToScreen) {
|
||||
hideSearchBar();
|
||||
getActionBar().setTitle(R.string.send_to_three_dots);
|
||||
} else {
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
|
||||
if (activity != null) {
|
||||
activity.binding.searchText.setOnClickListener(v -> {
|
||||
showSearchView(activity, searchView, searchItem);
|
||||
if (getResources() != null) {
|
||||
DisplayUtils.applyColorToStatusBar(
|
||||
activity,
|
||||
ResourcesCompat.getColor(getResources(), R.color.appbar, null)
|
||||
);
|
||||
searchItem.setVisible(callItems.size() > 0);
|
||||
if (activity != null) {
|
||||
if (adapter.hasFilter()) {
|
||||
showSearchView(activity, searchView, searchItem);
|
||||
searchView.setQuery(adapter.getFilter(String.class), false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
searchView.setOnCloseListener(() -> {
|
||||
if (TextUtils.isEmpty(searchView.getQuery().toString())) {
|
||||
searchView.onActionViewCollapsed();
|
||||
if (activity != null && getResources() != null) {
|
||||
DisplayUtils.applyColorToStatusBar(
|
||||
activity,
|
||||
ResourcesCompat.getColor(getResources(), R.color.bg_default, null)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
searchView.post(() -> searchView.setQuery("", true));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(MenuItem item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(MenuItem item) {
|
||||
searchView.onActionViewCollapsed();
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
if (activity != null) {
|
||||
activity.binding.appBar.setStateListAnimator(AnimatorInflater.loadStateListAnimator(
|
||||
activity.binding.appBar.getContext(),
|
||||
R.animator.appbar_elevation_off)
|
||||
);
|
||||
activity.binding.toolbar.setVisibility(View.GONE);
|
||||
activity.binding.searchToolbar.setVisibility(View.VISIBLE);
|
||||
activity.binding.searchText.setOnClickListener(v -> {
|
||||
showSearchView(activity, searchView, searchItem);
|
||||
if (getResources() != null) {
|
||||
DisplayUtils.applyColorToStatusBar(
|
||||
activity,
|
||||
ResourcesCompat.getColor(getResources(), R.color.appbar, null)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
searchView.setOnCloseListener(() -> {
|
||||
if (TextUtils.isEmpty(searchView.getQuery().toString())) {
|
||||
searchView.onActionViewCollapsed();
|
||||
if (activity != null && getResources() != null) {
|
||||
DisplayUtils.applyColorToStatusBar(
|
||||
activity,
|
||||
ResourcesCompat.getColor(getResources(), R.color.bg_default, null)
|
||||
);
|
||||
}
|
||||
}
|
||||
SmoothScrollLinearLayoutManager layoutManager =
|
||||
(SmoothScrollLinearLayoutManager) recyclerView.getLayoutManager();
|
||||
if (layoutManager != null) {
|
||||
layoutManager.scrollToPositionWithOffset(0, 0);
|
||||
} else {
|
||||
searchView.post(() -> searchView.setQuery(TAG, true));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(MenuItem item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(MenuItem item) {
|
||||
searchView.onActionViewCollapsed();
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
if (activity != null) {
|
||||
activity.binding.appBar.setStateListAnimator(AnimatorInflater.loadStateListAnimator(
|
||||
activity.binding.appBar.getContext(),
|
||||
R.animator.appbar_elevation_off)
|
||||
);
|
||||
activity.binding.toolbar.setVisibility(View.GONE);
|
||||
activity.binding.searchToolbar.setVisibility(View.VISIBLE);
|
||||
if (getResources() != null) {
|
||||
DisplayUtils.applyColorToStatusBar(
|
||||
activity,
|
||||
ResourcesCompat.getColor(getResources(), R.color.bg_default, null)
|
||||
);
|
||||
}
|
||||
}
|
||||
SmoothScrollLinearLayoutManager layoutManager =
|
||||
(SmoothScrollLinearLayoutManager) recyclerView.getLayoutManager();
|
||||
if (layoutManager != null) {
|
||||
layoutManager.scrollToPositionWithOffset(0, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasActivityActionSendIntent() {
|
||||
if (getActivity() != null) {
|
||||
return Intent.ACTION_SEND.equals(getActivity().getIntent().getAction())
|
||||
|| Intent.ACTION_SEND_MULTIPLE.equals(getActivity().getIntent().getAction());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void showSearchOrToolbar() {
|
||||
@ -414,7 +443,7 @@ public class ConversationsListController extends BaseController implements Searc
|
||||
|
||||
callItems = new ArrayList<>();
|
||||
|
||||
int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[] {ApiUtils.APIv4, ApiUtils.APIv3, 1});
|
||||
int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[]{ApiUtils.APIv4, ApiUtils.APIv3, 1});
|
||||
|
||||
roomsQueryDisposable = ncApi.getRooms(credentials, ApiUtils.getUrlForRooms(apiVersion,
|
||||
currentUser.getBaseUrl()))
|
||||
@ -716,39 +745,70 @@ public class ConversationsListController extends BaseController implements Searc
|
||||
|
||||
@Override
|
||||
public boolean onItemClick(View view, int position) {
|
||||
Object clickedItem = adapter.getItem(position);
|
||||
if (clickedItem != null && getActivity() != null) {
|
||||
Conversation conversation;
|
||||
if (shouldUseLastMessageLayout) {
|
||||
conversation = ((ConversationItem) clickedItem).getModel();
|
||||
selectedConversation = getConversation(position);
|
||||
if (selectedConversation != null && getActivity() != null) {
|
||||
if (showShareToScreen) {
|
||||
shareToScreenWasShown = true;
|
||||
showShareToConfirmDialog();
|
||||
} else {
|
||||
conversation = ((CallItem) clickedItem).getModel();
|
||||
}
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), currentUser);
|
||||
bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), conversation.getToken());
|
||||
bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), conversation.getRoomId());
|
||||
|
||||
if (conversation.hasPassword && (conversation.participantType.equals(Participant.ParticipantType.GUEST) ||
|
||||
conversation.participantType.equals(Participant.ParticipantType.USER_FOLLOWING_LINK))) {
|
||||
bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), 99);
|
||||
prepareAndShowBottomSheetWithBundle(bundle, false);
|
||||
} else {
|
||||
currentUser = userUtils.getCurrentUser();
|
||||
|
||||
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), Parcels.wrap(conversation));
|
||||
ConductorRemapping.INSTANCE.remapChatController(getRouter(), currentUser.getId(),
|
||||
conversation.getToken(), bundle, false);
|
||||
openConversation();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void showShareToConfirmDialog() {
|
||||
if (UploadAndShareFilesWorker.Companion.isStoragePermissionGranted(context)) {
|
||||
collectFilesToShareFromIntent();
|
||||
|
||||
StringBuilder fileNamesWithLineBreaks = new StringBuilder("\n");
|
||||
|
||||
for (String file : filesToShare) {
|
||||
String filename = UriUtils.Companion.getFileName(Uri.parse(file), context);
|
||||
fileNamesWithLineBreaks.append(filename).append("\n");
|
||||
}
|
||||
|
||||
String confirmationQuestion;
|
||||
if (filesToShare.size() == 1) {
|
||||
confirmationQuestion =
|
||||
String.format(getResources().getString(R.string.nc_upload_confirm_send_single),
|
||||
selectedConversation.getDisplayName());
|
||||
} else {
|
||||
confirmationQuestion =
|
||||
String.format(getResources().getString(R.string.nc_upload_confirm_send_multiple),
|
||||
selectedConversation.getDisplayName());
|
||||
}
|
||||
|
||||
new LovelyStandardDialog(getActivity())
|
||||
.setPositiveButtonColorRes(R.color.nc_darkGreen)
|
||||
.setTitle(confirmationQuestion)
|
||||
.setMessage(fileNamesWithLineBreaks.toString())
|
||||
.setPositiveButton(R.string.nc_yes, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
upload();
|
||||
openConversation();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.nc_no, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Log.d(TAG, "sharing files aborted");
|
||||
}
|
||||
})
|
||||
.show();
|
||||
} else {
|
||||
UploadAndShareFilesWorker.Companion.requestStoragePermission(ConversationsListController.this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemLongClick(int position) {
|
||||
if (currentUser.hasSpreedFeatureCapability("last-room-activity")) {
|
||||
|
||||
if (showShareToScreen) {
|
||||
Log.d(TAG, "sharing to multiple rooms not yet implemented. onItemLongClick is ignored.");
|
||||
|
||||
} else if (currentUser.hasSpreedFeatureCapability("last-room-activity")) {
|
||||
Object clickedItem = adapter.getItem(position);
|
||||
if (clickedItem != null) {
|
||||
Conversation conversation;
|
||||
@ -764,6 +824,100 @@ public class ConversationsListController extends BaseController implements Searc
|
||||
}
|
||||
}
|
||||
|
||||
private void collectFilesToShareFromIntent() {
|
||||
filesToShare = new ArrayList<>();
|
||||
if (getActivity() != null && getActivity().getIntent() != null) {
|
||||
Intent intent = getActivity().getIntent();
|
||||
if (Intent.ACTION_SEND.equals(intent.getAction())
|
||||
|| Intent.ACTION_SEND_MULTIPLE.equals(intent.getAction())) {
|
||||
if (intent.getClipData() != null) {
|
||||
for (int i = 0; i < intent.getClipData().getItemCount(); i++) {
|
||||
filesToShare.add(intent.getClipData().getItemAt(i).getUri().toString());
|
||||
}
|
||||
} else {
|
||||
filesToShare.add(intent.getData().toString());
|
||||
}
|
||||
if (filesToShare.isEmpty()) {
|
||||
Log.e(TAG, "failed to get files from intent");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void upload() {
|
||||
if (selectedConversation == null) {
|
||||
Log.e(TAG, "not able to upload any files because conversation was null.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String[] filesToShareArray = new String[filesToShare.size()];
|
||||
filesToShareArray = filesToShare.toArray(filesToShareArray);
|
||||
|
||||
Data data = new Data.Builder()
|
||||
.putStringArray(UploadAndShareFilesWorker.DEVICE_SOURCEFILES, filesToShareArray)
|
||||
.putString(UploadAndShareFilesWorker.NC_TARGETPATH, currentUser.getAttachmentFolder())
|
||||
.putString(UploadAndShareFilesWorker.ROOM_TOKEN, selectedConversation.getToken())
|
||||
.build();
|
||||
OneTimeWorkRequest uploadWorker = new OneTimeWorkRequest.Builder(UploadAndShareFilesWorker.class)
|
||||
.setInputData(data)
|
||||
.build();
|
||||
WorkManager.getInstance().enqueue(uploadWorker);
|
||||
|
||||
Toast.makeText(
|
||||
context, context.getResources().getString(R.string.nc_upload_in_progess),
|
||||
Toast.LENGTH_LONG
|
||||
).show();
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
Toast.makeText(context, context.getResources().getString(R.string.nc_upload_failed), Toast.LENGTH_LONG).show();
|
||||
Log.e(TAG, "Something went wrong when trying to upload file", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
if (requestCode == UploadAndShareFilesWorker.REQUEST_PERMISSION &&
|
||||
grantResults.length > 0 &&
|
||||
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
Log.d(TAG, "upload starting after permissions were granted");
|
||||
showShareToConfirmDialog();
|
||||
} else {
|
||||
Toast.makeText(context, context.getString(R.string.read_storage_no_permission), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void openConversation() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), currentUser);
|
||||
bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), selectedConversation.getToken());
|
||||
bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), selectedConversation.getRoomId());
|
||||
|
||||
if (selectedConversation.hasPassword && selectedConversation.participantType ==
|
||||
Participant.ParticipantType.GUEST ||
|
||||
selectedConversation.participantType == Participant.ParticipantType.USER_FOLLOWING_LINK) {
|
||||
bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), 99);
|
||||
prepareAndShowBottomSheetWithBundle(bundle, false);
|
||||
} else {
|
||||
currentUser = userUtils.getCurrentUser();
|
||||
|
||||
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), Parcels.wrap(selectedConversation));
|
||||
ConductorRemapping.INSTANCE.remapChatController(getRouter(), currentUser.getId(),
|
||||
selectedConversation.getToken(), bundle, false);
|
||||
}
|
||||
}
|
||||
|
||||
private Conversation getConversation(int position) {
|
||||
Object clickedItem = adapter.getItem(position);
|
||||
Conversation conversation;
|
||||
if (shouldUseLastMessageLayout) {
|
||||
conversation = ((ConversationItem) clickedItem).getModel();
|
||||
} else {
|
||||
conversation = ((CallItem) clickedItem).getModel();
|
||||
}
|
||||
return conversation;
|
||||
}
|
||||
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.BACKGROUND)
|
||||
public void onMessageEvent(EventStatus eventStatus) {
|
||||
if (currentUser != null && eventStatus.getUserId() == currentUser.getId()) {
|
||||
|
@ -169,13 +169,7 @@ public abstract class BaseController extends ButterKnifeController {
|
||||
R.animator.appbar_elevation_off)
|
||||
);
|
||||
} else {
|
||||
activity.binding.searchToolbar.setVisibility(View.GONE);
|
||||
activity.binding.toolbar.setVisibility(View.VISIBLE);
|
||||
layoutParams.setScrollFlags(0);
|
||||
activity.binding.appBar.setStateListAnimator(AnimatorInflater.loadStateListAnimator(
|
||||
activity.binding.appBar.getContext(),
|
||||
R.animator.appbar_elevation_on)
|
||||
);
|
||||
hideSearchBar();
|
||||
}
|
||||
|
||||
activity.binding.searchToolbar.setLayoutParams(layoutParams);
|
||||
@ -204,6 +198,20 @@ public abstract class BaseController extends ButterKnifeController {
|
||||
}
|
||||
}
|
||||
|
||||
protected void hideSearchBar() {
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
AppBarLayout.LayoutParams layoutParams =
|
||||
(AppBarLayout.LayoutParams) activity.binding.searchToolbar.getLayoutParams();
|
||||
|
||||
activity.binding.searchToolbar.setVisibility(View.GONE);
|
||||
activity.binding.toolbar.setVisibility(View.VISIBLE);
|
||||
layoutParams.setScrollFlags(0);
|
||||
activity.binding.appBar.setStateListAnimator(AnimatorInflater.loadStateListAnimator(
|
||||
activity.binding.appBar.getContext(),
|
||||
R.animator.appbar_elevation_on)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetach(@NonNull View view) {
|
||||
super.onDetach(view);
|
||||
|
@ -20,15 +20,19 @@
|
||||
|
||||
package com.nextcloud.talk.jobs
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.content.PermissionChecker
|
||||
import androidx.work.Data
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import autodagger.AutoInjector
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.models.database.UserEntity
|
||||
@ -69,6 +73,15 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
|
||||
override fun doWork(): Result {
|
||||
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||
|
||||
if (!isStoragePermissionGranted(context)) {
|
||||
Log.w(
|
||||
TAG, "Storage permission is not granted. As a developer please make sure you check for permissions " +
|
||||
"via UploadAndShareFilesWorker.isStoragePermissionGranted() and UploadAndShareFilesWorker" +
|
||||
".requestStoragePermission() beforehand. If you already did but end up with this warning, the user " +
|
||||
"most likely revoked the permission"
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
val currentUser = userUtils.currentUser
|
||||
val sourcefiles = inputData.getStringArray(DEVICE_SOURCEFILES)
|
||||
@ -172,8 +185,37 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
|
||||
|
||||
companion object {
|
||||
const val TAG = "UploadFileWorker"
|
||||
const val REQUEST_PERMISSION = 3123
|
||||
const val DEVICE_SOURCEFILES = "DEVICE_SOURCEFILES"
|
||||
const val NC_TARGETPATH = "NC_TARGETPATH"
|
||||
const val ROOM_TOKEN = "ROOM_TOKEN"
|
||||
|
||||
fun isStoragePermissionGranted(context: Context): Boolean {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (PermissionChecker.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
) == PermissionChecker.PERMISSION_GRANTED
|
||||
) {
|
||||
Log.d(TAG, "Permission is granted")
|
||||
return true
|
||||
} else {
|
||||
Log.d(TAG, "Permission is revoked")
|
||||
return false
|
||||
}
|
||||
} else { //permission is automatically granted on sdk<23 upon installation
|
||||
Log.d(TAG, "Permission is granted")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
fun requestStoragePermission(controller: Controller) {
|
||||
controller.requestPermissions(
|
||||
arrayOf(
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
),
|
||||
REQUEST_PERMISSION
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,28 +26,29 @@ import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import android.util.Log
|
||||
|
||||
object UriUtils {
|
||||
|
||||
fun getFileName(uri: Uri, context: Context?): String {
|
||||
var filename: String? = null
|
||||
if (uri.scheme == "content" && context != null) {
|
||||
val cursor: Cursor? = context.contentResolver.query(uri, null, null, null, null)
|
||||
try {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
|
||||
class UriUtils {
|
||||
companion object {
|
||||
fun getFileName(uri: Uri, context: Context?): String {
|
||||
var filename: String? = null
|
||||
if (uri.scheme == "content" && context != null) {
|
||||
val cursor: Cursor? = context.contentResolver.query(uri, null, null, null, null)
|
||||
try {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
|
||||
}
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
}
|
||||
if (filename == null) {
|
||||
Log.e("UriUtils", "failed to get DISPLAY_NAME from uri. using fallback.")
|
||||
filename = uri.path
|
||||
val lastIndexOfSlash = filename!!.lastIndexOf('/')
|
||||
if (lastIndexOfSlash != -1) {
|
||||
filename = filename.substring(lastIndexOfSlash + 1)
|
||||
if (filename == null) {
|
||||
Log.d("UriUtils", "failed to get DISPLAY_NAME from uri. using fallback.")
|
||||
filename = uri.path
|
||||
val lastIndexOfSlash = filename!!.lastIndexOf('/')
|
||||
if (lastIndexOfSlash != -1) {
|
||||
filename = filename.substring(lastIndexOfSlash + 1)
|
||||
}
|
||||
}
|
||||
return filename
|
||||
}
|
||||
return filename
|
||||
}
|
||||
}
|
||||
|
@ -362,6 +362,8 @@
|
||||
|
||||
<string name="share">Share</string>
|
||||
<string name="send_to">Send to</string>
|
||||
<string name="send_to_three_dots">Send to …</string>
|
||||
<string name="read_storage_no_permission">Sharing files from storage is not possible without permissions</string>
|
||||
<string name="open_in_files_app">Open in Files app</string>
|
||||
|
||||
<!-- Upload -->
|
||||
@ -425,6 +427,7 @@
|
||||
|
||||
<!-- Non-translatable strings -->
|
||||
<string name="tooManyUnreadMessages" translatable="false">999+</string>
|
||||
|
||||
<string name="nc_action_open_main_menu">Open main menu</string>
|
||||
<string name="failed_to_save">Failed to save %1$s</string>
|
||||
<string name="selected_list_item">selected</string>
|
||||
|
Loading…
Reference in New Issue
Block a user