Jelajahi Sumber

Merge branch 'master' of git.kdan.cc:Bomo/Bomo_for_Android_editorModule

liweihao 6 tahun lalu
induk
melakukan
6bb6a0d4ba

+ 1 - 0
build.gradle

@@ -63,6 +63,7 @@ dependencies {
 
     implementation 'com.squareup.picasso:picasso:2.71828'
     implementation 'com.github.naman14:TAndroidLame:1.1'
+    implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.16'
 }
 repositories {
     mavenCentral()

+ 5 - 1
src/main/java/com/bomostory/sceneeditmodule/SceneEditActivity.kt

@@ -1228,7 +1228,11 @@ class SceneEditActivity : AppCompatActivity(), ActorAdapter.OnActorDragListener,
             PHOTO_FROM_GALLERY ->
                 when (resultCode) {
                     Activity.RESULT_OK -> if (data != null) {
-                        FileUtils.saveImageForActor(this, data.data, System.currentTimeMillis().toString())
+                        var uri = data.data
+                        if (uri.path.endsWith(".gif"))
+                            FileUtils.saveGifForActor(this, data.data, System.currentTimeMillis().toString())
+                        else
+                            FileUtils.saveImageForActor(this, data.data, System.currentTimeMillis().toString())
                     }
                     Activity.RESULT_CANCELED -> {
                     }

+ 10 - 1
src/main/java/com/bomostory/sceneeditmodule/screen/view/ActorView.kt

@@ -7,6 +7,7 @@ import android.util.AttributeSet
 import android.widget.ImageView
 import com.bomostory.sceneeditmodule.DialogueDrawer
 import com.bomostory.sceneeditmodule.basicdata.Actor
+import pl.droidsonroids.gif.GifDrawable
 
 class ActorView : ImageView {
 
@@ -14,7 +15,15 @@ class ActorView : ImageView {
         set(value) {
             field = value
             value?.let {
-                if(!it.isDialogue) setImageDrawable(Drawable.createFromPath(it.resourcePath))
+                if(!it.isDialogue) {
+                    if (it.resourcePath.toLowerCase().endsWith(".gif")) {
+                        val gifDrawable = GifDrawable(it.resourcePath)
+                        setImageDrawable(gifDrawable)
+                        gifDrawable.start()
+                    } else {
+                        setImageDrawable(Drawable.createFromPath(it.resourcePath))
+                    }
+                }
                 if (it.isMirror && !it.isDialogue) {
                     this.scaleX = -1f
                     this.scaleY = 1f

+ 32 - 16
src/main/java/com/bomostory/sceneeditmodule/screen/view/EditActorView.kt

@@ -40,6 +40,7 @@ open class EditActorView @JvmOverloads constructor(
             }
         }
 
+    val MIN_ACTOR_SIZE = 160
     var actorCallback: OnActorChangeListener? = null
 
     private fun initView() {
@@ -105,6 +106,7 @@ open class EditActorView @JvmOverloads constructor(
         return View.OnTouchListener { view, motionEvent ->
             when (motionEvent.action) {
                 MotionEvent.ACTION_DOWN -> {
+                    println("ACTION_DOWN")
                     val layoutParams = actor_layout.layoutParams as RelativeLayout.LayoutParams
                     sizeX = layoutParams.width
                     sizeY = layoutParams.height
@@ -116,13 +118,14 @@ open class EditActorView @JvmOverloads constructor(
                 MotionEvent.ACTION_MOVE -> {
                     var mx =  motionEvent.rawX.toInt() - positionX
                     var my =  motionEvent.rawY.toInt() - positionY
-                    var dP = when (Math.abs(mx) > Math.abs(my)){
+//                    var dP = when (Math.abs(mx) > Math.abs(my)){
+                    var dP = when (my < mx){
                         true ->  my
                         false -> mx
                     }
                     var actorData = Actor().apply {
-                        sideLength = sizeX + dP
-                        sideHeight = sizeY + dP
+                        sideLength = Math.max(MIN_ACTOR_SIZE, sizeX + dP)
+                        sideHeight = Math.max(MIN_ACTOR_SIZE, sizeY + dP)
                         this.positionX = x
                         this.positionY = y
                         resourcePath = actor.resourcePath
@@ -140,6 +143,7 @@ open class EditActorView @JvmOverloads constructor(
                     actor = actorData
                 }
                 MotionEvent.ACTION_UP -> {
+                    println("ACTION_UP")
                     actor.isSelect = true
                     actorCallback?.onActorChange(actor)
                 }
@@ -155,6 +159,8 @@ open class EditActorView @JvmOverloads constructor(
         var sizeY = 0
         var x = 0
         var y = 0
+        var rightX = 0
+        var bottomY = 0
         return View.OnTouchListener { view, motionEvent ->
             when (motionEvent.action) {
                 MotionEvent.ACTION_DOWN -> {
@@ -165,19 +171,21 @@ open class EditActorView @JvmOverloads constructor(
                     y = layoutParams.topMargin
                     positionX = (motionEvent.rawX).toInt()
                     positionY = (motionEvent.rawY).toInt()
+                    rightX = x + sizeX
+                    bottomY = y + sizeY
                 }
                 MotionEvent.ACTION_MOVE -> {
                     val mx =  motionEvent.rawX.toInt() - positionX
                     val my =  motionEvent.rawY.toInt() - positionY
-                    var dP = when (Math.abs(mx) > Math.abs(my)){
+                    var dP = when (my > mx){
                         true ->  my
                         false -> mx
                     }
                     var actorData = Actor().apply {
-                        sideLength = sizeX - dP
-                        sideHeight = sizeY - dP
-                        this.positionX = x + dP
-                        this.positionY = y + dP
+                        sideLength = Math.max(MIN_ACTOR_SIZE, sizeX - dP)
+                        sideHeight = Math.max(MIN_ACTOR_SIZE, sizeY - dP)
+                        this.positionX = Math.min(rightX - MIN_ACTOR_SIZE, x + dP)
+                        this.positionY = Math.min(bottomY - MIN_ACTOR_SIZE, y + dP)
                         resourcePath = actor.resourcePath
                         text = actor.text
                         textColor = actor.textColor
@@ -208,6 +216,7 @@ open class EditActorView @JvmOverloads constructor(
         var sizeY = 0
         var x = 0
         var y = 0
+        var bottomY = 0
         return View.OnTouchListener { view, motionEvent ->
             when (motionEvent.action) {
                 MotionEvent.ACTION_DOWN -> {
@@ -218,19 +227,20 @@ open class EditActorView @JvmOverloads constructor(
                     y = layoutParams.topMargin
                     positionX = (motionEvent.rawX).toInt()
                     positionY = (motionEvent.rawY).toInt()
+                    bottomY = y + sizeY
                 }
                 MotionEvent.ACTION_MOVE -> {
                     var mx =  motionEvent.rawX.toInt() - positionX
                     var my =  motionEvent.rawY.toInt() - positionY
-                    var dP = when (Math.abs(mx) > Math.abs(my)){
+                    var dP = when (-mx < my){
                         true ->  my
-                        false -> mx
+                        false -> -mx
                     }
                     var actorData = Actor().apply {
-                        sideLength = sizeX + mx
-                        sideHeight = sizeY - my
+                        sideLength = Math.max(MIN_ACTOR_SIZE, sizeX - dP)
+                        sideHeight = Math.max(MIN_ACTOR_SIZE, sizeY - dP)
                         this.positionX = x
-                        this.positionY = y + my
+                        this.positionY = Math.min(bottomY - MIN_ACTOR_SIZE, y + dP)
                         resourcePath = actor.resourcePath
                         text = actor.text
                         textColor = actor.textColor
@@ -261,6 +271,7 @@ open class EditActorView @JvmOverloads constructor(
         var sizeY = 0
         var x = 0
         var y = 0
+        var rightX = 0
         return View.OnTouchListener { view, motionEvent ->
             when (motionEvent.action) {
                 MotionEvent.ACTION_DOWN -> {
@@ -271,14 +282,19 @@ open class EditActorView @JvmOverloads constructor(
                     y = layoutParams.topMargin
                     positionX = (motionEvent.rawX).toInt()
                     positionY = (motionEvent.rawY).toInt()
+                    rightX = x + sizeX
                 }
                 MotionEvent.ACTION_MOVE -> {
                     var mx =  motionEvent.rawX.toInt() - positionX
                     var my =  motionEvent.rawY.toInt() - positionY
+                    var dP = when (-mx > my){
+                        true ->  my
+                        false -> -mx
+                    }
                     var actorData = Actor().apply {
-                        sideLength = sizeX - mx
-                        sideHeight = sizeY + my
-                        this.positionX = x + mx
+                        sideLength = Math.max(MIN_ACTOR_SIZE, sizeX + dP)
+                        sideHeight = Math.max(MIN_ACTOR_SIZE, sizeY + dP)
+                        this.positionX = Math.min(rightX - MIN_ACTOR_SIZE, x - dP)
                         this.positionY = y
                         resourcePath = actor.resourcePath
                         text = actor.text

+ 159 - 4
src/main/java/com/bomostory/sceneeditmodule/utils/FileUtils.kt

@@ -1,18 +1,21 @@
 package com.bomostory.sceneeditmodule.utils
 
+import android.content.ContentUris
 import android.content.Context
+import android.database.Cursor
 import android.graphics.Bitmap
 import android.net.Uri
+import android.os.Build
+import android.os.Environment
+import android.provider.DocumentsContract
 import android.provider.MediaStore
 import com.bomostory.sceneeditmodule.Config
 import com.bomostory.sceneeditmodule.SceneDrawer
 import com.bomostory.sceneeditmodule.basicdata.Project
 import com.google.gson.Gson
 import io.reactivex.Completable
-import java.io.BufferedOutputStream
-import java.io.File
-import java.io.FileOutputStream
-import java.io.FileWriter
+import java.io.*
+
 
 object FileUtils {
 
@@ -21,6 +24,158 @@ object FileUtils {
         return File(projectFolder, Config.VIDEO_FILE_NAME)
     }
 
+    fun getRealPathFromURI(context: Context, uri: Uri): String? {
+        val isKitKat = Build.VERSION.SDK_INT >= 19
+
+        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
+            // DocumentProvider
+            if (isExternalStorageDocument(uri)) {
+                // ExternalStorageProvider
+                val docId = DocumentsContract.getDocumentId(uri)
+                val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+                val type = split[0]
+
+                return if ("primary".equals(type, ignoreCase = true)) {
+                    Environment.getExternalStorageDirectory().toString() + "/" + split[1]
+                } else {
+                    File(uri.toString()).absolutePath
+                }
+            } else if (isDownloadsDocument(uri)) {
+                // DownloadsProvider
+                val id = DocumentsContract.getDocumentId(uri)
+                if (id.startsWith("raw:")) {
+                    return id.replaceFirst("raw:", "");
+                }
+                try {
+                    val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), id.toLong())
+                    return getDataColumn(context, contentUri, null, null)
+                } catch (e: NumberFormatException) {
+                }
+
+            } else if (isMediaDocument(uri)) {
+                // MediaProvider
+                val docId = DocumentsContract.getDocumentId(uri)
+                val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+                val type = split[0]
+
+                var contentUri: Uri? = null
+                if ("image" == type) {
+                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
+                } else if ("video" == type) {
+                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
+                } else if ("audio" == type) {
+                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
+                }
+
+                val selection = "_id=?"
+                val selectionArgs = arrayOf(split[1])
+
+                return getDataColumn(context, contentUri, selection, selectionArgs)
+            }
+        } else if ("content".equals(uri.scheme!!, ignoreCase = true)) {
+            // Return the remote address
+            if (isGooglePhotosUri(uri))
+                return uri.lastPathSegment
+            return getDataColumn(context, uri, null, null)
+        } else if ("file".equals(uri.scheme!!, ignoreCase = true)) {
+            // File
+            return uri.path
+        }
+        return null
+    }
+
+    /**
+     * Get the value of the data column for this Uri. This is useful for MediaStore Uris, and other file-based ContentProviders.
+     *
+     * @param context
+     * The context.
+     * @param uri
+     * The Uri to query.
+     * @param selection
+     * (Optional) Filter used in the query.
+     * @param selectionArgs
+     * (Optional) Selection arguments used in the query.
+     * @return The value of the _data column, which is typically a file path.
+     */
+    private fun getDataColumn(context: Context, uri: Uri?, selection: String?, selectionArgs: Array<String>?): String? {
+        var cursor: Cursor? = null
+        val column = "_data"
+        val projection = arrayOf(column)
+
+        try {
+            cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs, null)
+            if (cursor != null && cursor.moveToFirst()) {
+                val index = cursor.getColumnIndexOrThrow(column)
+                return cursor.getString(index)
+            }
+        } finally {
+            cursor?.close()
+        }
+        return null
+    }
+
+    /**
+     * @param uri
+     * The Uri to check.
+     * @return Whether the Uri authority is ExternalStorageProvider.
+     */
+    private fun isExternalStorageDocument(uri: Uri): Boolean {
+        return "com.android.externalstorage.documents" == uri.authority
+    }
+
+    /**
+     * @param uri
+     * The Uri to check.
+     * @return Whether the Uri authority is DownloadsProvider.
+     */
+    private fun isDownloadsDocument(uri: Uri): Boolean {
+        return "com.android.providers.downloads.documents" == uri.authority
+    }
+
+    /**
+     * @param uri
+     * The Uri to check.
+     * @return Whether the Uri authority is MediaProvider.
+     */
+    private fun isMediaDocument(uri: Uri): Boolean {
+        return "com.android.providers.media.documents" == uri.authority
+    }
+
+    /**
+     * @param uri
+     * The Uri to check.
+     * @return Whether the Uri authority is Google Photos.
+     */
+    private fun isGooglePhotosUri(uri: Uri): Boolean {
+        return "com.google.android.apps.photos.content" == uri.authority
+    }
+
+    fun saveGifForActor(context: Context, uri: Uri, fileName: String) {
+        val dir = File(Config.IMAGE_FOLDER,"")
+        dir.mkdir()
+        val file = File(Config.IMAGE_FOLDER, fileName.plus(".gif"))
+        try {
+            var sourceFile = File(getRealPathFromURI(context, uri))
+            val bis = BufferedInputStream(FileInputStream(sourceFile))
+            val bos = BufferedOutputStream(FileOutputStream(file))
+            val buf = ByteArray(1024)
+            bis.read(buf)
+            do {
+                bos.write(buf)
+            } while (bis.read(buf) !== -1)
+            bos.flush()
+            bos.close()
+            bis.close()
+            if (context is OnSaveActorImage) {
+                context.onSaveActorImage(file.path)
+            } else {
+                throw RuntimeException(context.toString() + " must implement OnFragmentInteractionListener")
+            }
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+    }
+
     fun saveImageForActor(context: Context, uri: Uri, fileName: String){
         val dir = File(Config.IMAGE_FOLDER,"")
         dir.mkdir()