mirror of
https://github.com/nextcloud/android.git
synced 2024-11-27 09:39:25 +03:00
Merge pull request #10307 from nextcloud/fix/choosetemplate-button-nullpointer
Fix NPE in ChooseTemplateDialogFragment
This commit is contained in:
commit
3fd8928327
3 changed files with 412 additions and 452 deletions
|
@ -1,451 +0,0 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* @author Chris Narkiewicz
|
||||
*
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.dialog;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.widget.Button;
|
||||
|
||||
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.databinding.ChooseTemplateBinding;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
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.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.theme.ThemeButtonUtils;
|
||||
import com.owncloud.android.utils.theme.ThemeColorUtils;
|
||||
import com.owncloud.android.utils.theme.ThemeDrawableUtils;
|
||||
import com.owncloud.android.utils.theme.ThemeTextInputUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
/**
|
||||
* Dialog to show templates for new documents/spreadsheets/presentations.
|
||||
*/
|
||||
public class ChooseTemplateDialogFragment extends DialogFragment implements View.OnClickListener,
|
||||
TemplateAdapter.ClickListener, Injectable {
|
||||
|
||||
private static final String ARG_PARENT_FOLDER = "PARENT_FOLDER";
|
||||
private static final String ARG_CREATOR = "CREATOR";
|
||||
private static final String ARG_HEADLINE = "HEADLINE";
|
||||
private static final String TAG = ChooseTemplateDialogFragment.class.getSimpleName();
|
||||
private static final String DOT = ".";
|
||||
public static final int SINGLE_TEMPLATE = 1;
|
||||
|
||||
@Inject ClientFactory clientFactory;
|
||||
@Inject CurrentAccountProvider currentAccount;
|
||||
@Inject ThemeColorUtils themeColorUtils;
|
||||
@Inject ThemeDrawableUtils themeDrawableUtils;
|
||||
@Inject ThemeButtonUtils themeButtonUtils;
|
||||
@Inject ThemeTextInputUtils themeTextInputUtils;
|
||||
private TemplateAdapter adapter;
|
||||
private OCFile parentFolder;
|
||||
private String title;
|
||||
private Button positiveButton;
|
||||
private Creator creator;
|
||||
|
||||
public enum Type {
|
||||
DOCUMENT,
|
||||
SPREADSHEET,
|
||||
PRESENTATION
|
||||
}
|
||||
|
||||
ChooseTemplateBinding binding;
|
||||
|
||||
public static ChooseTemplateDialogFragment newInstance(OCFile parentFolder, Creator creator, String headline) {
|
||||
ChooseTemplateDialogFragment frag = new ChooseTemplateDialogFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable(ARG_PARENT_FOLDER, parentFolder);
|
||||
args.putParcelable(ARG_CREATOR, creator);
|
||||
args.putString(ARG_HEADLINE, headline);
|
||||
frag.setArguments(args);
|
||||
return frag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
AlertDialog alertDialog = (AlertDialog) getDialog();
|
||||
|
||||
positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
themeButtonUtils.themeBorderlessButton(themeColorUtils,
|
||||
positiveButton,
|
||||
alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL));
|
||||
positiveButton.setOnClickListener(this);
|
||||
positiveButton.setEnabled(false);
|
||||
|
||||
checkEnablingCreateButton();
|
||||
}
|
||||
|
||||
@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");
|
||||
}
|
||||
|
||||
parentFolder = arguments.getParcelable(ARG_PARENT_FOLDER);
|
||||
creator = arguments.getParcelable(ARG_CREATOR);
|
||||
title = arguments.getString(ARG_HEADLINE, getString(R.string.select_template));
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
title = arguments.getString(ARG_HEADLINE);
|
||||
} else {
|
||||
title = savedInstanceState.getString(ARG_HEADLINE);
|
||||
}
|
||||
|
||||
// Inflate the layout for the dialog
|
||||
LayoutInflater inflater = requireActivity().getLayoutInflater();
|
||||
binding = ChooseTemplateBinding.inflate(inflater, null, false);
|
||||
View view = binding.getRoot();
|
||||
|
||||
binding.filename.requestFocus();
|
||||
themeTextInputUtils.colorTextInput(binding.filenameContainer,
|
||||
binding.filename,
|
||||
themeColorUtils.primaryColor(getContext()));
|
||||
|
||||
binding.filename.setOnKeyListener((v, keyCode, event) -> {
|
||||
checkEnablingCreateButton();
|
||||
return false;
|
||||
});
|
||||
|
||||
binding.filename.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
// generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
checkEnablingCreateButton();
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
User user = currentAccount.getUser();
|
||||
new FetchTemplateTask(this, clientFactory, user, creator).execute();
|
||||
} catch (Exception e) {
|
||||
Log_OC.e(TAG, "Loading stream url not possible: " + e);
|
||||
}
|
||||
|
||||
binding.list.setHasFixedSize(true);
|
||||
binding.list.setLayoutManager(new GridLayoutManager(activity, 2));
|
||||
adapter = new TemplateAdapter(creator.getMimetype(),
|
||||
this,
|
||||
getContext(),
|
||||
currentAccount,
|
||||
clientFactory,
|
||||
themeColorUtils,
|
||||
themeDrawableUtils);
|
||||
binding.list.setAdapter(adapter);
|
||||
|
||||
// Build the dialog
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setView(view)
|
||||
.setPositiveButton(R.string.create, null)
|
||||
.setNeutralButton(R.string.common_cancel, null)
|
||||
.setTitle(title);
|
||||
Dialog dialog = builder.create();
|
||||
|
||||
Window window = dialog.getWindow();
|
||||
|
||||
if (window != null) {
|
||||
window.setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
||||
}
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
|
||||
super.onSaveInstanceState(savedInstanceState);
|
||||
savedInstanceState.putString(ARG_HEADLINE, title);
|
||||
}
|
||||
|
||||
private void createFromTemplate(Template template, String path) {
|
||||
new CreateFileFromTemplateTask(this, clientFactory, currentAccount.getUser(), template, path, creator).execute();
|
||||
}
|
||||
|
||||
public void setTemplateList(TemplateList templateList) {
|
||||
adapter.setTemplateList(templateList);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(Template template) {
|
||||
onTemplateChosen(template);
|
||||
}
|
||||
|
||||
private void onTemplateChosen(Template template) {
|
||||
adapter.setTemplateAsActive(template);
|
||||
prefillFilenameIfEmpty(template);
|
||||
checkEnablingCreateButton();
|
||||
}
|
||||
|
||||
private void prefillFilenameIfEmpty(Template template) {
|
||||
String name = binding.filename.getText().toString();
|
||||
if (name.isEmpty() || name.equalsIgnoreCase(DOT + template.getExtension())) {
|
||||
binding.filename.setText(String.format("%s.%s", template.getTitle(), template.getExtension()));
|
||||
name = binding.filename.getText().toString();
|
||||
int dotPos = name.lastIndexOf('.');
|
||||
binding.filename.setSelection((dotPos != -1) ? dotPos : name.length());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String name = binding.filename.getText().toString();
|
||||
String path = parentFolder.getRemotePath() + name;
|
||||
|
||||
Template selectedTemplate = adapter.getSelectedTemplate();
|
||||
|
||||
if (selectedTemplate == null) {
|
||||
DisplayUtils.showSnackMessage(binding.list, R.string.select_one_template);
|
||||
} else if (name.isEmpty() || name.equalsIgnoreCase(DOT + selectedTemplate.getExtension())) {
|
||||
DisplayUtils.showSnackMessage(binding.list, R.string.enter_filename);
|
||||
} else if (!name.endsWith(selectedTemplate.getExtension())) {
|
||||
createFromTemplate(selectedTemplate, path + DOT + selectedTemplate.getExtension());
|
||||
} else {
|
||||
createFromTemplate(selectedTemplate, path);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkEnablingCreateButton() {
|
||||
Template selectedTemplate = adapter.getSelectedTemplate();
|
||||
String name = binding.filename.getText().toString();
|
||||
|
||||
positiveButton.setEnabled(selectedTemplate != null && !name.isEmpty() &&
|
||||
!name.equalsIgnoreCase(DOT + selectedTemplate.getExtension()));
|
||||
}
|
||||
|
||||
private static class CreateFileFromTemplateTask extends AsyncTask<Void, Void, String> {
|
||||
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,
|
||||
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) {
|
||||
try {
|
||||
OwnCloudClient client = clientFactory.create(user);
|
||||
|
||||
RemoteOperationResult<String> result =
|
||||
new DirectEditingCreateFileRemoteOperation(path,
|
||||
creator.getEditor(),
|
||||
creator.getId(),
|
||||
template.getTitle()).execute(client);
|
||||
if (!result.isSuccess()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
RemoteOperationResult newFileResult = new ReadFileRemoteOperation(path).execute(client);
|
||||
if (!newFileResult.isSuccess()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
final ChooseTemplateDialogFragment fragment = chooseTemplateDialogFragmentWeakReference.get();
|
||||
if (fragment == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
final Context context = fragment.getContext();
|
||||
if (context == null) {
|
||||
// fragment has been detached
|
||||
return "";
|
||||
}
|
||||
|
||||
FileDataStorageManager storageManager = new FileDataStorageManager(user,
|
||||
context.getContentResolver());
|
||||
|
||||
OCFile temp = FileStorageUtils.fillOCFile((RemoteFile) newFileResult.getData().get(0));
|
||||
storageManager.saveFile(temp);
|
||||
file = storageManager.getFileByPath(path);
|
||||
|
||||
return result.getResultData();
|
||||
|
||||
} catch (ClientFactory.CreationException e) {
|
||||
Log_OC.e(TAG, "Error creating file from template!", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String url) {
|
||||
final ChooseTemplateDialogFragment fragment = chooseTemplateDialogFragmentWeakReference.get();
|
||||
|
||||
if (fragment != null && fragment.isAdded()) {
|
||||
if (url.isEmpty()) {
|
||||
DisplayUtils.showSnackMessage(fragment.binding.list, "Error creating file from template");
|
||||
} else {
|
||||
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 {
|
||||
Log_OC.e(TAG, "Error creating file from template!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class FetchTemplateTask extends AsyncTask<Void, Void, TemplateList> {
|
||||
|
||||
private User user;
|
||||
private ClientFactory clientFactory;
|
||||
private WeakReference<ChooseTemplateDialogFragment> chooseTemplateDialogFragmentWeakReference;
|
||||
private Creator creator;
|
||||
|
||||
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 TemplateList doInBackground(Void... voids) {
|
||||
|
||||
try {
|
||||
OwnCloudClient client = clientFactory.create(user);
|
||||
RemoteOperationResult<TemplateList> result =
|
||||
new DirectEditingObtainListOfTemplatesRemoteOperation(creator.getEditor(),
|
||||
creator.getId())
|
||||
.execute(client);
|
||||
|
||||
if (!result.isSuccess()) {
|
||||
return new TemplateList();
|
||||
}
|
||||
|
||||
return result.getResultData();
|
||||
} catch (ClientFactory.CreationException e) {
|
||||
Log_OC.e(TAG, "Could not fetch template", e);
|
||||
|
||||
return new TemplateList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(TemplateList templateList) {
|
||||
ChooseTemplateDialogFragment fragment = chooseTemplateDialogFragmentWeakReference.get();
|
||||
|
||||
if (fragment != null && fragment.isAdded()) {
|
||||
if (templateList.getTemplates().isEmpty()) {
|
||||
DisplayUtils.showSnackMessage(fragment.binding.list, R.string.error_retrieving_templates);
|
||||
} else {
|
||||
if (templateList.getTemplates().size() == SINGLE_TEMPLATE) {
|
||||
fragment.onTemplateChosen(templateList.getTemplates().values().iterator().next());
|
||||
fragment.binding.list.setVisibility(View.GONE);
|
||||
} else {
|
||||
String name = DOT + templateList.getTemplates().values().iterator().next().getExtension();
|
||||
fragment.binding.filename.setText(name);
|
||||
fragment.binding.helperText.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
fragment.setTemplateList(templateList);
|
||||
}
|
||||
} else {
|
||||
Log_OC.e(TAG, "Error streaming file: no previewMediaFragment!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* @author Chris Narkiewicz
|
||||
*
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.Button
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
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.nextcloud.client.network.ClientFactory.CreationException
|
||||
import com.owncloud.android.MainApp
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.databinding.ChooseTemplateBinding
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager
|
||||
import com.owncloud.android.datamodel.OCFile
|
||||
import com.owncloud.android.lib.common.Creator
|
||||
import com.owncloud.android.lib.common.Template
|
||||
import com.owncloud.android.lib.common.TemplateList
|
||||
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.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.theme.ThemeButtonUtils
|
||||
import com.owncloud.android.utils.theme.ThemeColorUtils
|
||||
import com.owncloud.android.utils.theme.ThemeDrawableUtils
|
||||
import com.owncloud.android.utils.theme.ThemeTextInputUtils
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Dialog to show templates for new documents/spreadsheets/presentations.
|
||||
*/
|
||||
class ChooseTemplateDialogFragment : DialogFragment(), View.OnClickListener, TemplateAdapter.ClickListener, Injectable {
|
||||
|
||||
@Inject
|
||||
lateinit var clientFactory: ClientFactory
|
||||
|
||||
@Inject
|
||||
lateinit var currentAccount: CurrentAccountProvider
|
||||
|
||||
@Inject
|
||||
lateinit var themeColorUtils: ThemeColorUtils
|
||||
|
||||
@Inject
|
||||
lateinit var themeDrawableUtils: ThemeDrawableUtils
|
||||
|
||||
@Inject
|
||||
lateinit var themeButtonUtils: ThemeButtonUtils
|
||||
|
||||
@Inject
|
||||
lateinit var themeTextInputUtils: ThemeTextInputUtils
|
||||
|
||||
private var adapter: TemplateAdapter? = null
|
||||
private var parentFolder: OCFile? = null
|
||||
private var title: String? = null
|
||||
private var positiveButton: Button? = null
|
||||
private var creator: Creator? = null
|
||||
|
||||
enum class Type {
|
||||
DOCUMENT, SPREADSHEET, PRESENTATION
|
||||
}
|
||||
|
||||
private var _binding: ChooseTemplateBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val alertDialog = dialog as AlertDialog
|
||||
val button = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||
|
||||
themeButtonUtils.themeBorderlessButton(
|
||||
themeColorUtils,
|
||||
button,
|
||||
alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)
|
||||
)
|
||||
button.setOnClickListener(this)
|
||||
button.isEnabled = false
|
||||
|
||||
positiveButton = button
|
||||
checkEnablingCreateButton()
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val arguments = arguments ?: throw IllegalArgumentException("Arguments may not be null")
|
||||
val activity = activity ?: throw IllegalArgumentException("Activity may not be null")
|
||||
|
||||
parentFolder = arguments.getParcelable(ARG_PARENT_FOLDER)
|
||||
creator = arguments.getParcelable(ARG_CREATOR)
|
||||
title = arguments.getString(ARG_HEADLINE, getString(R.string.select_template))
|
||||
title = when (savedInstanceState) {
|
||||
null -> arguments.getString(ARG_HEADLINE)
|
||||
else -> savedInstanceState.getString(ARG_HEADLINE)
|
||||
}
|
||||
|
||||
// Inflate the layout for the dialog
|
||||
val inflater = requireActivity().layoutInflater
|
||||
_binding = ChooseTemplateBinding.inflate(inflater, null, false)
|
||||
val view: View = binding.root
|
||||
|
||||
binding.filename.requestFocus()
|
||||
themeTextInputUtils.colorTextInput(
|
||||
binding.filenameContainer,
|
||||
binding.filename,
|
||||
themeColorUtils.primaryColor(context)
|
||||
)
|
||||
binding.filename.setOnKeyListener { _, _, _ ->
|
||||
checkEnablingCreateButton()
|
||||
false
|
||||
}
|
||||
binding.filename.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit
|
||||
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) = Unit
|
||||
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
checkEnablingCreateButton()
|
||||
}
|
||||
})
|
||||
|
||||
fetchTemplate()
|
||||
|
||||
binding.list.setHasFixedSize(true)
|
||||
binding.list.layoutManager = GridLayoutManager(activity, 2)
|
||||
adapter = TemplateAdapter(
|
||||
creator!!.mimetype,
|
||||
this,
|
||||
context,
|
||||
currentAccount,
|
||||
clientFactory,
|
||||
themeColorUtils,
|
||||
themeDrawableUtils
|
||||
)
|
||||
binding.list.adapter = adapter
|
||||
|
||||
// Build the dialog
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
builder.setView(view)
|
||||
.setPositiveButton(R.string.create, null)
|
||||
.setNeutralButton(R.string.common_cancel, null)
|
||||
.setTitle(title)
|
||||
val dialog: Dialog = builder.create()
|
||||
val window = dialog.window
|
||||
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
|
||||
return dialog
|
||||
}
|
||||
|
||||
@Suppress("TooGenericExceptionCaught") // legacy code
|
||||
private fun fetchTemplate() {
|
||||
try {
|
||||
val user = currentAccount.user
|
||||
FetchTemplateTask(this, clientFactory, user, creator).execute()
|
||||
} catch (e: Exception) {
|
||||
Log_OC.e(TAG, "Loading stream url not possible: $e")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||
super.onSaveInstanceState(savedInstanceState)
|
||||
savedInstanceState.putString(ARG_HEADLINE, title)
|
||||
}
|
||||
|
||||
private fun createFromTemplate(template: Template, path: String) {
|
||||
CreateFileFromTemplateTask(this, clientFactory, currentAccount.user, template, path, creator).execute()
|
||||
}
|
||||
|
||||
fun setTemplateList(templateList: TemplateList?) {
|
||||
adapter!!.setTemplateList(templateList)
|
||||
adapter!!.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onClick(template: Template) {
|
||||
onTemplateChosen(template)
|
||||
}
|
||||
|
||||
private fun onTemplateChosen(template: Template) {
|
||||
adapter!!.setTemplateAsActive(template)
|
||||
prefillFilenameIfEmpty(template)
|
||||
checkEnablingCreateButton()
|
||||
}
|
||||
|
||||
private fun prefillFilenameIfEmpty(template: Template) {
|
||||
var name = binding.filename.text.toString()
|
||||
if (name.isEmpty() || name.equals(DOT + template.extension, ignoreCase = true)) {
|
||||
binding.filename.setText(String.format("%s.%s", template.title, template.extension))
|
||||
name = binding.filename.text.toString()
|
||||
val dotPos = name.lastIndexOf('.')
|
||||
binding.filename.setSelection(if (dotPos != -1) dotPos else name.length)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
val name = binding.filename.text.toString()
|
||||
val path = parentFolder!!.remotePath + name
|
||||
|
||||
val selectedTemplate = adapter!!.selectedTemplate
|
||||
|
||||
if (selectedTemplate == null) {
|
||||
DisplayUtils.showSnackMessage(binding.list, R.string.select_one_template)
|
||||
} else if (name.isEmpty() || name.equals(DOT + selectedTemplate.extension, ignoreCase = true)) {
|
||||
DisplayUtils.showSnackMessage(binding.list, R.string.enter_filename)
|
||||
} else if (!name.endsWith(selectedTemplate.extension)) {
|
||||
createFromTemplate(selectedTemplate, path + DOT + selectedTemplate.extension)
|
||||
} else {
|
||||
createFromTemplate(selectedTemplate, path)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkEnablingCreateButton() {
|
||||
if (positiveButton != null) {
|
||||
val selectedTemplate = adapter!!.selectedTemplate
|
||||
val name = binding.filename.text.toString()
|
||||
positiveButton!!.isEnabled = selectedTemplate != null && name.isNotEmpty() &&
|
||||
!name.equals(DOT + selectedTemplate.extension, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList") // legacy code
|
||||
private class CreateFileFromTemplateTask(
|
||||
chooseTemplateDialogFragment: ChooseTemplateDialogFragment,
|
||||
private val clientFactory: ClientFactory?,
|
||||
user: User,
|
||||
template: Template,
|
||||
path: String,
|
||||
creator: Creator?
|
||||
) : AsyncTask<Void, Void, String>() {
|
||||
private val chooseTemplateDialogFragmentWeakReference: WeakReference<ChooseTemplateDialogFragment>
|
||||
private val template: Template
|
||||
private val path: String
|
||||
private val creator: Creator?
|
||||
private val user: User
|
||||
private var file: OCFile? = null
|
||||
|
||||
@Suppress("ReturnCount") // legacy code
|
||||
override fun doInBackground(vararg params: Void): String {
|
||||
return try {
|
||||
val client = clientFactory!!.create(user)
|
||||
val result = DirectEditingCreateFileRemoteOperation(
|
||||
path,
|
||||
creator!!.editor,
|
||||
creator.id,
|
||||
template.title
|
||||
).execute(client)
|
||||
if (!result.isSuccess) {
|
||||
return ""
|
||||
}
|
||||
val newFileResult = ReadFileRemoteOperation(path).execute(client)
|
||||
if (!newFileResult.isSuccess) {
|
||||
return ""
|
||||
}
|
||||
val fragment = chooseTemplateDialogFragmentWeakReference.get() ?: return ""
|
||||
val context = fragment.context
|
||||
?: // fragment has been detached
|
||||
return ""
|
||||
val storageManager = FileDataStorageManager(
|
||||
user,
|
||||
context.contentResolver
|
||||
)
|
||||
val temp = FileStorageUtils.fillOCFile(newFileResult.data[0] as RemoteFile)
|
||||
storageManager.saveFile(temp)
|
||||
file = storageManager.getFileByPath(path)
|
||||
result.resultData
|
||||
} catch (e: CreationException) {
|
||||
Log_OC.e(TAG, "Error creating file from template!", e)
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPostExecute(url: String) {
|
||||
val fragment = chooseTemplateDialogFragmentWeakReference.get()
|
||||
if (fragment != null && fragment.isAdded) {
|
||||
if (url.isEmpty()) {
|
||||
DisplayUtils.showSnackMessage(fragment.binding.list, "Error creating file from template")
|
||||
} else {
|
||||
val editorWebView = Intent(MainApp.getAppContext(), TextEditorWebView::class.java)
|
||||
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 {
|
||||
Log_OC.e(TAG, "Error creating file from template!")
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
chooseTemplateDialogFragmentWeakReference = WeakReference(chooseTemplateDialogFragment)
|
||||
this.template = template
|
||||
this.path = path
|
||||
this.creator = creator
|
||||
this.user = user
|
||||
}
|
||||
}
|
||||
|
||||
private class FetchTemplateTask(
|
||||
chooseTemplateDialogFragment: ChooseTemplateDialogFragment,
|
||||
private val clientFactory: ClientFactory?,
|
||||
private val user: User,
|
||||
creator: Creator?
|
||||
) : AsyncTask<Void, Void, TemplateList>() {
|
||||
private val chooseTemplateDialogFragmentWeakReference: WeakReference<ChooseTemplateDialogFragment>
|
||||
private val creator: Creator?
|
||||
|
||||
override fun doInBackground(vararg voids: Void): TemplateList {
|
||||
return try {
|
||||
val client = clientFactory!!.create(user)
|
||||
val result = DirectEditingObtainListOfTemplatesRemoteOperation(
|
||||
creator!!.editor,
|
||||
creator.id
|
||||
)
|
||||
.execute(client)
|
||||
if (!result.isSuccess) {
|
||||
TemplateList()
|
||||
} else result.resultData
|
||||
} catch (e: CreationException) {
|
||||
Log_OC.e(TAG, "Could not fetch template", e)
|
||||
TemplateList()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPostExecute(templateList: TemplateList) {
|
||||
val fragment = chooseTemplateDialogFragmentWeakReference.get()
|
||||
if (fragment != null && fragment.isAdded) {
|
||||
if (templateList.templates.isEmpty()) {
|
||||
DisplayUtils.showSnackMessage(fragment.binding.list, R.string.error_retrieving_templates)
|
||||
} else {
|
||||
if (templateList.templates.size == SINGLE_TEMPLATE) {
|
||||
fragment.onTemplateChosen(templateList.templates.values.iterator().next())
|
||||
fragment.binding.list.visibility = View.GONE
|
||||
} else {
|
||||
val name = DOT + templateList.templates.values.iterator().next().extension
|
||||
fragment.binding.filename.setText(name)
|
||||
fragment.binding.helperText.visibility = View.VISIBLE
|
||||
}
|
||||
fragment.setTemplateList(templateList)
|
||||
}
|
||||
} else {
|
||||
Log_OC.e(TAG, "Error streaming file: no previewMediaFragment!")
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
chooseTemplateDialogFragmentWeakReference = WeakReference(chooseTemplateDialogFragment)
|
||||
this.creator = creator
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ARG_PARENT_FOLDER = "PARENT_FOLDER"
|
||||
private const val ARG_CREATOR = "CREATOR"
|
||||
private const val ARG_HEADLINE = "HEADLINE"
|
||||
private val TAG = ChooseTemplateDialogFragment::class.java.simpleName
|
||||
private const val DOT = "."
|
||||
const val SINGLE_TEMPLATE = 1
|
||||
|
||||
@JvmStatic
|
||||
fun newInstance(parentFolder: OCFile?, creator: Creator?, headline: String?): ChooseTemplateDialogFragment {
|
||||
val frag = ChooseTemplateDialogFragment()
|
||||
val args = Bundle()
|
||||
args.putParcelable(ARG_PARENT_FOLDER, parentFolder)
|
||||
args.putParcelable(ARG_CREATOR, creator)
|
||||
args.putString(ARG_HEADLINE, headline)
|
||||
frag.arguments = args
|
||||
return frag
|
||||
}
|
||||
}
|
||||
}
|
|
@ -627,7 +627,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void showTemplate(Creator creator, String headline) {
|
||||
public void showTemplate(@NonNull Creator creator, @NonNull String headline) {
|
||||
ChooseTemplateDialogFragment.newInstance(mFile, creator, headline).show(requireActivity().getSupportFragmentManager(),
|
||||
DIALOG_CREATE_DOCUMENT);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue