react-native-video-trim 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -10
- package/android/build.gradle +0 -2
- package/android/src/main/java/com/videotrim/utils/VideoTrimmerUtil.java +0 -6
- package/android/src/main/java/iknow/android/utils/BaseUtils.java +33 -0
- package/android/src/main/java/iknow/android/utils/BuildConfig.java +18 -0
- package/android/src/main/java/iknow/android/utils/DateUtil.java +64 -0
- package/android/src/main/java/iknow/android/utils/DeviceUtil.java +46 -0
- package/android/src/main/java/iknow/android/utils/UnitConverter.java +48 -0
- package/android/src/main/java/iknow/android/utils/callback/SingleCallback.java +11 -0
- package/android/src/main/java/iknow/android/utils/thread/BackgroundExecutor.java +246 -0
- package/android/src/main/java/iknow/android/utils/thread/UiThreadExecutor.java +120 -0
- package/ios/VideoTrim.swift +15 -5
- package/lib/commonjs/index.js +3 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +3 -3
- package/lib/module/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.tsx +3 -3
package/README.md
CHANGED
|
@@ -15,16 +15,6 @@ npm install react-native-video-trim
|
|
|
15
15
|
|
|
16
16
|
yarn add react-native-video-trim
|
|
17
17
|
```
|
|
18
|
-
|
|
19
|
-
Next for Android, under `android/app/build.gradle`, add `jcenter` to `repositories` this:
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
repositories {
|
|
23
|
-
... other repos if any
|
|
24
|
-
jcenter()
|
|
25
|
-
}
|
|
26
|
-
```
|
|
27
|
-
|
|
28
18
|
Next install CocoaPods deps:
|
|
29
19
|
|
|
30
20
|
```
|
package/android/build.gradle
CHANGED
|
@@ -81,7 +81,6 @@ android {
|
|
|
81
81
|
repositories {
|
|
82
82
|
mavenCentral()
|
|
83
83
|
google()
|
|
84
|
-
jcenter()
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
|
|
@@ -90,7 +89,6 @@ dependencies {
|
|
|
90
89
|
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
|
|
91
90
|
//noinspection GradleDynamicVersion
|
|
92
91
|
implementation "com.facebook.react:react-native:+"
|
|
93
|
-
implementation 'com.github.iknow4:android-utils-sdk:1.1.2'
|
|
94
92
|
implementation 'androidx.recyclerview:recyclerview:1.3.1'
|
|
95
93
|
implementation 'com.arthenica:ffmpeg-kit-full:5.1.LTS'
|
|
96
94
|
}
|
|
@@ -7,13 +7,8 @@ import android.net.Uri;
|
|
|
7
7
|
import android.util.Log;
|
|
8
8
|
|
|
9
9
|
import com.arthenica.ffmpegkit.FFmpegKit;
|
|
10
|
-
import com.arthenica.ffmpegkit.FFmpegSession;
|
|
11
|
-
import com.arthenica.ffmpegkit.FFmpegSessionCompleteCallback;
|
|
12
|
-
import com.arthenica.ffmpegkit.LogCallback;
|
|
13
10
|
import com.arthenica.ffmpegkit.ReturnCode;
|
|
14
11
|
import com.arthenica.ffmpegkit.SessionState;
|
|
15
|
-
import com.arthenica.ffmpegkit.Statistics;
|
|
16
|
-
import com.arthenica.ffmpegkit.StatisticsCallback;
|
|
17
12
|
import com.videotrim.interfaces.VideoTrimListener;
|
|
18
13
|
|
|
19
14
|
import java.text.SimpleDateFormat;
|
|
@@ -47,7 +42,6 @@ public class VideoTrimmerUtil {
|
|
|
47
42
|
outputFile = outputFile + "/" + outputName;
|
|
48
43
|
|
|
49
44
|
String cmd = "-i " + inputFile + " -ss " + startMs + "ms" + " -to " + endMs + "ms -c copy " + outputFile;
|
|
50
|
-
String[] command = cmd.split(" ");
|
|
51
45
|
final String tempOutFile = outputFile;
|
|
52
46
|
|
|
53
47
|
callback.onStartTrim();
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
package iknow.android.utils;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
|
|
5
|
+
import java.lang.ref.WeakReference;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Author:J.Chou
|
|
9
|
+
* Date: 2016.07.21 11:45.
|
|
10
|
+
* Email: who_know_me@163.com
|
|
11
|
+
* Describe:
|
|
12
|
+
*/
|
|
13
|
+
public class BaseUtils {
|
|
14
|
+
|
|
15
|
+
private static final String ERROR_INIT = "Initialize BaseUtils with invoke init()";
|
|
16
|
+
|
|
17
|
+
private static WeakReference<Context> mWeakReferenceContext;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* init in Application
|
|
21
|
+
*/
|
|
22
|
+
public static void init(Context ctx){
|
|
23
|
+
mWeakReferenceContext = new WeakReference<>(ctx);
|
|
24
|
+
//something to do...
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public static Context getContext() {
|
|
28
|
+
if (mWeakReferenceContext == null) {
|
|
29
|
+
throw new IllegalArgumentException(ERROR_INIT);
|
|
30
|
+
}
|
|
31
|
+
return mWeakReferenceContext.get().getApplicationContext();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Source code recreated from a .class file by IntelliJ IDEA
|
|
3
|
+
// (powered by FernFlower decompiler)
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
package iknow.android.utils;
|
|
7
|
+
|
|
8
|
+
public final class BuildConfig {
|
|
9
|
+
public static final boolean DEBUG = false;
|
|
10
|
+
public static final String APPLICATION_ID = "iknow.android.utils";
|
|
11
|
+
public static final String BUILD_TYPE = "release";
|
|
12
|
+
public static final String FLAVOR = "";
|
|
13
|
+
public static final int VERSION_CODE = 1;
|
|
14
|
+
public static final String VERSION_NAME = "1.0";
|
|
15
|
+
|
|
16
|
+
public BuildConfig() {
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
package iknow.android.utils;
|
|
2
|
+
|
|
3
|
+
import android.text.TextUtils;
|
|
4
|
+
|
|
5
|
+
import java.text.SimpleDateFormat;
|
|
6
|
+
import java.util.Date;
|
|
7
|
+
import java.util.Locale;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Author:J.Chou
|
|
11
|
+
* Date: 2016.07.21 11:43.
|
|
12
|
+
* Email: who_know_me@163.com
|
|
13
|
+
* Describe:
|
|
14
|
+
*/
|
|
15
|
+
public final class DateUtil {
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* second to HH:MM:ss
|
|
19
|
+
* @param seconds
|
|
20
|
+
* @return
|
|
21
|
+
*/
|
|
22
|
+
public static String convertSecondsToTime(long seconds) {
|
|
23
|
+
String timeStr = null;
|
|
24
|
+
int hour = 0;
|
|
25
|
+
int minute = 0;
|
|
26
|
+
int second = 0;
|
|
27
|
+
if (seconds <= 0)
|
|
28
|
+
return "00:00";
|
|
29
|
+
else {
|
|
30
|
+
minute = (int)seconds / 60;
|
|
31
|
+
if (minute < 60) {
|
|
32
|
+
second = (int)seconds % 60;
|
|
33
|
+
timeStr = unitFormat(minute) + ":" + unitFormat(second);
|
|
34
|
+
} else {
|
|
35
|
+
hour = minute / 60;
|
|
36
|
+
if (hour > 99)
|
|
37
|
+
return "99:59:59";
|
|
38
|
+
minute = minute % 60;
|
|
39
|
+
second = (int)(seconds - hour * 3600 - minute * 60);
|
|
40
|
+
timeStr = unitFormat(hour) + ":" + unitFormat(minute) + ":" + unitFormat(second);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return timeStr;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public static String convertSecondsToFormat(long seconds,String format){
|
|
47
|
+
|
|
48
|
+
if(TextUtils.isEmpty(format))
|
|
49
|
+
return "";
|
|
50
|
+
|
|
51
|
+
Date date = new Date(seconds);
|
|
52
|
+
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault());
|
|
53
|
+
return sdf.format(date);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private static String unitFormat(int i) {
|
|
57
|
+
String retStr = null;
|
|
58
|
+
if (i >= 0 && i < 10)
|
|
59
|
+
retStr = "0" + Integer.toString(i);
|
|
60
|
+
else
|
|
61
|
+
retStr = "" + i;
|
|
62
|
+
return retStr;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
package iknow.android.utils;
|
|
2
|
+
|
|
3
|
+
import android.app.ActivityManager;
|
|
4
|
+
import android.content.Context;
|
|
5
|
+
import android.content.pm.PackageManager;
|
|
6
|
+
|
|
7
|
+
import java.util.List;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Author:J.Chou
|
|
11
|
+
* Date: 2016.07.19 11:40.
|
|
12
|
+
* Email: who_know_me@163.com
|
|
13
|
+
* Describe:
|
|
14
|
+
*/
|
|
15
|
+
public final class DeviceUtil {
|
|
16
|
+
|
|
17
|
+
public static int getDeviceWidth() {
|
|
18
|
+
return BaseUtils.getContext().getResources().getDisplayMetrics().widthPixels;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public static int getDeviceHeight(){
|
|
22
|
+
return BaseUtils.getContext().getResources().getDisplayMetrics().heightPixels;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public static boolean hasAppInstalled(String pkgName) {
|
|
26
|
+
try {
|
|
27
|
+
BaseUtils.getContext().getPackageManager().getPackageInfo(pkgName, PackageManager.PERMISSION_GRANTED);
|
|
28
|
+
return true;
|
|
29
|
+
} catch (PackageManager.NameNotFoundException e) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public static boolean isAppRunInBackground() {
|
|
35
|
+
ActivityManager activityManager = (ActivityManager) BaseUtils.getContext().getSystemService(Context.ACTIVITY_SERVICE);
|
|
36
|
+
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
|
|
37
|
+
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
|
|
38
|
+
if (appProcess.processName.equals(BaseUtils.getContext().getPackageName())) {
|
|
39
|
+
// return true -> Run in background
|
|
40
|
+
// return false - > Run in foreground
|
|
41
|
+
return appProcess.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
package iknow.android.utils;
|
|
2
|
+
|
|
3
|
+
import android.util.DisplayMetrics;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Created by choujason on 7/31/16.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
public class UnitConverter {
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
public static DisplayMetrics getDisplayMetrics(){
|
|
13
|
+
|
|
14
|
+
return BaseUtils.getContext().getResources().getDisplayMetrics();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public static float dpToPx(float dp) {
|
|
18
|
+
return dp * getDisplayMetrics().density;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public static int dpToPx(int dp) {
|
|
22
|
+
return (int) (dp * getDisplayMetrics().density + 0.5f);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public static float pxToDp(float px) {
|
|
26
|
+
return px / getDisplayMetrics().density;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public static int pxToDp(int px) {
|
|
30
|
+
return (int) (px / getDisplayMetrics().density + 0.5f);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public static float spToPx(float sp) {
|
|
34
|
+
return sp * getDisplayMetrics().scaledDensity;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public static int spToPx(int sp) {
|
|
38
|
+
return (int) (sp * getDisplayMetrics().scaledDensity + 0.5f);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public static float pxToSp(float px) {
|
|
42
|
+
return px / getDisplayMetrics().scaledDensity;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public static int pxToSp(int px) {
|
|
46
|
+
return (int) (px / getDisplayMetrics().scaledDensity + 0.5f);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2010-2016 eBusiness Information, Excilys Group
|
|
3
|
+
* <p>
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
5
|
+
* use this file except in compliance with the License. You may obtain a copy of
|
|
6
|
+
* the License at
|
|
7
|
+
* <p>
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
* <p>
|
|
10
|
+
* Unless required by applicable law or agreed To in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
12
|
+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
13
|
+
* License for the specific language governing permissions and limitations under
|
|
14
|
+
* the License.
|
|
15
|
+
*/
|
|
16
|
+
package iknow.android.utils.thread;
|
|
17
|
+
|
|
18
|
+
import android.util.Log;
|
|
19
|
+
|
|
20
|
+
import java.util.ArrayList;
|
|
21
|
+
import java.util.List;
|
|
22
|
+
import java.util.concurrent.Executor;
|
|
23
|
+
import java.util.concurrent.ExecutorService;
|
|
24
|
+
import java.util.concurrent.Executors;
|
|
25
|
+
import java.util.concurrent.Future;
|
|
26
|
+
import java.util.concurrent.ScheduledExecutorService;
|
|
27
|
+
import java.util.concurrent.TimeUnit;
|
|
28
|
+
import java.util.concurrent.atomic.AtomicBoolean;
|
|
29
|
+
|
|
30
|
+
public final class BackgroundExecutor {
|
|
31
|
+
|
|
32
|
+
private static final String TAG = "BackgroundExecutor";
|
|
33
|
+
|
|
34
|
+
public static final Executor DEFAULT_EXECUTOR = Executors.newScheduledThreadPool(2 * Runtime.getRuntime().availableProcessors());
|
|
35
|
+
private static Executor executor = DEFAULT_EXECUTOR;
|
|
36
|
+
private static final List<Task> TASKS = new ArrayList<>();
|
|
37
|
+
private static final ThreadLocal<String> CURRENT_SERIAL = new ThreadLocal<>();
|
|
38
|
+
|
|
39
|
+
private BackgroundExecutor() {
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Execute a runnable after the given delay.
|
|
44
|
+
*
|
|
45
|
+
* @param runnable the task to execute
|
|
46
|
+
* @param delay the time from now to delay execution, in milliseconds
|
|
47
|
+
* <p>
|
|
48
|
+
* if <code>delay</code> is strictly positive and the current
|
|
49
|
+
* executor does not support scheduling (if
|
|
50
|
+
* Executor has been called with such an
|
|
51
|
+
* executor)
|
|
52
|
+
* @return Future associated to the running task
|
|
53
|
+
* @throws IllegalArgumentException if the current executor set by Executor
|
|
54
|
+
* does not support scheduling
|
|
55
|
+
*/
|
|
56
|
+
private static Future<?> directExecute(Runnable runnable, long delay) {
|
|
57
|
+
Future<?> future = null;
|
|
58
|
+
if (delay > 0) {
|
|
59
|
+
/* no serial, but a delay: schedule the task */
|
|
60
|
+
if (!(executor instanceof ScheduledExecutorService)) {
|
|
61
|
+
throw new IllegalArgumentException("The executor set does not support scheduling");
|
|
62
|
+
}
|
|
63
|
+
ScheduledExecutorService scheduledExecutorService = (ScheduledExecutorService) executor;
|
|
64
|
+
future = scheduledExecutorService.schedule(runnable, delay, TimeUnit.MILLISECONDS);
|
|
65
|
+
} else {
|
|
66
|
+
if (executor instanceof ExecutorService) {
|
|
67
|
+
ExecutorService executorService = (ExecutorService) executor;
|
|
68
|
+
future = executorService.submit(runnable);
|
|
69
|
+
} else {
|
|
70
|
+
/* non-cancellable task */
|
|
71
|
+
executor.execute(runnable);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return future;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Execute a task after (at least) its delay <strong>and</strong> after all
|
|
79
|
+
* tasks added with the same non-null <code>serial</code> (if any) have
|
|
80
|
+
* completed execution.
|
|
81
|
+
*
|
|
82
|
+
* @param task the task to execute
|
|
83
|
+
* @throws IllegalArgumentException if <code>task.delay</code> is strictly positive and the
|
|
84
|
+
* current executor does not support scheduling (if
|
|
85
|
+
* Executor has been called with such an
|
|
86
|
+
* executor)
|
|
87
|
+
*/
|
|
88
|
+
public static synchronized void execute(Task task) {
|
|
89
|
+
Future<?> future = null;
|
|
90
|
+
if (task.serial == null || !hasSerialRunning(task.serial)) {
|
|
91
|
+
task.executionAsked = true;
|
|
92
|
+
future = directExecute(task, task.remainingDelay);
|
|
93
|
+
}
|
|
94
|
+
if ((task.id != null || task.serial != null) && !task.managed.get()) {
|
|
95
|
+
/* keep task */
|
|
96
|
+
task.future = future;
|
|
97
|
+
TASKS.add(task);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Indicates whether a task with the specified <code>serial</code> has been
|
|
103
|
+
* submitted to the executor.
|
|
104
|
+
*
|
|
105
|
+
* @param serial the serial queue
|
|
106
|
+
* @return <code>true</code> if such a task has been submitted,
|
|
107
|
+
* <code>false</code> otherwise
|
|
108
|
+
*/
|
|
109
|
+
private static boolean hasSerialRunning(String serial) {
|
|
110
|
+
for (Task task : TASKS) {
|
|
111
|
+
if (task.executionAsked && serial.equals(task.serial)) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Retrieve and remove the first task having the specified
|
|
120
|
+
* <code>serial</code> (if any).
|
|
121
|
+
*
|
|
122
|
+
* @param serial the serial queue
|
|
123
|
+
* @return task if found, <code>null</code> otherwise
|
|
124
|
+
*/
|
|
125
|
+
private static Task take(String serial) {
|
|
126
|
+
int len = TASKS.size();
|
|
127
|
+
for (int i = 0; i < len; i++) {
|
|
128
|
+
if (serial.equals(TASKS.get(i).serial)) {
|
|
129
|
+
return TASKS.remove(i);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Cancel all tasks having the specified <code>id</code>.
|
|
137
|
+
*
|
|
138
|
+
* @param id the cancellation identifier
|
|
139
|
+
* @param mayInterruptIfRunning <code>true</code> if the thread executing this task should be
|
|
140
|
+
* interrupted; otherwise, in-progress tasks are allowed to
|
|
141
|
+
* complete
|
|
142
|
+
*/
|
|
143
|
+
public static synchronized void cancelAll(String id, boolean mayInterruptIfRunning) {
|
|
144
|
+
for (int i = TASKS.size() - 1; i >= 0; i--) {
|
|
145
|
+
Task task = TASKS.get(i);
|
|
146
|
+
if (id.equals(task.id)) {
|
|
147
|
+
if (task.future != null) {
|
|
148
|
+
task.future.cancel(mayInterruptIfRunning);
|
|
149
|
+
if (!task.managed.getAndSet(true)) {
|
|
150
|
+
/*
|
|
151
|
+
* the task has been submitted to the executor, but its
|
|
152
|
+
* execution has not started yet, so that its run()
|
|
153
|
+
* method will never call postExecute()
|
|
154
|
+
*/
|
|
155
|
+
task.postExecute();
|
|
156
|
+
}
|
|
157
|
+
} else if (task.executionAsked) {
|
|
158
|
+
Log.w(TAG, "A task with id " + task.id + " cannot be cancelled (the executor set does not support it)");
|
|
159
|
+
} else {
|
|
160
|
+
/* this task has not been submitted to the executor */
|
|
161
|
+
TASKS.remove(i);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public static abstract class Task implements Runnable {
|
|
168
|
+
|
|
169
|
+
private String id;
|
|
170
|
+
private long remainingDelay;
|
|
171
|
+
private long targetTimeMillis; /* since epoch */
|
|
172
|
+
private String serial;
|
|
173
|
+
private boolean executionAsked;
|
|
174
|
+
private Future<?> future;
|
|
175
|
+
|
|
176
|
+
/*
|
|
177
|
+
* A task can be cancelled after it has been submitted to the executor
|
|
178
|
+
* but before its run() method is called. In that case, run() will never
|
|
179
|
+
* be called, hence neither will postExecute(): the tasks with the same
|
|
180
|
+
* serial identifier (if any) will never be submitted.
|
|
181
|
+
*
|
|
182
|
+
* Therefore, cancelAll() *must* call postExecute() if run() is not
|
|
183
|
+
* started.
|
|
184
|
+
*
|
|
185
|
+
* This flag guarantees that either cancelAll() or run() manages this
|
|
186
|
+
* task post execution, but not both.
|
|
187
|
+
*/
|
|
188
|
+
private AtomicBoolean managed = new AtomicBoolean();
|
|
189
|
+
|
|
190
|
+
public Task(String id, long delay, String serial) {
|
|
191
|
+
if (!"".equals(id)) {
|
|
192
|
+
this.id = id;
|
|
193
|
+
}
|
|
194
|
+
if (delay > 0) {
|
|
195
|
+
remainingDelay = delay;
|
|
196
|
+
targetTimeMillis = System.currentTimeMillis() + delay;
|
|
197
|
+
}
|
|
198
|
+
if (!"".equals(serial)) {
|
|
199
|
+
this.serial = serial;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
@Override
|
|
204
|
+
public void run() {
|
|
205
|
+
if (managed.getAndSet(true)) {
|
|
206
|
+
/* cancelled and postExecute() already called */
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
CURRENT_SERIAL.set(serial);
|
|
212
|
+
execute();
|
|
213
|
+
} finally {
|
|
214
|
+
/* handle next tasks */
|
|
215
|
+
postExecute();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public abstract void execute();
|
|
220
|
+
|
|
221
|
+
private void postExecute() {
|
|
222
|
+
if (id == null && serial == null) {
|
|
223
|
+
/* nothing to do */
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
CURRENT_SERIAL.set(null);
|
|
227
|
+
synchronized (BackgroundExecutor.class) {
|
|
228
|
+
/* execution complete */
|
|
229
|
+
TASKS.remove(this);
|
|
230
|
+
|
|
231
|
+
if (serial != null) {
|
|
232
|
+
Task next = take(serial);
|
|
233
|
+
if (next != null) {
|
|
234
|
+
if (next.remainingDelay != 0) {
|
|
235
|
+
/* the delay may not have elapsed yet */
|
|
236
|
+
next.remainingDelay = Math.max(0L, targetTimeMillis - System.currentTimeMillis());
|
|
237
|
+
}
|
|
238
|
+
/* a task having the same serial was queued, execute it */
|
|
239
|
+
BackgroundExecutor.execute(next);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2010-2016 eBusiness Information, Excilys Group
|
|
3
|
+
* <p>
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
5
|
+
* use this file except in compliance with the License. You may obtain a copy of
|
|
6
|
+
* the License at
|
|
7
|
+
* <p>
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
* <p>
|
|
10
|
+
* Unless required by applicable law or agreed To in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
12
|
+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
13
|
+
* License for the specific language governing permissions and limitations under
|
|
14
|
+
* the License.
|
|
15
|
+
*/
|
|
16
|
+
package iknow.android.utils.thread;
|
|
17
|
+
|
|
18
|
+
import android.os.Handler;
|
|
19
|
+
import android.os.Looper;
|
|
20
|
+
import android.os.Message;
|
|
21
|
+
import android.os.SystemClock;
|
|
22
|
+
|
|
23
|
+
import java.util.HashMap;
|
|
24
|
+
import java.util.Map;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* This class provide operations for
|
|
28
|
+
* UiThread tasks.
|
|
29
|
+
*/
|
|
30
|
+
public final class UiThreadExecutor {
|
|
31
|
+
|
|
32
|
+
private static final Handler HANDLER = new Handler(Looper.getMainLooper()) {
|
|
33
|
+
@Override
|
|
34
|
+
public void handleMessage(Message msg) {
|
|
35
|
+
Runnable callback = msg.getCallback();
|
|
36
|
+
if (callback != null) {
|
|
37
|
+
callback.run();
|
|
38
|
+
decrementToken((Token) msg.obj);
|
|
39
|
+
} else {
|
|
40
|
+
super.handleMessage(msg);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
private static final Map<String, Token> TOKENS = new HashMap<>();
|
|
46
|
+
|
|
47
|
+
private UiThreadExecutor() {
|
|
48
|
+
// should not be instantiated
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Store a new task in the map for providing cancellation. This method is
|
|
53
|
+
* used by AndroidAnnotations and not intended to be called by clients.
|
|
54
|
+
*
|
|
55
|
+
* @param id the identifier of the task
|
|
56
|
+
* @param task the task itself
|
|
57
|
+
* @param delay the delay or zero to run immediately
|
|
58
|
+
*/
|
|
59
|
+
public static void runTask(String id, Runnable task, long delay) {
|
|
60
|
+
if ("".equals(id)) {
|
|
61
|
+
HANDLER.postDelayed(task, delay);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
long time = SystemClock.uptimeMillis() + delay;
|
|
65
|
+
HANDLER.postAtTime(task, nextToken(id), time);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private static Token nextToken(String id) {
|
|
69
|
+
synchronized (TOKENS) {
|
|
70
|
+
Token token = TOKENS.get(id);
|
|
71
|
+
if (token == null) {
|
|
72
|
+
token = new Token(id);
|
|
73
|
+
TOKENS.put(id, token);
|
|
74
|
+
}
|
|
75
|
+
token.runnablesCount++;
|
|
76
|
+
return token;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private static void decrementToken(Token token) {
|
|
81
|
+
synchronized (TOKENS) {
|
|
82
|
+
if (--token.runnablesCount == 0) {
|
|
83
|
+
String id = token.id;
|
|
84
|
+
Token old = TOKENS.remove(id);
|
|
85
|
+
if (old != token) {
|
|
86
|
+
// a runnable finished after cancelling, we just removed a
|
|
87
|
+
// wrong token, lets put it back
|
|
88
|
+
TOKENS.put(id, old);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Cancel all tasks having the specified <code>id</code>.
|
|
96
|
+
*
|
|
97
|
+
* @param id the cancellation identifier
|
|
98
|
+
*/
|
|
99
|
+
public static void cancelAll(String id) {
|
|
100
|
+
Token token;
|
|
101
|
+
synchronized (TOKENS) {
|
|
102
|
+
token = TOKENS.remove(id);
|
|
103
|
+
}
|
|
104
|
+
if (token == null) {
|
|
105
|
+
// nothing to cancel
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
HANDLER.removeCallbacksAndMessages(token);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private static final class Token {
|
|
112
|
+
int runnablesCount = 0;
|
|
113
|
+
final String id;
|
|
114
|
+
|
|
115
|
+
private Token(String id) {
|
|
116
|
+
this.id = id;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
}
|
package/ios/VideoTrim.swift
CHANGED
|
@@ -7,6 +7,7 @@ class VideoTrim: RCTEventEmitter, UIVideoEditorControllerDelegate, UINavigationC
|
|
|
7
7
|
private var mSaveToPhoto = true
|
|
8
8
|
private var mMaxDuration: Int?
|
|
9
9
|
private var hasListeners = false
|
|
10
|
+
private var shouldFireFinishEvent = true
|
|
10
11
|
|
|
11
12
|
@objc
|
|
12
13
|
static override func requiresMainQueueSetup() -> Bool {
|
|
@@ -79,9 +80,14 @@ class VideoTrim: RCTEventEmitter, UIVideoEditorControllerDelegate, UINavigationC
|
|
|
79
80
|
|
|
80
81
|
func videoEditorController(_ editor: UIVideoEditorController,
|
|
81
82
|
didSaveEditedVideoToPath editedVideoPath: String) {
|
|
83
|
+
if (!shouldFireFinishEvent) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
shouldFireFinishEvent = false
|
|
87
|
+
|
|
82
88
|
let eventPayload: [String: Any] = ["outputPath": editedVideoPath]
|
|
83
89
|
self.emitEventToJS("onFinishTrimming", eventData: eventPayload)
|
|
84
|
-
|
|
90
|
+
|
|
85
91
|
if (mSaveToPhoto) {
|
|
86
92
|
PHPhotoLibrary.requestAuthorization { status in
|
|
87
93
|
guard status == .authorized else {
|
|
@@ -89,7 +95,7 @@ class VideoTrim: RCTEventEmitter, UIVideoEditorControllerDelegate, UINavigationC
|
|
|
89
95
|
self.emitEventToJS("onError", eventData: eventPayload)
|
|
90
96
|
return
|
|
91
97
|
}
|
|
92
|
-
|
|
98
|
+
|
|
93
99
|
PHPhotoLibrary.shared().performChanges({
|
|
94
100
|
let request = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: editedVideoPath))
|
|
95
101
|
request?.creationDate = Date()
|
|
@@ -103,14 +109,18 @@ class VideoTrim: RCTEventEmitter, UIVideoEditorControllerDelegate, UINavigationC
|
|
|
103
109
|
}
|
|
104
110
|
}
|
|
105
111
|
}
|
|
106
|
-
|
|
112
|
+
|
|
107
113
|
// the edit has a known bug where it fires "didSaveEditedVideoToPath" twice, so we have to set its delete to nil right after first call
|
|
108
|
-
editor.delegate = nil
|
|
109
|
-
|
|
114
|
+
// editor.delegate = nil
|
|
110
115
|
|
|
116
|
+
// but with the above solution, somehow it'll close React Native Modal when the editor controller dismissed
|
|
117
|
+
// so we have to create a flag shouldFireFinishEvent here
|
|
118
|
+
|
|
119
|
+
|
|
111
120
|
editor.dismiss(animated: true, completion: {
|
|
112
121
|
self.emitEventToJS("onHide", eventData: nil)
|
|
113
122
|
self.isShowing = false
|
|
123
|
+
self.shouldFireFinishEvent = true // reset this flag to true once dismiss
|
|
114
124
|
})
|
|
115
125
|
}
|
|
116
126
|
|
package/lib/commonjs/index.js
CHANGED
|
@@ -28,8 +28,8 @@ async function showEditor(videoPath) {
|
|
|
28
28
|
if (_reactNative.Platform.OS === 'android' && saveToPhoto) {
|
|
29
29
|
try {
|
|
30
30
|
const granted = await _reactNative.PermissionsAndroid.request(_reactNative.PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, {
|
|
31
|
-
title: 'Video Trimmer
|
|
32
|
-
message: 'Grant access to your
|
|
31
|
+
title: 'Video Trimmer Photos Access Required',
|
|
32
|
+
message: 'Grant access to your Photos to write output Video',
|
|
33
33
|
buttonNeutral: 'Ask Me Later',
|
|
34
34
|
buttonNegative: 'Cancel',
|
|
35
35
|
buttonPositive: 'OK'
|
|
@@ -38,7 +38,7 @@ async function showEditor(videoPath) {
|
|
|
38
38
|
await VideoTrim.saveVideo(outputPath);
|
|
39
39
|
} else {
|
|
40
40
|
VideoTrim.hideDialog();
|
|
41
|
-
throw new Error('
|
|
41
|
+
throw new Error('Photos Library permission denied');
|
|
42
42
|
}
|
|
43
43
|
} catch (err) {
|
|
44
44
|
throw err;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","VideoTrim","NativeModules","Proxy","get","Error","showEditor","videoPath","config","arguments","length","undefined","maxDuration","saveToPhoto","outputPath","OS","granted","PermissionsAndroid","request","PERMISSIONS","WRITE_EXTERNAL_STORAGE","title","message","buttonNeutral","buttonNegative","buttonPositive","RESULTS","GRANTED","saveVideo","hideDialog","err","isValidVideo"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,aAAa,GAChB,kFAAiF,GAClFC,qBAAQ,CAACC,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,SAAS,GAAGC,0BAAa,CAACD,SAAS,GACrCC,0BAAa,CAACD,SAAS,GACvB,IAAIE,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACT,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAOE,eAAeU,UAAUA,CAC9BC,SAAiB,EAEF;EAAA,IADfC,MAAoB,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EAEzB,MAAM;IAAEG,WAAW;IAAEC,WAAW,GAAG;EAAK,CAAC,GAAGL,MAAM;EAClD,MAAMM,UAAU,GAAG,MAAMb,SAAS,CAACK,UAAU,CAACC,SAAS,EAAE;IACvDM,WAAW;IACXD;EACF,CAAC,CAAC;EAEF,IAAIf,qBAAQ,CAACkB,EAAE,KAAK,SAAS,IAAIF,WAAW,EAAE;IAC5C,IAAI;MACF,MAAMG,OAAO,GAAG,MAAMC,+BAAkB,CAACC,OAAO,CAC9CD,+BAAkB,CAACE,WAAW,CAACC,sBAAsB,EACrD;QACEC,KAAK,EAAE,sCAAsC;QAC7CC,OAAO,EAAE,mDAAmD;QAC5DC,aAAa,EAAE,cAAc;QAC7BC,cAAc,EAAE,QAAQ;QACxBC,cAAc,EAAE;MAClB,CACF,CAAC;MACD,IAAIT,OAAO,KAAKC,+BAAkB,CAACS,OAAO,CAACC,OAAO,EAAE;QAClD,MAAM1B,SAAS,CAAC2B,SAAS,CAACd,UAAU,CAAC;MACvC,CAAC,MAAM;QACLb,SAAS,CAAC4B,UAAU,CAAC,CAAC;QACtB,MAAM,IAAIxB,KAAK,CAAC,
|
|
1
|
+
{"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","VideoTrim","NativeModules","Proxy","get","Error","showEditor","videoPath","config","arguments","length","undefined","maxDuration","saveToPhoto","outputPath","OS","granted","PermissionsAndroid","request","PERMISSIONS","WRITE_EXTERNAL_STORAGE","title","message","buttonNeutral","buttonNegative","buttonPositive","RESULTS","GRANTED","saveVideo","hideDialog","err","isValidVideo"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,aAAa,GAChB,kFAAiF,GAClFC,qBAAQ,CAACC,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,SAAS,GAAGC,0BAAa,CAACD,SAAS,GACrCC,0BAAa,CAACD,SAAS,GACvB,IAAIE,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACT,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAOE,eAAeU,UAAUA,CAC9BC,SAAiB,EAEF;EAAA,IADfC,MAAoB,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EAEzB,MAAM;IAAEG,WAAW;IAAEC,WAAW,GAAG;EAAK,CAAC,GAAGL,MAAM;EAClD,MAAMM,UAAU,GAAG,MAAMb,SAAS,CAACK,UAAU,CAACC,SAAS,EAAE;IACvDM,WAAW;IACXD;EACF,CAAC,CAAC;EAEF,IAAIf,qBAAQ,CAACkB,EAAE,KAAK,SAAS,IAAIF,WAAW,EAAE;IAC5C,IAAI;MACF,MAAMG,OAAO,GAAG,MAAMC,+BAAkB,CAACC,OAAO,CAC9CD,+BAAkB,CAACE,WAAW,CAACC,sBAAsB,EACrD;QACEC,KAAK,EAAE,sCAAsC;QAC7CC,OAAO,EAAE,mDAAmD;QAC5DC,aAAa,EAAE,cAAc;QAC7BC,cAAc,EAAE,QAAQ;QACxBC,cAAc,EAAE;MAClB,CACF,CAAC;MACD,IAAIT,OAAO,KAAKC,+BAAkB,CAACS,OAAO,CAACC,OAAO,EAAE;QAClD,MAAM1B,SAAS,CAAC2B,SAAS,CAACd,UAAU,CAAC;MACvC,CAAC,MAAM;QACLb,SAAS,CAAC4B,UAAU,CAAC,CAAC;QACtB,MAAM,IAAIxB,KAAK,CAAC,kCAAkC,CAAC;MACrD;IACF,CAAC,CAAC,OAAOyB,GAAG,EAAE;MACZ,MAAMA,GAAG;IACX;EACF;AACF;AAEO,SAASC,YAAYA,CAACxB,SAAiB,EAAoB;EAChE,OAAON,SAAS,CAAC8B,YAAY,CAACxB,SAAS,CAAC;AAC1C"}
|
package/lib/module/index.js
CHANGED
|
@@ -21,8 +21,8 @@ export async function showEditor(videoPath) {
|
|
|
21
21
|
if (Platform.OS === 'android' && saveToPhoto) {
|
|
22
22
|
try {
|
|
23
23
|
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, {
|
|
24
|
-
title: 'Video Trimmer
|
|
25
|
-
message: 'Grant access to your
|
|
24
|
+
title: 'Video Trimmer Photos Access Required',
|
|
25
|
+
message: 'Grant access to your Photos to write output Video',
|
|
26
26
|
buttonNeutral: 'Ask Me Later',
|
|
27
27
|
buttonNegative: 'Cancel',
|
|
28
28
|
buttonPositive: 'OK'
|
|
@@ -31,7 +31,7 @@ export async function showEditor(videoPath) {
|
|
|
31
31
|
await VideoTrim.saveVideo(outputPath);
|
|
32
32
|
} else {
|
|
33
33
|
VideoTrim.hideDialog();
|
|
34
|
-
throw new Error('
|
|
34
|
+
throw new Error('Photos Library permission denied');
|
|
35
35
|
}
|
|
36
36
|
} catch (err) {
|
|
37
37
|
throw err;
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","PermissionsAndroid","Platform","LINKING_ERROR","select","ios","default","VideoTrim","Proxy","get","Error","showEditor","videoPath","config","arguments","length","undefined","maxDuration","saveToPhoto","outputPath","OS","granted","request","PERMISSIONS","WRITE_EXTERNAL_STORAGE","title","message","buttonNeutral","buttonNegative","buttonPositive","RESULTS","GRANTED","saveVideo","hideDialog","err","isValidVideo"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"AAAA,SAASA,aAAa,EAAEC,kBAAkB,EAAEC,QAAQ,QAAQ,cAAc;AAE1E,MAAMC,aAAa,GAChB,kFAAiF,GAClFD,QAAQ,CAACE,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,SAAS,GAAGP,aAAa,CAACO,SAAS,GACrCP,aAAa,CAACO,SAAS,GACvB,IAAIC,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACP,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAOL,OAAO,eAAeQ,UAAUA,CAC9BC,SAAiB,EAEF;EAAA,IADfC,MAAoB,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EAEzB,MAAM;IAAEG,WAAW;IAAEC,WAAW,GAAG;EAAK,CAAC,GAAGL,MAAM;EAClD,MAAMM,UAAU,GAAG,MAAMZ,SAAS,CAACI,UAAU,CAACC,SAAS,EAAE;IACvDM,WAAW;IACXD;EACF,CAAC,CAAC;EAEF,IAAIf,QAAQ,CAACkB,EAAE,KAAK,SAAS,IAAIF,WAAW,EAAE;IAC5C,IAAI;MACF,MAAMG,OAAO,GAAG,MAAMpB,kBAAkB,CAACqB,OAAO,CAC9CrB,kBAAkB,CAACsB,WAAW,CAACC,sBAAsB,EACrD;QACEC,KAAK,EAAE,sCAAsC;QAC7CC,OAAO,EAAE,mDAAmD;QAC5DC,aAAa,EAAE,cAAc;QAC7BC,cAAc,EAAE,QAAQ;QACxBC,cAAc,EAAE;MAClB,CACF,CAAC;MACD,IAAIR,OAAO,KAAKpB,kBAAkB,CAAC6B,OAAO,CAACC,OAAO,EAAE;QAClD,MAAMxB,SAAS,CAACyB,SAAS,CAACb,UAAU,CAAC;MACvC,CAAC,MAAM;QACLZ,SAAS,CAAC0B,UAAU,CAAC,CAAC;QACtB,MAAM,IAAIvB,KAAK,CAAC,
|
|
1
|
+
{"version":3,"names":["NativeModules","PermissionsAndroid","Platform","LINKING_ERROR","select","ios","default","VideoTrim","Proxy","get","Error","showEditor","videoPath","config","arguments","length","undefined","maxDuration","saveToPhoto","outputPath","OS","granted","request","PERMISSIONS","WRITE_EXTERNAL_STORAGE","title","message","buttonNeutral","buttonNegative","buttonPositive","RESULTS","GRANTED","saveVideo","hideDialog","err","isValidVideo"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"AAAA,SAASA,aAAa,EAAEC,kBAAkB,EAAEC,QAAQ,QAAQ,cAAc;AAE1E,MAAMC,aAAa,GAChB,kFAAiF,GAClFD,QAAQ,CAACE,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,SAAS,GAAGP,aAAa,CAACO,SAAS,GACrCP,aAAa,CAACO,SAAS,GACvB,IAAIC,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACP,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAOL,OAAO,eAAeQ,UAAUA,CAC9BC,SAAiB,EAEF;EAAA,IADfC,MAAoB,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EAEzB,MAAM;IAAEG,WAAW;IAAEC,WAAW,GAAG;EAAK,CAAC,GAAGL,MAAM;EAClD,MAAMM,UAAU,GAAG,MAAMZ,SAAS,CAACI,UAAU,CAACC,SAAS,EAAE;IACvDM,WAAW;IACXD;EACF,CAAC,CAAC;EAEF,IAAIf,QAAQ,CAACkB,EAAE,KAAK,SAAS,IAAIF,WAAW,EAAE;IAC5C,IAAI;MACF,MAAMG,OAAO,GAAG,MAAMpB,kBAAkB,CAACqB,OAAO,CAC9CrB,kBAAkB,CAACsB,WAAW,CAACC,sBAAsB,EACrD;QACEC,KAAK,EAAE,sCAAsC;QAC7CC,OAAO,EAAE,mDAAmD;QAC5DC,aAAa,EAAE,cAAc;QAC7BC,cAAc,EAAE,QAAQ;QACxBC,cAAc,EAAE;MAClB,CACF,CAAC;MACD,IAAIR,OAAO,KAAKpB,kBAAkB,CAAC6B,OAAO,CAACC,OAAO,EAAE;QAClD,MAAMxB,SAAS,CAACyB,SAAS,CAACb,UAAU,CAAC;MACvC,CAAC,MAAM;QACLZ,SAAS,CAAC0B,UAAU,CAAC,CAAC;QACtB,MAAM,IAAIvB,KAAK,CAAC,kCAAkC,CAAC;MACrD;IACF,CAAC,CAAC,OAAOwB,GAAG,EAAE;MACZ,MAAMA,GAAG;IACX;EACF;AACF;AAEA,OAAO,SAASC,YAAYA,CAACvB,SAAiB,EAAoB;EAChE,OAAOL,SAAS,CAAC4B,YAAY,CAACvB,SAAS,CAAC;AAC1C"}
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -37,8 +37,8 @@ export async function showEditor(
|
|
|
37
37
|
const granted = await PermissionsAndroid.request(
|
|
38
38
|
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE!,
|
|
39
39
|
{
|
|
40
|
-
title: 'Video Trimmer
|
|
41
|
-
message: 'Grant access to your
|
|
40
|
+
title: 'Video Trimmer Photos Access Required',
|
|
41
|
+
message: 'Grant access to your Photos to write output Video',
|
|
42
42
|
buttonNeutral: 'Ask Me Later',
|
|
43
43
|
buttonNegative: 'Cancel',
|
|
44
44
|
buttonPositive: 'OK',
|
|
@@ -48,7 +48,7 @@ export async function showEditor(
|
|
|
48
48
|
await VideoTrim.saveVideo(outputPath);
|
|
49
49
|
} else {
|
|
50
50
|
VideoTrim.hideDialog();
|
|
51
|
-
throw new Error('
|
|
51
|
+
throw new Error('Photos Library permission denied');
|
|
52
52
|
}
|
|
53
53
|
} catch (err) {
|
|
54
54
|
throw err;
|