Kaydet (Commit) 1503769f authored tarafından brainbreaker's avatar brainbreaker Kaydeden (comit) Tomaž Vajngerl

tdf#106325 - No way to create a new Document

This commit will add the ability to create a new document.
A FAB is used in home screen which on expansion gives
four options namely new writer document, new impress,
new Sheet or new Draw. Two new events loadNewDocument
and saveDocumentAs have been added.
Another major change includes the use of constraint layout
in LOUIActivity layout as it decreases nesting of views and
improves the app performance. This was needed because
of the new FAB layouts being added.
Support for vector drawables has been enabled.

Change-Id: Ia3ea17f73c0d8514f8ddb7b9a1cbd2ce7de6ac08
Reviewed-on: https://gerrit.libreoffice.org/35183Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarTomaž Vajngerl <quikee@gmail.com>
üst 0466d0c8
......@@ -147,7 +147,7 @@ public class Document {
public native void setClientZoom(int nTilePixelWidth, int nTilePixelHeight, int nTileTwipWidth, int nTileTwipHeight);
private native void saveAs(String url, String format, String options);
public native void saveAs(String url, String format, String options);
private native void paintTileNative(ByteBuffer buffer, int canvasWidth, int canvasHeight, int tilePositionX, int tilePositionY, int tileWidth, int tileHeight);
......
......@@ -26,6 +26,7 @@ dependencies {
compile files("${liboWorkdir}/UnpackedTarball/owncloud_android_lib/bin/owncloud-android-library.jar")
compile 'com.android.support:appcompat-v7:25.1.0'
compile 'com.android.support:design:25.1.0'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
}
android {
......@@ -64,6 +65,7 @@ android {
// ToDo: fix openssl stuff to not block targeting 23 or later
targetSdkVersion 22
manifestPlaceholders = [installLocation: "preferExternal"]
vectorDrawables.useSupportLibrary = true
}
buildTypes {
debug {
......
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<scale
android:duration="300"
android:fromXScale="0.8"
android:fromYScale="0.8"
android:interpolator="@android:anim/linear_interpolator"
android:toXScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:toYScale="0.0" />
<alpha android:fromAlpha="1.0"
android:toAlpha="0.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:duration="300"/>
</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<scale
android:duration="300"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:interpolator="@android:anim/linear_interpolator"
android:toXScale="0.8"
android:pivotX="50%"
android:pivotY="50%"
android:toYScale="0.8"/>
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:duration="300"/>
</set>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>
......@@ -16,6 +16,10 @@
<string name="about_moreinfo">More Info</string>
<string name="back_again_to_quit">Press back again to quit</string>
<string name="new_impress">New Impress</string>
<string name="new_spreadsheet">New Sheet</string>
<string name="new_draw">New Draw</string>
<string name="browser_app_name">LibreOffice Browser</string>
<string name="menu_search">Search</string>
<string name="list_view">List</string>
......@@ -89,6 +93,7 @@
<string name="message_saved">Save complete</string>
<string name="message_saving">Saving the document…</string>
<string name="message_save_incomplete">Save incomplete. Were there any changes?</string>
<string name="new_file_created">File created in Documents folder</string>
<!-- Document provider settings -->
<string name="storage_provider_settings">Storage provider settings</string>
......@@ -117,6 +122,10 @@
<string name="save_document">SAVE</string>
<string name="cancel_save_document">CANCEL</string>
<string name="no_save_document">NO</string>
<string name="new_write">New Write</string>
<string name="save_as_success">Saved file -</string>
<string name="save_as_error">Unable to create new file, please check entered file name.</string>
</resources>
......@@ -34,6 +34,8 @@ public class LOEvent implements Comparable<LOEvent> {
public static final int NAVIGATION_CLICK = 13;
public static final int UNO_COMMAND = 14;
public static final int RESUME = 15;
public static final int LOAD_NEW = 16;
public static final int SAVE_AS = 17;
public final int mType;
public int mPriority = 0;
......@@ -42,6 +44,8 @@ public class LOEvent implements Comparable<LOEvent> {
public ThumbnailCreator.ThumbnailCreationTask mTask;
public int mPartIndex;
public String mString;
public String filePath;
public String fileType;
public ComposedTileLayer mComposedTileLayer;
public String mTouchType;
public PointF mDocumentCoordinate;
......@@ -81,6 +85,19 @@ public class LOEvent implements Comparable<LOEvent> {
mPartIndex = value;
}
public LOEvent(String filePath, int type) {
mType = type;
mTypeString = "Load";
this.filePath = filePath;
}
public LOEvent(String filePath, String fileType, int type) {
mType = type;
mTypeString = "Load New/Save As";
this.filePath = filePath;
this.fileType = fileType;
}
public LOEvent(int type, int partIndex) {
mType = type;
mPartIndex = partIndex;
......
......@@ -106,8 +106,16 @@ public class LOKitShell {
LOKitShell.sendEvent(new LOEvent(LOEvent.CHANGE_PART, part));
}
public static void sendLoadEvent(String inputFile) {
LOKitShell.sendEvent(new LOEvent(LOEvent.LOAD, inputFile));
public static void sendLoadEvent(String inputFilePath) {
LOKitShell.sendEvent(new LOEvent(inputFilePath, LOEvent.LOAD));
}
public static void sendNewDocumentLoadEvent(String newDocumentPath, String newDocumentType) {
LOKitShell.sendEvent(new LOEvent(newDocumentPath, newDocumentType, LOEvent.LOAD_NEW));
}
public static void sendSaveAsEvent(String filePath, String fileFormat) {
LOKitShell.sendEvent(new LOEvent(filePath, fileFormat, LOEvent.SAVE_AS));
}
public static void sendResumeEvent(String inputFile, int partIndex) {
......
......@@ -3,9 +3,11 @@ package org.libreoffice;
import android.graphics.Bitmap;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.Log;
import android.view.KeyEvent;
import org.libreoffice.canvas.SelectionHandle;
import org.libreoffice.ui.LibreOfficeUIActivity;
import org.mozilla.gecko.gfx.CairoImage;
import org.mozilla.gecko.gfx.ComposedTileLayer;
import org.mozilla.gecko.gfx.GeckoLayerClient;
......@@ -171,8 +173,6 @@ class LOKitThread extends Thread {
} else {
closeDocument();
}
}
/**
......@@ -189,24 +189,64 @@ class LOKitThread extends Thread {
/**
* Handle load document event.
* @param filename - filename where the document is located
* @param filePath - filePath to where the document is located
*/
private void loadDocument(String filename) {
private void loadDocument(String filePath) {
mLayerClient = mContext.getLayerClient();
mInvalidationHandler = new InvalidationHandler(mContext);
mTileProvider = TileProviderFactory.create(mContext, mInvalidationHandler, filePath);
if (mTileProvider.isReady()) {
LOKitShell.showProgressSpinner(mContext);
refresh();
LOKitShell.hideProgressSpinner(mContext);
} else {
closeDocument();
}
}
/**
* Handle load new document event.
* @param filePath - filePath to where new document is to be created
* @param fileType - fileType what type of new document is to be loaded
*/
private void loadNewDocument(String filePath, String fileType) {
mLayerClient = mContext.getLayerClient();
mInvalidationHandler = new InvalidationHandler(mContext);
mTileProvider = TileProviderFactory.create(mContext, mInvalidationHandler, filename);
mTileProvider = TileProviderFactory.create(mContext, mInvalidationHandler, fileType);
if (mTileProvider.isReady()) {
LOKitShell.showProgressSpinner(mContext);
refresh();
LOKitShell.hideProgressSpinner(mContext);
if (fileType.matches(LibreOfficeUIActivity.NEW_WRITER_STRING_KEY))
mTileProvider.saveDocumentAs(filePath, "odt");
else if (fileType.matches(LibreOfficeUIActivity.NEW_CALC_STRING_KEY))
mTileProvider.saveDocumentAs(filePath, "ods");
else if (fileType.matches(LibreOfficeUIActivity.NEW_IMPRESS_STRING_KEY))
mTileProvider.saveDocumentAs(filePath, "odp");
else
mTileProvider.saveDocumentAs(filePath, "odg");
} else {
closeDocument();
}
}
/**
* Save the currently loaded document.
*/
private void saveDocumentAs(String filePath, String fileType) {
if (mTileProvider == null) {
Log.e(LOGTAG, "Error in saving, Tile Provider instance is null");
} else {
mTileProvider.saveDocumentAs(filePath, fileType);
}
}
/**
* Close the currently loaded document.
*/
......@@ -223,7 +263,13 @@ class LOKitThread extends Thread {
private void processEvent(LOEvent event) {
switch (event.mType) {
case LOEvent.LOAD:
loadDocument(event.mString);
loadDocument(event.filePath);
break;
case LOEvent.LOAD_NEW:
loadNewDocument(event.filePath, event.fileType);
break;
case LOEvent.SAVE_AS:
saveDocumentAs(event.filePath, event.fileType);
break;
case LOEvent.RESUME:
resumeDocument(event.mString, event.mPartIndex);
......
......@@ -131,6 +131,30 @@ class LOKitTileProvider implements TileProvider {
});
}
@Override
public void saveDocumentAs(String filePath, String format) {
String newFilePath = "file://" + filePath;
Log.d("saveFilePathURL", newFilePath);
mDocument.saveAs(newFilePath, format, "");
if (!mOffice.getError().isEmpty()){
Log.e("Save Error", mOffice.getError());
LOKitShell.getMainHandler().post(new Runnable() {
@Override
public void run() {
// There was some error
mContext.showSaveStatusToast(true);
}
});
}
LOKitShell.getMainHandler().post(new Runnable() {
@Override
public void run() {
// There was no error
mContext.showSaveStatusToast(false);
}
});
}
private void setupDocumentFonts() {
String values = mDocument.getCommandValues(".uno:CharFontName");
if (values == null || values.isEmpty())
......
......@@ -20,6 +20,12 @@ import org.mozilla.gecko.gfx.IntSize;
* Provides the tiles and other document information.
*/
public interface TileProvider {
/**
* Save the current document.
*/
void saveDocumentAs(String filePath, String format);
/**
* Returns the page width in pixels.
*/
......
......@@ -98,7 +98,11 @@ public class ToolbarController implements Toolbar.OnMenuItemClickListener {
mContext.showAbout();
return true;
case R.id.action_save:
mContext.saveDocument();
if (mContext.isNewDocument) {
mContext.saveAs();
} else {
mContext.saveDocument();
}
return true;
case R.id.action_parts:
mContext.openDrawer();
......
......@@ -121,7 +121,7 @@ public class FileUtilities {
extensionToMimeTypeMap.put("oth", "application/vnd.oasis.opendocument.text-web");
}
private static final String getExtension(String filename) {
public static final String getExtension(String filename) {
if (filename == null)
return "";
int nExt = filename.lastIndexOf('.');
......
......@@ -23,11 +23,14 @@ import android.hardware.usb.UsbManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
......@@ -47,7 +50,11 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.OvershootInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
......@@ -60,10 +67,12 @@ import org.libreoffice.storage.DocumentProviderFactory;
import org.libreoffice.storage.DocumentProviderSettingsActivity;
import org.libreoffice.storage.IDocumentProvider;
import org.libreoffice.storage.IFile;
import org.libreoffice.storage.local.LocalFile;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
......@@ -74,7 +83,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class LibreOfficeUIActivity extends AppCompatActivity implements SettingsListenerModel.OnSettingsPreferenceChangedListener{
public class LibreOfficeUIActivity extends AppCompatActivity implements SettingsListenerModel.OnSettingsPreferenceChangedListener, View.OnClickListener{
private String LOGTAG = LibreOfficeUIActivity.class.getSimpleName();
private SharedPreferences prefs;
private int filterMode = FileUtilities.ALL;
......@@ -98,6 +107,12 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
public static final String SORT_MODE_KEY = "SORT_MODE";
private static final String RECENT_DOCUMENTS_KEY = "RECENT_DOCUMENTS";
public static final String NEW_DOC_TYPE_KEY = "NEW_DOC_TYPE_KEY";
public static final String NEW_WRITER_STRING_KEY = "private:factory/swriter";
public static final String NEW_IMPRESS_STRING_KEY = "private:factory/simpress";
public static final String NEW_CALC_STRING_KEY = "private:factory/scalc";
public static final String NEW_DRAW_STRING_KEY = "private:factory/sdraw";
public static final int GRID_VIEW = 0;
public static final int LIST_VIEW = 1;
......@@ -110,6 +125,20 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
private boolean canQuit = false;
private Animation fabOpenAnimation;
private Animation fabCloseAnimation;
private boolean isFabMenuOpen = false;
private FloatingActionButton editFAB;
private FloatingActionButton writerFAB;
private FloatingActionButton drawFAB;
private FloatingActionButton impressFAB;
private FloatingActionButton calcFAB;
private LinearLayout drawLayout;
private LinearLayout writerLayout;
private LinearLayout impressLayout;
private LinearLayout calcLayout;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......@@ -129,6 +158,7 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
// init UI and populate with contents from the provider
switchToDocumentProvider(documentProviderFactory.getDefaultProvider());
createUI();
getAnimations();
}
public void createUI() {
......@@ -143,6 +173,21 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
actionBar.setDisplayHomeAsUpEnabled(true);
}
editFAB = (FloatingActionButton) findViewById(R.id.editFAB);
editFAB.setOnClickListener(this);
impressFAB = (FloatingActionButton) findViewById(R.id.newImpressFAB);
impressFAB.setOnClickListener(this);
writerFAB = (FloatingActionButton) findViewById(R.id.newWriterFAB);
writerFAB.setOnClickListener(this);
calcFAB = (FloatingActionButton) findViewById(R.id.newCalcFAB);
calcFAB.setOnClickListener(this);
drawFAB = (FloatingActionButton) findViewById(R.id.newDrawFAB);
drawFAB.setOnClickListener(this);
writerLayout = (LinearLayout) findViewById(R.id.writerLayout);
impressLayout = (LinearLayout) findViewById(R.id.impressLayout);
calcLayout = (LinearLayout) findViewById(R.id.calcLayout);
drawLayout = (LinearLayout) findViewById(R.id.drawLayout);
recentRecyclerView = (RecyclerView) findViewById(R.id.list_recent);
Set<String> recentFileStrings = prefs.getStringSet(RECENT_DOCUMENTS_KEY, new HashSet<String>());
......@@ -235,6 +280,9 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
super.onDrawerOpened(drawerView);
supportInvalidateOptionsMenu();
navigationDrawer.requestFocus(); // Make keypad navigation easier
if (isFabMenuOpen) {
collapseFabMenu(); //Collapse FAB Menu when drawer is opened
}
}
@Override
......@@ -248,6 +296,37 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
drawerToggle.syncState();
}
private void getAnimations() {
fabOpenAnimation = AnimationUtils.loadAnimation(this, R.anim.fab_open);
fabCloseAnimation = AnimationUtils.loadAnimation(this, R.anim.fab_close);
}
private void expandFabMenu() {
ViewCompat.animate(editFAB).rotation(45.0F).withLayer().setDuration(300).setInterpolator(new OvershootInterpolator(10.0F)).start();
drawLayout.startAnimation(fabOpenAnimation);
impressLayout.startAnimation(fabOpenAnimation);
writerLayout.startAnimation(fabOpenAnimation);
calcLayout.startAnimation(fabOpenAnimation);
writerFAB.setClickable(true);
impressFAB.setClickable(true);
drawFAB.setClickable(true);
calcFAB.setClickable(true);
isFabMenuOpen = true;
}
private void collapseFabMenu() {
ViewCompat.animate(editFAB).rotation(0.0F).withLayer().setDuration(300).setInterpolator(new OvershootInterpolator(10.0F)).start();
writerLayout.startAnimation(fabCloseAnimation);
impressLayout.startAnimation(fabCloseAnimation);
drawLayout.startAnimation(fabCloseAnimation);
calcLayout.startAnimation(fabCloseAnimation);
writerFAB.setClickable(false);
impressFAB.setClickable(false);
drawFAB.setClickable(false);
calcFAB.setClickable(false);
isFabMenuOpen = false;
}
private boolean checkDocumentProviderAvailability(IDocumentProvider provider) {
return provider.checkProviderAvailability();
}
......@@ -273,15 +352,23 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
fileRecyclerView.setAdapter(new ExplorerItemAdapter(this, filePaths));
// close drawer if it was open
drawerLayout.closeDrawer(navigationDrawer);
if (isFabMenuOpen) {
collapseFabMenu();
}
}
@Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(navigationDrawer)) {
drawerLayout.closeDrawer(navigationDrawer);
if (isFabMenuOpen) {
collapseFabMenu();
}
} else if (!currentDirectory.equals(homeDirectory)) {
// navigate upwards in directory hierarchy
openParentDirectory();
} else if (isFabMenuOpen) {
collapseFabMenu();
} else {
// only exit if warning has been shown
if (canQuit) {
......@@ -460,6 +547,13 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
}.execute(document);
}
// For opening a new Document
private void open(String newDocumentType) {
Intent intent = new Intent(this, LibreOfficeMainActivity.class);
intent.putExtra(NEW_DOC_TYPE_KEY, newDocumentType);
startActivity(intent);
}
private void open(int position) {
IFile file = filePaths.get(position);
if (!file.isDirectory()) {
......@@ -884,6 +978,33 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
}
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id){
case R.id.editFAB:
if (isFabMenuOpen) {
collapseFabMenu();
} else {
expandFabMenu();
}
break;
case R.id.newWriterFAB:
open(NEW_WRITER_STRING_KEY);
break;
case R.id.newImpressFAB:
open(NEW_IMPRESS_STRING_KEY);
break;
case R.id.newCalcFAB:
open(NEW_CALC_STRING_KEY);
break;
case R.id.newDrawFAB:
open(NEW_DRAW_STRING_KEY);
break;
}
}
class ExplorerItemAdapter extends RecyclerView.Adapter<ExplorerItemAdapter.ViewHolder> {
private Activity mActivity;
......
......@@ -257,7 +257,7 @@ extern "C" SAL_JNI_EXPORT void JNICALL Java_org_libreoffice_kit_Document_initial
pDocument->pClass->initializeForRendering(pDocument, NULL);
}
extern "C" SAL_JNI_EXPORT jint JNICALL Java_org_libreoffice_kit_Office_saveAs
extern "C" SAL_JNI_EXPORT jint JNICALL Java_org_libreoffice_kit_Document_saveAs
(JNIEnv* pEnv, jobject aObject, jstring sUrl, jstring sFormat, jstring sOptions)
{
LibreOfficeKitDocument* pDocument = getHandle<LibreOfficeKitDocument>(pEnv, aObject);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment