/*
* 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;
}
}