From 06da82de578feaa59ba29602b47696662dcaff0b Mon Sep 17 00:00:00 2001 From: Ruby Hartono <58564005+rh-id@users.noreply.github.com> Date: Tue, 8 Aug 2023 12:48:09 +0800 Subject: [PATCH] [Feature] Enable multi select themes for Style Transfer --- .../app/provider/command/STApplyCommand.java | 5 +- .../rh/id/a_jarwis/app/ui/page/HomePage.java | 4 +- .../app/ui/page/common/SelectSTThemePage.java | 92 ++++++++++++++++--- .../app/ui/page/nav/param/SelectedTheme.java | 12 ++- app/src/main/res/drawable/state_selected.xml | 5 + .../main/res/layout/page_select_st_theme.xml | 32 +++++-- .../provider/component/STEngine.java | 5 +- .../workmanager/STApplyWorkRequest.java | 19 ++-- .../workmanager/model/STApplySerialFile.java | 12 ++- 9 files changed, 143 insertions(+), 43 deletions(-) create mode 100644 app/src/main/res/drawable/state_selected.xml diff --git a/app/src/main/java/m/co/rh/id/a_jarwis/app/provider/command/STApplyCommand.java b/app/src/main/java/m/co/rh/id/a_jarwis/app/provider/command/STApplyCommand.java index f22f524..144f1c3 100644 --- a/app/src/main/java/m/co/rh/id/a_jarwis/app/provider/command/STApplyCommand.java +++ b/app/src/main/java/m/co/rh/id/a_jarwis/app/provider/command/STApplyCommand.java @@ -3,6 +3,7 @@ import android.net.Uri; import java.io.File; +import java.util.Collection; import java.util.concurrent.ExecutorService; import io.reactivex.rxjava3.core.Single; @@ -21,7 +22,7 @@ public STApplyCommand(Provider provider) { mSTEngine = provider.get(STEngine.class); } - public Single execute(Uri uriFile, int theme) { + public Single execute(Uri uriFile, Collection themes) { return Single.fromFuture(mExecutorService.submit(() -> { String fullPath = uriFile.getPath(); int cut = fullPath.lastIndexOf("/"); @@ -33,7 +34,7 @@ public Single execute(Uri uriFile, int theme) { } File result = mFileHelper .createImageTempFile(fileName, uriFile); - mSTEngine.enqueueST(result, theme); + mSTEngine.enqueueST(result, themes); return result; })); } diff --git a/app/src/main/java/m/co/rh/id/a_jarwis/app/ui/page/HomePage.java b/app/src/main/java/m/co/rh/id/a_jarwis/app/ui/page/HomePage.java index 2fb14d3..62dac9b 100644 --- a/app/src/main/java/m/co/rh/id/a_jarwis/app/ui/page/HomePage.java +++ b/app/src/main/java/m/co/rh/id/a_jarwis/app/ui/page/HomePage.java @@ -447,7 +447,7 @@ public void onActivityResult(View currentView, Activity activity, INavigator INa if (!uriList.isEmpty()) { mRxDisposer.add("onActivityResult_nstApplyPicture_multiple", Flowable.fromIterable(uriList) - .map(uri -> mSTApplyCommand.execute(uri, mSelectedNSTTheme.getSelectedTheme()) + .map(uri -> mSTApplyCommand.execute(uri, mSelectedNSTTheme.getSelectedThemes()) .blockingGet()) .subscribeOn(Schedulers.from(mExecutorService)) .doOnError(throwable -> consumeFile.accept(null, throwable)) @@ -456,7 +456,7 @@ public void onActivityResult(View currentView, Activity activity, INavigator INa } } else { mRxDisposer.add("onActivityResult_nstApplyPicture", - mSTApplyCommand.execute(fullPhotoUri, mSelectedNSTTheme.getSelectedTheme()) + mSTApplyCommand.execute(fullPhotoUri, mSelectedNSTTheme.getSelectedThemes()) .subscribeOn(Schedulers.from(mExecutorService)) .subscribe(consumeFile)); } diff --git a/app/src/main/java/m/co/rh/id/a_jarwis/app/ui/page/common/SelectSTThemePage.java b/app/src/main/java/m/co/rh/id/a_jarwis/app/ui/page/common/SelectSTThemePage.java index 282e0eb..fddff64 100644 --- a/app/src/main/java/m/co/rh/id/a_jarwis/app/ui/page/common/SelectSTThemePage.java +++ b/app/src/main/java/m/co/rh/id/a_jarwis/app/ui/page/common/SelectSTThemePage.java @@ -4,18 +4,44 @@ import android.view.View; import android.view.ViewGroup; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import co.rh.id.lib.rx3_utils.subject.SerialBehaviorSubject; +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import m.co.rh.id.a_jarwis.R; import m.co.rh.id.a_jarwis.app.ui.page.nav.param.SelectedTheme; +import m.co.rh.id.a_jarwis.base.provider.IStatefulViewProvider; +import m.co.rh.id.a_jarwis.base.rx.RxDisposer; import m.co.rh.id.a_jarwis.ml_engine.provider.component.STEngine; import m.co.rh.id.anavigator.StatefulView; import m.co.rh.id.anavigator.annotation.NavInject; import m.co.rh.id.anavigator.component.INavigator; +import m.co.rh.id.anavigator.component.RequireComponent; +import m.co.rh.id.aprovider.Provider; -public class SelectSTThemePage extends StatefulView implements View.OnClickListener { +public class SelectSTThemePage extends StatefulView implements RequireComponent, View.OnClickListener { @NavInject private transient INavigator mNavigator; + private transient Provider mSvProvider; + + private transient RxDisposer mRxDisposer; + + private SerialBehaviorSubject> mSelectedThemesId; + + public SelectSTThemePage() { + mSelectedThemesId = new SerialBehaviorSubject<>(new HashSet<>()); + } + + @Override + public void provideComponent(Provider provider) { + mSvProvider = provider.get(IStatefulViewProvider.class); + mRxDisposer = mSvProvider.get(RxDisposer.class); + } + @Override protected View createView(Activity activity, ViewGroup container) { View rootView = activity.getLayoutInflater().inflate(R.layout.page_select_st_theme, container, false); @@ -31,24 +57,66 @@ protected View createView(Activity activity, ViewGroup container) { pointilism.setOnClickListener(this); View backButton = rootView.findViewById(R.id.button_back); backButton.setOnClickListener(this); + View nextButton = rootView.findViewById(R.id.button_next); + nextButton.setOnClickListener(this); + mRxDisposer.add("createView_onSelectedThemesChanged", mSelectedThemesId.getSubject() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(integers -> { + mosaic.setSelected(false); + candy.setSelected(false); + rainPrincess.setSelected(false); + udnie.setSelected(false); + pointilism.setSelected(false); + for (Integer id : integers) { + rootView.findViewById(id).setSelected(true); + } + nextButton.setEnabled(!integers.isEmpty()); + })); return rootView; } + @Override + public void dispose(Activity activity) { + super.dispose(activity); + if (mSvProvider != null) { + mSvProvider.dispose(); + mSvProvider = null; + } + } + @Override public void onClick(View view) { int id = view.getId(); - if (id == R.id.container_mosaic_theme) { - mNavigator.pop(new SelectedTheme(STEngine.THEME_MOSAIC)); - } else if (id == R.id.container_candy_theme) { - mNavigator.pop(new SelectedTheme(STEngine.THEME_CANDY)); - } else if (id == R.id.container_rain_princess_theme) { - mNavigator.pop(new SelectedTheme(STEngine.THEME_RAIN_PRINCESS)); - } else if (id == R.id.container_udnie_theme) { - mNavigator.pop(new SelectedTheme(STEngine.THEME_UDNIE)); - } else if (id == R.id.container_pointilism_theme) { - mNavigator.pop(new SelectedTheme(STEngine.THEME_POINTILISM)); - } else if (id == R.id.button_back) { + if (id == R.id.button_back) { mNavigator.pop(); + } else if (id == R.id.button_next) { + List result = new ArrayList<>(); + HashSet hashSet = mSelectedThemesId.getValue(); + for (Integer themeId : hashSet) { + if (themeId == R.id.container_mosaic_theme) { + result.add(STEngine.THEME_MOSAIC); + } else if (themeId == R.id.container_candy_theme) { + result.add(STEngine.THEME_CANDY); + } else if (themeId == R.id.container_rain_princess_theme) { + result.add(STEngine.THEME_RAIN_PRINCESS); + } else if (themeId == R.id.container_udnie_theme) { + result.add(STEngine.THEME_UDNIE); + } else if (themeId == R.id.container_pointilism_theme) { + result.add(STEngine.THEME_POINTILISM); + } + } + mNavigator.pop(new SelectedTheme(result)); + } else { + selectReselectTheme(id); + } + } + + private void selectReselectTheme(int theme) { + HashSet hashSet = mSelectedThemesId.getValue(); + boolean added = hashSet.add(theme); + if (!added) { + hashSet.remove(theme); } + mSelectedThemesId.onNext(hashSet); } } diff --git a/app/src/main/java/m/co/rh/id/a_jarwis/app/ui/page/nav/param/SelectedTheme.java b/app/src/main/java/m/co/rh/id/a_jarwis/app/ui/page/nav/param/SelectedTheme.java index b70505b..15f6636 100644 --- a/app/src/main/java/m/co/rh/id/a_jarwis/app/ui/page/nav/param/SelectedTheme.java +++ b/app/src/main/java/m/co/rh/id/a_jarwis/app/ui/page/nav/param/SelectedTheme.java @@ -1,15 +1,17 @@ package m.co.rh.id.a_jarwis.app.ui.page.nav.param; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; public class SelectedTheme implements Serializable { - private int selectedTheme; + private ArrayList selectedThemes; - public SelectedTheme(int selectedTheme) { - this.selectedTheme = selectedTheme; + public SelectedTheme(Collection selectedThemes) { + this.selectedThemes = new ArrayList<>(selectedThemes); } - public int getSelectedTheme() { - return selectedTheme; + public ArrayList getSelectedThemes() { + return selectedThemes; } } diff --git a/app/src/main/res/drawable/state_selected.xml b/app/src/main/res/drawable/state_selected.xml new file mode 100644 index 0000000..c629727 --- /dev/null +++ b/app/src/main/res/drawable/state_selected.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/page_select_st_theme.xml b/app/src/main/res/layout/page_select_st_theme.xml index 1df9fda..9ae01b4 100644 --- a/app/src/main/res/layout/page_select_st_theme.xml +++ b/app/src/main/res/layout/page_select_st_theme.xml @@ -16,7 +16,6 @@ + android:layout_margin="@dimen/text_margin" + android:background="@drawable/state_selected"> + android:layout_margin="@dimen/text_margin" + android:background="@drawable/state_selected"> + android:layout_margin="@dimen/text_margin" + android:background="@drawable/state_selected"> + android:layout_margin="@dimen/text_margin" + android:background="@drawable/state_selected"> + android:layout_margin="@dimen/text_margin" + android:background="@drawable/state_selected"> + + \ No newline at end of file diff --git a/ml-engine/src/main/java/m/co/rh/id/a_jarwis/ml_engine/provider/component/STEngine.java b/ml-engine/src/main/java/m/co/rh/id/a_jarwis/ml_engine/provider/component/STEngine.java index 2c13e36..d9d6026 100644 --- a/ml-engine/src/main/java/m/co/rh/id/a_jarwis/ml_engine/provider/component/STEngine.java +++ b/ml-engine/src/main/java/m/co/rh/id/a_jarwis/ml_engine/provider/component/STEngine.java @@ -10,6 +10,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; +import java.util.Collection; import m.co.rh.id.a_jarwis.base.provider.component.helper.FileHelper; import m.co.rh.id.a_jarwis.base.util.SerializeUtils; @@ -78,12 +79,12 @@ public Bitmap apply(Bitmap bitmap, int theme) { } } - public void enqueueST(File imageFile, int theme) { + public void enqueueST(File imageFile, Collection themes) { ObjectOutputStream oos = null; try { File serialFile = mFileHelper.createTempFile(); oos = new ObjectOutputStream(new FileOutputStream(serialFile)); - STApplySerialFile STApplySerialFile = new STApplySerialFile(imageFile, theme); + STApplySerialFile STApplySerialFile = new STApplySerialFile(imageFile, themes); oos.writeObject(STApplySerialFile); oos.close(); Data.Builder inputBuilder = new Data.Builder(); diff --git a/ml-engine/src/main/java/m/co/rh/id/a_jarwis/ml_engine/workmanager/STApplyWorkRequest.java b/ml-engine/src/main/java/m/co/rh/id/a_jarwis/ml_engine/workmanager/STApplyWorkRequest.java index 5722c96..fb8be70 100644 --- a/ml-engine/src/main/java/m/co/rh/id/a_jarwis/ml_engine/workmanager/STApplyWorkRequest.java +++ b/ml-engine/src/main/java/m/co/rh/id/a_jarwis/ml_engine/workmanager/STApplyWorkRequest.java @@ -13,6 +13,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; +import java.util.ArrayList; import m.co.rh.id.a_jarwis.base.BaseApplication; import m.co.rh.id.a_jarwis.base.provider.component.helper.MediaHelper; @@ -46,18 +47,18 @@ public Result doWork() { ois = new ObjectInputStream(new FileInputStream(serialFile)); STApplySerialFile STApplySerialFile = (STApplySerialFile) ois.readObject(); inputFile = STApplySerialFile.getInputFile(); - int theme = STApplySerialFile.getTheme(); - + ArrayList themes = STApplySerialFile.getThemes(); Bitmap input = BitmapFactory.decodeFile(inputFile.getAbsolutePath()); - Bitmap applied = STEngine.apply(input, theme); String fileName = inputFile.getName(); - if (applied != null) { - mediaHelper.insertImage(applied, fileName, fileName); - applied.recycle(); - input.recycle(); - logger.i(TAG, getApplicationContext() - .getString(m.co.rh.id.a_jarwis.base.R.string.done_processing_, fileName)); + for (Integer theme : themes) { + Bitmap applied = STEngine.apply(input, theme); + if (applied != null) { + mediaHelper.insertImage(applied, fileName, fileName); + applied.recycle(); + } } + logger.i(TAG, getApplicationContext() + .getString(m.co.rh.id.a_jarwis.base.R.string.done_processing_, fileName)); } catch (Exception e) { logger.e(TAG, e.getMessage(), e); return Result.failure(); diff --git a/ml-engine/src/main/java/m/co/rh/id/a_jarwis/ml_engine/workmanager/model/STApplySerialFile.java b/ml-engine/src/main/java/m/co/rh/id/a_jarwis/ml_engine/workmanager/model/STApplySerialFile.java index faa0cbb..aa9ef32 100644 --- a/ml-engine/src/main/java/m/co/rh/id/a_jarwis/ml_engine/workmanager/model/STApplySerialFile.java +++ b/ml-engine/src/main/java/m/co/rh/id/a_jarwis/ml_engine/workmanager/model/STApplySerialFile.java @@ -2,22 +2,24 @@ import java.io.File; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; public class STApplySerialFile implements Serializable { private File inputFile; - private int theme; + private ArrayList themes; - public STApplySerialFile(File inputFile, int theme) { + public STApplySerialFile(File inputFile, Collection themes) { this.inputFile = inputFile; - this.theme = theme; + this.themes = new ArrayList<>(themes); } public File getInputFile() { return inputFile; } - public int getTheme() { - return theme; + public ArrayList getThemes() { + return themes; } }