CURRENT_SERIAL = new ThreadLocal<>();
+
+ private BackgroundTask() {
+ }
+
+ /**
+ * Execute a runnable after the given delay.
+ *
+ * @param runnable the task to execute
+ * @param delay the time from now to delay execution, in milliseconds
+ *
+ * if delay
is strictly positive and the current
+ * executor does not support scheduling (if
+ * Executor has been called with such an
+ * executor)
+ * @return Future associated to the running task
+ * @throws IllegalArgumentException if the current executor set by Executor
+ * does not support scheduling
+ */
+ private static Future> directExecute(Runnable runnable, long delay) {
+ Future> future = null;
+ if (delay > 0) {
+ /* no serial, but a delay: schedule the task */
+ if (!(executor instanceof ScheduledExecutorService)) {
+ throw new IllegalArgumentException("The executor set does not support scheduling");
+ }
+ ScheduledExecutorService scheduledExecutorService = (ScheduledExecutorService) executor;
+ future = scheduledExecutorService.schedule(runnable, delay, TimeUnit.MILLISECONDS);
+ } else {
+ if (executor instanceof ExecutorService) {
+ ExecutorService executorService = (ExecutorService) executor;
+ future = executorService.submit(runnable);
+ } else {
+ /* non-cancellable task */
+ executor.execute(runnable);
+ }
+ }
+ return future;
+ }
+
+ /**
+ * Execute a task after (at least) its delay and after all
+ * tasks added with the same non-null serial
(if any) have
+ * completed execution.
+ *
+ * @param task the task to execute
+ * @throws IllegalArgumentException if task.delay
is strictly positive and the
+ * current executor does not support scheduling (if
+ * Executor has been called with such an
+ * executor)
+ */
+ public static synchronized void execute(Task task) {
+ Future> future = null;
+ if (task.serial == null || !hasRunning(task.serial)) {
+ task.executionAsked = true;
+ future = directExecute(task, task.remainingDelay);
+ }
+ if ((task.id != null || task.serial != null) && !task.managed.get()) {
+ /* keep task */
+ task.future = future;
+ TASKS.add(task);
+ }
+ }
+
+ /**
+ * Indicates whether a task with the specified serial
has been
+ * submitted to the executor.
+ *
+ * @param serial the serial queue
+ * @return true
if such a task has been submitted,
+ * false
otherwise
+ */
+ private static boolean hasRunning(String serial) {
+ for (Task task : TASKS) {
+ if (task.executionAsked && serial.equals(task.serial)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve and remove the first task having the specified
+ * serial
(if any).
+ *
+ * @param serial the serial queue
+ * @return task if found, null
otherwise
+ */
+ private static Task take(String serial) {
+ int len = TASKS.size();
+ for (int i = 0; i < len; i++) {
+ if (serial.equals(TASKS.get(i).serial)) {
+ return TASKS.remove(i);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Cancel all tasks having the specified id
.
+ *
+ * @param id the cancellation identifier
+ * @param mayInterruptIfRunning true
if the thread executing this task should be
+ * interrupted; otherwise, in-progress tasks are allowed to
+ * complete
+ */
+ public static synchronized void cancelAllTask(String id, boolean mayInterruptIfRunning) {
+ for (int i = TASKS.size() - 1; i >= 0; i--) {
+ Task task = TASKS.get(i);
+ if (id.equals(task.id)) {
+ if (task.future != null) {
+ task.future.cancel(mayInterruptIfRunning);
+ if (!task.managed.getAndSet(true)) {
+ /*
+ * the task has been submitted to the executor, but its
+ * execution has not started yet, so that its run()
+ * method will never call postExecute()
+ */
+ task.postExecute();
+ }
+ } else if (task.executionAsked) {
+ Log.w(TAG, "A task with id " + task.id + " cannot be cancelled (the executor set does not support it)");
+ } else {
+ /* this task has not been submitted to the executor */
+ TASKS.remove(i);
+ }
+ }
+ }
+ }
+
+ public static abstract class Task implements Runnable {
+
+ private String id;
+ private long remainingDelay;
+ private long targetTimeMillis; /* since epoch */
+ private String serial;
+ private boolean executionAsked;
+ private Future> future;
+
+ /*
+ * A task can be cancelled after it has been submitted to the executor
+ * but before its run() method is called. In that case, run() will never
+ * be called, hence neither will postExecute(): the tasks with the same
+ * serial identifier (if any) will never be submitted.
+ *
+ * Therefore, cancelAllTask() *must* call postExecute() if run() is not
+ * started.
+ *
+ * This flag guarantees that either cancelAllTask() or run() manages this
+ * task post execution, but not both.
+ */
+ private AtomicBoolean managed = new AtomicBoolean();
+
+ protected Task(String id, long delay, String serial) {
+ if (!"".equals(id)) {
+ this.id = id;
+ }
+ if (delay > 0) {
+ remainingDelay = delay;
+ targetTimeMillis = System.currentTimeMillis() + delay;
+ }
+ if (!"".equals(serial)) {
+ this.serial = serial;
+ }
+ }
+
+ @Override
+ public void run() {
+ if (managed.getAndSet(true)) {
+ /* cancelled and postExecute() already called */
+ return;
+ }
+
+ try {
+ CURRENT_SERIAL.set(serial);
+ execute();
+ } finally {
+ /* handle next tasks */
+ postExecute();
+ }
+ }
+
+ public abstract void execute();
+
+ private void postExecute() {
+ if (id == null && serial == null) {
+ /* nothing to do */
+ return;
+ }
+ CURRENT_SERIAL.set(null);
+ synchronized (BackgroundTask.class) {
+ /* execution complete */
+ TASKS.remove(this);
+
+ if (serial != null) {
+ Task next = take(serial);
+ if (next != null) {
+ if (next.remainingDelay != 0) {
+ /* the delay may not have elapsed yet */
+ next.remainingDelay = Math.max(0L, targetTimeMillis - System.currentTimeMillis());
+ }
+ /* a task having the same serial was queued, execute it */
+ BackgroundTask.execute(next);
+ }
+ }
+ }
+ }
+ }
+
+
+}
+
diff --git a/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/BarThumb.java b/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/BarThumb.java
new file mode 100644
index 0000000..4df4139
--- /dev/null
+++ b/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/BarThumb.java
@@ -0,0 +1,127 @@
+// The MIT License (MIT)
+
+// Copyright (c) 2018 Intuz Solutions Pvt Ltd.
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
+// (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
+// merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package com.ahmedbadereldin.videotrimmerapplication.javaCode.customVideoViews;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import androidx.annotation.NonNull;
+
+import com.ahmedbadereldin.videotrimmerapplication.R;
+
+import java.util.List;
+import java.util.Vector;
+
+
+public class BarThumb {
+
+ public static final int LEFT = 0;
+ public static final int RIGHT = 1;
+
+ private int mIndex;
+ private float mVal;
+ private float mPos;
+ private Bitmap mBitmap;
+ private int mWidthBitmap;
+ private int mHeightBitmap;
+
+ private float mLastTouchX;
+
+ private BarThumb() {
+ mVal = 0;
+ mPos = 0;
+ }
+
+ public int getIndex() {
+ return mIndex;
+ }
+
+ private void setIndex(int index) {
+ mIndex = index;
+ }
+
+ public float getVal() {
+ return mVal;
+ }
+
+ public void setVal(float val) {
+ mVal = val;
+ }
+
+ public float getPos() {
+ return mPos;
+ }
+
+ public void setPos(float pos) {
+ mPos = pos;
+ }
+
+ public Bitmap getBitmap() {
+ return mBitmap;
+ }
+
+ private void setBitmap(@NonNull Bitmap bitmap) {
+ mBitmap = bitmap;
+ mWidthBitmap = bitmap.getWidth();
+ mHeightBitmap = bitmap.getHeight();
+ }
+
+ @NonNull
+ public static List initThumbs(Resources resources) {
+
+ List barThumbs = new Vector<>();
+
+ for (int i = 0; i < 2; i++) {
+ BarThumb th = new BarThumb();
+ th.setIndex(i);
+ if (i == 0) {
+ int resImageLeft = R.drawable.time_line_a;
+ th.setBitmap(BitmapFactory.decodeResource(resources, resImageLeft));
+ } else {
+ int resImageRight = R.drawable.time_line_a;
+ th.setBitmap(BitmapFactory.decodeResource(resources, resImageRight));
+ }
+
+ barThumbs.add(th);
+ }
+
+ return barThumbs;
+ }
+
+ public static int getWidthBitmap(@NonNull List barThumbs) {
+ return barThumbs.get(0).getWidthBitmap();
+ }
+
+ public static int getHeightBitmap(@NonNull List barThumbs) {
+ return barThumbs.get(0).getHeightBitmap();
+ }
+
+ public float getLastTouchX() {
+ return mLastTouchX;
+ }
+
+ public void setLastTouchX(float lastTouchX) {
+ mLastTouchX = lastTouchX;
+ }
+
+ public int getWidthBitmap() {
+ return mWidthBitmap;
+ }
+
+ private int getHeightBitmap() {
+ return mHeightBitmap;
+ }
+}
diff --git a/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/CustomRangeSeekBar.java b/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/CustomRangeSeekBar.java
new file mode 100644
index 0000000..cf2e1c8
--- /dev/null
+++ b/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/CustomRangeSeekBar.java
@@ -0,0 +1,380 @@
+package com.ahmedbadereldin.videotrimmerapplication.javaCode.customVideoViews;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+
+import com.ahmedbadereldin.videotrimmerapplication.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class CustomRangeSeekBar extends View {
+
+ private int mHeightTimeLine;
+ private List mBarThumbs;
+ private List mListeners;
+ private float mMaxWidth;
+ private float mThumbWidth;
+ private float mThumbHeight;
+ private int mViewWidth;
+ private float mPixelRangeMin;
+ private float mPixelRangeMax;
+ private float mScaleRangeMax;
+ private boolean mFirstRun;
+
+ private final Paint mShadow = new Paint();
+ private final Paint mLine = new Paint();
+
+ public CustomRangeSeekBar(@NonNull Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CustomRangeSeekBar(@NonNull Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ private void init() {
+ mBarThumbs = BarThumb.initThumbs(getResources());
+ mThumbWidth = BarThumb.getWidthBitmap(mBarThumbs);
+ mThumbHeight = BarThumb.getHeightBitmap(mBarThumbs);
+
+ mScaleRangeMax = 100;
+ mHeightTimeLine = getContext().getResources().getDimensionPixelOffset(R.dimen.frames_video_height);
+
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+
+ mFirstRun = true;
+
+ int shadowColor = ContextCompat.getColor(getContext(), R.color.shadow_color);
+ mShadow.setAntiAlias(true);
+ mShadow.setColor(shadowColor);
+ mShadow.setAlpha(177);
+
+ int lineColor = ContextCompat.getColor(getContext(), R.color.line_color);
+ mLine.setAntiAlias(true);
+ mLine.setColor(lineColor);
+ mLine.setAlpha(200);
+ }
+
+ public void initMaxWidth() {
+ mMaxWidth = mBarThumbs.get(1).getPos() - mBarThumbs.get(0).getPos();
+
+ onSeekStop(this, 0, mBarThumbs.get(0).getVal());
+ onSeekStop(this, 1, mBarThumbs.get(1).getVal());
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ int minW = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
+ mViewWidth = resolveSizeAndState(minW, widthMeasureSpec, 1);
+
+ int minH = getPaddingBottom() + getPaddingTop() + (int) mThumbHeight;
+ int viewHeight = resolveSizeAndState(minH, heightMeasureSpec, 1);
+
+ setMeasuredDimension(mViewWidth, viewHeight);
+
+ mPixelRangeMin = 0;
+ mPixelRangeMax = mViewWidth - mThumbWidth;
+
+ if (mFirstRun) {
+ for (int i = 0; i < mBarThumbs.size(); i++) {
+ BarThumb th = mBarThumbs.get(i);
+ th.setVal(mScaleRangeMax * i);
+ th.setPos(mPixelRangeMax * i);
+ }
+ // Fire listener callback
+ onCreate(this, currentThumb, getThumbValue(currentThumb));
+ mFirstRun = false;
+ }
+ }
+
+ @Override
+ protected void onDraw(@NonNull Canvas canvas) {
+ super.onDraw(canvas);
+
+ drawShadow(canvas);
+ drawThumbs(canvas);
+ }
+
+ private int currentThumb = 0;
+
+ @Override
+ public boolean onTouchEvent(@NonNull MotionEvent ev) {
+ final BarThumb mBarThumb;
+ final BarThumb mBarThumb2;
+ final float coordinate = ev.getX();
+ final int action = ev.getAction();
+
+ switch (action) {
+ case MotionEvent.ACTION_DOWN: {
+ // Remember where we started
+ currentThumb = getClosestThumb(coordinate);
+
+ if (currentThumb == -1) {
+ return false;
+ }
+
+ mBarThumb = mBarThumbs.get(currentThumb);
+ mBarThumb.setLastTouchX(coordinate);
+ onSeekStart(this, currentThumb, mBarThumb.getVal());
+ return true;
+ }
+ case MotionEvent.ACTION_UP: {
+
+ if (currentThumb == -1) {
+ return false;
+ }
+
+ mBarThumb = mBarThumbs.get(currentThumb);
+ onSeekStop(this, currentThumb, mBarThumb.getVal());
+ return true;
+ }
+
+ case MotionEvent.ACTION_MOVE: {
+ mBarThumb = mBarThumbs.get(currentThumb);
+ mBarThumb2 = mBarThumbs.get(currentThumb == 0 ? 1 : 0);
+ // Calculate the distance moved
+ final float dx = coordinate - mBarThumb.getLastTouchX();
+ final float newX = mBarThumb.getPos() + dx;
+
+ if (currentThumb == 0) {
+
+ if ((newX + mBarThumb.getWidthBitmap()) >= mBarThumb2.getPos()) {
+ mBarThumb.setPos(mBarThumb2.getPos() - mBarThumb.getWidthBitmap());
+ } else if (newX <= mPixelRangeMin) {
+ mBarThumb.setPos(mPixelRangeMin);
+ if ((mBarThumb2.getPos() - (mBarThumb.getPos() + dx)) > mMaxWidth) {
+ mBarThumb2.setPos(mBarThumb.getPos() + dx + mMaxWidth);
+ setThumbPos(1, mBarThumb2.getPos());
+ }
+ } else {
+ //Check if thumb is not out of max width
+// checkPositionThumb(mBarThumb, mBarThumb2, dx, true, coordinate);
+ if ((mBarThumb2.getPos() - (mBarThumb.getPos() + dx)) > mMaxWidth) {
+ mBarThumb2.setPos(mBarThumb.getPos() + dx + mMaxWidth);
+ setThumbPos(1, mBarThumb2.getPos());
+ }
+ // Move the object
+ mBarThumb.setPos(mBarThumb.getPos() + dx);
+
+ // Remember this touch position for the next move event
+ mBarThumb.setLastTouchX(coordinate);
+ }
+
+ } else {
+ if (newX <= mBarThumb2.getPos() + mBarThumb2.getWidthBitmap()) {
+ mBarThumb.setPos(mBarThumb2.getPos() + mBarThumb.getWidthBitmap());
+ } else if (newX >= mPixelRangeMax) {
+ mBarThumb.setPos(mPixelRangeMax);
+ if (((mBarThumb.getPos() + dx) - mBarThumb2.getPos()) > mMaxWidth) {
+ mBarThumb2.setPos(mBarThumb.getPos() + dx - mMaxWidth);
+ setThumbPos(0, mBarThumb2.getPos());
+ }
+ } else {
+ //Check if thumb is not out of max width
+// checkPositionThumb(mBarThumb2, mBarThumb, dx, false, coordinate);
+ if (((mBarThumb.getPos() + dx) - mBarThumb2.getPos()) > mMaxWidth) {
+ mBarThumb2.setPos(mBarThumb.getPos() + dx - mMaxWidth);
+ setThumbPos(0, mBarThumb2.getPos());
+ }
+ // Move the object
+ mBarThumb.setPos(mBarThumb.getPos() + dx);
+ // Remember this touch position for the next move event
+ mBarThumb.setLastTouchX(coordinate);
+ }
+ }
+
+ setThumbPos(currentThumb, mBarThumb.getPos());
+
+ // Invalidate to request a redraw
+ invalidate();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void checkPositionThumb(@NonNull BarThumb mBarThumbLeft, @NonNull BarThumb mBarThumbRight, float dx, boolean isLeftMove, float coordinate) {
+
+ if (isLeftMove && dx < 0) {
+ if ((mBarThumbRight.getPos() - (mBarThumbLeft.getPos() + dx)) > mMaxWidth) {
+ mBarThumbRight.setPos(mBarThumbLeft.getPos() + dx + mMaxWidth);
+ setThumbPos(1, mBarThumbRight.getPos());
+ }
+ } else if (!isLeftMove && dx > 0) {
+ if (((mBarThumbRight.getPos() + dx) - mBarThumbLeft.getPos()) > mMaxWidth) {
+ mBarThumbLeft.setPos(mBarThumbRight.getPos() + dx - mMaxWidth);
+ setThumbPos(0, mBarThumbLeft.getPos());
+ }
+ }
+
+ }
+
+
+ private float pixelToScale(int index, float pixelValue) {
+ float scale = (pixelValue * 100) / mPixelRangeMax;
+ if (index == 0) {
+ float pxThumb = (scale * mThumbWidth) / 100;
+ return scale + (pxThumb * 100) / mPixelRangeMax;
+ } else {
+ float pxThumb = ((100 - scale) * mThumbWidth) / 100;
+ return scale - (pxThumb * 100) / mPixelRangeMax;
+ }
+ }
+
+ private float scaleToPixel(int index, float scaleValue) {
+ float px = (scaleValue * mPixelRangeMax) / 100;
+ if (index == 0) {
+ float pxThumb = (scaleValue * mThumbWidth) / 100;
+ return px - pxThumb;
+ } else {
+ float pxThumb = ((100 - scaleValue) * mThumbWidth) / 100;
+ return px + pxThumb;
+ }
+ }
+
+ private void calculateThumbValue(int index) {
+ if (index < mBarThumbs.size() && !mBarThumbs.isEmpty()) {
+ BarThumb th = mBarThumbs.get(index);
+ th.setVal(pixelToScale(index, th.getPos()));
+ onSeek(this, index, th.getVal());
+ }
+ }
+
+ private void calculateThumbPos(int index) {
+ if (index < mBarThumbs.size() && !mBarThumbs.isEmpty()) {
+ BarThumb th = mBarThumbs.get(index);
+ th.setPos(scaleToPixel(index, th.getVal()));
+ }
+ }
+
+ private float getThumbValue(int index) {
+ return mBarThumbs.get(index).getVal();
+ }
+
+ public void setThumbValue(int index, float value) {
+ mBarThumbs.get(index).setVal(value);
+ calculateThumbPos(index);
+ // Tell the view we want a complete redraw
+ invalidate();
+ }
+
+ private void setThumbPos(int index, float pos) {
+ mBarThumbs.get(index).setPos(pos);
+ calculateThumbValue(index);
+ // Tell the view we want a complete redraw
+ invalidate();
+ }
+
+ private int getClosestThumb(float coordinate) {
+ int closest = -1;
+ if (!mBarThumbs.isEmpty()) {
+ for (int i = 0; i < mBarThumbs.size(); i++) {
+ // Find thumb closest to x coordinate
+ final float tcoordinate = mBarThumbs.get(i).getPos() + mThumbWidth;
+ if (coordinate >= mBarThumbs.get(i).getPos() && coordinate <= tcoordinate) {
+ closest = mBarThumbs.get(i).getIndex();
+ }
+ }
+ }
+ return closest;
+ }
+
+ private void drawShadow(@NonNull Canvas canvas) {
+ if (!mBarThumbs.isEmpty()) {
+
+ for (BarThumb th : mBarThumbs) {
+ if (th.getIndex() == 0) {
+ final float x = th.getPos();
+ if (x > mPixelRangeMin) {
+ Rect mRect = new Rect(0, (int) (mThumbHeight - mHeightTimeLine) / 2,
+ (int) (x + (mThumbWidth / 2)), mHeightTimeLine + (int) (mThumbHeight - mHeightTimeLine) / 2);
+ canvas.drawRect(mRect, mShadow);
+ }
+ } else {
+ final float x = th.getPos();
+ if (x < mPixelRangeMax) {
+ Rect mRect = new Rect((int) (x + (mThumbWidth / 2)), (int) (mThumbHeight - mHeightTimeLine) / 2,
+ (mViewWidth), mHeightTimeLine + (int) (mThumbHeight - mHeightTimeLine) / 2);
+ canvas.drawRect(mRect, mShadow);
+ }
+ }
+ }
+ }
+ }
+
+ private void drawThumbs(@NonNull Canvas canvas) {
+
+ if (!mBarThumbs.isEmpty()) {
+ for (BarThumb th : mBarThumbs) {
+ if (th.getIndex() == 0) {
+ canvas.drawBitmap(th.getBitmap(), th.getPos() + getPaddingLeft(), getPaddingTop(), null);
+ } else {
+ canvas.drawBitmap(th.getBitmap(), th.getPos() - getPaddingRight(), getPaddingTop(), null);
+ }
+ }
+ }
+ }
+
+ public void addOnRangeSeekBarListener(OnRangeSeekBarChangeListener listener) {
+
+ if (mListeners == null) {
+ mListeners = new ArrayList<>();
+ }
+
+ mListeners.add(listener);
+ }
+
+ private void onCreate(CustomRangeSeekBar CustomRangeSeekBar, int index, float value) {
+ if (mListeners == null)
+ return;
+
+ for (OnRangeSeekBarChangeListener item : mListeners) {
+ item.onCreate(CustomRangeSeekBar, index, value);
+ }
+ }
+
+ private void onSeek(CustomRangeSeekBar CustomRangeSeekBar, int index, float value) {
+ if (mListeners == null)
+ return;
+
+ for (OnRangeSeekBarChangeListener item : mListeners) {
+ item.onSeek(CustomRangeSeekBar, index, value);
+ }
+ }
+
+ private void onSeekStart(CustomRangeSeekBar CustomRangeSeekBar, int index, float value) {
+ if (mListeners == null)
+ return;
+
+ for (OnRangeSeekBarChangeListener item : mListeners) {
+ item.onSeekStart(CustomRangeSeekBar, index, value);
+ }
+ }
+
+ private void onSeekStop(CustomRangeSeekBar CustomRangeSeekBar, int index, float value) {
+ if (mListeners == null)
+ return;
+
+ for (OnRangeSeekBarChangeListener item : mListeners) {
+ item.onSeekStop(CustomRangeSeekBar, index, value);
+ }
+ }
+
+ public List getThumbs() {
+ return mBarThumbs;
+ }
+}
diff --git a/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/OnRangeSeekBarChangeListener.java b/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/OnRangeSeekBarChangeListener.java
new file mode 100644
index 0000000..7be4d8a
--- /dev/null
+++ b/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/OnRangeSeekBarChangeListener.java
@@ -0,0 +1,10 @@
+package com.ahmedbadereldin.videotrimmerapplication.javaCode.customVideoViews;
+public interface OnRangeSeekBarChangeListener {
+ void onCreate(CustomRangeSeekBar CustomRangeSeekBar, int index, float value);
+
+ void onSeek(CustomRangeSeekBar CustomRangeSeekBar, int index, float value);
+
+ void onSeekStart(CustomRangeSeekBar CustomRangeSeekBar, int index, float value);
+
+ void onSeekStop(CustomRangeSeekBar CustomRangeSeekBar, int index, float value);
+}
diff --git a/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/OnVideoTrimListener.java b/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/OnVideoTrimListener.java
new file mode 100644
index 0000000..949d6c0
--- /dev/null
+++ b/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/OnVideoTrimListener.java
@@ -0,0 +1,14 @@
+package com.ahmedbadereldin.videotrimmerapplication.javaCode.customVideoViews;
+
+import android.net.Uri;
+
+public interface OnVideoTrimListener {
+
+ void onTrimStarted();
+
+ void getResult(final Uri uri);
+
+ void cancelAction();
+
+ void onError(final String message);
+}
diff --git a/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/TileView.java b/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/TileView.java
new file mode 100644
index 0000000..1faca51
--- /dev/null
+++ b/app/src/main/java/com/ahmedbadereldin/videotrimmerapplication/javaCode/customVideoViews/TileView.java
@@ -0,0 +1,236 @@
+package com.ahmedbadereldin.videotrimmerapplication.javaCode.customVideoViews;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.media.MediaMetadataRetriever;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.util.LongSparseArray;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+
+import com.ahmedbadereldin.videotrimmerapplication.R;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TileView extends View {
+
+ private Uri mVideoUri;
+ private int mHeightView;
+ private LongSparseArray mBitmapList = null;
+ private int viewWidth = 0;
+ private int viewHeight = 0;
+
+ public TileView(@NonNull Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TileView(@NonNull Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ private void init() {
+ mHeightView = getContext().getResources().getDimensionPixelOffset(R.dimen.frames_video_height);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int minW = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
+ int w = resolveSizeAndState(minW, widthMeasureSpec, 1);
+
+ final int minH = getPaddingBottom() + getPaddingTop() + mHeightView;
+ int h = resolveSizeAndState(minH, heightMeasureSpec, 1);
+
+ setMeasuredDimension(w, h);
+ }
+
+ @Override
+ protected void onSizeChanged(final int w, int h, final int oldW, int oldH) {
+ super.onSizeChanged(w, h, oldW, oldH);
+ viewWidth = w;
+ viewHeight = h;
+ if (w != oldW) {
+ if (mVideoUri != null)
+ getBitmap();
+ }
+ }
+
+ private void getBitmap() {
+ BackgroundTask
+ .execute(new BackgroundTask.Task("", 0L, "") {
+ @Override
+ public void execute() {
+ try {
+ LongSparseArray thumbnailList = new LongSparseArray<>();
+
+ MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
+ mediaMetadataRetriever.setDataSource(getContext(), mVideoUri);
+
+ // Retrieve media data
+ long videoLengthInMs = Integer.parseInt(mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)) * 1000;
+
+ // Set thumbnail properties (Thumbs are squares)
+ final int thumbWidth = mHeightView;
+ final int thumbHeight = mHeightView;
+
+ int numThumbs = (int) Math.ceil(((float) viewWidth) / thumbWidth);
+
+ final long interval = videoLengthInMs / numThumbs;
+
+ for (int i = 0; i < numThumbs; ++i) {
+ Bitmap bitmap = mediaMetadataRetriever.getFrameAtTime(i * interval, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
+ // TODO: bitmap might be null here, hence throwing NullPointerException. You were right
+ try {
+ bitmap = Bitmap.createScaledBitmap(bitmap, thumbWidth, thumbHeight, false);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ thumbnailList.put(i, bitmap);
+ }
+
+ mediaMetadataRetriever.release();
+ returnBitmaps(thumbnailList);
+ } catch (final Throwable e) {
+ Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
+ }
+ }
+ }
+ );
+ }
+
+ private void returnBitmaps(final LongSparseArray thumbnailList) {
+ new MainThreadExecutor().runTask("", new Runnable() {
+ @Override
+ public void run() {
+ mBitmapList = thumbnailList;
+ invalidate();
+ }
+ }
+ , 0L);
+ }
+
+ @Override
+ protected void onDraw(@NonNull Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (mBitmapList != null) {
+ canvas.save();
+ int x = 0;
+
+ for (int i = 0; i < mBitmapList.size(); i++) {
+ Bitmap bitmap = mBitmapList.get(i);
+
+ if (bitmap != null) {
+ canvas.drawBitmap(bitmap, x, 0, null);
+ x = x + bitmap.getWidth();
+ }
+ }
+ }
+ }
+
+ public void setVideo(@NonNull Uri data) {
+ mVideoUri = data;
+ getBitmap();
+ }
+
+ public final class MainThreadExecutor {
+
+ private final Handler HANDLER = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ Runnable callback = msg.getCallback();
+ if (callback != null) {
+ callback.run();
+ decrementToken((Token) msg.obj);
+ } else {
+ super.handleMessage(msg);
+ }
+ }
+ };
+
+ private final Map TOKENS = new HashMap<>();
+
+ private MainThreadExecutor() {
+ // should not be instantiated
+ }
+
+ /**
+ * Store a new task in the map for providing cancellation. This method is
+ * used by AndroidAnnotations and not intended to be called by clients.
+ *
+ * @param id the identifier of the task
+ * @param task the task itself
+ * @param delay the delay or zero to run immediately
+ */
+ public void runTask(String id, Runnable task, long delay) {
+ if ("".equals(id)) {
+ HANDLER.postDelayed(task, delay);
+ return;
+ }
+ long time = SystemClock.uptimeMillis() + delay;
+ HANDLER.postAtTime(task, nextToken(id), time);
+ }
+
+ private Token nextToken(String id) {
+ synchronized (TOKENS) {
+ Token token = TOKENS.get(id);
+ if (token == null) {
+ token = new MainThreadExecutor.Token(id);
+ TOKENS.put(id, token);
+ }
+ token.runnablesCount++;
+ return token;
+ }
+ }
+
+ private void decrementToken(Token token) {
+ synchronized (TOKENS) {
+ if (--token.runnablesCount == 0) {
+ String id = token.id;
+ Token old = TOKENS.remove(id);
+ if (old != token) {
+ // a runnable finished after cancelling, we just removed a
+ // wrong token, lets put it back
+ TOKENS.put(id, old);
+ }
+ }
+ }
+ }
+
+ /**
+ * Cancel all tasks having the specified id
.
+ *
+ * @param id the cancellation identifier
+ */
+ public void cancelAll(String id) {
+ Token token;
+ synchronized (TOKENS) {
+ token = TOKENS.remove(id);
+ }
+ if (token == null) {
+ // nothing to cancel
+ return;
+ }
+ HANDLER.removeCallbacksAndMessages(token);
+ }
+
+ private final class Token {
+ int runnablesCount = 0;
+ final String id;
+
+ private Token(String id) {
+ this.id = id;
+ }
+ }
+
+ }
+
+}
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/circle_thumb.xml b/app/src/main/res/drawable/circle_thumb.xml
new file mode 100644
index 0000000..39d0f8e
--- /dev/null
+++ b/app/src/main/res/drawable/circle_thumb.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/error_logo.png b/app/src/main/res/drawable/error_logo.png
new file mode 100644
index 0000000..46cff06
Binary files /dev/null and b/app/src/main/res/drawable/error_logo.png differ
diff --git a/app/src/main/res/drawable/ic_baseline_close_24.xml b/app/src/main/res/drawable/ic_baseline_close_24.xml
new file mode 100644
index 0000000..16d6d37
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_close_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_videocam_24a.xml b/app/src/main/res/drawable/ic_baseline_videocam_24a.xml
new file mode 100644
index 0000000..340bff2
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_videocam_24a.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_white_pause.png b/app/src/main/res/drawable/ic_white_pause.png
new file mode 100644
index 0000000..15e08b5
Binary files /dev/null and b/app/src/main/res/drawable/ic_white_pause.png differ
diff --git a/app/src/main/res/drawable/ic_white_play.png b/app/src/main/res/drawable/ic_white_play.png
new file mode 100644
index 0000000..33169d5
Binary files /dev/null and b/app/src/main/res/drawable/ic_white_play.png differ
diff --git a/app/src/main/res/drawable/round_corner_white_fill3.xml b/app/src/main/res/drawable/round_corner_white_fill3.xml
new file mode 100644
index 0000000..704ac04
--- /dev/null
+++ b/app/src/main/res/drawable/round_corner_white_fill3.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/seekbar_drawable_video.xml b/app/src/main/res/drawable/seekbar_drawable_video.xml
new file mode 100644
index 0000000..46ca651
--- /dev/null
+++ b/app/src/main/res/drawable/seekbar_drawable_video.xml
@@ -0,0 +1,19 @@
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/time_line_a.png b/app/src/main/res/drawable/time_line_a.png
new file mode 100644
index 0000000..6050902
Binary files /dev/null and b/app/src/main/res/drawable/time_line_a.png differ
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..2853329
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_new_post.xml b/app/src/main/res/layout/activity_new_post.xml
new file mode 100644
index 0000000..17584dc
--- /dev/null
+++ b/app/src/main/res/layout/activity_new_post.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_video_trim.xml b/app/src/main/res/layout/activity_video_trim.xml
new file mode 100644
index 0000000..27bdba9
--- /dev/null
+++ b/app/src/main/res/layout/activity_video_trim.xml
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a571e60
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..61da551
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c41dd28
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..db5080a
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6dba46d
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..da31a87
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..15ac681
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b216f2d
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f25a419
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..e96783c
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..703bd70
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,15 @@
+
+
+ #6200EE
+ #3700B3
+ #03DAC5
+
+ #65b7b7b7
+ #0e1f2f
+ #000000
+ #3be3e3
+ #FF15FF00
+ #00000000
+ #ffffff
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml
new file mode 100644
index 0000000..a6dfba3
--- /dev/null
+++ b/app/src/main/res/values/dimen.xml
@@ -0,0 +1,14 @@
+
+
+
+ @dimen/_8sdp
+ @dimen/_5sdp
+ @dimen/_165sdp
+ @dimen/_28sdp
+
+ @dimen/_19ssp
+ @dimen/_12sdp
+
+ 62dp
+ 150dp
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..77e42c3
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,12 @@
+
+ VideoTrimmerApplication
+ Save
+ Cancel
+ Done
+ Select 1 min video
+ Video should be of minimum 3 seconds
+ Should allow permission to work app correct
+ Some Permissions were Denied
+ File format is not supported
+ com.demo.videotrimmer.provider
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..0fe5728
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/test/java/com/ahmedbadereldin/videotrimmerapplication/ExampleUnitTest.kt b/app/src/test/java/com/ahmedbadereldin/videotrimmerapplication/ExampleUnitTest.kt
new file mode 100644
index 0000000..1eebf5f
--- /dev/null
+++ b/app/src/test/java/com/ahmedbadereldin/videotrimmerapplication/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.ahmedbadereldin.videotrimmerapplication
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..59b07ee
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,27 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ ext.kotlin_version = "1.3.72"
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath "com.android.tools.build:gradle:4.0.1"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ maven { url "https://www.jitpack.io" }
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..4d15d01
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,21 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app"s APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..1ab4bdb
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sun Aug 09 08:23:17 EEST 2020
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..6cb3ea2
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+include ':app'
+rootProject.name = "VideoTrimmerApplication"
\ No newline at end of file