/* * Copyright (c) 2015 Ushahidi. * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program in the file LICENSE-AGPL. If not, see * https://www.gnu.org/licenses/agpl-3.0.html */ package com.ushahidi.platform.mobile.app.presentation.view.ui.activity; import com.addhen.android.raiburari.presentation.di.HasComponent; import com.cocosw.bottomsheet.BottomSheet; import com.ushahidi.platform.mobile.app.R; import com.ushahidi.platform.mobile.app.data.PrefsFactory; import com.ushahidi.platform.mobile.app.data.api.account.PlatformSession; import com.ushahidi.platform.mobile.app.data.api.account.SessionManager; import com.ushahidi.platform.mobile.app.presentation.di.components.post.AddPostComponent; import com.ushahidi.platform.mobile.app.presentation.di.components.post.DaggerAddPostComponent; import com.ushahidi.platform.mobile.app.presentation.model.FormAttributeModel; import com.ushahidi.platform.mobile.app.presentation.model.FormStageModel; import com.ushahidi.platform.mobile.app.presentation.model.PostModel; import com.ushahidi.platform.mobile.app.presentation.model.TagModel; import com.ushahidi.platform.mobile.app.presentation.presenter.formattribute.ListFormAttributePresenter; import com.ushahidi.platform.mobile.app.presentation.presenter.formstage.ListFormStagePresenter; import com.ushahidi.platform.mobile.app.presentation.presenter.post.AddPostPresenter; import com.ushahidi.platform.mobile.app.presentation.presenter.tags.ListTagPresenter; import com.ushahidi.platform.mobile.app.presentation.util.ConfigurePostModelUtility; import com.ushahidi.platform.mobile.app.presentation.util.PostValueUtility; import com.ushahidi.platform.mobile.app.presentation.util.Utility; import com.ushahidi.platform.mobile.app.presentation.view.formattribute.ListFormAttributeView; import com.ushahidi.platform.mobile.app.presentation.view.formstage.ListFormStageView; import com.ushahidi.platform.mobile.app.presentation.view.post.AddPostView; import com.ushahidi.platform.mobile.app.presentation.view.tags.ListTagsView; import com.ushahidi.platform.mobile.app.presentation.view.ui.adapter.AddPostFragmentStatePageAdapter; import com.ushahidi.platform.mobile.app.presentation.view.ui.form.ScreenFragmentCallbacks; import com.ushahidi.platform.mobile.app.presentation.view.ui.form.ui.widgets.Widget; import com.ushahidi.platform.mobile.app.presentation.view.ui.form.wizard.Screen; import com.ushahidi.platform.mobile.app.presentation.view.ui.form.wizard.ScreenModelCallbacks; import com.ushahidi.platform.mobile.app.presentation.view.ui.form.wizard.model.AbstractScreenModel; import com.ushahidi.platform.mobile.app.presentation.view.ui.form.wizard.model.PostFormWizardModel; import com.ushahidi.platform.mobile.app.presentation.view.ui.form.wizard.model.PostItemModel; import com.ushahidi.platform.mobile.app.presentation.view.ui.fragment.AddPostFragment; import com.ushahidi.platform.mobile.app.presentation.view.ui.widget.ScrollConfigurableViewPager; import com.ushahidi.platform.mobile.app.presentation.view.ui.widget.TitlePageIndicator; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.view.ViewPager; import android.util.TypedValue; import android.view.View; import android.widget.Button; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import butterknife.Bind; /** * Renders {@link AddPostFragment} * * @author Ushahidi Team <team@ushahidi.com> */ public class AddPostActivity extends BaseAppActivity implements HasComponent<AddPostComponent>, ScreenFragmentCallbacks, ScreenModelCallbacks { /** Key to get post title */ public static final String POST_TITLE_KEY = "post_title"; /** Key to get post content */ public static final String POST_CONTENT_KEY = "post_content"; /** Key to get post tags */ public static final String POST_CATEGORIES = "post_categories"; private static final String INTENT_EXTRA_PARAM_FORM_ID = "com.ushahidi.android.INTENT_PARAM_FORM_ID"; private static final String INTENT_EXTRA_PARAM_FORM_TITLE = "com.ushahidi.android.INTENT_PARAM_FORM_TITLE"; private static final String BUNDLE_STATE_PARAM_FORM_ID = "com.ushahidi.android.STATE_PARAM_FORM_ID"; private static final String BUNDLE_STATE_PARAM_FORM_TITLE = "com.ushahidi.android.STATE_PARAM_FORM_TITLE"; private static final String BUNDLE_STATE_PARAM_FORM_STEPS = "com.ushahidi.android.STATE_PARAM_FORM_STEPS"; private static final String BUNDLE_STATE_PARAM_FORM_ATTRIBUTES = "com.ushahidi.android.STATE_PARAM_FORM_ATTRIBUTES"; private static final String FRAG_TAG = "add_post"; @Bind(R.id.add_post_view_pager) ScrollConfigurableViewPager mAddPostViewPager; @Bind(R.id.next_post_step_button) Button mNextButton; @Bind(R.id.previous_post_step_button) Button mPrevButton; @Inject ListTagPresenter mListTagPresenter; @Bind(R.id.post_step_title_strip) TitlePageIndicator mStepPagerStrip; @Inject ListFormAttributePresenter mListFormAttributePresenter; @Inject ListFormStagePresenter mListFormStagePresenter; @Inject AddPostPresenter mAddPostPresenter; @Inject PrefsFactory mPrefsFactory; private SessionManager<PlatformSession> mSessionManager; private AddPostComponent mAddPostComponent; private AddPostFragment mAddPostFragment; private Long mFormId; private String mFormTitle; private AddPostFragmentStatePageAdapter mAddPostFragmentStatePageAdapter; private AbstractScreenModel mScreenModel; private boolean mConsumeScreenSelectedEvent; private List<Screen> mCurrentScreenSequence = new ArrayList<>(); private List<FormStageModel> mFormStages = new ArrayList<>(); private List<FormAttributeModel> mFormAttributeModels = new ArrayList<>(); private Screen mFirstScreen; /** * Default constructor */ public AddPostActivity() { super(R.layout.activity_add_post, 0); } /** * Provides {@link Intent} for launching this activity * * @param context The calling context * @return The intent to launch this activity */ public static Intent getIntent(final Context context, Long formId, String formTitle) { Intent intent = new Intent(context, AddPostActivity.class); intent.putExtra(INTENT_EXTRA_PARAM_FORM_ID, formId); intent.putExtra(INTENT_EXTRA_PARAM_FORM_TITLE, formTitle); return intent; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); injector(); initialize(savedInstanceState); } @Override public void onResume() { super.onResume(); } @Override public void onPause() { super.onPause(); mListFormAttributePresenter.pause(); mListFormStagePresenter.pause(); mAddPostPresenter.pause(); } @Override public void onDestroy() { super.onDestroy(); mListFormStagePresenter.destroy(); mListFormAttributePresenter.destroy(); mAddPostPresenter.destroy(); if (mScreenModel != null) { mScreenModel.unregisterListener(this); } } @Override public void onSaveInstanceState(Bundle savedInstanceState) { savedInstanceState.putLong(BUNDLE_STATE_PARAM_FORM_ID, mFormId); savedInstanceState.putString(BUNDLE_STATE_PARAM_FORM_TITLE, mFormTitle); savedInstanceState .putParcelableArrayList(BUNDLE_STATE_PARAM_FORM_STEPS, (ArrayList) mFormStages); savedInstanceState.putParcelableArrayList(BUNDLE_STATE_PARAM_FORM_ATTRIBUTES, (ArrayList) mFormAttributeModels); super.onSaveInstanceState(savedInstanceState); } private void injector() { mAddPostComponent = DaggerAddPostComponent.builder() .appComponent(getAppComponent()) .activityModule(getActivityModule()) .build(); mSessionManager = getAppComponent().platformSessionManager(); getComponent().inject(this); } private void initialize(Bundle savedInstanceState) { if (savedInstanceState == null) { mFormId = getIntent().getLongExtra(INTENT_EXTRA_PARAM_FORM_ID, 0l); mFormTitle = getIntent().getStringExtra(INTENT_EXTRA_PARAM_FORM_TITLE); initializeTagsView(); initializeFormAttributeView(); } else { mFormId = savedInstanceState.getLong(BUNDLE_STATE_PARAM_FORM_ID); mFormTitle = savedInstanceState.getString(BUNDLE_STATE_PARAM_FORM_TITLE); mFormStages = (ArrayList) savedInstanceState .getParcelableArrayList(BUNDLE_STATE_PARAM_FORM_STEPS); mFormAttributeModels = (ArrayList) savedInstanceState .getParcelableArrayList(BUNDLE_STATE_PARAM_FORM_ATTRIBUTES); } getSupportActionBar().setTitle(mFormTitle); } private void initView() { mStepPagerStrip.setViewPager(mAddPostViewPager); mStepPagerStrip.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if (!isScreenValid()) { showToast(R.string.required_field_error); mAddPostViewPager.enableScroll(false); mAddPostViewPager.setCurrentItem(position); } else { mAddPostViewPager.enableScroll(true); } updateBottomBar(); } @Override public void onPageScrollStateChanged(int state) { } }); mNextButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mAddPostViewPager.getCurrentItem() == mCurrentScreenSequence.size() - 1) { ArrayList<PostItemModel> postItems = new ArrayList<PostItemModel>(); boolean isValid = true; for (int i = 0; i < mCurrentScreenSequence.size(); i++) { Screen screen = mCurrentScreenSequence.get(i); if (screen.isFirstScreen()) { mFirstScreen = screen; } for (Widget widget : screen.getWidgets()) { if (!widget.validate()) { isValid = false; break; } } screen.getPostItems(postItems); } Collections.sort(postItems, new Comparator<PostItemModel>() { @Override public int compare(PostItemModel a, PostItemModel b) { return a.getWeight() > b.getWeight() ? +1 : a.getWeight() < b.getWeight() ? -1 : 0; } }); if (isValid && mFirstScreen != null) { // TODO: Post item to the API // Configure PostModel String title = mFirstScreen.getStaticViewData().getString(POST_TITLE_KEY); String content = mFirstScreen.getStaticViewData() .getString(POST_CONTENT_KEY); ConfigurePostModelUtility.Builder configurePostModel = new ConfigurePostModelUtility.Builder( mPrefsFactory.getActiveDeploymentId().get(), title, content); // Use form attribute to build post model's value PostValueUtility.Builder postBuilder = new PostValueUtility.Builder(); for (PostItemModel postItemModel : postItems) { FormAttributeModel formAttributeModel = findFormAttribute( postItemModel.getFieldKey()); if (formAttributeModel != null) { // Process point and geometry differently. They should be returned // as object not array if (!formAttributeModel.getType() .equals(FormAttributeModel.Type.POINT) || !formAttributeModel.getType() .equals(FormAttributeModel.Type.GEOMETRY)) { List<String> values = new ArrayList<String>(); values.add(postItemModel.getDisplayValue()); postBuilder.withArray(postItemModel.getFieldKey(), values); } else if (formAttributeModel.getType() .equals(FormAttributeModel.Type.POINT)) { Map<String, String> data = new HashMap<>(); // The LocationWidget returns it's values as string with // a `:` separator in the form, location name:latitude:longitude // Split by : to get the individual values final String[] location = postItemModel.getDisplayValue() .split(":"); data.put("location", location[0]); data.put("lat", location[1]); data.put("lon", location[2]); postBuilder.withObject(postItemModel.getFieldKey(), data); // TODO: Configure geometry } } } configurePostModel.postValue(postBuilder.build()); configurePostModel.postFormId(mFormId); configurePostModel.postUserId(mSessionManager.getActiveSession().getId()); //TODO: Configure post tags and form stages new BottomSheet.Builder(AddPostActivity.this).sheet(R.menu.menu_publish_to) .listener(((dialog, which) -> { PostModel postModel; switch (which) { case R.id.menu_publish_post_to_editors: configurePostModel.postPublishTo("user"); postModel = configurePostModel.build().getPostModel(); mAddPostPresenter.addPost(postModel); break; case R.id.menu_publish_post_to_admin: configurePostModel.postPublishTo("admin"); postModel = configurePostModel.build().getPostModel(); mAddPostPresenter.addPost(postModel); break; default: postModel = configurePostModel.build().getPostModel(); mAddPostPresenter.addPost(postModel); break; } })) .show(); } } else { mAddPostViewPager.setCurrentItem(mAddPostViewPager.getCurrentItem() + 1); } } }); mPrevButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mAddPostViewPager.setCurrentItem(mAddPostViewPager.getCurrentItem() - 1); } }); updateBottomBar(); } private void updateBottomBar() { int position = mAddPostViewPager.getCurrentItem(); if (position == mCurrentScreenSequence.size() - 1) { mNextButton.setText(R.string.finish); } else { TypedValue v = new TypedValue(); getTheme().resolveAttribute(android.R.attr.textAppearanceMedium, v, true); mNextButton.setTextAppearance(this, v.resourceId); } if (position <= 0) { mPrevButton.setText(R.string.who_can_see); } else { mPrevButton.setText(R.string.prev); } } private void initializeFormAttributeView() { mListFormAttributePresenter.setView(new ListFormAttributeView() { @Override public void renderFormAttribute(List<FormAttributeModel> formModel) { mFormAttributeModels = formModel; initListFormStageView(); } @Override public void showLoading() { } @Override public void hideLoading() { } @Override public void showRetry() { } @Override public void hideRetry() { } @Override public void showError(String s) { showSnackbar(mAddPostViewPager, s); } @Override public Context getAppContext() { return getApplicationContext(); } }); mListFormAttributePresenter.getFormDb(mFormId); } private void initListFormStageView() { mListFormStagePresenter.setView(new ListFormStageView() { @Override public void showError(String message) { } @Override public Context getAppContext() { return getApplicationContext(); } @Override public void showLoading() { } @Override public void hideLoading() { } @Override public void showRetry() { } @Override public void hideRetry() { } @Override public void renderFormStage(List<FormStageModel> formModels) { setupPageView(formModels); } }); mListFormStagePresenter.getFormDb(mFormId); } private void addPost(PostModel postModel) { mAddPostPresenter.setView(new AddPostView() { @Override public void onPostSuccessfullyAdded(Long row) { } @Override public void showLoading() { } @Override public void hideLoading() { } @Override public void showRetry() { } @Override public void hideRetry() { } @Override public void showError(String message) { } @Override public Context getAppContext() { return AddPostActivity.this; } }); mAddPostPresenter.addPost(postModel); } private void initializeTagsView() { mListTagPresenter.setView(new ListTagsView() { @Override public void renderTagList(List<TagModel> tagModels) { if (!Utility.isCollectionEmpty(tagModels)) { // TODO: Render post tags } } @Override public void showLoading() { // Do nothing } @Override public void hideLoading() { // Do nothing } @Override public void showRetry() { // Do nothing } @Override public void hideRetry() { // Do nothing } @Override public void showError(String s) { // Do nothing } @Override public Context getAppContext() { return getApplicationContext(); } }); mListTagPresenter.loadTags(); } @Override public AddPostComponent getComponent() { return mAddPostComponent; } @Override public void onScreenDataChanged(Screen page) { if (isScreenValid()) { mAddPostViewPager.enableScroll(true); } else { mAddPostViewPager.enableScroll(false); } } @Override public Screen onGetScreen(String key) { if (mScreenModel != null) { return mScreenModel.findByKey(key); } return null; } private boolean isScreenValid() { Screen page = mCurrentScreenSequence.get(mAddPostViewPager.getCurrentItem()); if (page.isRequired() && !page.isCompleted()) { return false; } return true; } private void setupPageView(List<FormStageModel> result) { mFormStages = result; mScreenModel = new PostFormWizardModel(this, mFormStages, mFormAttributeModels); mScreenModel.registerListener(this); List<String> titles = new ArrayList<>(); for (FormStageModel stage : mFormStages) { titles.add(stage.getLabel()); } mCurrentScreenSequence = mScreenModel.getCurrentScreenSequence(); mAddPostFragmentStatePageAdapter = new AddPostFragmentStatePageAdapter( getSupportFragmentManager(), mCurrentScreenSequence, titles); mAddPostViewPager.setAdapter(mAddPostFragmentStatePageAdapter); initView(); } @Nullable private FormAttributeModel findFormAttribute(@NonNull String formAttributeKey) { if (Utility.isCollectionEmpty(mFormAttributeModels)) { FormAttributeModel foundFormAttributeModel = null; for (FormAttributeModel formAttributeModel : mFormAttributeModels) { if (formAttributeModel.getKey().equals(formAttributeKey)) { foundFormAttributeModel = formAttributeModel; break; } } return foundFormAttributeModel; } return null; } }