diff options
author | brainbreaker <gautamprajapati06@gmail.com> | 2017-03-14 19:12:20 +0530 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2017-03-30 19:59:10 +0000 |
commit | 1503769fe15c122ff2bb8f6f7e7b4ab72656ddc2 (patch) | |
tree | c839a253bebc30893e94887d80d48f7c0182a38f | |
parent | 0466d0c815f8b0f60497faec8b60a18d35a61eca (diff) |
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/35183
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
17 files changed, 586 insertions, 68 deletions
diff --git a/android/Bootstrap/src/org/libreoffice/kit/Document.java b/android/Bootstrap/src/org/libreoffice/kit/Document.java index a7d3f04938bb..7cf99413644c 100644 --- a/android/Bootstrap/src/org/libreoffice/kit/Document.java +++ b/android/Bootstrap/src/org/libreoffice/kit/Document.java @@ -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); diff --git a/android/source/build.gradle b/android/source/build.gradle index d5fc5c932be0..302d34a54754 100644 --- a/android/source/build.gradle +++ b/android/source/build.gradle @@ -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 { diff --git a/android/source/res/anim/fab_close.xml b/android/source/res/anim/fab_close.xml new file mode 100644 index 000000000000..ba13b0f038be --- /dev/null +++ b/android/source/res/anim/fab_close.xml @@ -0,0 +1,18 @@ +<?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> diff --git a/android/source/res/anim/fab_open.xml b/android/source/res/anim/fab_open.xml new file mode 100644 index 000000000000..9099d8b53c80 --- /dev/null +++ b/android/source/res/anim/fab_open.xml @@ -0,0 +1,19 @@ +<?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> diff --git a/android/source/res/drawable/ic_add_black_24dp.xml b/android/source/res/drawable/ic_add_black_24dp.xml new file mode 100644 index 000000000000..0258249cc482 --- /dev/null +++ b/android/source/res/drawable/ic_add_black_24dp.xml @@ -0,0 +1,9 @@ +<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> diff --git a/android/source/res/layout/activity_document_browser.xml b/android/source/res/layout/activity_document_browser.xml index 20ca14125003..fab1b095035e 100644 --- a/android/source/res/layout/activity_document_browser.xml +++ b/android/source/res/layout/activity_document_browser.xml @@ -6,32 +6,45 @@ License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. --> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" +<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical" > + android:orientation="vertical"> <!-- The toolbar --> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" - android:layout_width="match_parent" + android:layout_width="0dp" android:layout_height="wrap_content" android:elevation="3dp" android:background="@color/toolbar_background" app:theme="@style/LibreOfficeTheme.Toolbar" tools:theme="@style/LibreOfficeTheme.Toolbar" - app:popupTheme="@style/LibreOfficeTheme"> + app:popupTheme="@style/LibreOfficeTheme" + tools:layout_constraintTop_creator="1" + tools:layout_constraintRight_creator="1" + app:layout_constraintRight_toRightOf="parent" + tools:layout_constraintLeft_creator="1" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toTopOf="parent"> </android.support.v7.widget.Toolbar> <android.support.v4.widget.DrawerLayout android:id="@+id/drawer_layout" - android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_width="0dp" + android:layout_height="0dp" + tools:layout_constraintTop_creator="1" + tools:layout_constraintRight_creator="1" + tools:layout_constraintBottom_creator="1" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@+id/toolbar" + tools:layout_constraintLeft_creator="1" + app:layout_constraintLeft_toLeftOf="parent"> <!-- The content --> <ScrollView @@ -53,7 +66,7 @@ android:gravity="center_vertical" android:textSize="14sp" android:padding="16dp" - android:textStyle="bold"/> + android:textStyle="bold" /> <!--Recent files--> <android.support.v7.widget.RecyclerView @@ -61,7 +74,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" - android:layout_marginBottom="8dp"/> + android:layout_marginBottom="8dp" /> <TextView android:layout_width="match_parent" @@ -82,19 +95,177 @@ android:background="@color/background_normal" android:orientation="vertical" /> - </LinearLayout> + </LinearLayout> - </ScrollView> + </ScrollView> - <!-- The navigation drawer --> - <android.support.design.widget.NavigationView - android:id="@+id/navigation_drawer" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_gravity="start" - android:background="@color/background_normal" - app:menu="@menu/navigation_menu" - android:theme="@style/LibreOfficeTheme.NavigationView" /> + <!-- The navigation drawer --> + <android.support.design.widget.NavigationView + android:id="@+id/navigation_drawer" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="start" + android:background="@color/background_normal" + app:menu="@menu/navigation_menu" + android:theme="@style/LibreOfficeTheme.NavigationView" /> </android.support.v4.widget.DrawerLayout> -</LinearLayout> + + <android.support.design.widget.FloatingActionButton + android:id="@+id/editFAB" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="16dp" + android:layout_marginEnd="16dp" + android:layout_marginRight="16dp" + android:clickable="true" + app:fabSize="normal" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:backgroundTint="@color/background_normal" + app:srcCompat="@drawable/ic_add_black_24dp" /> + + <LinearLayout + android:id="@+id/writerLayout" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:orientation="horizontal" + android:visibility="invisible" + app:layout_constraintBottom_toTopOf="@+id/editFAB" + app:layout_constraintRight_toRightOf="parent"> + + <TextView + android:id="@+id/newWriterTextView" + android:layout_width="120dp" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:layout_marginRight="8dp" + android:elevation="2dp" + android:gravity="center_horizontal" + android:text="@string/new_write" + android:textSize="18sp" + android:textStyle="bold" + android:background="@color/background_normal" + android:typeface="normal" /> + + <android.support.design.widget.FloatingActionButton + android:id="@+id/newWriterFAB" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clickable="true" + app:fabSize="normal" + app:backgroundTint="@color/background_normal" + app:srcCompat="@drawable/writer" /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/impressLayout" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:orientation="horizontal" + android:visibility="invisible" + app:layout_constraintBottom_toTopOf="@+id/writerLayout" + app:layout_constraintLeft_toLeftOf="@+id/writerLayout" + app:layout_constraintRight_toRightOf="parent"> + + <TextView + android:id="@+id/newImpressTextView" + android:layout_width="120dp" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:layout_marginRight="8dp" + android:elevation="2dp" + android:gravity="center_horizontal" + android:text="@string/new_impress" + android:textSize="18sp" + android:textStyle="bold" + android:background="@color/background_normal" + android:typeface="normal" /> + + <android.support.design.widget.FloatingActionButton + android:id="@+id/newImpressFAB" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clickable="true" + app:fabSize="normal" + app:backgroundTint="@color/background_normal" + app:srcCompat="@drawable/impress" /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/calcLayout" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:orientation="horizontal" + android:visibility="invisible" + app:layout_constraintBottom_toTopOf="@+id/impressLayout" + app:layout_constraintLeft_toLeftOf="@+id/impressLayout" + app:layout_constraintRight_toRightOf="parent"> + + <TextView + android:id="@+id/newCalcTextView" + android:layout_width="120dp" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:layout_marginRight="8dp" + android:elevation="2dp" + android:gravity="center_horizontal" + android:text="@string/new_spreadsheet" + android:background="@color/background_normal" + android:textSize="18sp" + android:textStyle="bold" + android:typeface="normal" /> + + <android.support.design.widget.FloatingActionButton + android:id="@+id/newCalcFAB" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clickable="true" + app:fabSize="normal" + app:backgroundTint="@color/background_normal" + app:srcCompat="@drawable/calc" /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/drawLayout" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:orientation="horizontal" + android:visibility="invisible" + app:layout_constraintBottom_toTopOf="@+id/calcLayout" + app:layout_constraintLeft_toLeftOf="@+id/calcLayout" + app:layout_constraintRight_toRightOf="parent"> + + <TextView + android:id="@+id/newDrawTextView" + android:layout_width="120dp" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:layout_marginRight="8dp" + android:elevation="2dp" + android:gravity="center_horizontal" + android:text="@string/new_draw" + android:background="@color/background_normal" + android:textSize="18sp" + android:textStyle="bold" + android:typeface="normal" /> + + <android.support.design.widget.FloatingActionButton + android:id="@+id/newDrawFAB" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clickable="true" + app:fabSize="normal" + app:backgroundTint="@color/background_normal" + app:srcCompat="@drawable/draw" /> + + </LinearLayout> + +</android.support.constraint.ConstraintLayout> diff --git a/android/source/res/values/strings.xml b/android/source/res/values/strings.xml index 9832d8b72eb2..ce3754ee3d15 100644 --- a/android/source/res/values/strings.xml +++ b/android/source/res/values/strings.xml @@ -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> diff --git a/android/source/src/java/org/libreoffice/LOEvent.java b/android/source/src/java/org/libreoffice/LOEvent.java index 23109e8d7f6a..3e058c8c035e 100644 --- a/android/source/src/java/org/libreoffice/LOEvent.java +++ b/android/source/src/java/org/libreoffice/LOEvent.java @@ -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; diff --git a/android/source/src/java/org/libreoffice/LOKitShell.java b/android/source/src/java/org/libreoffice/LOKitShell.java index 35a8fd009dc2..7b7525722250 100644 --- a/android/source/src/java/org/libreoffice/LOKitShell.java +++ b/android/source/src/java/org/libreoffice/LOKitShell.java @@ -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) { diff --git a/android/source/src/java/org/libreoffice/LOKitThread.java b/android/source/src/java/org/libreoffice/LOKitThread.java index 742b1cb6e34c..31d3b96440ed 100644 --- a/android/source/src/java/org/libreoffice/LOKitThread.java +++ b/android/source/src/java/org/libreoffice/LOKitThread.java @@ -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,25 +189,65 @@ 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. */ private void closeDocument() { @@ -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); diff --git a/android/source/src/java/org/libreoffice/LOKitTileProvider.java b/android/source/src/java/org/libreoffice/LOKitTileProvider.java index d0fbe9431de7..6ed73ee32805 100644 --- a/android/source/src/java/org/libreoffice/LOKitTileProvider.java +++ b/android/source/src/java/org/libreoffice/LOKitTileProvider.java @@ -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()) diff --git a/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java b/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java index 02129e50a7e8..fb41762af342 100755 --- a/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java +++ b/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java @@ -10,8 +10,10 @@ import android.content.SharedPreferences; import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; import android.graphics.RectF; +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.v4.widget.DrawerLayout; @@ -23,12 +25,13 @@ import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.ListView; -import android.widget.TabHost; import android.widget.Toast; import org.libreoffice.overlay.DocumentOverlay; import org.libreoffice.storage.DocumentProviderFactory; import org.libreoffice.storage.IFile; +import org.libreoffice.ui.FileUtilities; +import org.libreoffice.ui.LibreOfficeUIActivity; import org.mozilla.gecko.ZoomConstraints; import org.mozilla.gecko.gfx.GeckoLayerClient; import org.mozilla.gecko.gfx.LayerView; @@ -66,19 +69,23 @@ public class LibreOfficeMainActivity extends AppCompatActivity { private URI documentUri; private DrawerLayout mDrawerLayout; + Toolbar toolbarTop; private ListView mDrawerList; private List<DocumentPartView> mDocumentPartView = new ArrayList<DocumentPartView>(); private DocumentPartViewListAdapter mDocumentPartViewListAdapter; private int partIndex=-1; private File mInputFile; + private String newFileName = "untitled"; + private String newFilePath = "/storage/emulated/0/Documents/"; private DocumentOverlay mDocumentOverlay; private File mTempFile = null; - + private String newDocumentType = null; private FormattingController mFormattingController; private ToolbarController mToolbarController; private FontController mFontController; private SearchController mSearchController; + private static final int PICKFOLDER_RESULT_CODE = 1; public GeckoLayerClient getLayerClient() { return mLayerClient; @@ -96,7 +103,7 @@ public class LibreOfficeMainActivity extends AppCompatActivity { private boolean isFormattingToolbarOpen = false; private boolean isSearchToolbarOpen = false; private boolean isDocumentChanged = false; - + public boolean isNewDocument = false; @Override public void onCreate(Bundle savedInstanceState) { Log.w(LOGTAG, "onCreate.."); @@ -112,7 +119,7 @@ public class LibreOfficeMainActivity extends AppCompatActivity { } setContentView(R.layout.activity_main); - Toolbar toolbarTop = (Toolbar) findViewById(R.id.toolbar); + toolbarTop = (Toolbar) findViewById(R.id.toolbar); hideBottomToolbar(); mToolbarController = new ToolbarController(this, toolbarTop); @@ -127,32 +134,48 @@ public class LibreOfficeMainActivity extends AppCompatActivity { mFontController = new FontController(this); mSearchController = new SearchController(this); + // New document type string is not null, it means we want to open a new document + if (getIntent().getStringExtra(LibreOfficeUIActivity.NEW_DOC_TYPE_KEY) != null) { + newDocumentType = getIntent().getStringExtra(LibreOfficeUIActivity.NEW_DOC_TYPE_KEY); + if (newDocumentType.matches(LibreOfficeUIActivity.NEW_WRITER_STRING_KEY)) + newFileName = newFileName + ".odt"; + else if (newDocumentType.matches(LibreOfficeUIActivity.NEW_IMPRESS_STRING_KEY)) + newFileName = newFileName + ".odp"; + else if (newDocumentType.matches(LibreOfficeUIActivity.NEW_CALC_STRING_KEY)) + newFileName = newFileName + ".ods"; + else + newFileName = newFileName + ".odg"; + // We want to create a new Document, create an alert dialogue to name the new file. + openSelectPathIntent(); + isNewDocument = true; + } + if (getIntent().getData() != null) { if (getIntent().getData().getScheme().equals(ContentResolver.SCHEME_CONTENT)) { if (copyFileToTemp() && mTempFile != null) { mInputFile = mTempFile; - Log.d(LOGTAG, "SCHEME_CONTENT: getPath(): " + getIntent().getData().getPath()); + Log.e(LOGTAG, "SCHEME_CONTENT: getPath(): " + getIntent().getData().getPath()); + toolbarTop.setTitle(mInputFile.getName()); } else { // TODO: can't open the file Log.e(LOGTAG, "couldn't create temporary file from " + getIntent().getData()); } } else if (getIntent().getData().getScheme().equals(ContentResolver.SCHEME_FILE)) { mInputFile = new File(getIntent().getData().getPath()); - Log.d(LOGTAG, "SCHEME_FILE: getPath(): " + getIntent().getData().getPath()); - + Log.e(LOGTAG, "SCHEME_FILE: getPath(): " + getIntent().getData().getPath()); + toolbarTop.setTitle(mInputFile.getName()); // Gather data to rebuild IFile object later providerId = getIntent().getIntExtra( "org.libreoffice.document_provider_id", 0); documentUri = (URI) getIntent().getSerializableExtra( "org.libreoffice.document_uri"); } + } else if (isNewDocument){ + toolbarTop.setTitle(newFileName); } else { mInputFile = new File(DEFAULT_DOC_PATH); } - toolbarTop.setTitle(mInputFile.getName()); - - mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); if (mDocumentPartViewListAdapter == null) { @@ -187,24 +210,42 @@ public class LibreOfficeMainActivity extends AppCompatActivity { mDocumentOverlay = new DocumentOverlay(this, layerView); mToolbarController.setupToolbars(); + } - TabHost host = (TabHost) findViewById(R.id.toolbarTabHost); - host.setup(); - - TabHost.TabSpec spec = host.newTabSpec("Character"); - spec.setContent(R.id.tab_character); - spec.setIndicator("Character"); - host.addTab(spec); - - spec = host.newTabSpec("Paragraph"); - spec.setContent(R.id.tab_paragraph); - spec.setIndicator("Paragraph"); - host.addTab(spec); + private void openSelectPathIntent() { + Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT) + .addCategory(Intent.CATEGORY_OPENABLE) + .setType("*/*") + .putExtra(Intent.EXTRA_TITLE, newFileName); + startActivityForResult(intent, PICKFOLDER_RESULT_CODE); + } - spec = host.newTabSpec("Insert"); - spec.setContent(R.id.tab_insert); - spec.setIndicator("Insert"); - host.addTab(spec); + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch(requestCode){ + case PICKFOLDER_RESULT_CODE: + if(resultCode==RESULT_OK){ + Uri fileURI = data.getData(); + newFilePath = fileURI.getPath(); + if (newFilePath.contains("primary")) { + /* When file is being saved in primary storage folder other than Documents home. + * newFilePath content is similar to this - /document/primary:Downloads/untitled1.odt */ + newFilePath = Environment.getExternalStorageDirectory().getPath() + "/" + newFilePath.split(":")[1]; + } else if (newFilePath.contains("home")) { + /* When file is being saved in documents folder itself i.e. Document home. + * newFilePath content is similar to this - /document/home:untitled1.odt */ + newFilePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/" + newFilePath.split(":")[1]; + } else { + newFilePath = Environment.getExternalStorageDirectory().getPath() + "/"; + } + Log.d("newFilePath", newFilePath); + } + // Now set the input file variable to new file created + mInputFile = new File(newFilePath); + // and load the new document + LOKitShell.sendNewDocumentLoadEvent(newFilePath, newDocumentType); + break; + } } public RectF getCurrentCursorPosition() { @@ -252,10 +293,21 @@ public class LibreOfficeMainActivity extends AppCompatActivity { } /** + * Save a new document + * */ + public void saveAs(){ + LOKitShell.sendSaveAsEvent(mInputFile.getPath(), FileUtilities.getExtension(mInputFile.getPath()).substring(1)); + } + + /** * Save the document and invoke save on document provider to upload the file * to the cloud if necessary. */ public void saveDocument() { + if (!mInputFile.exists()) { + // Needed for handling null in case new document is not created. + mInputFile = new File(DEFAULT_DOC_PATH); + } final long lastModified = mInputFile.lastModified(); final Activity activity = LibreOfficeMainActivity.this; Toast.makeText(this, R.string.message_saving, Toast.LENGTH_SHORT).show(); @@ -341,10 +393,12 @@ public class LibreOfficeMainActivity extends AppCompatActivity { protected void onStart() { Log.i(LOGTAG, "onStart.."); super.onStart(); - if(partIndex == -1) - LOKitShell.sendLoadEvent(mInputFile.getPath()); - else - LOKitShell.sendResumeEvent(mInputFile.getPath(), partIndex); + if (!isNewDocument){ + if (partIndex == -1) + LOKitShell.sendLoadEvent(mInputFile.getPath()); + else + LOKitShell.sendResumeEvent(mInputFile.getPath(), partIndex); + } } @Override @@ -381,12 +435,14 @@ public class LibreOfficeMainActivity extends AppCompatActivity { public void onClick(DialogInterface dialog, int which) { switch (which){ case DialogInterface.BUTTON_POSITIVE: - //SAVE - saveDocument(); + if (isNewDocument) { + saveAs(); + } else { + saveDocument(); + } isDocumentChanged=false; onBackPressed(); break; - case DialogInterface.BUTTON_NEGATIVE: //CANCEL break; @@ -640,7 +696,7 @@ public class LibreOfficeMainActivity extends AppCompatActivity { } private static boolean copyFromAssets(AssetManager assetManager, - String fromAssetPath, String targetDir) { + String fromAssetPath, String targetDir) { try { String[] files = assetManager.list(fromAssetPath); @@ -695,6 +751,14 @@ public class LibreOfficeMainActivity extends AppCompatActivity { return false; } } + + // This method is used in LOKitTileProvider.java to show status of new file creation. + public void showSaveStatusToast(boolean error) { + if (!error) + Toast.makeText(this, getString(R.string.save_as_success) + newFilePath, Toast.LENGTH_SHORT).show(); + else + Toast.makeText(this, R.string.save_as_error, Toast.LENGTH_SHORT).show(); + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/android/source/src/java/org/libreoffice/TileProvider.java b/android/source/src/java/org/libreoffice/TileProvider.java index 0ab5a1f641c9..e84127cb0715 100644 --- a/android/source/src/java/org/libreoffice/TileProvider.java +++ b/android/source/src/java/org/libreoffice/TileProvider.java @@ -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. */ diff --git a/android/source/src/java/org/libreoffice/ToolbarController.java b/android/source/src/java/org/libreoffice/ToolbarController.java index e4a55dd424b6..0012fdbeae06 100644 --- a/android/source/src/java/org/libreoffice/ToolbarController.java +++ b/android/source/src/java/org/libreoffice/ToolbarController.java @@ -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(); diff --git a/android/source/src/java/org/libreoffice/ui/FileUtilities.java b/android/source/src/java/org/libreoffice/ui/FileUtilities.java index 811fc4562dc7..aff6e0bfd7f3 100644 --- a/android/source/src/java/org/libreoffice/ui/FileUtilities.java +++ b/android/source/src/java/org/libreoffice/ui/FileUtilities.java @@ -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('.'); diff --git a/android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java b/android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java index f2f408a7c331..01585b1077be 100644 --- a/android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java +++ b/android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java @@ -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; diff --git a/desktop/source/lib/lokandroid.cxx b/desktop/source/lib/lokandroid.cxx index af3604aed6b6..0f807d061590 100644 --- a/desktop/source/lib/lokandroid.cxx +++ b/desktop/source/lib/lokandroid.cxx @@ -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); |