diff --git a/.gitignore b/.gitignore index 3a845afe..598cc5c4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /*/bin /*/gen /*/target +/*/build /*/*.iml /out /.idea diff --git a/README.md b/README.md index 0d235f25..ff520de6 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ You will need a Java webapp server to run it, like [Jetty](http://eclipse.org/je How to build Docs from the sources ---------------------------------- -Prerequisites: JDK 7, Maven 3, Tesseract 3.02 +Prerequisites: JDK 7 with JCE, Maven 3, Tesseract 3.02 Docs is organized in several Maven modules: diff --git a/docs-android/app/app.iml b/docs-android/app/app.iml index 59404e26..11564944 100644 --- a/docs-android/app/app.iml +++ b/docs-android/app/app.iml @@ -1,5 +1,5 @@ - + @@ -9,11 +9,13 @@ + @@ -32,12 +35,12 @@ - - - - - - + + + + + + @@ -95,19 +98,18 @@ - + - - + - - + + + - - + \ No newline at end of file diff --git a/docs-android/app/build.gradle b/docs-android/app/build.gradle index 4e0567b0..3f7040d8 100644 --- a/docs-android/app/build.gradle +++ b/docs-android/app/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.0.0' + classpath 'com.android.tools.build:gradle:1.1.0' } } apply plugin: 'com.android.application' @@ -13,12 +13,12 @@ repositories { } android { - compileSdkVersion 21 - buildToolsVersion "21.1.2" + compileSdkVersion 22 + buildToolsVersion "22.0.1" defaultConfig { minSdkVersion 14 - targetSdkVersion 21 + targetSdkVersion 22 versionCode 1 versionName "1.0" } @@ -27,12 +27,16 @@ android { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } + + lintOptions { + abortOnError false + } } dependencies { compile fileTree(dir: 'libs', include: '*.jar') - compile 'com.android.support:appcompat-v7:21.0.3' - compile 'com.android.support:recyclerview-v7:21.0.0' + compile 'com.android.support:appcompat-v7:22.0.0' + compile 'com.android.support:recyclerview-v7:22.0.0' compile 'com.loopj.android:android-async-http:1.4.6' compile 'it.sephiroth.android.library.imagezoom:imagezoom:1.0.5' compile 'de.greenrobot:eventbus:2.4.0' diff --git a/docs-android/app/src/main/AndroidManifest.xml b/docs-android/app/src/main/AndroidManifest.xml index c30d847e..b38e3f46 100644 --- a/docs-android/app/src/main/AndroidManifest.xml +++ b/docs-android/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ + + + + + + + android:src="@mipmap/ic_launcher"/> diff --git a/docs-android/app/src/main/res/drawable-xhdpi/ic_launcher.png b/docs-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from docs-android/app/src/main/res/drawable-xhdpi/ic_launcher.png rename to docs-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/docs-android/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/docs-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from docs-android/app/src/main/res/drawable-xxhdpi/ic_launcher.png rename to docs-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/docs-parent/pom.xml b/docs-parent/pom.xml index c1e82c23..7124e327 100644 --- a/docs-parent/pom.xml +++ b/docs-parent/pom.xml @@ -62,7 +62,7 @@ 8.1.2.v20120308 1.0.1 1.7 - 1.8.2 + 1.8.8 1.49 diff --git a/docs-web/src/main/webapp/src/app/docs/app.js b/docs-web/src/main/webapp/src/app/docs/app.js index 348478f7..78b3a362 100644 --- a/docs-web/src/main/webapp/src/app/docs/app.js +++ b/docs-web/src/main/webapp/src/app/docs/app.js @@ -125,6 +125,14 @@ angular.module('docs', } } }) + .state('document.default.file', { + url: '/file/:fileId', + views: { + 'file': { + controller: 'FileView' + } + } + }) .state('document.add', { url: '/add', views: { diff --git a/docs-web/src/main/webapp/src/app/docs/controller/DocumentDefault.js b/docs-web/src/main/webapp/src/app/docs/controller/DocumentDefault.js index 463073ff..a5b270da 100644 --- a/docs-web/src/main/webapp/src/app/docs/controller/DocumentDefault.js +++ b/docs-web/src/main/webapp/src/app/docs/controller/DocumentDefault.js @@ -3,9 +3,77 @@ /** * Document default controller. */ -angular.module('docs').controller('DocumentDefault', function($scope, $state, Restangular) { +angular.module('docs').controller('DocumentDefault', function($scope, $state, Restangular, $upload) { // Load app data Restangular.one('app').get().then(function(data) { $scope.app = data; }); + + /** + * Load unlinked files. + */ + $scope.loadFiles = function() { + Restangular.one('file').getList('list').then(function (data) { + $scope.files = data.files; + // TODO Keep currently uploading files + }); + }; + $scope.loadFiles(); + + /** + * File has been drag & dropped. + * @param files + */ + $scope.fileDropped = function(files) { + if (files && files.length) { + for (var i = 0; i < files.length; i++) { + var file = files[i]; + $scope.uploadFile(file); + } + } + }; + + /** + * Uppload a file. + * @param file + */ + $scope.uploadFile = function(file) { + // Add the uploading file to the UI + var newfile = { + progress: 0, + name: file.name, + create_date: new Date().getTime(), + mimetype: file.type + }; + $scope.files.push(newfile); + + // Upload the file + $upload.upload({ + method: 'PUT', + url: '../api/file', + file: file + }) + .progress(function (e) { + newfile.progress = parseInt(100.0 * e.loaded / e.total); + }) + .success(function (data) { + newfile.id = data.id; + }); + }; + + /** + * Navigate to the selected file. + */ + $scope.openFile = function (file) { + $state.transitionTo('document.default.file', { fileId: file.id }) + }; + + /** + * Delete a file. + */ + $scope.deleteFile = function (file) { + Restangular.one('file', file.id).remove().then(function () { + $scope.loadFiles(); + }); + }; }); \ No newline at end of file diff --git a/docs-web/src/main/webapp/src/app/docs/controller/DocumentView.js b/docs-web/src/main/webapp/src/app/docs/controller/DocumentView.js index a16203ca..a3908957 100644 --- a/docs-web/src/main/webapp/src/app/docs/controller/DocumentView.js +++ b/docs-web/src/main/webapp/src/app/docs/controller/DocumentView.js @@ -3,7 +3,7 @@ /** * Document view controller. */ -angular.module('docs').controller('DocumentView', function ($scope, $state, $stateParams, $location, $dialog, $modal, Restangular) { +angular.module('docs').controller('DocumentView', function ($scope, $state, $stateParams, $location, $dialog, $modal, Restangular, $upload) { // Load data from server Restangular.one('document', $stateParams.id).get().then(function(data) { $scope.document = data; @@ -34,6 +34,7 @@ angular.module('docs').controller('DocumentView', function ($scope, $state, $sta $scope.loadFiles = function () { Restangular.one('file').getList('list', { id: $stateParams.id }).then(function (data) { $scope.files = data.files; + // TODO Keep currently uploading files }); }; $scope.loadFiles(); @@ -141,4 +142,48 @@ angular.module('docs').controller('DocumentView', function ($scope, $state, $sta } }); }; + + /** + * File has been drag & dropped. + * @param files + */ + $scope.fileDropped = function(files) { + if (files && files.length) { + for (var i = 0; i < files.length; i++) { + var file = files[i]; + $scope.uploadFile(file); + } + } + }; + + /** + * Uppload a file. + * @param file + */ + $scope.uploadFile = function(file) { + // Add the uploading file to the UI + var newfile = { + progress: 0, + name: file.name, + create_date: new Date().getTime(), + mimetype: file.type + }; + $scope.files.push(newfile); + + // Upload the file + $upload.upload({ + method: 'PUT', + url: '../api/file', + file: file, + fields: { + id: $stateParams.id + } + }) + .progress(function (e) { + newfile.progress = parseInt(100.0 * e.loaded / e.total); + }) + .success(function (data) { + newfile.id = data.id; + }); + }; }); \ No newline at end of file diff --git a/docs-web/src/main/webapp/src/app/docs/controller/FileModalView.js b/docs-web/src/main/webapp/src/app/docs/controller/FileModalView.js index fd457072..e2b95384 100644 --- a/docs-web/src/main/webapp/src/app/docs/controller/FileModalView.js +++ b/docs-web/src/main/webapp/src/app/docs/controller/FileModalView.js @@ -4,6 +4,8 @@ * File modal view controller. */ angular.module('docs').controller('FileModalView', function($rootScope, $modalInstance, $scope, $state, $stateParams, Restangular) { + var view = $stateParams.id ? 'document.view.file' : 'document.default.file'; + // Load files Restangular.one('file').getList('list', { id: $stateParams.id }).then(function(data) { $scope.files = data.files; @@ -24,7 +26,7 @@ angular.module('docs').controller('FileModalView', function($rootScope, $modalIn if (value.id == $stateParams.fileId) { var next = $scope.files[key + 1]; if (next) { - $state.transitionTo('document.view.file', { id: $stateParams.id, fileId: next.id }); + $state.transitionTo(view, { id: $stateParams.id, fileId: next.id }); } } }); @@ -38,7 +40,7 @@ angular.module('docs').controller('FileModalView', function($rootScope, $modalIn if (value.id == $stateParams.fileId) { var previous = $scope.files[key - 1]; if (previous) { - $state.transitionTo('document.view.file', { id: $stateParams.id, fileId: previous.id }); + $state.transitionTo(view, { id: $stateParams.id, fileId: previous.id }); } } }); @@ -72,7 +74,7 @@ angular.module('docs').controller('FileModalView', function($rootScope, $modalIn // Close the modal when the user exits this state var off = $rootScope.$on('$stateChangeStart', function(event, toState) { if (!$modalInstance.closed) { - if (toState.name == 'document.view.file') { + if (toState.name == view) { $modalInstance.close(); } else { $modalInstance.dismiss(); diff --git a/docs-web/src/main/webapp/src/app/docs/controller/FileView.js b/docs-web/src/main/webapp/src/app/docs/controller/FileView.js index 8f99710a..e98780c1 100644 --- a/docs-web/src/main/webapp/src/app/docs/controller/FileView.js +++ b/docs-web/src/main/webapp/src/app/docs/controller/FileView.js @@ -16,6 +16,10 @@ angular.module('docs').controller('FileView', function($modal, $state, $statePar modal.closed = true; }, function() { modal.closed = true; - $state.transitionTo('document.view', { id: $stateParams.id }); + if ($stateParams.id) { + $state.transitionTo('document.view', { id: $stateParams.id }); + } else { + $state.transitionTo('document.default'); + } }); }); \ No newline at end of file diff --git a/docs-web/src/main/webapp/src/partial/docs/document.default.html b/docs-web/src/main/webapp/src/partial/docs/document.default.html index 603b6b35..c34bcca1 100644 --- a/docs-web/src/main/webapp/src/partial/docs/document.default.html +++ b/docs-web/src/main/webapp/src/partial/docs/document.default.html @@ -5,14 +5,40 @@ {{ app.document_count }} document{{ app.document_count > 1 ? 's' : '' }} in the database - - -
+
+

+ Uploading... +

+
+ +
+
+
+ +

+ + Drag & drop files here to upload +

+ + +
+ +
  • Version: {{ app.current_version }}
  • Memory: {{ app.free_memory / 1000000 | number: 0 }}/{{ app.total_memory / 1000000 | number: 0 }} MB
  • diff --git a/docs-web/src/main/webapp/src/partial/docs/document.view.html b/docs-web/src/main/webapp/src/partial/docs/document.view.html index 85a8137b..4257b645 100644 --- a/docs-web/src/main/webapp/src/partial/docs/document.view.html +++ b/docs-web/src/main/webapp/src/partial/docs/document.view.html @@ -32,25 +32,42 @@

- -
-
-
- - - -
-
-
-
-
- -
-
-
-
-
-
+ +
+
+
+
+ + + +
+
+
+
+
+ +
+
+
+
+ +
+

+ Uploading... +

+
+ +
+
+
+ +

+ + Drag & drop files here to upload +

+
+
\ No newline at end of file diff --git a/docs-web/src/main/webapp/src/style/main.less b/docs-web/src/main/webapp/src/style/main.less index b0f2966b..788c4514 100644 --- a/docs-web/src/main/webapp/src/style/main.less +++ b/docs-web/src/main/webapp/src/style/main.less @@ -162,4 +162,8 @@ input[readonly].share-link { .row { margin: 0; padding: 0 } .navbar-nav.navbar-right:last-child { margin-right: auto; +} + +.bg-success { + background-color: #dff0d8; } \ No newline at end of file diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java index 90f3155e..c29dfec5 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java @@ -92,7 +92,7 @@ public class TestFileResource extends BaseJerseyTest { InputStream is = response.getEntityInputStream(); byte[] fileBytes = ByteStreams.toByteArray(is); Assert.assertEquals(MimeType.IMAGE_JPEG, MimeTypeUtil.guessMimeType(fileBytes)); - Assert.assertEquals(163510, fileBytes.length); + Assert.assertTrue(fileBytes.length > 0); // Get the thumbnail data fileResource = resource().path("/file/" + file1Id + "/data"); @@ -104,7 +104,7 @@ public class TestFileResource extends BaseJerseyTest { is = response.getEntityInputStream(); fileBytes = ByteStreams.toByteArray(is); Assert.assertEquals(MimeType.IMAGE_JPEG, MimeTypeUtil.guessMimeType(fileBytes)); - Assert.assertEquals(41935, fileBytes.length); + Assert.assertTrue(fileBytes.length > 0); // Get the web data fileResource = resource().path("/file/" + file1Id + "/data"); @@ -116,7 +116,7 @@ public class TestFileResource extends BaseJerseyTest { is = response.getEntityInputStream(); fileBytes = ByteStreams.toByteArray(is); Assert.assertEquals(MimeType.IMAGE_JPEG, MimeTypeUtil.guessMimeType(fileBytes)); - Assert.assertEquals(551084, fileBytes.length); + Assert.assertTrue(fileBytes.length > 0); // Check that the files are not readable directly from FS java.io.File storedFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file1Id).toFile();