adding some video editor related things

This commit is contained in:
tibbi 2020-11-28 20:51:18 +01:00
parent 89656e5936
commit b6f49fc08d
7 changed files with 327 additions and 5 deletions

View file

@ -106,12 +106,18 @@ if (is_proprietary) {
apply plugin: 'ly.img.android.sdk' apply plugin: 'ly.img.android.sdk'
imglyConfig { imglyConfig {
vesdk {
enabled true
licencePath 'vesdk_license'
}
pesdk { pesdk {
enabled true enabled true
licencePath 'pesdk_license' licencePath 'pesdk_license'
} }
modules { modules {
include 'ui:video-trim'
include 'ui:core' include 'ui:core'
include 'ui:text' include 'ui:text'
include 'ui:focus' include 'ui:focus'

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_new_photo_edit_holder"
android:id="@+id/activity_new_edit_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="#FF000000" /> android:background="#FF000000" />

View 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" />

View file

@ -35,5 +35,18 @@
<data android:mimeType="image/*"/> <data android:mimeType="image/*"/>
</intent-filter> </intent-filter>
</activity> </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> </application>
</manifest> </manifest>

View 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="}

View file

@ -51,7 +51,7 @@ class NewPhotoEditActivity : SimpleActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_new_edit) setContentView(R.layout.activity_new_photo_edit)
if (checkAppSideloading()) { if (checkAppSideloading()) {
return 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) { private fun handleFileOverwriting(path: String, callback: () -> Unit) {
if (getDoesFilePathExist(path) && isPathOnSD(path)) { if (getDoesFilePathExist(path) && isPathOnSD(path)) {
val fileDirItem = FileDirItem(path, path.getFilenameFromPath()) val fileDirItem = FileDirItem(path, path.getFilenameFromPath())

View file

@ -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
}
}