Direct editing support
- abstract EditorWebView - support direct editing endpoint Create new files via direct editing Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
parent
b0758e4b74
commit
59585d0f5b
|
@ -1,2 +1,2 @@
|
|||
include ':'
|
||||
//include 'nextcloud-android-library'
|
||||
//include ':nextcloud-android-library'
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
*/
|
||||
package com.nextcloud.client.appinfo;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* This class provides general, static information about application
|
||||
* build.
|
||||
|
@ -36,4 +38,5 @@ public interface AppInfo {
|
|||
|
||||
boolean isDebugBuild();
|
||||
|
||||
String getAppVersion(Context context);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,12 @@
|
|||
*/
|
||||
package com.nextcloud.client.appinfo;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import com.owncloud.android.BuildConfig;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
||||
class AppInfoImpl implements AppInfo {
|
||||
|
||||
|
@ -32,4 +37,20 @@ class AppInfoImpl implements AppInfo {
|
|||
public boolean isDebugBuild() {
|
||||
return BuildConfig.DEBUG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAppVersion(Context context) {
|
||||
try {
|
||||
PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||
if (pInfo != null) {
|
||||
return pInfo.versionName;
|
||||
} else {
|
||||
return "n/a";
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log_OC.e(this, "Trying to get packageName", e.getCause());
|
||||
|
||||
return "n/a";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,13 @@ import java.util.Locale
|
|||
class DeviceInfo {
|
||||
val vendor: String = Build.MANUFACTURER.toLowerCase(Locale.ROOT)
|
||||
val apiLevel: Int = Build.VERSION.SDK_INT
|
||||
val androidVersion = Build.VERSION.RELEASE
|
||||
|
||||
fun hasCamera(context: Context): Boolean {
|
||||
return context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
|
||||
}
|
||||
|
||||
fun editorSupported(): Boolean {
|
||||
return apiLevel < Build.VERSION_CODES.LOLLIPOP
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ import com.owncloud.android.ui.activity.TextEditorWebView;
|
|||
import com.owncloud.android.ui.activity.UploadFilesActivity;
|
||||
import com.owncloud.android.ui.activity.UploadListActivity;
|
||||
import com.owncloud.android.ui.activity.UserInfoActivity;
|
||||
import com.owncloud.android.ui.dialog.ChooseRichDocumentsTemplateDialogFragment;
|
||||
import com.owncloud.android.ui.dialog.ChooseTemplateDialogFragment;
|
||||
import com.owncloud.android.ui.dialog.MultipleAccountsDialog;
|
||||
import com.owncloud.android.ui.fragment.ExtendedListFragment;
|
||||
|
@ -136,6 +137,9 @@ abstract class ComponentsModule {
|
|||
@ContributesAndroidInjector abstract FileDetailActivitiesFragment fileDetailActivitiesFragment();
|
||||
@ContributesAndroidInjector abstract FileDetailSharingFragment fileDetailSharingFragment();
|
||||
@ContributesAndroidInjector abstract ChooseTemplateDialogFragment chooseTemplateDialogFragment();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract ChooseRichDocumentsTemplateDialogFragment chooseRichDocumentsTemplateDialogFragment();
|
||||
@ContributesAndroidInjector abstract PreviewImageFragment previewImageFragment();
|
||||
@ContributesAndroidInjector abstract ContactListFragment chooseContactListFragment();
|
||||
@ContributesAndroidInjector abstract PreviewMediaFragment previewMediaFragment();
|
||||
|
|
|
@ -31,7 +31,7 @@ import com.owncloud.android.MainApp;
|
|||
*/
|
||||
public class ProviderMeta {
|
||||
public static final String DB_NAME = "filelist";
|
||||
public static final int DB_VERSION = 52;
|
||||
public static final int DB_VERSION = 53;
|
||||
|
||||
private ProviderMeta() {
|
||||
// No instance
|
||||
|
|
|
@ -25,7 +25,7 @@ import com.owncloud.android.lib.common.OwnCloudClient;
|
|||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.ui.dialog.ChooseTemplateDialogFragment;
|
||||
import com.owncloud.android.ui.dialog.ChooseRichDocumentsTemplateDialogFragment;
|
||||
|
||||
import org.apache.commons.httpclient.HttpStatus;
|
||||
import org.apache.commons.httpclient.methods.GetMethod;
|
||||
|
@ -41,14 +41,14 @@ public class FetchTemplateOperation extends RemoteOperation {
|
|||
private static final int SYNC_CONNECTION_TIMEOUT = 5000;
|
||||
private static final String TEMPLATE_URL = "/ocs/v2.php/apps/richdocuments/api/v1/templates/";
|
||||
|
||||
private ChooseTemplateDialogFragment.Type type;
|
||||
private ChooseRichDocumentsTemplateDialogFragment.Type type;
|
||||
|
||||
// JSON node names
|
||||
private static final String NODE_OCS = "ocs";
|
||||
private static final String NODE_DATA = "data";
|
||||
private static final String JSON_FORMAT = "?format=json";
|
||||
|
||||
public FetchTemplateOperation(ChooseTemplateDialogFragment.Type type) {
|
||||
public FetchTemplateOperation(ChooseRichDocumentsTemplateDialogFragment.Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,8 @@ public class FetchTemplateOperation extends RemoteOperation {
|
|||
templateArray.add(new Template(templateObject.getInt("id"),
|
||||
templateObject.getString("name"),
|
||||
templateObject.optString("preview"),
|
||||
Template.Type.valueOf(templateObject.getString("type")),
|
||||
Template.Type.valueOf(templateObject.getString("type")
|
||||
.toUpperCase(Locale.ROOT)),
|
||||
templateObject.getString("extension")));
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ import android.view.Menu;
|
|||
import android.view.MenuItem;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.nextcloud.client.device.DeviceInfo;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProvider;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
|
@ -58,45 +60,62 @@ public class FileMenuFilter {
|
|||
|
||||
private static final int SINGLE_SELECT_ITEMS = 1;
|
||||
|
||||
private int mNumberOfAllFiles;
|
||||
private Collection<OCFile> mFiles;
|
||||
private ComponentsGetter mComponentsGetter;
|
||||
private Account mAccount;
|
||||
private Context mContext;
|
||||
private boolean mOverflowMenu;
|
||||
private int numberOfAllFiles;
|
||||
private Collection<OCFile> files;
|
||||
private ComponentsGetter componentsGetter;
|
||||
private Account account;
|
||||
private Context context;
|
||||
private boolean overflowMenu;
|
||||
private DeviceInfo deviceInfo;
|
||||
private User user;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param numberOfAllFiles Number of all displayed files
|
||||
* @param targetFiles Collection of {@link OCFile} file targets of the action to filter in the {@link Menu}.
|
||||
* @param files Collection of {@link OCFile} file targets of the action to filter in the {@link Menu}.
|
||||
* @param account ownCloud {@link Account} holding targetFile.
|
||||
* @param cg Accessor to app components, needed to access synchronization services
|
||||
* @param componentsGetter Accessor to app components, needed to access synchronization services
|
||||
* @param context Android {@link Context}, needed to access build setup resources.
|
||||
* @param overflowMenu true if the overflow menu items are being filtered
|
||||
*/
|
||||
public FileMenuFilter(int numberOfAllFiles, Collection<OCFile> targetFiles, Account account,
|
||||
ComponentsGetter cg, Context context, boolean overflowMenu) {
|
||||
mNumberOfAllFiles = numberOfAllFiles;
|
||||
mFiles = targetFiles;
|
||||
mAccount = account;
|
||||
mComponentsGetter = cg;
|
||||
mContext = context;
|
||||
mOverflowMenu = overflowMenu;
|
||||
public FileMenuFilter(int numberOfAllFiles,
|
||||
Collection<OCFile> files,
|
||||
Account account,
|
||||
ComponentsGetter componentsGetter,
|
||||
Context context,
|
||||
boolean overflowMenu,
|
||||
DeviceInfo deviceInfo,
|
||||
User user
|
||||
) {
|
||||
this.numberOfAllFiles = numberOfAllFiles;
|
||||
this.files = files;
|
||||
this.account = account;
|
||||
this.componentsGetter = componentsGetter;
|
||||
this.context = context;
|
||||
this.overflowMenu = overflowMenu;
|
||||
this.deviceInfo = deviceInfo;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param targetFile {@link OCFile} target of the action to filter in the {@link Menu}.
|
||||
* @param file {@link OCFile} target of the action to filter in the {@link Menu}.
|
||||
* @param account ownCloud {@link Account} holding targetFile.
|
||||
* @param cg Accessor to app components, needed to access synchronization services
|
||||
* @param componentsGetter Accessor to app components, needed to access synchronization services
|
||||
* @param context Android {@link Context}, needed to access build setup resources.
|
||||
* @param overflowMenu true if the overflow menu items are being filtered
|
||||
*/
|
||||
public FileMenuFilter(OCFile targetFile, Account account, ComponentsGetter cg, Context context,
|
||||
boolean overflowMenu) {
|
||||
this(1, Collections.singletonList(targetFile), account, cg, context, overflowMenu);
|
||||
public FileMenuFilter(OCFile file,
|
||||
Account account,
|
||||
ComponentsGetter componentsGetter,
|
||||
Context context,
|
||||
boolean overflowMenu,
|
||||
DeviceInfo deviceInfo,
|
||||
User user
|
||||
) {
|
||||
this(1, Collections.singletonList(file), account, componentsGetter, context, overflowMenu, deviceInfo, user);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,7 +127,7 @@ public class FileMenuFilter {
|
|||
* @param isMediaSupported True is media playback is supported for this user
|
||||
*/
|
||||
public void filter(Menu menu, boolean inSingleFileFragment, boolean isMediaSupported) {
|
||||
if (mFiles == null || mFiles.isEmpty()) {
|
||||
if (files == null || files.isEmpty()) {
|
||||
hideAll(menu);
|
||||
} else {
|
||||
List<Integer> toShow = new ArrayList<>();
|
||||
|
@ -177,7 +196,7 @@ public class FileMenuFilter {
|
|||
boolean isMediaSupported,
|
||||
Menu menu) {
|
||||
boolean synchronizing = anyFileSynchronizing();
|
||||
OCCapability capability = mComponentsGetter.getStorageManager().getCapability(mAccount.name);
|
||||
OCCapability capability = componentsGetter.getStorageManager().getCapability(account.name);
|
||||
boolean endToEndEncryptionEnabled = capability.getEndToEndEncryption().isTrue();
|
||||
|
||||
filterEdit(toShow, toHide, capability);
|
||||
|
@ -202,8 +221,8 @@ public class FileMenuFilter {
|
|||
|
||||
private void filterShareFile(List<Integer> toShow, List<Integer> toHide, OCCapability capability) {
|
||||
if (containsEncryptedFile() || (!isShareViaLinkAllowed() && !isShareWithUsersAllowed()) ||
|
||||
!isSingleSelection() || !isShareApiEnabled(capability) || !mFiles.iterator().next().canReshare()
|
||||
|| mOverflowMenu) {
|
||||
!isSingleSelection() || !isShareApiEnabled(capability) || !files.iterator().next().canReshare()
|
||||
|| overflowMenu) {
|
||||
toHide.add(R.id.action_send_share_file);
|
||||
} else {
|
||||
toShow.add(R.id.action_send_share_file);
|
||||
|
@ -219,7 +238,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private void filterFavorite(List<Integer> toShow, List<Integer> toHide, boolean synchronizing) {
|
||||
if (mFiles.isEmpty() || synchronizing || allFavorites()) {
|
||||
if (files.isEmpty() || synchronizing || allFavorites()) {
|
||||
toHide.add(R.id.action_favorite);
|
||||
} else {
|
||||
toShow.add(R.id.action_favorite);
|
||||
|
@ -227,7 +246,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private void filterUnfavorite(List<Integer> toShow, List<Integer> toHide, boolean synchronizing) {
|
||||
if (mFiles.isEmpty() || synchronizing || allNotFavorites()) {
|
||||
if (files.isEmpty() || synchronizing || allNotFavorites()) {
|
||||
toHide.add(R.id.action_unset_favorite);
|
||||
} else {
|
||||
toShow.add(R.id.action_unset_favorite);
|
||||
|
@ -235,7 +254,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private void filterEncrypt(List<Integer> toShow, List<Integer> toHide, boolean endToEndEncryptionEnabled) {
|
||||
if (mFiles.isEmpty() || !isSingleSelection() || isSingleFile() || isEncryptedFolder()
|
||||
if (files.isEmpty() || !isSingleSelection() || isSingleFile() || isEncryptedFolder()
|
||||
|| !endToEndEncryptionEnabled) {
|
||||
toHide.add(R.id.action_encrypted);
|
||||
} else {
|
||||
|
@ -244,7 +263,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private void filterUnsetEncrypted(List<Integer> toShow, List<Integer> toHide, boolean endToEndEncryptionEnabled) {
|
||||
if (mFiles.isEmpty() || !isSingleSelection() || isSingleFile() || !isEncryptedFolder()
|
||||
if (files.isEmpty() || !isSingleSelection() || isSingleFile() || !isEncryptedFolder()
|
||||
|| !endToEndEncryptionEnabled) {
|
||||
toHide.add(R.id.action_unset_encrypted);
|
||||
} else {
|
||||
|
@ -253,7 +272,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private void filterSetPictureAs(List<Integer> toShow, List<Integer> toHide) {
|
||||
if (isSingleImage() && !MimeTypeUtil.isSVG(mFiles.iterator().next())) {
|
||||
if (isSingleImage() && !MimeTypeUtil.isSVG(files.iterator().next())) {
|
||||
toShow.add(R.id.action_set_as_wallpaper);
|
||||
} else {
|
||||
toHide.add(R.id.action_set_as_wallpaper);
|
||||
|
@ -264,15 +283,15 @@ public class FileMenuFilter {
|
|||
List<Integer> toHide,
|
||||
OCCapability capability
|
||||
) {
|
||||
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (deviceInfo.editorSupported()) {
|
||||
toHide.add(R.id.action_edit);
|
||||
return;
|
||||
}
|
||||
|
||||
String mimeType = mFiles.iterator().next().getMimeType();
|
||||
String mimeType = files.iterator().next().getMimeType();
|
||||
|
||||
if (isRichDocumentEditingSupported(capability, mimeType) || isEditorAvailable(mContext.getContentResolver(),
|
||||
mAccount,
|
||||
if (isRichDocumentEditingSupported(capability, mimeType) || isEditorAvailable(context.getContentResolver(),
|
||||
user,
|
||||
mimeType)) {
|
||||
toShow.add(R.id.action_edit);
|
||||
} else {
|
||||
|
@ -280,13 +299,14 @@ public class FileMenuFilter {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean isEditorAvailable(ContentResolver contentResolver, Account account, String mimeType) {
|
||||
return getEditor(contentResolver, account, mimeType) != null;
|
||||
public static boolean isEditorAvailable(ContentResolver contentResolver, User user, String mimeType) {
|
||||
return getEditor(contentResolver, user, mimeType) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Editor getEditor(ContentResolver contentResolver, Account account, String mimeType) {
|
||||
String json = new ArbitraryDataProvider(contentResolver).getValue(account, ArbitraryDataProvider.DIRECT_EDITING);
|
||||
public static Editor getEditor(ContentResolver contentResolver, User user, String mimeType) {
|
||||
String json = new ArbitraryDataProvider(contentResolver).getValue(user.toPlatformAccount(),
|
||||
ArbitraryDataProvider.DIRECT_EDITING);
|
||||
|
||||
if (json.isEmpty()) {
|
||||
return null;
|
||||
|
@ -315,7 +335,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private void filterSync(List<Integer> toShow, List<Integer> toHide, boolean synchronizing) {
|
||||
if (mFiles.isEmpty() || (!anyFileDown() && !containsFolder()) || synchronizing) {
|
||||
if (files.isEmpty() || (!anyFileDown() && !containsFolder()) || synchronizing) {
|
||||
toHide.add(R.id.action_sync_file);
|
||||
} else {
|
||||
toShow.add(R.id.action_sync_file);
|
||||
|
@ -323,7 +343,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private void filterCancelSync(List<Integer> toShow, List<Integer> toHide, boolean synchronizing) {
|
||||
if (mFiles.isEmpty() || !synchronizing) {
|
||||
if (files.isEmpty() || !synchronizing) {
|
||||
toHide.add(R.id.action_cancel_sync);
|
||||
} else {
|
||||
toShow.add(R.id.action_cancel_sync);
|
||||
|
@ -344,7 +364,7 @@ public class FileMenuFilter {
|
|||
toHide.add(R.id.action_deselect_all_action_menu);
|
||||
} else {
|
||||
// Show only if at least one item is selected.
|
||||
if (mFiles.isEmpty() || mOverflowMenu) {
|
||||
if (files.isEmpty() || overflowMenu) {
|
||||
toHide.add(R.id.action_deselect_all_action_menu);
|
||||
} else {
|
||||
toShow.add(R.id.action_deselect_all_action_menu);
|
||||
|
@ -355,7 +375,7 @@ public class FileMenuFilter {
|
|||
private void filterSelectAll(List<Integer> toShow, List<Integer> toHide, boolean inSingleFileFragment) {
|
||||
if (!inSingleFileFragment) {
|
||||
// Show only if at least one item isn't selected.
|
||||
if (mFiles.size() >= mNumberOfAllFiles || mOverflowMenu) {
|
||||
if (files.size() >= numberOfAllFiles || overflowMenu) {
|
||||
toHide.add(R.id.action_select_all_action_menu);
|
||||
} else {
|
||||
toShow.add(R.id.action_select_all_action_menu);
|
||||
|
@ -367,7 +387,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private void filterRemove(List<Integer> toShow, List<Integer> toHide, boolean synchronizing) {
|
||||
if (mFiles.isEmpty() || synchronizing || containsEncryptedFolder()) {
|
||||
if (files.isEmpty() || synchronizing || containsEncryptedFolder()) {
|
||||
toHide.add(R.id.action_remove_file);
|
||||
} else {
|
||||
toShow.add(R.id.action_remove_file);
|
||||
|
@ -375,7 +395,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private void filterMoveCopy(List<Integer> toShow, List<Integer> toHide, boolean synchronizing) {
|
||||
if (mFiles.isEmpty() || synchronizing || containsEncryptedFile() || containsEncryptedFolder()) {
|
||||
if (files.isEmpty() || synchronizing || containsEncryptedFile() || containsEncryptedFolder()) {
|
||||
toHide.add(R.id.action_move);
|
||||
toHide.add(R.id.action_copy);
|
||||
} else {
|
||||
|
@ -393,7 +413,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private void filterDownload(List<Integer> toShow, List<Integer> toHide, boolean synchronizing) {
|
||||
if (mFiles.isEmpty() || containsFolder() || anyFileDown() || synchronizing) {
|
||||
if (files.isEmpty() || containsFolder() || anyFileDown() || synchronizing) {
|
||||
toHide.add(R.id.action_download_file);
|
||||
} else {
|
||||
toShow.add(R.id.action_download_file);
|
||||
|
@ -401,7 +421,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private void filterStream(List<Integer> toShow, List<Integer> toHide, boolean isMediaSupported) {
|
||||
if (mFiles.isEmpty() || !isSingleFile() || !isSingleMedia() || !isMediaSupported) {
|
||||
if (files.isEmpty() || !isSingleFile() || !isSingleMedia() || !isMediaSupported) {
|
||||
toHide.add(R.id.action_stream_media);
|
||||
} else {
|
||||
toShow.add(R.id.action_stream_media);
|
||||
|
@ -410,10 +430,10 @@ public class FileMenuFilter {
|
|||
|
||||
private boolean anyFileSynchronizing() {
|
||||
boolean synchronizing = false;
|
||||
if (mComponentsGetter != null && !mFiles.isEmpty() && mAccount != null) {
|
||||
OperationsServiceBinder opsBinder = mComponentsGetter.getOperationsServiceBinder();
|
||||
FileUploaderBinder uploaderBinder = mComponentsGetter.getFileUploaderBinder();
|
||||
FileDownloaderBinder downloaderBinder = mComponentsGetter.getFileDownloaderBinder();
|
||||
if (componentsGetter != null && !files.isEmpty() && account != null) {
|
||||
OperationsServiceBinder opsBinder = componentsGetter.getOperationsServiceBinder();
|
||||
FileUploaderBinder uploaderBinder = componentsGetter.getFileUploaderBinder();
|
||||
FileDownloaderBinder downloaderBinder = componentsGetter.getFileDownloaderBinder();
|
||||
synchronizing = anyFileSynchronizing(opsBinder) || // comparing local and remote
|
||||
anyFileDownloading(downloaderBinder) ||
|
||||
anyFileUploading(uploaderBinder);
|
||||
|
@ -424,8 +444,8 @@ public class FileMenuFilter {
|
|||
private boolean anyFileSynchronizing(OperationsServiceBinder opsBinder) {
|
||||
boolean synchronizing = false;
|
||||
if (opsBinder != null) {
|
||||
for (Iterator<OCFile> iterator = mFiles.iterator(); !synchronizing && iterator.hasNext(); ) {
|
||||
synchronizing = opsBinder.isSynchronizing(mAccount, iterator.next());
|
||||
for (Iterator<OCFile> iterator = files.iterator(); !synchronizing && iterator.hasNext(); ) {
|
||||
synchronizing = opsBinder.isSynchronizing(account, iterator.next());
|
||||
}
|
||||
}
|
||||
return synchronizing;
|
||||
|
@ -434,8 +454,8 @@ public class FileMenuFilter {
|
|||
private boolean anyFileDownloading(FileDownloaderBinder downloaderBinder) {
|
||||
boolean downloading = false;
|
||||
if (downloaderBinder != null) {
|
||||
for (Iterator<OCFile> iterator = mFiles.iterator(); !downloading && iterator.hasNext(); ) {
|
||||
downloading = downloaderBinder.isDownloading(mAccount, iterator.next());
|
||||
for (Iterator<OCFile> iterator = files.iterator(); !downloading && iterator.hasNext(); ) {
|
||||
downloading = downloaderBinder.isDownloading(account, iterator.next());
|
||||
}
|
||||
}
|
||||
return downloading;
|
||||
|
@ -444,8 +464,8 @@ public class FileMenuFilter {
|
|||
private boolean anyFileUploading(FileUploaderBinder uploaderBinder) {
|
||||
boolean uploading = false;
|
||||
if (uploaderBinder != null) {
|
||||
for (Iterator<OCFile> iterator = mFiles.iterator(); !uploading && iterator.hasNext(); ) {
|
||||
uploading = uploaderBinder.isUploading(mAccount, iterator.next());
|
||||
for (Iterator<OCFile> iterator = files.iterator(); !uploading && iterator.hasNext(); ) {
|
||||
uploading = uploaderBinder.isUploading(account, iterator.next());
|
||||
}
|
||||
}
|
||||
return uploading;
|
||||
|
@ -459,26 +479,26 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private boolean isShareWithUsersAllowed() {
|
||||
return mContext != null &&
|
||||
mContext.getResources().getBoolean(R.bool.share_with_users_feature);
|
||||
return context != null &&
|
||||
context.getResources().getBoolean(R.bool.share_with_users_feature);
|
||||
}
|
||||
|
||||
private boolean isShareViaLinkAllowed() {
|
||||
return mContext != null &&
|
||||
mContext.getResources().getBoolean(R.bool.share_via_link_feature);
|
||||
return context != null &&
|
||||
context.getResources().getBoolean(R.bool.share_via_link_feature);
|
||||
}
|
||||
|
||||
private boolean isSingleSelection() {
|
||||
return mFiles.size() == SINGLE_SELECT_ITEMS;
|
||||
return files.size() == SINGLE_SELECT_ITEMS;
|
||||
}
|
||||
|
||||
private boolean isSingleFile() {
|
||||
return isSingleSelection() && !mFiles.iterator().next().isFolder();
|
||||
return isSingleSelection() && !files.iterator().next().isFolder();
|
||||
}
|
||||
|
||||
private boolean isEncryptedFolder() {
|
||||
if (isSingleSelection()) {
|
||||
OCFile file = mFiles.iterator().next();
|
||||
OCFile file = files.iterator().next();
|
||||
|
||||
return file.isFolder() && file.isEncrypted();
|
||||
} else {
|
||||
|
@ -487,16 +507,16 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private boolean isSingleImage() {
|
||||
return isSingleSelection() && MimeTypeUtil.isImage(mFiles.iterator().next());
|
||||
return isSingleSelection() && MimeTypeUtil.isImage(files.iterator().next());
|
||||
}
|
||||
|
||||
private boolean isSingleMedia() {
|
||||
OCFile file = mFiles.iterator().next();
|
||||
OCFile file = files.iterator().next();
|
||||
return isSingleSelection() && (MimeTypeUtil.isVideo(file) || MimeTypeUtil.isAudio(file));
|
||||
}
|
||||
|
||||
private boolean containsEncryptedFile() {
|
||||
for (OCFile file : mFiles) {
|
||||
for (OCFile file : files) {
|
||||
if (!file.isFolder() && file.isEncrypted()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -505,7 +525,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private boolean containsEncryptedFolder() {
|
||||
for (OCFile file : mFiles) {
|
||||
for (OCFile file : files) {
|
||||
if (file.isFolder() && file.isEncrypted()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -514,7 +534,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private boolean containsFolder() {
|
||||
for (OCFile file : mFiles) {
|
||||
for (OCFile file : files) {
|
||||
if (file.isFolder()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -523,7 +543,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private boolean anyFileDown() {
|
||||
for (OCFile file : mFiles) {
|
||||
for (OCFile file : files) {
|
||||
if (file.isDown()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -532,7 +552,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private boolean allFavorites() {
|
||||
for (OCFile file : mFiles) {
|
||||
for (OCFile file : files) {
|
||||
if (!file.isFavorite()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -541,7 +561,7 @@ public class FileMenuFilter {
|
|||
}
|
||||
|
||||
private boolean allNotFavorites() {
|
||||
for (OCFile file : mFiles) {
|
||||
for (OCFile file : files) {
|
||||
if (file.isFavorite()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -2085,8 +2085,8 @@ public class FileContentProvider extends ContentProvider {
|
|||
Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
|
||||
}
|
||||
|
||||
if (oldVersion < 52 && newVersion >= 52) {
|
||||
Log_OC.i(SQL, "Entering in the #52 add rich workspace to file table");
|
||||
if (oldVersion < 53 && newVersion >= 53) {
|
||||
Log_OC.i(SQL, "Entering in the #53 add rich workspace to file table");
|
||||
db.beginTransaction();
|
||||
try {
|
||||
db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
|
||||
|
@ -2103,17 +2103,5 @@ public class FileContentProvider extends ContentProvider {
|
|||
Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if (oldVersion == 25 && newVersion == 24) {
|
||||
db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
|
||||
REMOVE_COLUMN + ProviderTableMeta.FILE_IS_ENCRYPTED);
|
||||
db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
|
||||
REMOVE_COLUMN + ProviderTableMeta.FILE_ENCRYPTED_NAME);
|
||||
db.execSQL(ALTER_TABLE + ProviderTableMeta.CAPABILITIES_TABLE_NAME +
|
||||
REMOVE_COLUMN + ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import android.content.Intent;
|
|||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.webkit.JavascriptInterface;
|
||||
import android.widget.ImageView;
|
||||
|
@ -39,8 +38,6 @@ import com.google.android.material.snackbar.Snackbar;
|
|||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.ui.asynctasks.LoadUrlTask;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.MimeTypeUtil;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
|
@ -53,32 +50,30 @@ import lombok.Setter;
|
|||
|
||||
public abstract class EditorWebView extends ExternalSiteWebView {
|
||||
@Getter @Setter protected Snackbar loadingSnackbar;
|
||||
protected OCFile file;
|
||||
|
||||
protected String fileName;
|
||||
protected String mimeType;
|
||||
|
||||
@BindView(R.id.progressBar2)
|
||||
ProgressBar progressBar;
|
||||
|
||||
@BindView(R.id.thumbnail)
|
||||
ImageView thumbnail;
|
||||
ImageView thumbnailView;
|
||||
|
||||
@BindView(R.id.filename)
|
||||
TextView fileName;
|
||||
TextView fileNameTextView;
|
||||
|
||||
private Unbinder unbinder;
|
||||
|
||||
private static final String TAG = EditorWebView.class.getSimpleName();
|
||||
|
||||
protected void loadUrl(String url, OCFile file) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
new LoadUrlTask(this, getAccount(), file).execute();
|
||||
} else {
|
||||
webview.loadUrl(url);
|
||||
}
|
||||
protected void loadUrl(String url) {
|
||||
webview.loadUrl(url);
|
||||
}
|
||||
|
||||
protected void hideLoading() {
|
||||
thumbnail.setVisibility(View.GONE);
|
||||
fileName.setVisibility(View.GONE);
|
||||
thumbnailView.setVisibility(View.GONE);
|
||||
fileNameTextView.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
webview.setVisibility(View.VISIBLE);
|
||||
|
||||
|
@ -127,19 +122,29 @@ public abstract class EditorWebView extends ExternalSiteWebView {
|
|||
|
||||
unbinder = ButterKnife.bind(this);
|
||||
|
||||
file = getIntent().getParcelableExtra(ExternalSiteWebView.EXTRA_FILE);
|
||||
setFile(getIntent().getParcelableExtra(ExternalSiteWebView.EXTRA_FILE));
|
||||
|
||||
if (getFile() == null) {
|
||||
Toast.makeText(getApplicationContext(),
|
||||
R.string.richdocuments_failed_to_load_document, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
|
||||
if (getFile() != null) {
|
||||
fileName = getFile().getFileName();
|
||||
}
|
||||
|
||||
initLoadingScreen();
|
||||
}
|
||||
|
||||
protected void initLoadingScreen() {
|
||||
setThumbnail(file, thumbnail);
|
||||
fileName.setText(file.getFileName());
|
||||
setThumbnailView();
|
||||
fileNameTextView.setText(fileName);
|
||||
}
|
||||
|
||||
private void openShareDialog() {
|
||||
Intent intent = new Intent(this, ShareActivity.class);
|
||||
intent.putExtra(FileActivity.EXTRA_FILE, file);
|
||||
intent.putExtra(FileActivity.EXTRA_FILE, getFile());
|
||||
intent.putExtra(FileActivity.EXTRA_ACCOUNT, getAccount());
|
||||
startActivity(intent);
|
||||
}
|
||||
|
@ -152,12 +157,15 @@ public abstract class EditorWebView extends ExternalSiteWebView {
|
|||
super.onDestroy();
|
||||
}
|
||||
|
||||
protected void setThumbnail(OCFile file, ImageView thumbnailView) {
|
||||
protected void setThumbnailView() {
|
||||
// Todo minimize: only icon by mimetype
|
||||
|
||||
OCFile file = getFile();
|
||||
if (file.isFolder()) {
|
||||
thumbnailView.setImageDrawable(MimeTypeUtil.getFolderTypeIcon(file.isSharedWithMe() ||
|
||||
file.isSharedWithSharee(), file.isSharedViaLink(), file.isEncrypted(), file.getMountType(),
|
||||
file.isSharedWithSharee(),
|
||||
file.isSharedViaLink(),
|
||||
file.isEncrypted(),
|
||||
file.getMountType(),
|
||||
this));
|
||||
} else {
|
||||
if ((MimeTypeUtil.isImage(file) || MimeTypeUtil.isVideo(file)) && file.getRemoteId() != null) {
|
||||
|
@ -172,30 +180,6 @@ public abstract class EditorWebView extends ExternalSiteWebView {
|
|||
} else {
|
||||
thumbnailView.setImageBitmap(thumbnail);
|
||||
}
|
||||
} else {
|
||||
// generate new thumbnail
|
||||
if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, thumbnailView)) {
|
||||
try {
|
||||
final ThumbnailsCacheManager.ThumbnailGenerationTask task =
|
||||
new ThumbnailsCacheManager.ThumbnailGenerationTask(thumbnailView,
|
||||
getStorageManager(), getAccount());
|
||||
|
||||
if (thumbnail == null) {
|
||||
if (MimeTypeUtil.isVideo(file)) {
|
||||
thumbnail = ThumbnailsCacheManager.mDefaultVideo;
|
||||
} else {
|
||||
thumbnail = ThumbnailsCacheManager.mDefaultImg;
|
||||
}
|
||||
}
|
||||
final ThumbnailsCacheManager.AsyncThumbnailDrawable asyncDrawable =
|
||||
new ThumbnailsCacheManager.AsyncThumbnailDrawable(getResources(), thumbnail, task);
|
||||
thumbnailView.setImageDrawable(asyncDrawable);
|
||||
task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file,
|
||||
file.getRemoteId()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log_OC.d(TAG, "ThumbnailGenerationTask : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("image/png".equalsIgnoreCase(file.getMimeType())) {
|
||||
|
|
|
@ -32,6 +32,7 @@ import android.content.Intent;
|
|||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.KeyEvent;
|
||||
import android.webkit.JavascriptInterface;
|
||||
import android.webkit.ValueCallback;
|
||||
|
@ -39,26 +40,23 @@ import android.webkit.WebChromeClient;
|
|||
import android.webkit.WebView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.nextcloud.client.account.CurrentAccountProvider;
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.nextcloud.client.network.ClientFactory;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.Template;
|
||||
import com.owncloud.android.lib.common.OwnCloudAccount;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.operations.RichDocumentsCreateAssetOperation;
|
||||
import com.owncloud.android.ui.asynctasks.PrintAsyncTask;
|
||||
import com.owncloud.android.ui.asynctasks.RichDocumentsLoadUrlTask;
|
||||
import com.owncloud.android.ui.fragment.OCFileListFragment;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.FileStorageUtils;
|
||||
import com.owncloud.android.utils.glide.CustomGlideStreamLoader;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
@ -130,49 +128,9 @@ public class RichDocumentsEditorWebView extends EditorWebView {
|
|||
});
|
||||
|
||||
// load url in background
|
||||
loadUrl(getIntent().getStringExtra(EXTRA_URL), file);
|
||||
loadUrl(getIntent().getStringExtra(EXTRA_URL));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLoadingScreen() {
|
||||
if (file == null) {
|
||||
fileName.setText(R.string.create_file_from_template);
|
||||
|
||||
Template template = Parcels.unwrap(getIntent().getParcelableExtra(EXTRA_TEMPLATE));
|
||||
|
||||
int placeholder;
|
||||
|
||||
switch (template.getType()) {
|
||||
case DOCUMENT:
|
||||
placeholder = R.drawable.file_doc;
|
||||
break;
|
||||
|
||||
case SPREADSHEET:
|
||||
placeholder = R.drawable.file_xls;
|
||||
break;
|
||||
|
||||
case PRESENTATION:
|
||||
placeholder = R.drawable.file_ppt;
|
||||
break;
|
||||
|
||||
default:
|
||||
placeholder = R.drawable.file;
|
||||
break;
|
||||
}
|
||||
|
||||
Glide.with(this).using(new CustomGlideStreamLoader(currentAccountProvider, clientFactory))
|
||||
.load(template.getThumbnailLink())
|
||||
.placeholder(placeholder)
|
||||
.error(placeholder)
|
||||
.into(thumbnail);
|
||||
} else {
|
||||
setThumbnail(file, thumbnail);
|
||||
fileName.setText(file.getFileName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
@ -292,6 +250,15 @@ public class RichDocumentsEditorWebView extends EditorWebView {
|
|||
downloadmanager.enqueue(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadUrl(String url) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
new RichDocumentsLoadUrlTask(this, getUser().get(), getFile()).execute();
|
||||
} else {
|
||||
super.loadUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
private class RichDocumentsMobileInterface extends MobileInterface {
|
||||
@JavascriptInterface
|
||||
public void insertGraphic() {
|
||||
|
@ -328,7 +295,7 @@ public class RichDocumentsEditorWebView extends EditorWebView {
|
|||
try {
|
||||
JSONObject renameJson = new JSONObject(renameString);
|
||||
String newName = renameJson.getString(NEW_NAME);
|
||||
file.setFileName(newName);
|
||||
getFile().setFileName(newName);
|
||||
} catch (JSONException e) {
|
||||
Log_OC.e(this, "Failed to parse rename json message: " + e);
|
||||
}
|
||||
|
|
|
@ -21,24 +21,33 @@
|
|||
|
||||
package com.owncloud.android.ui.activity
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.pm.PackageManager.NameNotFoundException
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.nextcloud.client.appinfo.AppInfo
|
||||
import com.nextcloud.client.device.DeviceInfo
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.files.FileMenuFilter
|
||||
import com.owncloud.android.lib.common.utils.Log_OC
|
||||
import com.owncloud.android.ui.asynctasks.TextEditorLoadUrlTask
|
||||
import javax.inject.Inject
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
class TextEditorWebView : EditorWebView() {
|
||||
@Inject
|
||||
lateinit var appInfo: AppInfo
|
||||
@Inject
|
||||
lateinit var deviceInfo: DeviceInfo
|
||||
|
||||
@SuppressLint("AddJavascriptInterface")
|
||||
// suppress warning as webview is only used >= Lollipop
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val editor = FileMenuFilter.getEditor(contentResolver, account, file.mimeType)
|
||||
if (!user.isPresent) {
|
||||
Toast.makeText(this, getString(R.string.failed_to_start_editor), Toast.LENGTH_LONG).show()
|
||||
finish()
|
||||
}
|
||||
|
||||
val editor = FileMenuFilter.getEditor(contentResolver, user.get(), file.mimeType)
|
||||
|
||||
if (editor != null && editor.id == "onlyoffice") {
|
||||
webview.settings.userAgentString = generateOnlyOfficeUserAgent()
|
||||
|
@ -46,22 +55,20 @@ class TextEditorWebView : EditorWebView() {
|
|||
|
||||
webview.addJavascriptInterface(MobileInterface(), "DirectEditingMobileInterface")
|
||||
|
||||
loadUrl(intent.getStringExtra(ExternalSiteWebView.EXTRA_URL), file)
|
||||
loadUrl(intent.getStringExtra(ExternalSiteWebView.EXTRA_URL))
|
||||
}
|
||||
|
||||
override fun loadUrl(url: String?) {
|
||||
if (url.isNullOrEmpty()) {
|
||||
TextEditorLoadUrlTask(this, user.get(), file).execute()
|
||||
} else {
|
||||
super.loadUrl(url)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateOnlyOfficeUserAgent(): String {
|
||||
val appString = applicationContext.resources.getString(R.string.only_office_user_agent)
|
||||
val packageName = applicationContext.packageName
|
||||
val androidVersion = Build.VERSION.RELEASE
|
||||
var appVersion = ""
|
||||
try {
|
||||
val pInfo = applicationContext.packageManager.getPackageInfo(packageName, 0)
|
||||
if (pInfo != null) {
|
||||
appVersion = pInfo.versionName
|
||||
}
|
||||
} catch (e: NameNotFoundException) {
|
||||
Log_OC.e(this, "Trying to get packageName", e.cause)
|
||||
}
|
||||
return String.format(appString, androidVersion, appVersion)
|
||||
val userAgent = applicationContext.resources.getString(R.string.only_office_user_agent)
|
||||
|
||||
return String.format(userAgent, deviceInfo.androidVersion, appInfo.getAppVersion(this))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -673,11 +673,13 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
|||
}
|
||||
|
||||
public OCFile getItem(int position) {
|
||||
if (shouldShowHeader()) {
|
||||
return mFiles.get(position - 1);
|
||||
} else {
|
||||
return mFiles.get(position);
|
||||
int newPosition = position;
|
||||
|
||||
if (shouldShowHeader() && position > 0) {
|
||||
newPosition = position - 1;
|
||||
}
|
||||
|
||||
return mFiles.get(newPosition);
|
||||
}
|
||||
|
||||
private boolean shouldShowHeader() {
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2019 Tobias Kaminsky
|
||||
* Copyright (C) 2019 Nextcloud GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.nextcloud.client.account.CurrentAccountProvider;
|
||||
import com.nextcloud.client.network.ClientFactory;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.Template;
|
||||
import com.owncloud.android.ui.dialog.ChooseRichDocumentsTemplateDialogFragment;
|
||||
import com.owncloud.android.utils.NextcloudServer;
|
||||
import com.owncloud.android.utils.glide.CustomGlideStreamLoader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
/**
|
||||
* Adapter for handling Templates, used to create files out of it via RichDocuments app
|
||||
*/
|
||||
public class RichDocumentsTemplateAdapter extends RecyclerView.Adapter<RichDocumentsTemplateAdapter.ViewHolder> {
|
||||
|
||||
private List<Template> templateList = new ArrayList<>();
|
||||
private ClickListener clickListener;
|
||||
private Context context;
|
||||
private ChooseRichDocumentsTemplateDialogFragment.Type type;
|
||||
private CurrentAccountProvider currentAccountProvider;
|
||||
private ClientFactory clientFactory;
|
||||
|
||||
public RichDocumentsTemplateAdapter(
|
||||
ChooseRichDocumentsTemplateDialogFragment.Type type,
|
||||
ClickListener clickListener,
|
||||
Context context,
|
||||
CurrentAccountProvider currentAccountProvider,
|
||||
ClientFactory clientFactory
|
||||
) {
|
||||
this.clickListener = clickListener;
|
||||
this.type = type;
|
||||
this.context = context;
|
||||
this.currentAccountProvider = currentAccountProvider;
|
||||
this.clientFactory = clientFactory;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
@NextcloudServer(max = 18) // remove entire class
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.template_button, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
holder.setData(templateList.get(position));
|
||||
}
|
||||
|
||||
public void setTemplateList(List<Template> templateList) {
|
||||
this.templateList = templateList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return templateList.size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
|
||||
@BindView(R.id.name)
|
||||
public TextView name;
|
||||
|
||||
@BindView(R.id.thumbnail)
|
||||
public ImageView thumbnail;
|
||||
|
||||
private Template template;
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
itemView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (clickListener != null) {
|
||||
clickListener.onClick(template);
|
||||
}
|
||||
}
|
||||
|
||||
public void setData(Template template) {
|
||||
this.template = template;
|
||||
|
||||
int placeholder;
|
||||
|
||||
switch (type) {
|
||||
case DOCUMENT:
|
||||
placeholder = R.drawable.file_doc;
|
||||
break;
|
||||
|
||||
case SPREADSHEET:
|
||||
placeholder = R.drawable.file_xls;
|
||||
break;
|
||||
|
||||
case PRESENTATION:
|
||||
placeholder = R.drawable.file_ppt;
|
||||
break;
|
||||
|
||||
default:
|
||||
placeholder = R.drawable.file;
|
||||
break;
|
||||
}
|
||||
|
||||
Glide.with(context).using(new CustomGlideStreamLoader(currentAccountProvider, clientFactory)).
|
||||
load(template.getThumbnailLink())
|
||||
.placeholder(placeholder)
|
||||
.error(placeholder)
|
||||
.into(thumbnail);
|
||||
|
||||
name.setText(template.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public interface ClickListener {
|
||||
void onClick(Template template);
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@
|
|||
package com.owncloud.android.ui.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -35,13 +36,11 @@ import com.bumptech.glide.Glide;
|
|||
import com.nextcloud.client.account.CurrentAccountProvider;
|
||||
import com.nextcloud.client.network.ClientFactory;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.Template;
|
||||
import com.owncloud.android.ui.dialog.ChooseTemplateDialogFragment;
|
||||
import com.owncloud.android.lib.common.Template;
|
||||
import com.owncloud.android.lib.common.TemplateList;
|
||||
import com.owncloud.android.utils.MimeTypeUtil;
|
||||
import com.owncloud.android.utils.glide.CustomGlideStreamLoader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
|
@ -52,22 +51,22 @@ import butterknife.ButterKnife;
|
|||
*/
|
||||
public class TemplateAdapter extends RecyclerView.Adapter<TemplateAdapter.ViewHolder> {
|
||||
|
||||
private List<Template> templateList = new ArrayList<>();
|
||||
private TemplateList templateList = new TemplateList();
|
||||
private ClickListener clickListener;
|
||||
private Context context;
|
||||
private ChooseTemplateDialogFragment.Type type;
|
||||
private CurrentAccountProvider currentAccountProvider;
|
||||
private ClientFactory clientFactory;
|
||||
private String mimetype;
|
||||
|
||||
public TemplateAdapter(
|
||||
ChooseTemplateDialogFragment.Type type,
|
||||
String mimetype,
|
||||
ClickListener clickListener,
|
||||
Context context,
|
||||
CurrentAccountProvider currentAccountProvider,
|
||||
ClientFactory clientFactory
|
||||
) {
|
||||
this.mimetype = mimetype;
|
||||
this.clickListener = clickListener;
|
||||
this.type = type;
|
||||
this.context = context;
|
||||
this.currentAccountProvider = currentAccountProvider;
|
||||
this.clientFactory = clientFactory;
|
||||
|
@ -81,20 +80,19 @@ public class TemplateAdapter extends RecyclerView.Adapter<TemplateAdapter.ViewHo
|
|||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
holder.setData(templateList.get(position));
|
||||
holder.setData(templateList.getTemplateList().get(position));
|
||||
}
|
||||
|
||||
public void setTemplateList(List<Template> templateList) {
|
||||
public void setTemplateList(TemplateList templateList) {
|
||||
this.templateList = templateList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return templateList.size();
|
||||
return templateList.getTemplateList().size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
|
||||
@BindView(R.id.name)
|
||||
public TextView name;
|
||||
|
||||
|
@ -119,33 +117,18 @@ public class TemplateAdapter extends RecyclerView.Adapter<TemplateAdapter.ViewHo
|
|||
public void setData(Template template) {
|
||||
this.template = template;
|
||||
|
||||
int placeholder;
|
||||
|
||||
switch (type) {
|
||||
case DOCUMENT:
|
||||
placeholder = R.drawable.file_doc;
|
||||
break;
|
||||
|
||||
case SPREADSHEET:
|
||||
placeholder = R.drawable.file_xls;
|
||||
break;
|
||||
|
||||
case PRESENTATION:
|
||||
placeholder = R.drawable.file_ppt;
|
||||
break;
|
||||
|
||||
default:
|
||||
placeholder = R.drawable.file;
|
||||
break;
|
||||
}
|
||||
Drawable placeholder = MimeTypeUtil.getFileTypeIcon(mimetype,
|
||||
template.getTitle(),
|
||||
currentAccountProvider.getUser().toPlatformAccount(),
|
||||
context);
|
||||
|
||||
Glide.with(context).using(new CustomGlideStreamLoader(currentAccountProvider, clientFactory))
|
||||
.load(template.getThumbnailLink())
|
||||
.load(template.getPreview())
|
||||
.placeholder(placeholder)
|
||||
.error(placeholder)
|
||||
.into(thumbnail);
|
||||
|
||||
name.setText(template.getName());
|
||||
name.setText(template.getTitle());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2020 Tobias Kaminsky
|
||||
* Copyright (C) 2020 Nextcloud GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.asynctasks;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.operations.RichDocumentsUrlOperation;
|
||||
import com.owncloud.android.ui.activity.EditorWebView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class RichDocumentsLoadUrlTask extends AsyncTask<Void, Void, String> {
|
||||
|
||||
private Account account;
|
||||
private WeakReference<EditorWebView> editorWebViewWeakReference;
|
||||
private OCFile file;
|
||||
|
||||
public RichDocumentsLoadUrlTask(EditorWebView editorWebView, User user, OCFile file) {
|
||||
this.account = user.toPlatformAccount();
|
||||
this.editorWebViewWeakReference = new WeakReference<>(editorWebView);
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... voids) {
|
||||
final EditorWebView editorWebView = editorWebViewWeakReference.get();
|
||||
|
||||
if (editorWebView == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
RemoteOperationResult result = new RichDocumentsUrlOperation(file.getLocalId()).execute(account, editorWebView);
|
||||
|
||||
if (!result.isSuccess()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return (String) result.getData().get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String url) {
|
||||
EditorWebView editorWebView = editorWebViewWeakReference.get();
|
||||
|
||||
if (editorWebView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
editorWebView.onUrlLoaded(url);
|
||||
}
|
||||
}
|
|
@ -24,25 +24,25 @@ import android.accounts.Account;
|
|||
import android.os.AsyncTask;
|
||||
|
||||
import com.nextcloud.android.lib.resources.directediting.DirectEditingOpenFileRemoteOperation;
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.files.FileMenuFilter;
|
||||
import com.owncloud.android.lib.common.Editor;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.operations.RichDocumentsUrlOperation;
|
||||
import com.owncloud.android.ui.activity.EditorWebView;
|
||||
import com.owncloud.android.ui.activity.RichDocumentsEditorWebView;
|
||||
import com.owncloud.android.ui.activity.TextEditorWebView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class LoadUrlTask extends AsyncTask<Void, Void, String> {
|
||||
public class TextEditorLoadUrlTask extends AsyncTask<Void, Void, String> {
|
||||
|
||||
private Account account;
|
||||
private WeakReference<EditorWebView> editorWebViewWeakReference;
|
||||
private OCFile file;
|
||||
private User user;
|
||||
|
||||
public LoadUrlTask(EditorWebView editorWebView, Account account, OCFile file) {
|
||||
this.account = account;
|
||||
public TextEditorLoadUrlTask(EditorWebView editorWebView, User user, OCFile file) {
|
||||
this.user = user;
|
||||
this.account = user.toPlatformAccount();
|
||||
this.editorWebViewWeakReference = new WeakReference<>(editorWebView);
|
||||
this.file = file;
|
||||
}
|
||||
|
@ -55,24 +55,16 @@ public class LoadUrlTask extends AsyncTask<Void, Void, String> {
|
|||
return "";
|
||||
}
|
||||
|
||||
RemoteOperationResult result;
|
||||
Editor editor = FileMenuFilter.getEditor(editorWebView.getContentResolver(), user, file.getMimeType());
|
||||
|
||||
|
||||
if (editorWebView instanceof RichDocumentsEditorWebView) {
|
||||
result = new RichDocumentsUrlOperation(file.getLocalId()).execute(account, editorWebView);
|
||||
} else if (editorWebView instanceof TextEditorWebView) {
|
||||
Editor editor = FileMenuFilter.getEditor(editorWebView.getContentResolver(), account, file.getMimeType());
|
||||
|
||||
if (editor == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
result = new DirectEditingOpenFileRemoteOperation(file.getRemotePath(), editor.id)
|
||||
.execute(account, editorWebViewWeakReference.get());
|
||||
} else {
|
||||
if (editor == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
RemoteOperationResult result = new DirectEditingOpenFileRemoteOperation(file.getRemotePath(), editor.id)
|
||||
.execute(account, editorWebViewWeakReference.get());
|
||||
|
||||
|
||||
if (!result.isSuccess()) {
|
||||
return "";
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2019 Tobias Kaminsky
|
||||
* Copyright (C) 2019 Nextcloud GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.dialog;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.nextcloud.client.account.CurrentAccountProvider;
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.nextcloud.client.di.Injectable;
|
||||
import com.nextcloud.client.network.ClientFactory;
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.Template;
|
||||
import com.owncloud.android.files.CreateFileFromTemplateOperation;
|
||||
import com.owncloud.android.files.FetchTemplateOperation;
|
||||
import com.owncloud.android.lib.common.OwnCloudAccount;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation;
|
||||
import com.owncloud.android.lib.resources.files.model.RemoteFile;
|
||||
import com.owncloud.android.ui.activity.ExternalSiteWebView;
|
||||
import com.owncloud.android.ui.activity.RichDocumentsEditorWebView;
|
||||
import com.owncloud.android.ui.adapter.RichDocumentsTemplateAdapter;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.FileStorageUtils;
|
||||
import com.owncloud.android.utils.NextcloudServer;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
/**
|
||||
* Dialog to show templates for new documents/spreadsheets/presentations.
|
||||
*/
|
||||
public class ChooseRichDocumentsTemplateDialogFragment extends DialogFragment implements DialogInterface.OnClickListener,
|
||||
RichDocumentsTemplateAdapter.ClickListener, Injectable {
|
||||
|
||||
private static final String ARG_PARENT_FOLDER = "PARENT_FOLDER";
|
||||
private static final String ARG_TYPE = "TYPE";
|
||||
private static final String TAG = ChooseRichDocumentsTemplateDialogFragment.class.getSimpleName();
|
||||
private static final String DOT = ".";
|
||||
|
||||
private RichDocumentsTemplateAdapter adapter;
|
||||
private OCFile parentFolder;
|
||||
private OwnCloudClient client;
|
||||
@Inject CurrentAccountProvider currentAccount;
|
||||
@Inject ClientFactory clientFactory;
|
||||
|
||||
public enum Type {
|
||||
DOCUMENT,
|
||||
SPREADSHEET,
|
||||
PRESENTATION
|
||||
}
|
||||
|
||||
@BindView(R.id.list)
|
||||
RecyclerView listView;
|
||||
|
||||
@BindView(R.id.filename)
|
||||
EditText fileName;
|
||||
|
||||
@NextcloudServer(max = 18) // will be removed in favor of generic direct editing
|
||||
public static ChooseRichDocumentsTemplateDialogFragment newInstance(OCFile parentFolder, Type type) {
|
||||
ChooseRichDocumentsTemplateDialogFragment frag = new ChooseRichDocumentsTemplateDialogFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable(ARG_PARENT_FOLDER, parentFolder);
|
||||
args.putString(ARG_TYPE, type.name());
|
||||
frag.setArguments(args);
|
||||
return frag;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
int color = ThemeUtils.primaryAccentColor(getContext());
|
||||
|
||||
AlertDialog alertDialog = (AlertDialog) getDialog();
|
||||
|
||||
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(color);
|
||||
alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(color);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Bundle arguments = getArguments();
|
||||
if (arguments == null) {
|
||||
throw new IllegalArgumentException("Arguments may not be null");
|
||||
}
|
||||
|
||||
Activity activity = getActivity();
|
||||
if (activity == null) {
|
||||
throw new IllegalArgumentException("Activity may not be null");
|
||||
}
|
||||
|
||||
int accentColor = ThemeUtils.primaryAccentColor(getContext());
|
||||
|
||||
parentFolder = arguments.getParcelable(ARG_PARENT_FOLDER);
|
||||
Type type = Type.valueOf(arguments.getString(ARG_TYPE));
|
||||
|
||||
// Inflate the layout for the dialog
|
||||
LayoutInflater inflater = activity.getLayoutInflater();
|
||||
@SuppressLint("InflateParams") View view = inflater.inflate(R.layout.choose_template, null);
|
||||
ButterKnife.bind(this, view);
|
||||
|
||||
fileName.requestFocus();
|
||||
fileName.getBackground().setColorFilter(accentColor, PorterDuff.Mode.SRC_ATOP);
|
||||
|
||||
try {
|
||||
Account account = currentAccount.getCurrentAccount();
|
||||
OwnCloudAccount ocAccount = new OwnCloudAccount(account, activity);
|
||||
client = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, getContext());
|
||||
|
||||
new FetchTemplateTask(this, client).execute(type);
|
||||
} catch (Exception e) {
|
||||
Log_OC.e(TAG, "Loading stream url not possible: " + e);
|
||||
}
|
||||
|
||||
listView.setHasFixedSize(true);
|
||||
listView.setLayoutManager(new GridLayoutManager(activity, 2));
|
||||
adapter = new RichDocumentsTemplateAdapter(type, this, getContext(), currentAccount, clientFactory);
|
||||
listView.setAdapter(adapter);
|
||||
|
||||
// Build the dialog
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setView(view)
|
||||
.setNegativeButton(R.string.common_cancel, this)
|
||||
.setTitle(ThemeUtils.getColoredTitle(getResources().getString(R.string.select_template), accentColor));
|
||||
Dialog dialog = builder.create();
|
||||
|
||||
Window window = dialog.getWindow();
|
||||
|
||||
if (window != null) {
|
||||
window.setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
||||
}
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private void createFromTemplate(Template template, String path) {
|
||||
new CreateFileFromTemplateTask(this, client, template, path, currentAccount.getUser()).execute();
|
||||
}
|
||||
|
||||
public void setTemplateList(List<Template> templateList) {
|
||||
adapter.setTemplateList(templateList);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(Template template) {
|
||||
String name = fileName.getText().toString();
|
||||
String path = parentFolder.getRemotePath() + name;
|
||||
|
||||
if (name.isEmpty() || name.equalsIgnoreCase(DOT + template.getExtension())) {
|
||||
DisplayUtils.showSnackMessage(listView, R.string.enter_filename);
|
||||
} else if (!name.endsWith(template.getExtension())) {
|
||||
createFromTemplate(template, path + DOT + template.getExtension());
|
||||
} else {
|
||||
createFromTemplate(template, path);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// cancel is handled by dialog itself, no other button available
|
||||
}
|
||||
|
||||
private static class CreateFileFromTemplateTask extends AsyncTask<Void, Void, String> {
|
||||
private OwnCloudClient client;
|
||||
private WeakReference<ChooseRichDocumentsTemplateDialogFragment> chooseTemplateDialogFragmentWeakReference;
|
||||
private Template template;
|
||||
private String path;
|
||||
private User user;
|
||||
private OCFile file;
|
||||
|
||||
CreateFileFromTemplateTask(ChooseRichDocumentsTemplateDialogFragment chooseTemplateDialogFragment,
|
||||
OwnCloudClient client,
|
||||
Template template,
|
||||
String path,
|
||||
User user
|
||||
) {
|
||||
this.client = client;
|
||||
this.chooseTemplateDialogFragmentWeakReference = new WeakReference<>(chooseTemplateDialogFragment);
|
||||
this.template = template;
|
||||
this.path = path;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... voids) {
|
||||
RemoteOperationResult result = new CreateFileFromTemplateOperation(path, template.getId()).execute(client);
|
||||
|
||||
if (result.isSuccess()) {
|
||||
// get file
|
||||
RemoteOperationResult newFileResult = new ReadFileRemoteOperation(path).execute(client);
|
||||
|
||||
if (newFileResult.isSuccess()) {
|
||||
OCFile temp = FileStorageUtils.fillOCFile((RemoteFile) newFileResult.getData().get(0));
|
||||
|
||||
if (chooseTemplateDialogFragmentWeakReference.get() != null) {
|
||||
FileDataStorageManager storageManager = new FileDataStorageManager(
|
||||
user.toPlatformAccount(),
|
||||
chooseTemplateDialogFragmentWeakReference.get().requireContext().getContentResolver());
|
||||
storageManager.saveFile(temp);
|
||||
file = storageManager.getFileByPath(path);
|
||||
|
||||
return result.getData().get(0).toString();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String url) {
|
||||
ChooseRichDocumentsTemplateDialogFragment fragment = chooseTemplateDialogFragmentWeakReference.get();
|
||||
|
||||
if (fragment != null && fragment.isAdded()) {
|
||||
if (url.isEmpty()) {
|
||||
DisplayUtils.showSnackMessage(fragment.listView, "Error creating file from template");
|
||||
} else {
|
||||
Intent collaboraWebViewIntent = new Intent(MainApp.getAppContext(), RichDocumentsEditorWebView.class);
|
||||
collaboraWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, "Collabora");
|
||||
collaboraWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_URL, url);
|
||||
collaboraWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_FILE, file);
|
||||
collaboraWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false);
|
||||
collaboraWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_TEMPLATE, Parcels.wrap(template));
|
||||
fragment.startActivity(collaboraWebViewIntent);
|
||||
|
||||
fragment.dismiss();
|
||||
}
|
||||
} else {
|
||||
Log_OC.e(TAG, "Error creating file from template!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class FetchTemplateTask extends AsyncTask<Type, Void, List<Template>> {
|
||||
|
||||
private OwnCloudClient client;
|
||||
private WeakReference<ChooseRichDocumentsTemplateDialogFragment> chooseTemplateDialogFragmentWeakReference;
|
||||
|
||||
FetchTemplateTask(ChooseRichDocumentsTemplateDialogFragment chooseTemplateDialogFragment, OwnCloudClient client) {
|
||||
this.client = client;
|
||||
this.chooseTemplateDialogFragmentWeakReference = new WeakReference<>(chooseTemplateDialogFragment);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Template> doInBackground(Type... type) {
|
||||
FetchTemplateOperation fetchTemplateOperation = new FetchTemplateOperation(type[0]);
|
||||
RemoteOperationResult result = fetchTemplateOperation.execute(client);
|
||||
|
||||
if (!result.isSuccess()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<Template> templateList = new ArrayList<>();
|
||||
for (Object object : result.getData()) {
|
||||
templateList.add((Template) object);
|
||||
}
|
||||
|
||||
return templateList;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<Template> templateList) {
|
||||
ChooseRichDocumentsTemplateDialogFragment fragment = chooseTemplateDialogFragmentWeakReference.get();
|
||||
|
||||
if (fragment != null) {
|
||||
if (templateList.isEmpty()) {
|
||||
DisplayUtils.showSnackMessage(fragment.listView, R.string.error_retrieving_templates);
|
||||
} else {
|
||||
fragment.setTemplateList(templateList);
|
||||
|
||||
String name = DOT + templateList.get(0).getExtension();
|
||||
fragment.fileName.setText(name);
|
||||
}
|
||||
} else {
|
||||
Log_OC.e(TAG, "Error streaming file: no previewMediaFragment!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,30 +38,32 @@ import android.view.Window;
|
|||
import android.view.WindowManager.LayoutParams;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.nextcloud.android.lib.resources.directediting.DirectEditingCreateFileRemoteOperation;
|
||||
import com.nextcloud.android.lib.resources.directediting.DirectEditingObtainListOfTemplatesRemoteOperation;
|
||||
import com.nextcloud.client.account.CurrentAccountProvider;
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.nextcloud.client.di.Injectable;
|
||||
import com.nextcloud.client.network.ClientFactory;
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.Template;
|
||||
import com.owncloud.android.files.CreateFileFromTemplateOperation;
|
||||
import com.owncloud.android.files.FetchTemplateOperation;
|
||||
import com.owncloud.android.lib.common.Creator;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.Template;
|
||||
import com.owncloud.android.lib.common.TemplateList;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation;
|
||||
import com.owncloud.android.lib.resources.files.model.RemoteFile;
|
||||
import com.owncloud.android.ui.activity.ExternalSiteWebView;
|
||||
import com.owncloud.android.ui.activity.RichDocumentsEditorWebView;
|
||||
import com.owncloud.android.ui.activity.TextEditorWebView;
|
||||
import com.owncloud.android.ui.adapter.TemplateAdapter;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.FileStorageUtils;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
@ -80,15 +82,15 @@ public class ChooseTemplateDialogFragment extends DialogFragment implements Dial
|
|||
TemplateAdapter.ClickListener, Injectable {
|
||||
|
||||
private static final String ARG_PARENT_FOLDER = "PARENT_FOLDER";
|
||||
private static final String ARG_TYPE = "TYPE";
|
||||
private static final String ARG_CREATOR = "CREATOR";
|
||||
private static final String TAG = ChooseTemplateDialogFragment.class.getSimpleName();
|
||||
private static final String DOT = ".";
|
||||
|
||||
private TemplateAdapter adapter;
|
||||
private OCFile parentFolder;
|
||||
private OwnCloudClient client;
|
||||
@Inject CurrentAccountProvider currentUser;
|
||||
@Inject ClientFactory clientFactory;
|
||||
private Creator creator;
|
||||
@Inject CurrentAccountProvider currentAccount;
|
||||
|
||||
public enum Type {
|
||||
DOCUMENT,
|
||||
|
@ -102,11 +104,11 @@ public class ChooseTemplateDialogFragment extends DialogFragment implements Dial
|
|||
@BindView(R.id.filename)
|
||||
EditText fileName;
|
||||
|
||||
public static ChooseTemplateDialogFragment newInstance(OCFile parentFolder, Type type) {
|
||||
public static ChooseTemplateDialogFragment newInstance(OCFile parentFolder, Creator creator) {
|
||||
ChooseTemplateDialogFragment frag = new ChooseTemplateDialogFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable(ARG_PARENT_FOLDER, parentFolder);
|
||||
args.putString(ARG_TYPE, type.name());
|
||||
args.putParcelable(ARG_CREATOR, creator);
|
||||
frag.setArguments(args);
|
||||
return frag;
|
||||
|
||||
|
@ -140,7 +142,7 @@ public class ChooseTemplateDialogFragment extends DialogFragment implements Dial
|
|||
int accentColor = ThemeUtils.primaryAccentColor(getContext());
|
||||
|
||||
parentFolder = arguments.getParcelable(ARG_PARENT_FOLDER);
|
||||
Type type = Type.valueOf(arguments.getString(ARG_TYPE));
|
||||
creator = arguments.getParcelable(ARG_CREATOR);
|
||||
|
||||
// Inflate the layout for the dialog
|
||||
LayoutInflater inflater = activity.getLayoutInflater();
|
||||
|
@ -151,17 +153,15 @@ public class ChooseTemplateDialogFragment extends DialogFragment implements Dial
|
|||
fileName.getBackground().setColorFilter(accentColor, PorterDuff.Mode.SRC_ATOP);
|
||||
|
||||
try {
|
||||
User user = currentUser.getUser();
|
||||
client = clientFactory.create(user);
|
||||
|
||||
new FetchTemplateTask(this, client).execute(type);
|
||||
User user = currentAccount.getUser();
|
||||
new FetchTemplateTask(this, clientFactory, user, creator).execute();
|
||||
} catch (Exception e) {
|
||||
Log_OC.e(TAG, "Loading stream url not possible: " + e);
|
||||
}
|
||||
|
||||
listView.setHasFixedSize(true);
|
||||
listView.setLayoutManager(new GridLayoutManager(activity, 2));
|
||||
adapter = new TemplateAdapter(type, this, getContext(), currentUser, clientFactory);
|
||||
adapter = new TemplateAdapter(creator.getMimetype(), this, getContext(), currentAccount, clientFactory);
|
||||
listView.setAdapter(adapter);
|
||||
|
||||
// Build the dialog
|
||||
|
@ -181,10 +181,10 @@ public class ChooseTemplateDialogFragment extends DialogFragment implements Dial
|
|||
}
|
||||
|
||||
private void createFromTemplate(Template template, String path) {
|
||||
new CreateFileFromTemplateTask(this, client, template, path).execute();
|
||||
new CreateFileFromTemplateTask(this, clientFactory, currentAccount.getUser(), template, path, creator).execute();
|
||||
}
|
||||
|
||||
public void setTemplateList(List<Template> templateList) {
|
||||
public void setTemplateList(TemplateList templateList) {
|
||||
adapter.setTemplateList(templateList);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
@ -209,26 +209,69 @@ public class ChooseTemplateDialogFragment extends DialogFragment implements Dial
|
|||
}
|
||||
|
||||
private static class CreateFileFromTemplateTask extends AsyncTask<Void, Void, String> {
|
||||
private OwnCloudClient client;
|
||||
private ClientFactory clientFactory;
|
||||
private WeakReference<ChooseTemplateDialogFragment> chooseTemplateDialogFragmentWeakReference;
|
||||
private Template template;
|
||||
private String path;
|
||||
private Creator creator;
|
||||
private User user;
|
||||
private OCFile file;
|
||||
|
||||
CreateFileFromTemplateTask(ChooseTemplateDialogFragment chooseTemplateDialogFragment, OwnCloudClient client,
|
||||
Template template, String path) {
|
||||
this.client = client;
|
||||
CreateFileFromTemplateTask(ChooseTemplateDialogFragment chooseTemplateDialogFragment,
|
||||
ClientFactory clientFactory,
|
||||
User user,
|
||||
Template template,
|
||||
String path,
|
||||
Creator creator
|
||||
) {
|
||||
this.clientFactory = clientFactory;
|
||||
this.chooseTemplateDialogFragmentWeakReference = new WeakReference<>(chooseTemplateDialogFragment);
|
||||
this.template = template;
|
||||
this.path = path;
|
||||
this.creator = creator;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... voids) {
|
||||
RemoteOperationResult result = new CreateFileFromTemplateOperation(path, template.getId()).execute(client);
|
||||
try {
|
||||
OwnCloudClient client = clientFactory.create(user);
|
||||
|
||||
if (result.isSuccess()) {
|
||||
return result.getData().get(0).toString();
|
||||
} else {
|
||||
RemoteOperationResult result =
|
||||
new DirectEditingCreateFileRemoteOperation(path,
|
||||
creator.getEditor(),
|
||||
creator.getId(),
|
||||
template.getTitle())
|
||||
.execute(client);
|
||||
|
||||
if (result.isSuccess()) {
|
||||
// get file
|
||||
RemoteOperationResult newFileResult = new ReadFileRemoteOperation(path)
|
||||
.execute(client);
|
||||
|
||||
if (newFileResult.isSuccess()) {
|
||||
OCFile temp = FileStorageUtils.fillOCFile((RemoteFile) newFileResult.getData().get(0));
|
||||
|
||||
if (chooseTemplateDialogFragmentWeakReference.get() != null) {
|
||||
FileDataStorageManager storageManager = new FileDataStorageManager(
|
||||
user.toPlatformAccount(),
|
||||
chooseTemplateDialogFragmentWeakReference.get().requireContext().getContentResolver());
|
||||
storageManager.saveFile(temp);
|
||||
file = storageManager.getFileByPath(path);
|
||||
|
||||
return result.getData().get(0).toString();
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} catch (ClientFactory.CreationException e) {
|
||||
Log_OC.e(TAG, "Error creating file from template!", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
@ -241,12 +284,13 @@ public class ChooseTemplateDialogFragment extends DialogFragment implements Dial
|
|||
if (url.isEmpty()) {
|
||||
DisplayUtils.showSnackMessage(fragment.listView, "Error creating file from template");
|
||||
} else {
|
||||
Intent collaboraWebViewIntent = new Intent(MainApp.getAppContext(), RichDocumentsEditorWebView.class);
|
||||
collaboraWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, "Collabora");
|
||||
collaboraWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_URL, url);
|
||||
collaboraWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false);
|
||||
collaboraWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_TEMPLATE, Parcels.wrap(template));
|
||||
fragment.startActivity(collaboraWebViewIntent);
|
||||
Intent editorWebView = new Intent(MainApp.getAppContext(), TextEditorWebView.class);
|
||||
editorWebView.putExtra(ExternalSiteWebView.EXTRA_TITLE, "Text");
|
||||
editorWebView.putExtra(ExternalSiteWebView.EXTRA_URL, url);
|
||||
editorWebView.putExtra(ExternalSiteWebView.EXTRA_FILE, file);
|
||||
editorWebView.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false);
|
||||
fragment.startActivity(editorWebView);
|
||||
|
||||
fragment.dismiss();
|
||||
}
|
||||
} else {
|
||||
|
@ -255,44 +299,55 @@ public class ChooseTemplateDialogFragment extends DialogFragment implements Dial
|
|||
}
|
||||
}
|
||||
|
||||
private static class FetchTemplateTask extends AsyncTask<Type, Void, List<Template>> {
|
||||
private static class FetchTemplateTask extends AsyncTask<Void, Void, TemplateList> {
|
||||
|
||||
private OwnCloudClient client;
|
||||
private User user;
|
||||
private ClientFactory clientFactory;
|
||||
private WeakReference<ChooseTemplateDialogFragment> chooseTemplateDialogFragmentWeakReference;
|
||||
private Creator creator;
|
||||
|
||||
FetchTemplateTask(ChooseTemplateDialogFragment chooseTemplateDialogFragment, OwnCloudClient client) {
|
||||
this.client = client;
|
||||
FetchTemplateTask(ChooseTemplateDialogFragment chooseTemplateDialogFragment,
|
||||
ClientFactory clientFactory,
|
||||
User user,
|
||||
Creator creator) {
|
||||
this.user = user;
|
||||
this.clientFactory = clientFactory;
|
||||
this.chooseTemplateDialogFragmentWeakReference = new WeakReference<>(chooseTemplateDialogFragment);
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Template> doInBackground(Type... type) {
|
||||
FetchTemplateOperation fetchTemplateOperation = new FetchTemplateOperation(type[0]);
|
||||
RemoteOperationResult result = fetchTemplateOperation.execute(client);
|
||||
protected TemplateList doInBackground(Void... voids) {
|
||||
|
||||
if (!result.isSuccess()) {
|
||||
return new ArrayList<>();
|
||||
try {
|
||||
OwnCloudClient client = clientFactory.create(user);
|
||||
RemoteOperationResult result = new DirectEditingObtainListOfTemplatesRemoteOperation(creator.getEditor(),
|
||||
creator.getId())
|
||||
.execute(client);
|
||||
|
||||
if (!result.isSuccess()) {
|
||||
return new TemplateList();
|
||||
}
|
||||
|
||||
return (TemplateList) result.getSingleData();
|
||||
} catch (ClientFactory.CreationException e) {
|
||||
Log_OC.e(TAG, "Could not fetch template", e);
|
||||
|
||||
return new TemplateList();
|
||||
}
|
||||
|
||||
List<Template> templateList = new ArrayList<>();
|
||||
for (Object object : result.getData()) {
|
||||
templateList.add((Template) object);
|
||||
}
|
||||
|
||||
return templateList;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<Template> templateList) {
|
||||
protected void onPostExecute(TemplateList templateList) {
|
||||
ChooseTemplateDialogFragment fragment = chooseTemplateDialogFragmentWeakReference.get();
|
||||
|
||||
if (fragment != null) {
|
||||
if (templateList.isEmpty()) {
|
||||
if (fragment != null && fragment.isAdded()) {
|
||||
if (templateList.templates.isEmpty()) {
|
||||
DisplayUtils.showSnackMessage(fragment.listView, R.string.error_retrieving_templates);
|
||||
} else {
|
||||
fragment.setTemplateList(templateList);
|
||||
|
||||
String name = DOT + templateList.get(0).getExtension();
|
||||
String name = DOT + templateList.templates.values().iterator().next().getExtension();
|
||||
fragment.fileName.setText(name);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -45,6 +45,7 @@ import android.widget.TextView;
|
|||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.nextcloud.client.account.UserAccountManager;
|
||||
import com.nextcloud.client.device.DeviceInfo;
|
||||
import com.nextcloud.client.di.Injectable;
|
||||
import com.nextcloud.client.network.ConnectivityService;
|
||||
import com.nextcloud.client.preferences.AppPreferences;
|
||||
|
@ -152,6 +153,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
|
|||
@Inject AppPreferences preferences;
|
||||
@Inject ConnectivityService connectivityService;
|
||||
@Inject UserAccountManager accountManager;
|
||||
@Inject DeviceInfo deviceInfo;
|
||||
|
||||
/**
|
||||
* Public factory method to create new FileDetailFragment instances.
|
||||
|
@ -418,7 +420,9 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
|
|||
currentAccount,
|
||||
containerActivity,
|
||||
getActivity(),
|
||||
false
|
||||
false,
|
||||
deviceInfo,
|
||||
accountManager.getUser()
|
||||
);
|
||||
|
||||
mf.filter(menu,
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
package com.owncloud.android.ui.fragment;
|
||||
|
||||
import com.owncloud.android.lib.common.Creator;
|
||||
|
||||
/**
|
||||
* Actions interface to be implemented by any class that makes use of
|
||||
* {@link com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog}.
|
||||
|
@ -59,4 +61,9 @@ public interface OCFileListBottomSheetActions {
|
|||
* offers direct camera upload to the current folder.
|
||||
*/
|
||||
void directCameraUpload();
|
||||
|
||||
/**
|
||||
* open template selection for creator @link Creator
|
||||
*/
|
||||
void showTemplate(Creator creator);
|
||||
}
|
||||
|
|
|
@ -20,19 +20,28 @@
|
|||
|
||||
package com.owncloud.android.ui.fragment;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.google.gson.Gson;
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.nextcloud.client.device.DeviceInfo;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProvider;
|
||||
import com.owncloud.android.lib.common.Creator;
|
||||
import com.owncloud.android.lib.common.DirectEditing;
|
||||
import com.owncloud.android.lib.resources.status.OCCapability;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
import com.owncloud.android.utils.MimeTypeUtil;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
|
||||
import butterknife.BindView;
|
||||
|
@ -60,6 +69,9 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog {
|
|||
@BindView(R.id.templates)
|
||||
public View templates;
|
||||
|
||||
@BindView(R.id.creators)
|
||||
public LinearLayout creators;
|
||||
|
||||
@BindView(R.id.menu_direct_camera_upload)
|
||||
public View cameraView;
|
||||
|
||||
|
@ -67,14 +79,17 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog {
|
|||
private OCFileListBottomSheetActions actions;
|
||||
private FileActivity fileActivity;
|
||||
private DeviceInfo deviceInfo;
|
||||
private User user;
|
||||
|
||||
public OCFileListBottomSheetDialog(FileActivity fileActivity,
|
||||
OCFileListBottomSheetActions actions,
|
||||
DeviceInfo deviceInfo) {
|
||||
DeviceInfo deviceInfo,
|
||||
User user) {
|
||||
super(fileActivity);
|
||||
this.actions = actions;
|
||||
this.fileActivity = fileActivity;
|
||||
this.deviceInfo = deviceInfo;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -105,6 +120,37 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog {
|
|||
templates.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
String json = new ArbitraryDataProvider(getContext().getContentResolver())
|
||||
.getValue(user.toPlatformAccount(), ArbitraryDataProvider.DIRECT_EDITING);
|
||||
|
||||
if (!json.isEmpty()) {
|
||||
DirectEditing directEditing = new Gson().fromJson(json, DirectEditing.class);
|
||||
|
||||
if (!directEditing.getCreators().isEmpty()) {
|
||||
creators.setVisibility(View.VISIBLE);
|
||||
|
||||
LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
for (Creator creator : directEditing.getCreators().values()) {
|
||||
View creatorView = vi.inflate(R.layout.file_list_actions_bottom_sheet_creator, null);
|
||||
((TextView) creatorView.findViewById(R.id.creator_name)).setText(creator.getName());
|
||||
ImageView thumbnail = creatorView.findViewById(R.id.creator_thumbnail);
|
||||
|
||||
thumbnail.setImageDrawable(MimeTypeUtil.getFileTypeIcon(creator.getMimetype(),
|
||||
creator.getExtension(),
|
||||
user.toPlatformAccount(),
|
||||
getContext()));
|
||||
|
||||
creatorView.setOnClickListener(v -> {
|
||||
actions.showTemplate(creator);
|
||||
dismiss();
|
||||
});
|
||||
|
||||
creators.addView(creatorView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!deviceInfo.hasCamera(getContext())) {
|
||||
cameraView.setVisibility(View.GONE);
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager;
|
|||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.VirtualFolderType;
|
||||
import com.owncloud.android.files.FileMenuFilter;
|
||||
import com.owncloud.android.lib.common.Creator;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
|
@ -74,6 +75,7 @@ import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
|
|||
import com.owncloud.android.ui.activity.ToolbarActivity;
|
||||
import com.owncloud.android.ui.activity.UploadFilesActivity;
|
||||
import com.owncloud.android.ui.adapter.OCFileListAdapter;
|
||||
import com.owncloud.android.ui.dialog.ChooseRichDocumentsTemplateDialogFragment;
|
||||
import com.owncloud.android.ui.dialog.ChooseTemplateDialogFragment;
|
||||
import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
|
||||
import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
|
||||
|
@ -396,9 +398,11 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
*/
|
||||
private void registerFabListener() {
|
||||
FileActivity activity = (FileActivity) getActivity();
|
||||
getFabMain().setOnClickListener(v -> {
|
||||
new OCFileListBottomSheetDialog(activity, this, deviceInfo).show();
|
||||
});
|
||||
getFabMain().setOnClickListener(v -> new OCFileListBottomSheetDialog(activity,
|
||||
this,
|
||||
deviceInfo,
|
||||
accountManager.getUser())
|
||||
.show());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -470,7 +474,9 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
Collections.singleton(file),
|
||||
currentAccount,
|
||||
mContainerActivity, getActivity(),
|
||||
true);
|
||||
true,
|
||||
deviceInfo,
|
||||
accountManager.getUser());
|
||||
mf.filter(popup.getMenu(),
|
||||
true,
|
||||
accountManager.isMediaStreamingSupported(currentAccount));
|
||||
|
@ -484,19 +490,22 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
|
||||
@Override
|
||||
public void newDocument() {
|
||||
ChooseTemplateDialogFragment.newInstance(mFile, ChooseTemplateDialogFragment.Type.DOCUMENT)
|
||||
ChooseRichDocumentsTemplateDialogFragment.newInstance(mFile,
|
||||
ChooseRichDocumentsTemplateDialogFragment.Type.DOCUMENT)
|
||||
.show(requireActivity().getSupportFragmentManager(), DIALOG_CREATE_DOCUMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newSpreadsheet() {
|
||||
ChooseTemplateDialogFragment.newInstance(mFile, ChooseTemplateDialogFragment.Type.SPREADSHEET)
|
||||
ChooseRichDocumentsTemplateDialogFragment.newInstance(mFile,
|
||||
ChooseRichDocumentsTemplateDialogFragment.Type.SPREADSHEET)
|
||||
.show(requireActivity().getSupportFragmentManager(), DIALOG_CREATE_DOCUMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newPresentation() {
|
||||
ChooseTemplateDialogFragment.newInstance(mFile, ChooseTemplateDialogFragment.Type.PRESENTATION)
|
||||
ChooseRichDocumentsTemplateDialogFragment.newInstance(mFile,
|
||||
ChooseRichDocumentsTemplateDialogFragment.Type.PRESENTATION)
|
||||
.show(requireActivity().getSupportFragmentManager(), DIALOG_CREATE_DOCUMENT);
|
||||
}
|
||||
|
||||
|
@ -505,6 +514,12 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
((FileDisplayActivity) mContainerActivity).startRichWorkspacePreview(getCurrentFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showTemplate(Creator creator) {
|
||||
ChooseTemplateDialogFragment.newInstance(mFile, creator).show(requireActivity().getSupportFragmentManager(),
|
||||
DIALOG_CREATE_DOCUMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for multiple selection mode.
|
||||
* <p>
|
||||
|
@ -614,12 +629,14 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
mode.setTitle(title);
|
||||
Account currentAccount = ((FileActivity) getActivity()).getAccount();
|
||||
FileMenuFilter mf = new FileMenuFilter(
|
||||
mAdapter.getFiles().size(),
|
||||
checkedFiles,
|
||||
currentAccount,
|
||||
mContainerActivity,
|
||||
getActivity(),
|
||||
false
|
||||
mAdapter.getFiles().size(),
|
||||
checkedFiles,
|
||||
currentAccount,
|
||||
mContainerActivity,
|
||||
getActivity(),
|
||||
false,
|
||||
deviceInfo,
|
||||
accountManager.getUser()
|
||||
);
|
||||
|
||||
mf.filter(menu,
|
||||
|
@ -954,7 +971,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
// stream media preview on >= NC14
|
||||
((FileDisplayActivity) mContainerActivity).startMediaPreview(file, 0, true, true, true);
|
||||
} else if (FileMenuFilter.isEditorAvailable(requireContext().getContentResolver(),
|
||||
account.toPlatformAccount(),
|
||||
accountManager.getUser(),
|
||||
file.getMimeType()) &&
|
||||
android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
mContainerActivity.getFileOperationsHelper().openFileWithTextEditor(file, getContext());
|
||||
|
@ -1030,7 +1047,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
// should not be necessary, as menu item is filtered, but better play safe
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (FileMenuFilter.isEditorAvailable(requireContext().getContentResolver(),
|
||||
account,
|
||||
accountManager.getUser(),
|
||||
singleFile.getMimeType())) {
|
||||
mContainerActivity.getFileOperationsHelper().openFileWithTextEditor(singleFile,
|
||||
getContext());
|
||||
|
|
|
@ -54,6 +54,7 @@ import com.caverock.androidsvg.SVGParseException;
|
|||
import com.github.chrisbanes.photoview.PhotoView;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.nextcloud.client.account.UserAccountManager;
|
||||
import com.nextcloud.client.device.DeviceInfo;
|
||||
import com.nextcloud.client.di.Injectable;
|
||||
import com.nextcloud.client.network.ConnectivityService;
|
||||
import com.owncloud.android.MainApp;
|
||||
|
@ -127,6 +128,7 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
|
|||
|
||||
@Inject ConnectivityService connectivityService;
|
||||
@Inject UserAccountManager accountManager;
|
||||
@Inject DeviceInfo deviceInfo;
|
||||
|
||||
/**
|
||||
* Public factory method to create a new fragment that previews an image.
|
||||
|
@ -331,11 +333,13 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
|
|||
|
||||
Account currentAccount = containerActivity.getStorageManager().getAccount();
|
||||
FileMenuFilter mf = new FileMenuFilter(
|
||||
getFile(),
|
||||
currentAccount,
|
||||
getFile(),
|
||||
currentAccount,
|
||||
containerActivity,
|
||||
getActivity(),
|
||||
false
|
||||
getActivity(),
|
||||
false,
|
||||
deviceInfo,
|
||||
accountManager.getUser()
|
||||
);
|
||||
|
||||
mf.filter(menu,
|
||||
|
|
|
@ -53,6 +53,7 @@ import android.widget.TextView;
|
|||
import android.widget.VideoView;
|
||||
|
||||
import com.nextcloud.client.account.UserAccountManager;
|
||||
import com.nextcloud.client.device.DeviceInfo;
|
||||
import com.nextcloud.client.di.Injectable;
|
||||
import com.nextcloud.client.media.ErrorFormat;
|
||||
import com.nextcloud.client.media.PlayerServiceConnection;
|
||||
|
@ -125,6 +126,7 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
|
|||
|
||||
private Uri mVideoUri;
|
||||
@Inject UserAccountManager accountManager;
|
||||
@Inject DeviceInfo deviceInfo;
|
||||
|
||||
/**
|
||||
* Creates a fragment to preview a file.
|
||||
|
@ -348,7 +350,9 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
|
|||
currentAccount,
|
||||
containerActivity,
|
||||
getActivity(),
|
||||
false
|
||||
false,
|
||||
deviceInfo,
|
||||
accountManager.getUser()
|
||||
);
|
||||
|
||||
mf.filter(menu,
|
||||
|
|
|
@ -263,7 +263,9 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
|
|||
currentAccount,
|
||||
containerActivity,
|
||||
getActivity(),
|
||||
false
|
||||
false,
|
||||
deviceInfo,
|
||||
accountManager.getUser()
|
||||
);
|
||||
mf.filter(menu,
|
||||
true,
|
||||
|
|
|
@ -40,6 +40,7 @@ import android.widget.RelativeLayout;
|
|||
import android.widget.TextView;
|
||||
|
||||
import com.nextcloud.client.account.UserAccountManager;
|
||||
import com.nextcloud.client.device.DeviceInfo;
|
||||
import com.nextcloud.client.di.Injectable;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
|
@ -95,6 +96,7 @@ public abstract class PreviewTextFragment extends FileFragment implements Search
|
|||
private ProgressBar mMultiListProgress;
|
||||
|
||||
@Inject UserAccountManager accountManager;
|
||||
@Inject DeviceInfo deviceInfo;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
@ -172,7 +174,7 @@ public abstract class PreviewTextFragment extends FileFragment implements Search
|
|||
mTextPreview.setText(Html.fromHtml(coloredText.replace("\n", "<br \\>")));
|
||||
}
|
||||
} else {
|
||||
setText(mTextPreview, mOriginalText, getFile(), requireActivity());
|
||||
setText(mTextPreview, mOriginalText, getFile(), getActivity());
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~
|
||||
~ Nextcloud Android client application
|
||||
~
|
||||
~ @author Tobias Kaminsky
|
||||
~ Copyright (C) 2019 Tobias Kaminsky
|
||||
~ Copyright (C) 2019 Nextcloud GmbH
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU Affero General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU Affero General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU Affero General Public License
|
||||
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="@dimen/standard_padding"
|
||||
android:paddingTop="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/standard_padding"
|
||||
android:paddingBottom="@dimen/standard_padding"
|
||||
tools:ignore="UseCompoundDrawables">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/creator_thumbnail"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/file_ppt" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/creator_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="@dimen/standard_margin"
|
||||
android:layout_marginLeft="@dimen/standard_margin"
|
||||
android:text="@string/create_new_presentation"
|
||||
android:textColor="@color/text_color"
|
||||
android:textSize="@dimen/bottom_sheet_text_size" />
|
||||
</LinearLayout>
|
|
@ -281,4 +281,22 @@
|
|||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/creators"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginLeft="@dimen/standard_margin"
|
||||
android:layout_marginTop="@dimen/standard_half_margin"
|
||||
android:layout_marginRight="@dimen/standard_margin"
|
||||
android:layout_marginBottom="@dimen/standard_half_margin"
|
||||
android:background="@color/list_divider_background" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -908,4 +908,5 @@
|
|||
<string name="file">file</string>
|
||||
<string name="share_internal_link">Share internal link</string>
|
||||
<string name="action_edit">Edit</string>
|
||||
<string name="failed_to_start_editor">Failed to start editor</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue