add ability to "share to" files to nextcloud talk app

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2021-05-15 09:39:02 +02:00
parent 74f6f91dc9
commit 36fdd6d82b
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
8 changed files with 358 additions and 122 deletions

View File

@ -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" />

View File

@ -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(

View File

@ -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)

View File

@ -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()) {

View File

@ -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);

View File

@ -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
)
}
}
}

View File

@ -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
}
}

View File

@ -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>