diff options
9 files changed, 624 insertions, 10 deletions
diff --git a/res/layout/filtershow_presets_management_dialog.xml b/res/layout/filtershow_presets_management_dialog.xml new file mode 100644 index 000000000..f6c6fb764 --- /dev/null +++ b/res/layout/filtershow_presets_management_dialog.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:divider="?android:dividerVertical" + android:showDividers="middle"> + + <ListView + android:id="@+id/listItems" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="8dip" + android:divider="@android:color/transparent" + android:dividerHeight="8dip"/> + + <LinearLayout + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="48dp" + style="?android:attr/buttonBarStyle"> + + <Button + android:id="@+id/cancel" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:text="@string/cancel" + style="?android:attr/buttonBarButtonStyle" /> + + <Button + android:id="@+id/addpreset" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:text="@string/filtershow_save_preset" + style="?android:attr/buttonBarButtonStyle"/> + + <Button + android:id="@+id/ok" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:text="@string/ok" + style="?android:attr/buttonBarButtonStyle"/> + + </LinearLayout> + +</LinearLayout>
\ No newline at end of file diff --git a/res/layout/filtershow_presets_management_row.xml b/res/layout/filtershow_presets_management_row.xml new file mode 100644 index 000000000..648e8746b --- /dev/null +++ b/res/layout/filtershow_presets_management_row.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ImageView + android:id="@+id/imageView" + android:layout_weight=".1" + android:layout_width="80dip" + android:layout_height="80dip" + android:scaleType="fitCenter" + android:layout_gravity="left|center_vertical"/> + + <EditText + android:id="@+id/editView" + android:gravity="center" + android:textSize="18sp" + android:layout_weight="1" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:focusable="true" + android:imeOptions="actionDone" + android:singleLine="true"/> + + <ImageButton + android:id="@+id/deleteUserPreset" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="right|center_vertical" + android:background="@android:color/transparent" + android:layout_weight=".1" + android:gravity="center" + android:src="@drawable/ic_menu_trash_holo_light"/> +</LinearLayout>
\ No newline at end of file diff --git a/res/menu/filtershow_activity_menu.xml b/res/menu/filtershow_activity_menu.xml index cf083de9f..09c6ffe57 100644 --- a/res/menu/filtershow_activity_menu.xml +++ b/res/menu/filtershow_activity_menu.xml @@ -25,6 +25,11 @@ android:visible="true" android:title="@string/show_imagestate_panel" /> <item + android:id="@+id/manageUserPresets" + android:showAsAction="never" + android:visible="true" + android:title="@string/filtershow_manage_preset" /> + <item android:id="@+id/exportFlattenButton" android:showAsAction="never" android:visible="true" diff --git a/res/values/filtershow_strings.xml b/res/values/filtershow_strings.xml index a5c3dc8c4..a820871c6 100644 --- a/res/values/filtershow_strings.xml +++ b/res/values/filtershow_strings.xml @@ -221,4 +221,11 @@ <!-- Label for the notification message [CHAR LIMIT=50] --> <string name="filtershow_notification_message">Processing...</string> + <!-- Label for the save preset menu [CHAR LIMIT=30] --> + <string name="filtershow_save_preset">Save current preset</string> + <!-- Label for the manage preset menu [CHAR LIMIT=30] --> + <string name="filtershow_manage_preset">Manage user presets</string> + <!-- Label for newly created user preset [CHAR LIMIT=30] --> + <string name="filtershow_new_preset">New Preset</string> + </resources> diff --git a/src/com/android/gallery3d/filtershow/data/UserPresetsManager.java b/src/com/android/gallery3d/filtershow/data/UserPresetsManager.java new file mode 100644 index 000000000..114cd3ebc --- /dev/null +++ b/src/com/android/gallery3d/filtershow/data/UserPresetsManager.java @@ -0,0 +1,149 @@ +package com.android.gallery3d.filtershow.data; + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.FilterShowActivity; +import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; +import com.android.gallery3d.filtershow.pipeline.ImagePreset; + +import java.util.ArrayList; + +public class UserPresetsManager implements Handler.Callback { + + private static final String LOGTAG = "UserPresetsManager"; + + private FilterShowActivity mActivity; + private HandlerThread mHandlerThread = null; + private Handler mProcessingHandler = null; + private FilterStackSource mUserPresets; + + private static final int LOAD = 1; + private static final int LOAD_RESULT = 2; + private static final int SAVE = 3; + private static final int DELETE = 4; + private static final int UPDATE = 5; + + private ArrayList<FilterUserPresetRepresentation> mRepresentations; + + private final Handler mResultHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case LOAD_RESULT: + resultLoad(msg); + break; + } + } + }; + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case LOAD: + processLoad(); + return true; + case SAVE: + processSave(msg); + return true; + case DELETE: + processDelete(msg); + return true; + case UPDATE: + processUpdate(msg); + return true; + } + return false; + } + + public UserPresetsManager(FilterShowActivity context) { + mActivity = context; + mHandlerThread = new HandlerThread(LOGTAG, + android.os.Process.THREAD_PRIORITY_BACKGROUND); + mHandlerThread.start(); + mProcessingHandler = new Handler(mHandlerThread.getLooper(), this); + mUserPresets = new FilterStackSource(mActivity); + mUserPresets.open(); + } + + public ArrayList<FilterUserPresetRepresentation> getRepresentations() { + return mRepresentations; + } + + public void load() { + Message msg = mProcessingHandler.obtainMessage(LOAD); + mProcessingHandler.sendMessage(msg); + } + + public void close() { + mUserPresets.close(); + mHandlerThread.quit(); + } + + static class SaveOperation { + String json; + String name; + } + + public void save(ImagePreset preset) { + Message msg = mProcessingHandler.obtainMessage(SAVE); + SaveOperation op = new SaveOperation(); + op.json = preset.getJsonString(mActivity.getString(R.string.saved)); + op.name= mActivity.getString(R.string.filtershow_new_preset); + msg.obj = op; + mProcessingHandler.sendMessage(msg); + } + + public void delete(int id) { + Message msg = mProcessingHandler.obtainMessage(DELETE); + msg.arg1 = id; + mProcessingHandler.sendMessage(msg); + } + + static class UpdateOperation { + int id; + String name; + } + + public void update(FilterUserPresetRepresentation representation) { + Message msg = mProcessingHandler.obtainMessage(UPDATE); + UpdateOperation op = new UpdateOperation(); + op.id = representation.getId(); + op.name = representation.getName(); + msg.obj = op; + mProcessingHandler.sendMessage(msg); + } + + private void processLoad() { + ArrayList<FilterUserPresetRepresentation> list = mUserPresets.getAllUserPresets(); + Message msg = mResultHandler.obtainMessage(LOAD_RESULT); + msg.obj = list; + mResultHandler.sendMessage(msg); + } + + private void resultLoad(Message msg) { + mRepresentations = + (ArrayList<FilterUserPresetRepresentation>) msg.obj; + mActivity.updateUserPresetsFromManager(); + } + + private void processSave(Message msg) { + SaveOperation op = (SaveOperation) msg.obj; + mUserPresets.insertStack(op.name, op.json.getBytes()); + processLoad(); + } + + private void processDelete(Message msg) { + int id = msg.arg1; + mUserPresets.removeStack(id); + processLoad(); + } + + private void processUpdate(Message msg) { + UpdateOperation op = (UpdateOperation) msg.obj; + mUserPresets.updateStackName(op.id, op.name); + processLoad(); + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterUserPresetRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterUserPresetRepresentation.java new file mode 100644 index 000000000..dfdb6fcf0 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterUserPresetRepresentation.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; +import com.android.gallery3d.filtershow.pipeline.ImagePreset; + +public class FilterUserPresetRepresentation extends FilterRepresentation { + + private ImagePreset mPreset; + private int mId; + + public FilterUserPresetRepresentation(String name, ImagePreset preset, int id) { + super(name); + setEditorId(ImageOnlyEditor.ID); + setFilterType(FilterRepresentation.TYPE_FX); + mPreset = preset; + mId = id; + } + + public ImagePreset getImagePreset() { + return mPreset; + } + + public int getId() { + return mId; + } + + public FilterRepresentation copy(){ + FilterRepresentation representation = new FilterUserPresetRepresentation(getName(), + new ImagePreset(mPreset), mId); + return representation; + } + + @Override + public boolean allowsSingleInstanceOnly() { + return true; + } +} diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java index 5a0857bce..28ae2694e 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java @@ -33,6 +33,7 @@ import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation; import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation; import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation; +import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.filters.ImageFilter; import com.android.gallery3d.filtershow.imageshow.GeometryMetadata; @@ -52,8 +53,6 @@ public class ImagePreset { private Vector<FilterRepresentation> mFilters = new Vector<FilterRepresentation>(); - protected boolean mIsFxPreset = false; - private boolean mDoApplyGeometry = true; private boolean mDoApplyFilters = true; @@ -65,7 +64,6 @@ public class ImagePreset { } public ImagePreset(ImagePreset source) { - for (int i = 0; i < source.mFilters.size(); i++) { FilterRepresentation representation = null; FilterRepresentation sourceRepresentation = source.mFilters.elementAt(i); @@ -77,9 +75,8 @@ public class ImagePreset { } else { representation = sourceRepresentation.copy(); } - addFilter(representation); + mFilters.add(representation); } - } public FilterRepresentation getFilterRepresentation(int position) { @@ -340,7 +337,21 @@ public class ImagePreset { setGeometry((GeometryMetadata) representation); return; } - + if (representation instanceof FilterUserPresetRepresentation) { + ImagePreset preset = ((FilterUserPresetRepresentation) representation).getImagePreset(); + // user preset replace everything but geometry + GeometryMetadata geometry = getGeometry(); + mFilters.clear(); + mFilters.add(geometry); + for (int i = 0; i < preset.nbFilters(); i++) { + FilterRepresentation rep = preset.getFilterRepresentation(i); + if (!(representation instanceof GeometryMetadata)) { + addFilter(rep); + } + } + mFilters.add(representation); + return; + } if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) { removeFilter(representation); if (!isNoneBorderFilter(representation)) { @@ -349,7 +360,8 @@ public class ImagePreset { } else if (representation.getFilterType() == FilterRepresentation.TYPE_FX) { boolean found = false; for (int i = 0; i < mFilters.size(); i++) { - int type = mFilters.elementAt(i).getFilterType(); + FilterRepresentation current = mFilters.elementAt(i); + int type = current.getFilterType(); if (found) { if (type != FilterRepresentation.TYPE_VIGNETTE) { mFilters.remove(i); @@ -357,9 +369,33 @@ public class ImagePreset { } } if (type == FilterRepresentation.TYPE_FX) { - mFilters.remove(i); - if (!isNoneFxFilter(representation)) { - mFilters.add(i, representation); + if (current instanceof FilterUserPresetRepresentation) { + ImagePreset preset = ((FilterUserPresetRepresentation) current) + .getImagePreset(); + // If we had an existing user preset, let's remove all the presets that + // were added by it + for (int j = 0; j < preset.nbFilters(); j++) { + FilterRepresentation rep = preset.getFilterRepresentation(j); + int pos = getPositionForRepresentation(rep); + if (pos != -1) { + mFilters.remove(pos); + } + } + int pos = getPositionForRepresentation(current); + if (pos != -1) { + mFilters.remove(pos); + } else { + pos = 0; + } + if (!isNoneFxFilter(representation)) { + mFilters.add(pos, representation); + } + + } else { + mFilters.remove(i); + if (!isNoneFxFilter(representation)) { + mFilters.add(i, representation); + } } found = true; } @@ -535,6 +571,10 @@ public class ImagePreset { // TODO: supports Geometry representations in the state panel. continue; } + if (filter instanceof FilterUserPresetRepresentation) { + // do not show the user preset itself in the state panel + continue; + } State state = new State(filter.getName()); state.setFilterRepresentation(filter); states.add(state); @@ -583,6 +623,9 @@ public class ImagePreset { writer.beginObject(); for (int i = 0; i < numFilters; i++) { FilterRepresentation filter = mFilters.get(i); + if (filter instanceof FilterUserPresetRepresentation) { + continue; + } String sname = filter.getSerializationName(); if (DEBUG) { Log.v(LOGTAG, "Serialization: " + sname); diff --git a/src/com/android/gallery3d/filtershow/presets/PresetManagementDialog.java b/src/com/android/gallery3d/filtershow/presets/PresetManagementDialog.java new file mode 100644 index 000000000..7ab61fcc9 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/presets/PresetManagementDialog.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.filtershow.presets; + +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.FilterShowActivity; + +public class PresetManagementDialog extends DialogFragment implements View.OnClickListener { + private UserPresetsAdapter mAdapter; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.filtershow_presets_management_dialog, container); + + FilterShowActivity activity = (FilterShowActivity) getActivity(); + mAdapter = activity.getUserPresetsAdapter(); + ListView panel = (ListView) view.findViewById(R.id.listItems); + panel.setAdapter(mAdapter); + + view.findViewById(R.id.cancel).setOnClickListener(this); + view.findViewById(R.id.addpreset).setOnClickListener(this); + view.findViewById(R.id.ok).setOnClickListener(this); + getDialog().setTitle(getString(R.string.filtershow_manage_preset)); + return view; + } + + @Override + public void onClick(View v) { + FilterShowActivity activity = (FilterShowActivity) getActivity(); + switch (v.getId()) { + case R.id.cancel: + mAdapter.clearChangedRepresentations(); + mAdapter.clearDeletedRepresentations(); + activity.updateUserPresetsFromAdapter(mAdapter); + dismiss(); + break; + case R.id.addpreset: + activity.saveCurrentImagePreset(); + dismiss(); + break; + case R.id.ok: + mAdapter.updateCurrent(); + activity.updateUserPresetsFromAdapter(mAdapter); + dismiss(); + break; + } + } +} diff --git a/src/com/android/gallery3d/filtershow/presets/UserPresetsAdapter.java b/src/com/android/gallery3d/filtershow/presets/UserPresetsAdapter.java new file mode 100644 index 000000000..dab9ea454 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/presets/UserPresetsAdapter.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.filtershow.presets; + +import android.content.Context; +import android.graphics.Rect; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.ImageView; +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.category.Action; +import com.android.gallery3d.filtershow.category.CategoryView; +import com.android.gallery3d.filtershow.filters.FilterRepresentation; +import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; + +import java.util.ArrayList; + +public class UserPresetsAdapter extends ArrayAdapter<Action> + implements View.OnClickListener, View.OnFocusChangeListener { + private static final String LOGTAG = "UserPresetsAdapter"; + private LayoutInflater mInflater; + private int mIconSize = 160; + private ArrayList<FilterUserPresetRepresentation> mDeletedRepresentations = + new ArrayList<FilterUserPresetRepresentation>(); + private ArrayList<FilterUserPresetRepresentation> mChangedRepresentations = + new ArrayList<FilterUserPresetRepresentation>(); + private EditText mCurrentEditText; + + public UserPresetsAdapter(Context context, int textViewResourceId) { + super(context, textViewResourceId); + mInflater = LayoutInflater.from(context); + mIconSize = context.getResources().getDimensionPixelSize(R.dimen.category_panel_icon_size); + } + + public UserPresetsAdapter(Context context) { + this(context, 0); + } + + @Override + public void add(Action action) { + super.add(action); + action.setAdapter(this); + } + + private void deletePreset(Action action) { + FilterRepresentation rep = action.getRepresentation(); + if (rep instanceof FilterUserPresetRepresentation) { + mDeletedRepresentations.add((FilterUserPresetRepresentation) rep); + } + remove(action); + notifyDataSetChanged(); + } + + private void changePreset(Action action) { + FilterRepresentation rep = action.getRepresentation(); + rep.setName(action.getName()); + if (rep instanceof FilterUserPresetRepresentation) { + mChangedRepresentations.add((FilterUserPresetRepresentation) rep); + } + } + + public void updateCurrent() { + if (mCurrentEditText != null) { + updateActionFromEditText(mCurrentEditText); + } + } + + static class UserPresetViewHolder { + ImageView imageView; + EditText editText; + ImageButton deleteButton; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + UserPresetViewHolder viewHolder; + if (convertView == null) { + convertView = mInflater.inflate(R.layout.filtershow_presets_management_row, null); + viewHolder = new UserPresetViewHolder(); + viewHolder.imageView = (ImageView) convertView.findViewById(R.id.imageView); + viewHolder.editText = (EditText) convertView.findViewById(R.id.editView); + viewHolder.deleteButton = (ImageButton) convertView.findViewById(R.id.deleteUserPreset); + viewHolder.editText.setOnClickListener(this); + viewHolder.editText.setOnFocusChangeListener(this); + viewHolder.deleteButton.setOnClickListener(this); + convertView.setTag(viewHolder); + } else { + viewHolder = (UserPresetViewHolder) convertView.getTag(); + } + Action action = getItem(position); + viewHolder.imageView.setImageBitmap(action.getImage()); + if (action.getImage() == null) { + // queue image rendering for this action + action.setImageFrame(new Rect(0, 0, mIconSize, mIconSize), CategoryView.VERTICAL); + } + viewHolder.deleteButton.setTag(action); + viewHolder.editText.setTag(action); + viewHolder.editText.setHint(action.getName()); + + return convertView; + } + + public ArrayList<FilterUserPresetRepresentation> getDeletedRepresentations() { + return mDeletedRepresentations; + } + + public void clearDeletedRepresentations() { + mDeletedRepresentations.clear(); + } + + public ArrayList<FilterUserPresetRepresentation> getChangedRepresentations() { + return mChangedRepresentations; + } + + public void clearChangedRepresentations() { + mChangedRepresentations.clear(); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.editView: + v.requestFocus(); + break; + case R.id.deleteUserPreset: + Action action = (Action) v.getTag(); + deletePreset(action); + break; + } + } + + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (v.getId() != R.id.editView) { + return; + } + EditText editText = (EditText) v; + if (!hasFocus) { + updateActionFromEditText(editText); + } else { + mCurrentEditText = editText; + } + } + + private void updateActionFromEditText(EditText editText) { + Action action = (Action) editText.getTag(); + String newName = editText.getText().toString(); + if (newName.length() > 0) { + action.setName(editText.getText().toString()); + changePreset(action); + } + } +} |