Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Bug 123 trim media #23

Merged
merged 18 commits into from

2 participants

@vitriolix
Owner

No description provided.

@n8fr8 n8fr8 was assigned
@n8fr8
Owner

not sure why github isn't seeing this, but i have merged all of this into master

@n8fr8 n8fr8 closed this
@n8fr8 n8fr8 reopened this
@n8fr8 n8fr8 merged commit 9b7ca63 into from
@n8fr8
Owner

xclnt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 3, 2013
  1. @vitriolix

    adding RangeSeekBar librari

    vitriolix authored
  2. @vitriolix

    work on trim ui

    vitriolix authored
    work on trim ui
  3. @vitriolix
  4. @vitriolix
  5. @vitriolix
  6. @vitriolix
  7. @vitriolix
  8. @vitriolix
  9. @vitriolix
  10. @vitriolix
  11. @vitriolix
  12. @vitriolix
  13. @vitriolix
  14. @vitriolix
  15. @vitriolix
  16. @vitriolix
  17. @vitriolix

    fix trim cancel not working

    vitriolix authored
  18. @vitriolix
This page is out of date. Refresh to see the latest.
View
3  .gitmodules
@@ -16,3 +16,6 @@
[submodule "external/HoloEverywhere"]
path = external/HoloEverywhere
url = git://github.com/ChristopheVersieux/HoloEverywhere.git
+[submodule "external/RangeSeekBar"]
+ path = external/RangeSeekBar
+ url = git@github.com:vitriolix/RangeSeekBar.git
View
1  app/project.properties
@@ -21,3 +21,4 @@ android.library.reference.5=../external/OnionKit/library
android.library.reference.6=../external/SlidingMenu/library
android.library.reference.7=../external/cardsui-for-android/CardsUILib
android.library.reference.8=../external/Android-ViewPagerIndicator/library
+android.library.reference.9=../external/RangeSeekBar/library
View
138 app/res/layout/fragment_order_clips.xml
@@ -4,81 +4,87 @@
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:orientation="vertical" >
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="#000000" >
- <ImageView
- android:id="@+id/imageView1"
- android:layout_width="fill_parent"
- android:layout_height="200dip"
- android:adjustViewBounds="true"
- android:src="@drawable/cliptype_long" />
- <info.guardianproject.mrapp.PreviewVideoView
- android:id="@+id/previewVideoView"
- android:layout_width="match_parent"
- android:layout_height="200dip"
- android:visibility="gone"
- android:adjustViewBounds="true"
-
- />
-</LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="#000000"
+ android:orientation="vertical" >
+
+ <ImageView
+ android:id="@+id/imageView1"
+ android:layout_width="fill_parent"
+ android:layout_height="200dip"
+ android:adjustViewBounds="true"
+ android:src="@drawable/cliptype_long" />
+
+ <info.guardianproject.mrapp.PreviewVideoView
+ android:id="@+id/previewVideoView"
+ android:layout_width="match_parent"
+ android:layout_height="200dip"
+ android:adjustViewBounds="true"
+ android:visibility="gone" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/llControlBar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="#000000" >
+
+ <Button
+ android:id="@+id/buttonPlay"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="30dp"
+ android:text="@string/play_recording" />
+
+ <SeekBar
+ android:id="@+id/seekBar1"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+ </LinearLayout>
+
<LinearLayout
+ android:id="@+id/llRangeSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#000000"
+ android:visibility="gone"
>
+ </LinearLayout>
+
- <Button
- android:id="@+id/buttonPlay"
- style="?android:attr/buttonStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="30dp"
- android:text="@string/play_recording" />
-
- <SeekBar
- android:id="@+id/seekBar1"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
-
- android:layout_weight="1" />
-
- </LinearLayout>
- <com.animoto.android.views.DraggableGridView
+ <com.animoto.android.views.DraggableGridView
android:id="@+id/DraggableGridView01"
android:layout_width="fill_parent"
- android:layout_height="150dp">
+ android:layout_height="150dp" >
</com.animoto.android.views.DraggableGridView>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:orientation="horizontal"
- >
-
- <Button
- android:id="@+id/buttonAddNarration"
- style="?android:attr/buttonStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/button_add_narration"
- android:layout_weight="1"
-
- android:enabled="false"
- />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:orientation="horizontal" >
+
+ <Button
+ android:id="@+id/buttonAddNarration"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:enabled="false"
+ android:text="@string/button_add_narration" />
+
+ <Button
+ android:id="@+id/buttonPlayNarration"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:enabled="false"
+ android:text="@string/button_play_narration" />
+ </LinearLayout>
- <Button
- android:id="@+id/buttonPlayNarration"
- style="?android:attr/buttonStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/button_play_narration"
- android:layout_weight="1"
- android:enabled="false"
- />
- </LinearLayout>
-
-</LinearLayout>
+</LinearLayout>
View
4 app/res/menu/context_menu_trim.xml
@@ -0,0 +1,4 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_cancel" android:title="@string/cancel"></item>
+ <item android:id="@+id/menu_trim_clip" android:title="@string/scene_editor_trim_clip"></item>
+</menu>
View
4 app/res/values/strings.xml
@@ -276,4 +276,8 @@ Build number: <xliff:g id="build_number">%s</xliff:g>\n
<string name="err_you_need_at_least_one_account_configured_on_your_device">You need at least one account configured on your device</string>
<string name="you_began_a_new_lesson">You began a new lesson</string>
+ <string name="scene_editor_please_add_clips">Please add clips on the \'Make\' tab before selecting this tab.</string>
+ <string name="scene_editor_trim_clip">Trim clip</string>
+ <string name="cancel">Cancel</string>
+
</resources>
View
180 app/src/info/guardianproject/mrapp/OrderClipsFragment.java
@@ -9,10 +9,12 @@
import java.io.IOException;
import org.ffmpeg.android.MediaDesc;
+import org.holoeverywhere.widget.LinearLayout;
import org.holoeverywhere.widget.SeekBar;
import org.holoeverywhere.widget.SeekBar.OnSeekBarChangeListener;
import org.json.JSONException;
+import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -34,10 +36,13 @@
import com.animoto.android.views.DraggableGridView;
import com.animoto.android.views.OnRearrangeListener;
+import com.efor18.rangeseekbar.RangeSeekBar;
+import com.efor18.rangeseekbar.RangeSeekBar.OnRangeSeekBarChangeListener;
/**
*
*/
+@SuppressLint("ValidFragment") // FIXME don't do this
public class OrderClipsFragment extends Fragment {
private final static String TAG = "OrderClipsFragment";
int layout;
@@ -47,13 +52,17 @@
Button mPlayButton, mButtonAddNarration, mButtonPlayNarration;
private ImageView mImageViewMedia;
private PreviewVideoView mPreviewVideoView = null;
+ private LinearLayout mLLControlBar = null;
private SeekBar mSeekBar = null;
+ RangeSeekBar<Integer> mRangeSeekBar = null;
+ ViewGroup mRangeSeekBarContainer = null;
public MediaProjectManager mMPM;
private Handler mHandlerPub;
-
+ int mCurrentClipIdx = 0;
AudioRecorderView mAudioNarrator = null;
private boolean mKeepRunningPreview = false;
-
+ boolean mTrimMode = false;
+
private File mFileAudioNarration = null;
int mPhotoEssaySlideLength = -1;//5 seconds
@@ -95,6 +104,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
mPreviewVideoView = (PreviewVideoView) view.findViewById(R.id.previewVideoView);
+ mLLControlBar = (LinearLayout) view.findViewById(R.id.llControlBar);
+
mSeekBar = (SeekBar) view.findViewById(R.id.seekBar1);
mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
@@ -122,6 +133,40 @@ public void onStopTrackingTouch(SeekBar seekBar) {
});
+ mRangeSeekBar = new RangeSeekBar<Integer>(0, 99, getActivity());
+
+ mRangeSeekBarContainer = (ViewGroup) view.findViewById(R.id.llRangeSeekBar);
+ mRangeSeekBarContainer.addView(mRangeSeekBar);
+
+ mRangeSeekBar.setOnRangeSeekBarChangeListener(new OnRangeSeekBarChangeListener<Integer>() {
+
+ @Override
+ public void onRangeSeekBarValuesChanged(RangeSeekBar<?> bar, Integer minValue,
+ Integer maxValue) {
+ }
+
+ int min = -1;
+ int max = -1;
+ @Override
+ public void onStartTrackingTouch(RangeSeekBar<?> bar) {
+ min = bar.getSelectedMinValue().intValue();
+ max = bar.getSelectedMaxValue().intValue();
+ }
+
+ @Override
+ public void onStopTrackingTouch(RangeSeekBar<?> bar) {
+ saveTrim();
+ previewClip(mCurrentClipIdx);
+// if (min != bar.getSelectedMinValue().intValue()) {
+// // they were dragging the first handle
+// previewClip(mCurrentClipIdx);
+// } else {
+// // they were dragging the second handle
+// // FIXME try showing the last 1 second only to help picking the end point
+// }
+ }
+ });
+
if (mMPM.mProject.getStoryType() == Project.STORY_TYPE_ESSAY)
{
@@ -199,13 +244,24 @@ else if (mMPM.mProject.getStoryType() == Project.STORY_TYPE_ESSAY
public void run() {
mImageViewMedia.setVisibility(View.VISIBLE);
mPreviewVideoView.setVisibility(View.GONE);
- mKeepRunningPreview = false;;
+ mKeepRunningPreview = false;
+ mPlayButton.setText(R.string.play_recording);
+ showThumbnail(mCurrentClipIdx);
}
});
+
+
loadMedia();
-
+ mImageViewMedia.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ previewClip(mCurrentClipIdx);
+ }
+ });
+
+ showThumbnail(mCurrentClipIdx);
return view;
@@ -364,8 +420,7 @@ private void handleVideoAudioPlayToggle ()
mPreviewVideoView.setVisibility(View.VISIBLE);
// play
- String[] pathArray = mMPM.mScene.getMediaAsPathArray();
- mPreviewVideoView.setMedia(pathArray);
+ mPreviewVideoView.setMedia(mMPM.mScene.getMediaAsArray());
mPreviewVideoView.play();
new Thread ()
@@ -418,33 +473,48 @@ public void onRearrange(int oldIndex, int newIndex) {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- Log.d(TAG, "item clicked");
- Media[] medias = mMPM.mScene.getMediaAsArray();
- if (medias[position] != null) {
-
- if (medias[position].getMimeType().startsWith("video"))
- {
- mImageViewMedia.setVisibility(View.GONE);
- mPreviewVideoView.setVisibility(View.VISIBLE);
- // play
- mPreviewVideoView.stopPlayback();
- String[] pathArray = {medias[position].getPath()};
- mPreviewVideoView.setMedia(pathArray);
- mPreviewVideoView.play();
-
- //mSeekBar.setMax(mPreviewVideoView.getDuration());
-
- }
- else
- {
- mImageViewMedia.setImageBitmap(mActivity.getThumbnail(medias[position]));
- }
+ if (!mTrimMode) {
+ Log.d(TAG, "item clicked");
+ mCurrentClipIdx = position;
+ showThumbnail(position);
+ // previewClip(position);
}
}
});
}
+ private void previewClip(int position) {
+ Media[] medias = mMPM.mScene.getMediaAsArray();
+ if (medias[position] != null) {
+
+ if (medias[position].getMimeType().startsWith("video"))
+ {
+ mImageViewMedia.setVisibility(View.GONE);
+ mPreviewVideoView.setVisibility(View.VISIBLE);
+ // play
+ mPreviewVideoView.stopPlayback();
+ Media[] mediaArray = {medias[position]};
+ mPreviewVideoView.setMedia(mediaArray);
+ mPreviewVideoView.play();
+
+ //mSeekBar.setMax(mPreviewVideoView.getDuration());
+
+ }
+ else
+ {
+ showThumbnail(position);
+ }
+ }
+ }
+
+ private void showThumbnail(int position) {
+ Media[] medias = mMPM.mScene.getMediaAsArray();
+ if (medias[position] != null) {
+ mImageViewMedia.setImageBitmap(mActivity.getThumbnail(medias[position]));
+ }
+ }
+
private void renderPreview ()
{
@@ -480,6 +550,62 @@ private void renderPreview ()
mHandlerPub.sendMessage(msgErr);
Log.e(AppConstants.TAG, "error posting", e);
}
+ }
+
+ public void enableTrimMode(boolean enable) {
+ if (enable) {
+ mLLControlBar.setVisibility(View.GONE);
+ mRangeSeekBarContainer.setVisibility(View.VISIBLE);
+ mTrimMode = true;
+ setupTrimUndo();
+ } else {
+ mLLControlBar.setVisibility(View.VISIBLE);
+ mRangeSeekBarContainer.setVisibility(View.GONE);
+ mTrimMode = false;
+ }
+ }
+
+ public void saveTrim() {
+ Media media = mMPM.mScene.getMediaAsArray()[mCurrentClipIdx];
+ boolean dirty = false;
+
+ if (media.getTrimStart() != mRangeSeekBar.getSelectedMinValue()) {
+ media.setTrimStart(mRangeSeekBar.getSelectedMinValue());
+ dirty = true;
+ }
+
+ if (media.getTrimEnd() != mRangeSeekBar.getSelectedMaxValue()) {
+ media.setTrimEnd(mRangeSeekBar.getSelectedMaxValue());
+ dirty = true;
+ }
+
+ if (dirty) media.save(); // FIXME move dirty into model classes save() method
+ }
+
+ private int trimStartUndo = -1;
+ private int trimEndUndo = -1;
+ public void setupTrimUndo() {
+ Media media = mMPM.mScene.getMediaAsArray()[mCurrentClipIdx];
+
+ trimStartUndo = media.getTrimStart();
+ trimEndUndo = media.getTrimEnd();
+ }
+ public void undoSaveTrim() {
+ Media media = mMPM.mScene.getMediaAsArray()[mCurrentClipIdx];
+
+ if (trimStartUndo != -1) media.setTrimStart(trimStartUndo);
+ if (trimEndUndo != -1) media.setTrimEnd(trimEndUndo);
+ media.save();
+ }
+
+ public void loadTrim() {
+ Media media = mMPM.mScene.getMediaAsArray()[mCurrentClipIdx];
+ mRangeSeekBar.setSelectedMinValue(media.getTrimStart());
+ if (media.getTrimEnd() > 0) {
+ mRangeSeekBar.setSelectedMaxValue(media.getTrimEnd());
+ } else {
+ mRangeSeekBar.setSelectedMaxValue(99);
+ }
}
}
View
81 app/src/info/guardianproject/mrapp/PreviewVideoView.java
@@ -8,6 +8,7 @@
import info.guardianproject.mrapp.model.Media;
import android.content.Context;
import android.media.MediaPlayer;
+import android.os.Handler;
import android.util.AttributeSet;
import android.widget.VideoView;
@@ -18,10 +19,19 @@
public class PreviewVideoView extends VideoView implements MediaPlayer.OnCompletionListener {
private final static String TAG = "PreviewVideoView";
protected int mCurrentMedia = 0;
- protected String[] mPathArray;
+ protected Media[] mMediaArray;
//MediaPlayer mp;
protected Runnable mCompletionCallback = null;
+ private Handler mHandler = new Handler();
+ private Runnable mTrimClipEndTask = new Runnable() {
+ public void run() {
+ PreviewVideoView.this.stopPlayback();
+ PreviewVideoView.this.doComplete();
+ }
+ };
+
+
public PreviewVideoView(Context context) {
super(context);
setOnCompletionListener(this);
@@ -41,8 +51,8 @@ public PreviewVideoView(Context context, AttributeSet attrs, int defStyle) {
}
- public void setMedia(String[] pathArray) {
- mPathArray = pathArray;
+ public void setMedia(Media[] media) {
+ mMediaArray = media;
mCurrentMedia = 0;
}
@@ -51,20 +61,26 @@ public void setCompletionCallback(Runnable runnable) {
}
public void play() {
- for (; mCurrentMedia <= mPathArray.length ; mCurrentMedia++) {
- if (mCurrentMedia == mPathArray.length) {
+ for (; mCurrentMedia <= mMediaArray.length ; mCurrentMedia++) {
+ if (mCurrentMedia == mMediaArray.length) {
mCurrentMedia = 0;
if (mCompletionCallback != null) {
mCompletionCallback.run();
}
break;
} else {
- String path = mPathArray[mCurrentMedia];
+ Media media = mMediaArray[mCurrentMedia];
+ String path = media.getPath();
if (path != null) {
File file = new File(path);
if (file.exists()) {
- this.setVideoPath(path);
- this.start();
+ setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ PreviewVideoView.this.doPlay();
+ }
+ });
+ this.setVideoPath(path);
break;
}
}
@@ -72,9 +88,33 @@ public void play() {
}
}
+ private void doPlay() {
+ Media media = mMediaArray[mCurrentMedia];
+
+ if (media.getDuration() == 0) {
+ // old projects didn't save duration, we need it
+ media.setDuration(getDuration());
+ media.save();
+ }
+
+ if ((media.getTrimStart() > 0) && (media.getTrimStart() < 99)) {
+ int startTime = media.getTrimmedStartTime();
+ seekTo(startTime);
+ }
+
+ if ((media.getTrimEnd() != 0) && (media.getTrimEnd() < 99)) {// && (media.getTrimStart() < media.getTrimEnd())) {
+ mHandler.removeCallbacks(mTrimClipEndTask);
+ int duration = media.getTrimmedDuration();
+ mHandler.postDelayed(mTrimClipEndTask, duration);
+ }
+
+ start();
+ // FIXME make sure to kill off the timer if we close the activity/stop
+ }
+
public void play(int startFrom) {
// TODO if we are already playing, stop, load the new video and start.
- if (startFrom >= 0 && startFrom < mPathArray.length) {
+ if (startFrom >= 0 && startFrom < mMediaArray.length) {
mCurrentMedia = startFrom;
this.play();
@@ -83,14 +123,19 @@ public void play(int startFrom) {
@Override
public void onCompletion(MediaPlayer mp) {
- if (mCurrentMedia < mPathArray.length) {
- mCurrentMedia++;
- play();
- } else {
- mCurrentMedia = 0;
- if (mCompletionCallback != null) {
- mCompletionCallback.run();
- }
- }
+ doComplete();
+ }
+
+ private void doComplete() {
+ mHandler.removeCallbacks(mTrimClipEndTask);
+ if (mCurrentMedia < mMediaArray.length) {
+ mCurrentMedia++;
+ play();
+ } else {
+ mCurrentMedia = 0;
+ if (mCompletionCallback != null) {
+ mCompletionCallback.run();
+ }
+ }
}
}
View
63 app/src/info/guardianproject/mrapp/SceneEditorActivity.java
@@ -39,7 +39,9 @@
import android.widget.Toast;
import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
public class SceneEditorActivity extends EditorBaseActivity implements ActionBar.TabListener {
@@ -53,6 +55,8 @@
private Project mProject = null;
private Template mTemplate = null;
private int mSceneIndex = 0;
+
+ boolean mTrimMode = false;
private final static String CAPTURE_MIMETYPE_AUDIO = "audio/3gpp";
public Fragment mFragmentTab0, mFragmentTab1, mLastTabFrag;
@@ -185,11 +189,70 @@ public boolean onOptionsItemSelected(MenuItem item) {
addShotToScene();
return true;
+ case R.id.itemTrim:
+ if (mFragmentTab1 != null) {
+ ((OrderClipsFragment) mFragmentTab1).loadTrim();
+ ((OrderClipsFragment) mFragmentTab1).enableTrimMode(true);
+ startActionMode(mActionModeCallback);
+ }
+ return true;
}
return super.onOptionsItemSelected(item);
}
+ private boolean actionModelCancel = false;
+ private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
+
+ // Called when the action mode is created; startActionMode() was called
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ // Inflate a menu resource providing context menu items
+ MenuInflater inflater = mode.getMenuInflater();
+ inflater.inflate(R.menu.context_menu_trim, menu);
+ actionModelCancel = false;
+ return true;
+ }
+
+ // Called each time the action mode is shown. Always called after onCreateActionMode, but
+ // may be called multiple times if the mode is invalidated.
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ mTrimMode = true;
+ return false; // Return false if nothing is done
+ }
+
+ // Called when the user selects a contextual menu item
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.menu_cancel:
+ actionModelCancel = true;
+ mode.finish();
+ return true;
+ case R.id.menu_trim_clip:
+ mode.finish();
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ // this has slightly odd save logic so that I can always save exit actionmode as
+ // the checkmark button acts as a cancel but the users will treat it as an accept
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+// mActionMode = null;
+ ((OrderClipsFragment) mFragmentTab1).enableTrimMode(false);
+ mTrimMode = false;
+ if (actionModelCancel) {
+ ((OrderClipsFragment) mFragmentTab1).undoSaveTrim();
+ } else {
+ ((OrderClipsFragment) mFragmentTab1).saveTrim();
+ }
+ }
+ };
+
// FIXME move this into AddClipsFragment?
public void addShotToScene ()
{
View
46 app/src/info/guardianproject/mrapp/Utils.java
@@ -0,0 +1,46 @@
+package info.guardianproject.mrapp;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+
+import org.holoeverywhere.app.Activity;
+import org.holoeverywhere.widget.Toast;
+
+import android.support.v4.app.FragmentActivity;
+
+public class Utils {
+ public static void toastOnUiThread(Activity activity, String message) {
+ final Activity _activity = activity;
+ final String _msg = message;
+ activity.runOnUiThread(new Runnable() {
+ public void run() {
+ Toast.makeText(_activity.getApplicationContext(), _msg, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ public static void toastOnUiThread(FragmentActivity fragmentActivity, String message) {
+ final FragmentActivity _activity = fragmentActivity;
+ final String _msg = message;
+ fragmentActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ Toast.makeText(_activity.getApplicationContext(), _msg, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ /**
+ *
+ * @param timeString in 00:00:00.000 format (hour:min:second.ms)
+ * @return time in ms
+ */
+ public static int convertTimeStringToInt(String timeString) {
+ int duration = 0;
+ try {
+ duration = (int) (new SimpleDateFormat("hh:mm:ss.SS").parse(timeString)).getTime();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return duration;
+ }
+}
View
31 app/src/info/guardianproject/mrapp/db/StoryMakerDB.java
@@ -6,7 +6,7 @@
public class StoryMakerDB extends SQLiteOpenHelper {
- private static final int DB_VERSION = 2;
+ private static final int DB_VERSION = 3;
private static final String DB_NAME = "sm.db";
public StoryMakerDB(Context context) {
@@ -24,7 +24,14 @@ public void onCreate(SQLiteDatabase db) {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- db.execSQL(StoryMakerDB.Schema.Projects.UPDATE_TABLE_PROJECTS);
+ if ((oldVersion < 2) && (newVersion == 2)) {
+ db.execSQL(StoryMakerDB.Schema.Projects.UPDATE_TABLE_PROJECTS);
+ }
+ if ((oldVersion < 3) && (newVersion == 3)) {
+ db.execSQL(StoryMakerDB.Schema.Media.UPDATE_TABLE_MEDIA_ADD_TRIM_START);
+ db.execSQL(StoryMakerDB.Schema.Media.UPDATE_TABLE_MEDIA_ADD_TRIM_END);
+ db.execSQL(StoryMakerDB.Schema.Media.UPDATE_TABLE_MEDIA_ADD_DURATION);
+ }
}
public class Schema
@@ -98,6 +105,9 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
public static final String COL_MIME_TYPE = "mime_type";
public static final String COL_CLIP_TYPE = "clip_type";
public static final String COL_CLIP_INDEX = "clip_index";
+ public static final String COL_TRIM_START = "trim_start";
+ public static final String COL_TRIM_END = "trim_end";
+ public static final String COL_DURATION = "duration";
private static final String CREATE_TABLE_MEDIA = "create table " + NAME + " ("
+ ID + " integer primary key autoincrement, "
@@ -105,8 +115,23 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ COL_PATH + " text not null, "
+ COL_MIME_TYPE + " text not null, "
+ COL_CLIP_TYPE + " text not null, "
- + COL_CLIP_INDEX + " integer not null"
+ + COL_CLIP_INDEX + " integer not null,"
+ + COL_TRIM_START + " integer,"
+ + COL_TRIM_END + " integer,"
+ + COL_DURATION + " integer"
+ "); ";
+
+ private static final String UPDATE_TABLE_MEDIA_ADD_TRIM_START = "alter table " + NAME + " "
+ + "ADD COLUMN "
+ + COL_TRIM_START + " integer;";
+
+ private static final String UPDATE_TABLE_MEDIA_ADD_TRIM_END = "alter table " + NAME + " "
+ + "ADD COLUMN "
+ + COL_TRIM_END + " integer;";
+
+ private static final String UPDATE_TABLE_MEDIA_ADD_DURATION = "alter table " + NAME + " "
+ + "ADD COLUMN "
+ + COL_DURATION + " integer;";
}
// public static final String DB_SCHEMA = Lessons.CREATE_TABLE_LESSONS
View
6 app/src/info/guardianproject/mrapp/media/MediaProjectManager.java
@@ -237,6 +237,12 @@ public void doExportMedia (File fileExport, boolean doCompress, boolean doOverwr
MediaDesc mDesc = new MediaDesc();
mDesc.mimeType = media.getMimeType();
mDesc.path = media.getPath();
+ if (media.getTrimStart() > 0) {
+ mDesc.startTime = "" + media.getTrimmedStartTime() / 1000F;
+ mDesc.duration = "" + media.getTrimmedDuration() / 1000F;
+ } else if ((media.getTrimEnd() < 99) && media.getTrimEnd() > 0) {
+ mDesc.duration = "" + media.getTrimmedDuration() / 1000F;
+ }
applyExportSettings(mDesc);
alMediaIn.add(mIdx, mDesc);
View
141 app/src/info/guardianproject/mrapp/model/Media.java
@@ -20,13 +20,16 @@
protected String clipType; // R.arrays.cliptypes
protected int clipIndex; // which clip is this in the scene
protected int sceneId; // foreign key to the Scene which holds this media
+ protected int trimStart;
+ protected int trimEnd;
+ protected int duration;
public Media(Context context) {
this.context = context;
}
public Media(Context context, int id, String path, String mimeType, String clipType, int clipIndex,
- int sceneId) {
+ int sceneId, int trimStart, int trimEnd, int duration) {
super();
this.context = context;
this.id = id;
@@ -35,6 +38,9 @@ public Media(Context context, int id, String path, String mimeType, String clipT
this.clipType = clipType;
this.clipIndex = clipIndex;
this.sceneId = sceneId;
+ this.trimStart = trimStart;
+ this.trimEnd = trimEnd;
+ this.duration = duration;
}
public Media(Context context, Cursor cursor) {
@@ -52,7 +58,13 @@ public Media(Context context, Cursor cursor) {
cursor.getInt(cursor
.getColumnIndex(StoryMakerDB.Schema.Media.COL_CLIP_INDEX)),
cursor.getInt(cursor
- .getColumnIndex(StoryMakerDB.Schema.Media.COL_SCENE_ID)));
+ .getColumnIndex(StoryMakerDB.Schema.Media.COL_SCENE_ID)),
+ cursor.getInt(cursor
+ .getColumnIndex(StoryMakerDB.Schema.Media.COL_TRIM_START)),
+ cursor.getInt(cursor
+ .getColumnIndex(StoryMakerDB.Schema.Media.COL_TRIM_END)),
+ cursor.getInt(cursor
+ .getColumnIndex(StoryMakerDB.Schema.Media.COL_DURATION)));
}
/***** Table level static methods *****/
@@ -73,6 +85,45 @@ public static Media get(Context context, int id) {
return null;
}
}
+
+ /***** Calculated object level methods *****/
+
+ /**
+ * @return 0.0-1.0 percent into the clip to start play
+ */
+ public float getTrimmedStartPercent() {
+ return (trimStart + 1) / 100F;
+ }
+
+ /**
+ * @return 0.0-1.0 percent into the clip to end play
+ */
+ public float getTrimmedEndPercent() {
+ return (trimEnd + 1) / 100F;
+ }
+
+ /**
+ * @return milliseconds into clip trimmed clip to start playback
+ */
+ public int getTrimmedStartTime() {
+ return Math.round(getTrimmedStartPercent() * duration);
+ }
+
+ /**
+ * @return milliseconds to end of trimmed clip
+ */
+ public int getTrimmedEndTime() {
+ return Math.round(getTrimmedEndPercent() * duration);
+ }
+
+ /**
+ * @return milliseconds trimmed clip will last
+ */
+ public int getTrimmedDuration() {
+ return getTrimmedEndTime() - getTrimmedStartTime();
+ }
+
+ /***** Object level methods *****/
/*
@@ -116,22 +167,6 @@ public static Cursor getAllAsCursor(Context context) {
}
/***** Object level methods *****/
-
-// public void save() {
-// // FIXME be smart about insert vs update
-// ContentValues values = new ContentValues();
-// values.put(StoryMakerDB.Schema.Media.COL_PATH, path);
-// values.put(StoryMakerDB.Schema.Media.COL_MIME_TYPE, mimeType);
-// values.put(StoryMakerDB.Schema.Media.COL_CLIP_TYPE, clipType);
-// values.put(StoryMakerDB.Schema.Media.COL_CLIP_INDEX, clipIndex);
-// values.put(StoryMakerDB.Schema.Media.COL_SCENE_ID, sceneId);
-// ContentResolver cr = context.getContentResolver();
-// Uri uri = cr.insert(
-// ProjectsProvider.MEDIA_CONTENT_URI, values);
-// String lastSegment = uri.getLastPathSegment();
-// int newId = Integer.parseInt(lastSegment);
-// this.setId(newId);
-// }
public void save() {
Cursor cursor = getAsCursor(context, id);
@@ -153,6 +188,9 @@ private ContentValues getValues() {
values.put(StoryMakerDB.Schema.Media.COL_CLIP_TYPE, clipType);
values.put(StoryMakerDB.Schema.Media.COL_CLIP_INDEX, clipIndex);
values.put(StoryMakerDB.Schema.Media.COL_SCENE_ID, sceneId);
+ values.put(StoryMakerDB.Schema.Media.COL_TRIM_START, trimStart);
+ values.put(StoryMakerDB.Schema.Media.COL_TRIM_END, trimEnd);
+ values.put(StoryMakerDB.Schema.Media.COL_DURATION, duration);
return values;
}
@@ -273,17 +311,60 @@ public void setClipType(String clipType) {
this.clipType = clipType;
}
- /**
- * @return the clipIndex
- */
- public int getClipIndex() {
- return clipIndex;
- }
+ /**
+ * @return the clipIndex
+ */
+ public int getClipIndex() {
+ return clipIndex;
+ }
- /**
- * @param clipIndex the clipIndex to set
- */
- public void setClipIndex(int clipIndex) {
- this.clipIndex = clipIndex;
- }
+ /**
+ * @param clipIndex the clipIndex to set
+ */
+ public void setClipIndex(int clipIndex) {
+ this.clipIndex = clipIndex;
+ }
+
+ /**
+ * @return the trimStart
+ */
+ public int getTrimStart() {
+ return trimStart;
+ }
+
+ /**
+ * @param trimStart the trimStart to set
+ */
+ public void setTrimStart(int trimStart) {
+ this.trimStart = trimStart;
+ }
+
+ /**
+ * @return the trimEnd
+ */
+ public int getTrimEnd() {
+ return trimEnd;
+ }
+
+ /**
+ * @param trimEnd the trimEnd to set
+ */
+ public void setTrimEnd(int trimEnd) {
+ this.trimEnd = trimEnd;
+ }
+
+
+ /**
+ * @return the duration
+ */
+ public int getDuration() {
+ return duration;
+ }
+
+ /**
+ * @param duration the duration to set
+ */
+ public void setDuration(int duration) {
+ this.duration = duration;
+ }
}
2  external/OnionKit
@@ -1 +1 @@
-Subproject commit 4d65cf32cd722956986c7bbe17800b23023b59ae
+Subproject commit b6ecf03202452f6657fcc3e668f0253e0b8d95b8
1  external/RangeSeekBar
@@ -0,0 +1 @@
+Subproject commit c823aabb301a8cc2ae086b864f6677eb91245c58
Something went wrong with that request. Please try again.