mirror of
https://github.com/FossifyOrg/Gallery.git
synced 2024-11-26 14:37:59 +01:00
adding some video editor related things
This commit is contained in:
parent
89656e5936
commit
b6f49fc08d
7 changed files with 327 additions and 5 deletions
|
@ -106,12 +106,18 @@ if (is_proprietary) {
|
|||
apply plugin: 'ly.img.android.sdk'
|
||||
|
||||
imglyConfig {
|
||||
vesdk {
|
||||
enabled true
|
||||
licencePath 'vesdk_license'
|
||||
}
|
||||
|
||||
pesdk {
|
||||
enabled true
|
||||
licencePath 'pesdk_license'
|
||||
}
|
||||
|
||||
modules {
|
||||
include 'ui:video-trim'
|
||||
include 'ui:core'
|
||||
include 'ui:text'
|
||||
include 'ui:focus'
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/activity_new_edit_holder"
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/activity_new_photo_edit_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#FF000000" />
|
6
app/src/main/res/layout/activity_new_video_edit.xml
Normal file
6
app/src/main/res/layout/activity_new_video_edit.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/activity_new_photo_edit_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#FF000000" />
|
|
@ -35,5 +35,18 @@
|
|||
<data android:mimeType="image/*"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.NewVideoEditActivity"
|
||||
android:label="@string/editor">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.EDIT"/>
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
|
||||
<data android:mimeType="video/*"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
1
app/src/proprietary/assets/vesdk_license
Normal file
1
app/src/proprietary/assets/vesdk_license
Normal file
|
@ -0,0 +1 @@
|
|||
{"api_token":"8mq68_8PExmT5EixFLi8Ng","app_identifiers":["com.simplemobiletools.gallery.pro"],"available_actions":[],"domains":["https://api.photoeditorsdk.com"],"enterprise_license":false,"expires_at":1577836800,"features":["camera","library","export","whitelabel","customassets","adjustment","brush","filter","focus","overlay","sticker","text","textdesign","transform","trim"],"issued_at":1606584014,"minimum_sdk_version":"1.0","owner":"Tikap s.r.o.","platform":"Android","products":["vesdk"],"version":"2.4","signature":"Rr1ocNzO1ZVhN0fo/mfXnd1WGot4psPhlM4i7koo0Bd4zIF9MAkDL6EREOeDisNMMQD4zVtuXRPxM+miDMmZY/2PchwdF2hYssNqD76XAEEIwF3HXNouGCWfFScU2XkOKw9evrlfWgTlfO3H2rDgujo22qhSebDeAGP2satWBcvxkPrF6YJ5GYZUZHyCZ0/INQKyU6zAntfw2er8c46iBMiz00Evp0bYdXFpSk8KQCtgZ9koJYTyKVEFLz1BjOoJkkt8rLyHX2l9VVlRinY+0ss+N2oI5PQVwLqftvWIEL7pOGBrXY5EJFRITeXaVWlPZd7AAzxt54nK3G/5k/RwLoBDbN/q2Kv5fD3kZ7XqOklXgrBogEGm2KEu031Si7yMaOpG+mDJsyKuSh8TRwpsRYUdO+4m0uYqjo/WEmmStNVzCMau4Z9PRcsXmux3UKZHv6yHXxtGK0ZalfOwqCEN27KgTgyLIxEOYyt37cRN/iRUsHqpTG44qNwLPPUPE1VRkhV+XThi8ohJMl2vJeIvggabauuXOg+Hnmty4dZ61k5DGBPZhOxHGEEgKxzqBF5iwDKcnUVx/zhfDfmZo5OD8E2E3gC0MODov0M+cbDXBBE9rkV67zPRz5pUPN4G+gaNryndwRm6sa9xnq8TDaWaHsQtDRgXFQj8PV/XSJQfqTQ="}
|
|
@ -51,7 +51,7 @@ class NewPhotoEditActivity : SimpleActivity() {
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_new_edit)
|
||||
setContentView(R.layout.activity_new_photo_edit)
|
||||
|
||||
if (checkAppSideloading()) {
|
||||
return
|
||||
|
@ -201,7 +201,7 @@ class NewPhotoEditActivity : SimpleActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
// in case the user wants to overwrite the original file and it is on an SD card, delete it manually. Else the system just appends (1)
|
||||
// In case the user wants to overwrite the original file and it is on an SD card, delete it manually first. Else the system just appends (1)
|
||||
private fun handleFileOverwriting(path: String, callback: () -> Unit) {
|
||||
if (getDoesFilePathExist(path) && isPathOnSD(path)) {
|
||||
val fileDirItem = FileDirItem(path, path.getFilenameFromPath())
|
||||
|
|
|
@ -0,0 +1,297 @@
|
|||
package com.simplemobiletools.gallery.pro.activities
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.media.ExifInterface
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
|
||||
import com.simplemobiletools.commons.helpers.REAL_FILE_PATH
|
||||
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
|
||||
import com.simplemobiletools.commons.helpers.isNougatPlus
|
||||
import com.simplemobiletools.commons.models.FileDirItem
|
||||
import com.simplemobiletools.gallery.pro.R
|
||||
import com.simplemobiletools.gallery.pro.dialogs.SaveAsDialog
|
||||
import com.simplemobiletools.gallery.pro.extensions.config
|
||||
import com.simplemobiletools.gallery.pro.extensions.fixDateTaken
|
||||
import com.simplemobiletools.gallery.pro.extensions.tryDeleteFileDirItem
|
||||
import ly.img.android.pesdk.VideoEditorSettingsList
|
||||
import ly.img.android.pesdk.assets.filter.basic.FilterPackBasic
|
||||
import ly.img.android.pesdk.assets.font.basic.FontPackBasic
|
||||
import ly.img.android.pesdk.backend.model.config.CropAspectAsset
|
||||
import ly.img.android.pesdk.backend.model.constant.OutputMode
|
||||
import ly.img.android.pesdk.backend.model.state.BrushSettings
|
||||
import ly.img.android.pesdk.backend.model.state.LoadSettings
|
||||
import ly.img.android.pesdk.backend.model.state.VideoEditorSaveSettings
|
||||
import ly.img.android.pesdk.backend.model.state.manager.SettingsList
|
||||
import ly.img.android.pesdk.ui.activity.VideoEditorBuilder
|
||||
import ly.img.android.pesdk.ui.model.state.*
|
||||
import ly.img.android.pesdk.ui.panels.item.CropAspectItem
|
||||
import ly.img.android.pesdk.ui.panels.item.ToggleAspectItem
|
||||
import ly.img.android.pesdk.ui.panels.item.ToolItem
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
class NewVideoEditActivity : SimpleActivity() {
|
||||
private val VESDK_EDIT_VIDEO = 1
|
||||
private val SETTINGS_LIST = "SETTINGS_LIST"
|
||||
private val SOURCE_URI = "SOURCE_URI"
|
||||
private val RESULT_URI = "RESULT_URI"
|
||||
private var sourceFileLastModified = 0L
|
||||
private var oldExif: ExifInterface? = null
|
||||
|
||||
private lateinit var uri: Uri
|
||||
private lateinit var saveUri: Uri
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_new_video_edit)
|
||||
|
||||
if (checkAppSideloading()) {
|
||||
return
|
||||
}
|
||||
|
||||
handlePermission(PERMISSION_WRITE_STORAGE) {
|
||||
if (it) {
|
||||
initEditActivity()
|
||||
} else {
|
||||
toast(R.string.no_storage_permissions)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initEditActivity() {
|
||||
if (intent.data == null) {
|
||||
toast(R.string.invalid_video_path)
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
uri = intent.data!!
|
||||
if (uri.scheme != "file" && uri.scheme != "content") {
|
||||
toast(R.string.unknown_file_location)
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
if (intent.extras?.containsKey(REAL_FILE_PATH) == true) {
|
||||
val realPath = intent.extras!!.getString(REAL_FILE_PATH)
|
||||
uri = when {
|
||||
isPathOnOTG(realPath!!) -> uri
|
||||
realPath.startsWith("file:/") -> Uri.parse(realPath)
|
||||
else -> Uri.fromFile(File(realPath))
|
||||
}
|
||||
} else {
|
||||
(getRealPathFromURI(uri))?.apply {
|
||||
uri = Uri.fromFile(File(this))
|
||||
}
|
||||
}
|
||||
|
||||
saveUri = when {
|
||||
intent.extras?.containsKey(MediaStore.EXTRA_OUTPUT) == true -> intent.extras!!.get(MediaStore.EXTRA_OUTPUT) as Uri
|
||||
else -> uri
|
||||
}
|
||||
|
||||
openEditor(uri)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
|
||||
if (requestCode == VESDK_EDIT_VIDEO) {
|
||||
val extras = resultData?.extras
|
||||
val resultPath = extras?.get(RESULT_URI)?.toString() ?: ""
|
||||
val sourcePath = Uri.decode(extras?.get(SOURCE_URI)?.toString() ?: "")
|
||||
val settings = extras?.getParcelable<SettingsList>(SETTINGS_LIST)
|
||||
if (settings != null) {
|
||||
val brush = settings.getSettingsModel(BrushSettings::class.java)
|
||||
config.editorBrushColor = brush.brushColor
|
||||
config.editorBrushHardness = brush.brushHardness
|
||||
config.editorBrushSize = brush.brushSize
|
||||
}
|
||||
|
||||
if (resultCode != Activity.RESULT_OK || resultPath.isEmpty()) {
|
||||
toast(R.string.video_editing_cancelled)
|
||||
finish()
|
||||
} else {
|
||||
val source = if (sourcePath.isEmpty() || sourcePath.startsWith("content")) {
|
||||
internalStoragePath
|
||||
} else {
|
||||
sourcePath.substringAfter("file://")
|
||||
}
|
||||
|
||||
SaveAsDialog(this, source, true, cancelCallback = {
|
||||
toast(R.string.video_editing_failed)
|
||||
finish()
|
||||
}, callback = {
|
||||
val destinationFilePath = it
|
||||
handleSAFDialog(destinationFilePath) {
|
||||
if (it) {
|
||||
ensureBackgroundThread {
|
||||
storeOldExif(source)
|
||||
sourceFileLastModified = File(source).lastModified()
|
||||
|
||||
handleFileOverwriting(destinationFilePath) {
|
||||
var inputStream: InputStream? = null
|
||||
var outputStream: OutputStream? = null
|
||||
try {
|
||||
inputStream = contentResolver.openInputStream(Uri.parse(resultPath))
|
||||
outputStream = getFileOutputStreamSync(destinationFilePath, destinationFilePath.getMimeType())
|
||||
inputStream!!.copyTo(outputStream!!)
|
||||
outputStream.flush()
|
||||
inputStream.close()
|
||||
outputStream.close()
|
||||
|
||||
try {
|
||||
if (isNougatPlus()) {
|
||||
val newExif = ExifInterface(destinationFilePath)
|
||||
oldExif?.copyTo(newExif, false)
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
if (config.keepLastModified) {
|
||||
// add 1 s to the last modified time to properly update the thumbnail
|
||||
updateLastModified(destinationFilePath, sourceFileLastModified + 1000)
|
||||
}
|
||||
|
||||
val paths = arrayListOf(destinationFilePath)
|
||||
rescanPaths(arrayListOf(destinationFilePath)) {
|
||||
fixDateTaken(paths, false)
|
||||
}
|
||||
|
||||
setResult(Activity.RESULT_OK, intent)
|
||||
toast(R.string.file_edited_successfully)
|
||||
finish()
|
||||
} catch (e: Exception) {
|
||||
showErrorToast(e)
|
||||
} finally {
|
||||
inputStream?.close()
|
||||
outputStream?.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
toast(R.string.video_editing_failed)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, resultData)
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
private fun storeOldExif(sourcePath: String) {
|
||||
var inputStream: InputStream? = null
|
||||
try {
|
||||
if (isNougatPlus()) {
|
||||
inputStream = contentResolver.openInputStream(Uri.fromFile(File(sourcePath)))
|
||||
oldExif = ExifInterface(inputStream!!)
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
} finally {
|
||||
inputStream?.close()
|
||||
}
|
||||
}
|
||||
|
||||
// In case the user wants to overwrite the original file and it is on an SD card, delete it manually first. Else the system just appends (1)
|
||||
private fun handleFileOverwriting(path: String, callback: () -> Unit) {
|
||||
if (getDoesFilePathExist(path) && isPathOnSD(path)) {
|
||||
val fileDirItem = FileDirItem(path, path.getFilenameFromPath())
|
||||
tryDeleteFileDirItem(fileDirItem, false, true) { success ->
|
||||
if (success) {
|
||||
callback()
|
||||
} else {
|
||||
toast(R.string.unknown_error_occurred)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
private fun openEditor(inputVideo: Uri) {
|
||||
val settingsList = createPesdkSettingsList()
|
||||
|
||||
settingsList.configure<LoadSettings> {
|
||||
it.source = inputVideo
|
||||
}
|
||||
|
||||
settingsList[LoadSettings::class].source = inputVideo
|
||||
|
||||
VideoEditorBuilder(this)
|
||||
.setSettingsList(settingsList)
|
||||
.startActivityForResult(this, VESDK_EDIT_VIDEO)
|
||||
}
|
||||
|
||||
private fun createPesdkSettingsList(): VideoEditorSettingsList {
|
||||
val settingsList = VideoEditorSettingsList().apply {
|
||||
configure<UiConfigFilter> {
|
||||
it.setFilterList(FilterPackBasic.getFilterPack())
|
||||
}
|
||||
|
||||
configure<UiConfigText> {
|
||||
it.setFontList(FontPackBasic.getFontPack())
|
||||
}
|
||||
|
||||
config.getAssetMap(CropAspectAsset::class.java).apply {
|
||||
add(CropAspectAsset("my_crop_1_2", 1, 2, false))
|
||||
add(CropAspectAsset("my_crop_2_1", 2, 1, false))
|
||||
add(CropAspectAsset("my_crop_19_9", 19, 9, false))
|
||||
add(CropAspectAsset("my_crop_9_19", 9, 19, false))
|
||||
add(CropAspectAsset("my_crop_5_4", 5, 4, false))
|
||||
add(CropAspectAsset("my_crop_4_5", 4, 5, false))
|
||||
add(CropAspectAsset("my_crop_37_18", 37, 18, false))
|
||||
add(CropAspectAsset("my_crop_18_37", 18, 37, false))
|
||||
add(CropAspectAsset("my_crop_16_10", 16, 10, false))
|
||||
add(CropAspectAsset("my_crop_10_16", 10, 16, false))
|
||||
}
|
||||
|
||||
getSettingsModel(UiConfigAspect::class.java).aspectList.apply {
|
||||
add(ToggleAspectItem(CropAspectItem("my_crop_2_1"), CropAspectItem("my_crop_1_2")))
|
||||
add(ToggleAspectItem(CropAspectItem("my_crop_19_9"), CropAspectItem("my_crop_9_19")))
|
||||
add(ToggleAspectItem(CropAspectItem("my_crop_5_4"), CropAspectItem("my_crop_4_5")))
|
||||
add(ToggleAspectItem(CropAspectItem("my_crop_37_18"), CropAspectItem("my_crop_18_37")))
|
||||
add(ToggleAspectItem(CropAspectItem("my_crop_16_10"), CropAspectItem("my_crop_10_16")))
|
||||
}
|
||||
|
||||
getSettingsModel(BrushSettings::class.java).apply {
|
||||
brushColor = applicationContext.config.editorBrushColor
|
||||
brushHardness = applicationContext.config.editorBrushHardness
|
||||
brushSize = applicationContext.config.editorBrushSize
|
||||
}
|
||||
|
||||
// do not use Text Design, it takes up too much space
|
||||
val tools = getSettingsModel(UiConfigMainMenu::class.java).toolList
|
||||
val newTools = tools.filterNot {
|
||||
it.name!!.isEmpty()
|
||||
}.toMutableList() as ArrayList<ToolItem>
|
||||
|
||||
// move Focus at the end, as it is the least used
|
||||
// on some devices it is not obvious that the toolbar can be scrolled horizontally, so move the best ones at the beginning to make them visible
|
||||
val focus = newTools.firstOrNull { it.name == getString(R.string.pesdk_focus_title_name) }
|
||||
if (focus != null) {
|
||||
newTools.remove(focus)
|
||||
newTools.add(focus)
|
||||
}
|
||||
|
||||
getSettingsModel(UiConfigMainMenu::class.java).setToolList(newTools)
|
||||
|
||||
getSettingsModel(UiConfigTheme::class.java).theme = R.style.Imgly_Theme_NoFullscreen
|
||||
|
||||
configure<VideoEditorSaveSettings> {
|
||||
it.setOutputToTemp()
|
||||
it.outputMode = OutputMode.EXPORT_IF_NECESSARY
|
||||
}
|
||||
}
|
||||
|
||||
return settingsList
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue