Create Challenge with Tasks

This commit is contained in:
Negue 2017-04-20 22:10:52 +02:00
parent f43eb684c8
commit 8ccc323417
15 changed files with 218 additions and 38 deletions

View file

@ -36,7 +36,7 @@
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:hint="New challenge title"
android:id="@+id/create_challenge_title"
android:textColor="@color/white"
android:textColorHighlight="@color/brand_500"
android:textColorHint="@color/brand_500"
@ -57,6 +57,7 @@
android:hint="Description"
android:inputType="textMultiLine"
android:id="@+id/create_challenge_description"
android:maxLines="5"
android:minLines="3"
android:textColor="@color/white"
@ -115,6 +116,7 @@
android:inputType="number"
android:textColor="#8a000000"
android:text="1"
android:id="@+id/create_challenge_prize"
android:textAlignment="center" />
<Button
@ -160,6 +162,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="23dp"
android:id="@+id/create_challenge_tag"
android:hint="Identify your challenge with a tag .."
android:textColorHint="#61000000" />

View file

@ -814,17 +814,22 @@ public class ApiClientImpl implements Action1<Throwable>, ApiClient {
@Override
public Observable<Challenge> createChallenge(PostChallenge challenge){
public Observable<Challenge> createChallenge(PostChallenge challenge) {
return apiService.createChallenge(challenge).compose(configureApiCallObserver());
}
@Override
public Observable<Challenge> updateChallenge(PostChallenge challenge){
public Observable<Void> createChallengeTasks(String challengeId, List<Task> tasks) {
return apiService.createChallengeTasks(challengeId, tasks).compose(configureApiCallObserver());
}
@Override
public Observable<Challenge> updateChallenge(PostChallenge challenge) {
return apiService.updateChallenge(challenge.id, challenge).compose(configureApiCallObserver());
}
@Override
public Observable<Void> deleteChallenge(String challengeId){
public Observable<Void> deleteChallenge(String challengeId) {
return apiService.deleteChallenge(challengeId).compose(configureApiCallObserver());
}

View file

@ -2,11 +2,14 @@ package com.habitrpg.android.habitica.data;
import com.magicmicky.habitrpgwrapper.lib.models.Challenge;
import com.magicmicky.habitrpgwrapper.lib.models.PostChallenge;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
import java.util.List;
import rx.Observable;
public interface ChallengeRepository extends BaseRepository {
Observable<Challenge> createChallenge(PostChallenge challenge);
Observable<Challenge> updateChallenge(PostChallenge challenge);
Observable<Challenge> createChallenge(PostChallenge challenge, List<Task> taskList);
Observable<Challenge> updateChallenge(PostChallenge challenge, List<Task> taskList);
Observable<Void> deleteChallenge(String challengeId);
}

View file

@ -1,10 +1,16 @@
package com.habitrpg.android.habitica.data.implementation;
import com.github.underscore.$;
import com.habitrpg.android.habitica.data.ChallengeRepository;
import com.habitrpg.android.habitica.data.local.ChallengeLocalRepository;
import com.magicmicky.habitrpgwrapper.lib.api.ApiClient;
import com.magicmicky.habitrpgwrapper.lib.models.Challenge;
import com.magicmicky.habitrpgwrapper.lib.models.PostChallenge;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.TasksOrder;
import java.util.List;
import java.util.Map;
import rx.Observable;
@ -16,12 +22,47 @@ public class ChallengeRepositoryImpl extends BaseRepositoryImpl<ChallengeLocalRe
}
@Override
public Observable<Challenge> createChallenge(PostChallenge challenge) {
return apiClient.createChallenge(challenge);
public Observable<Challenge> createChallenge(PostChallenge challenge, List<Task> taskList) {
Map<String, List<Task>> stringListMap = $.groupBy(taskList, t -> t.getType());
TasksOrder tasksOrder = new TasksOrder();
for (Map.Entry<String, List<Task>> entry : stringListMap.entrySet()){
List<String> taskIdList = $.map(entry.getValue(), t -> t.getId());
switch(entry.getKey()) {
case Task.TYPE_HABIT:
tasksOrder.setHabits(taskIdList);
break;
case Task.TYPE_DAILY:
tasksOrder.setDailys(taskIdList);
break;
case Task.TYPE_TODO:
tasksOrder.setTodos(taskIdList);
break;
case Task.TYPE_REWARD:
tasksOrder.setRewards(taskIdList);
break;
}
}
challenge.tasksOrder = tasksOrder;
return Observable.create(subscriber -> {
apiClient.createChallenge(challenge).subscribe(challenge1 -> {
apiClient.createChallengeTasks(challenge1.id, taskList).subscribe(tasks -> {
subscriber.onNext(challenge1);
subscriber.onCompleted();
}, throwable ->
subscriber.onError(throwable));
}, throwable ->
subscriber.onError(throwable));
});
}
@Override
public Observable<Challenge> updateChallenge(PostChallenge challenge) {
public Observable<Challenge> updateChallenge(PostChallenge challenge, List<Task> taskList) {
return apiClient.updateChallenge(challenge);
}

View file

@ -8,5 +8,5 @@ import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
public class TaskSaveEvent {
public Task task;
public boolean created;
public boolean ignoreEvent;
}

View file

@ -5,8 +5,14 @@ package com.habitrpg.android.habitica.events.commands;
*/
public class DeleteTaskCommand {
public String TaskIdToDelete;
public boolean ignoreEvent;
public DeleteTaskCommand(String id) {
this(id, false);
}
public DeleteTaskCommand(String id, boolean ignore) {
TaskIdToDelete = id;
ignoreEvent = ignore;
}
}

View file

@ -14,35 +14,54 @@ import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import com.habitrpg.android.habitica.HabiticaApplication;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.components.AppComponent;
import com.habitrpg.android.habitica.data.ChallengeRepository;
import com.habitrpg.android.habitica.data.local.ChallengeLocalRepository;
import com.habitrpg.android.habitica.events.TaskSaveEvent;
import com.habitrpg.android.habitica.events.TaskTappedEvent;
import com.habitrpg.android.habitica.events.commands.DeleteTaskCommand;
import com.habitrpg.android.habitica.ui.adapter.social.challenges.ChallengeTasksRecyclerViewAdapter;
import com.magicmicky.habitrpgwrapper.lib.models.Challenge;
import com.magicmicky.habitrpgwrapper.lib.models.Group;
import com.magicmicky.habitrpgwrapper.lib.models.PostChallenge;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.OnClick;
public class CreateChallengeActivity extends BaseActivity {
@BindView(R.id.create_challenge_title)
EditText create_challenge_title;
@BindView(R.id.create_challenge_description)
EditText create_challenge_description;
@BindView(R.id.create_challenge_prize)
EditText create_challenge_prize;
@BindView(R.id.create_challenge_tag)
EditText create_challenge_tag;
@BindView(R.id.challenge_location_spinner)
Spinner challenge_location_spinner;
@ -53,12 +72,16 @@ public class CreateChallengeActivity extends BaseActivity {
@Inject
ChallengeLocalRepository challengeLocalRepository;
@Inject
ChallengeRepository challengeRepository;
private ChallengeTasksRecyclerViewAdapter challengeTasks;
Task addHabit;
Task addDaily;
Task addTodo;
Task addReward;
private GroupArrayAdapter locationAdapter;
@Override
@ -73,6 +96,40 @@ public class CreateChallengeActivity extends BaseActivity {
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_save) {
saveChallenge();
}
return super.onOptionsItemSelected(item);
}
private void saveChallenge() {
PostChallenge c = new PostChallenge();
int locationPos = challenge_location_spinner.getSelectedItemPosition();
Group locationGroup = locationAdapter.getItem(locationPos);
c.group = locationGroup.id;
c.name = create_challenge_title.getText().toString();
c.description = create_challenge_description.getText().toString();
c.shortName = create_challenge_tag.getText().toString();
c.prize = Integer.parseInt(create_challenge_prize.getText().toString());
List<Task> taskList = challengeTasks.getTaskList();
taskList.remove(addHabit);
taskList.remove(addDaily);
taskList.remove(addTodo);
taskList.remove(addReward);
challengeRepository.createChallenge(c, taskList).subscribe(createdChallenge -> {
finish();
}, throwable -> {
// UHOH
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -90,11 +147,11 @@ public class CreateChallengeActivity extends BaseActivity {
supportActionBar.setElevation(0);
}
GroupArrayAdapter locationAdapter = new GroupArrayAdapter(this);
locationAdapter = new GroupArrayAdapter(this);
locationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
challengeLocalRepository.getGroups().subscribe(groups -> {
Group tavern =new Group();
tavern.id = "habitrpg";
Group tavern = new Group();
tavern.id = "00000000-0000-4000-A000-000000000000";
tavern.name = getString(R.string.tavern);
locationAdapter.add(tavern);
@ -145,6 +202,7 @@ public class CreateChallengeActivity extends BaseActivity {
Bundle bundle = new Bundle();
bundle.putString(TaskFormActivity.TASK_TYPE_KEY, type);
bundle.putBoolean(TaskFormActivity.SAVE_TO_DB, false);
bundle.putBoolean(TaskFormActivity.SET_IGNORE_FLAG, true);
bundle.putBoolean(TaskFormActivity.SHOW_TAG_SELECTION, false);
if (HabiticaApplication.User != null && HabiticaApplication.User.getPreferences() != null) {
@ -165,6 +223,7 @@ public class CreateChallengeActivity extends BaseActivity {
Bundle bundle = new Bundle();
bundle.putParcelable(TaskFormActivity.PARCELABLE_TASK, task);
bundle.putBoolean(TaskFormActivity.SAVE_TO_DB, false);
bundle.putBoolean(TaskFormActivity.SET_IGNORE_FLAG, true);
bundle.putBoolean(TaskFormActivity.SHOW_TAG_SELECTION, false);
if (HabiticaApplication.User != null && HabiticaApplication.User.getPreferences() != null) {
@ -182,23 +241,22 @@ public class CreateChallengeActivity extends BaseActivity {
}
@Subscribe
public void onEvent(DeleteTaskCommand deleteTask){
public void onEvent(DeleteTaskCommand deleteTask) {
challengeTasks.removeTask(deleteTask.TaskIdToDelete);
}
@Subscribe
public void onEvent(TaskTappedEvent tappedEvent)
{
public void onEvent(TaskTappedEvent tappedEvent) {
openNewTaskActivity(tappedEvent.Task);
}
@Subscribe
public void onEvent(TaskSaveEvent saveEvent) {
if(saveEvent.task.getId() == null)
if (saveEvent.task.getId() == null)
saveEvent.task.setId(UUID.randomUUID().toString());
if (!challengeTasks.updateTask(saveEvent.task)) {
if (!challengeTasks.replaceTask(saveEvent.task)) {
Task taskAbove;
switch (saveEvent.task.getType()) {
@ -261,4 +319,24 @@ public class CreateChallengeActivity extends BaseActivity {
return checkedTextView;
}
}
@OnClick(R.id.challenge_add_gem_btn)
public void onAddGem() {
int currentVal = Integer.parseInt(create_challenge_prize.getText().toString());
currentVal++;
create_challenge_prize.setText("" + currentVal);
}
@OnClick(R.id.challenge_remove_gem_btn)
public void onRemoveGem() {
int currentVal = Integer.parseInt(create_challenge_prize.getText().toString());
currentVal--;
if (currentVal == 0)
currentVal = 1;
create_challenge_prize.setText("" + currentVal);
}
}

View file

@ -1120,6 +1120,10 @@ public class MainActivity extends BaseActivity implements Action1<Throwable>, Ha
@Subscribe
public void onEvent(final DeleteTaskCommand cmd) {
if(cmd.ignoreEvent) {
return;
}
apiClient.deleteTask(cmd.TaskIdToDelete)
.subscribe(aVoid -> {
EventBus.getDefault().post(new TaskRemovedEvent(cmd.TaskIdToDelete));
@ -1464,6 +1468,9 @@ public class MainActivity extends BaseActivity implements Action1<Throwable>, Ha
@Subscribe
public void onEvent(final TaskSaveEvent event) {
if(event.ignoreEvent)
return;
Task task = event.task;
if (event.created) {
this.taskRepository.createTask(task).subscribe(new TaskCreationCallback(), throwable -> {

View file

@ -92,6 +92,9 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
public static final String ALLOCATION_MODE_KEY = "allocationModeKey";
public static final String SAVE_TO_DB = "saveToDb";
// in order to disable the event handler in MainActivity
public static final String SET_IGNORE_FLAG = "ignoreFlag";
@BindView(R.id.task_value_edittext)
EditText taskValue;
@BindView(R.id.task_value_layout)
@ -205,6 +208,7 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
private String taskId;
private String userId;
private boolean showTagSelection;
private boolean setIgnoreFlag;
private Task task;
private String allocationMode;
private List<CheckBox> weekdayCheckboxes = new ArrayList<>();
@ -238,6 +242,7 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
showTagSelection = bundle.getBoolean(SHOW_TAG_SELECTION, true);
allocationMode = bundle.getString(ALLOCATION_MODE_KEY);
saveToDb = bundle.getBoolean(SAVE_TO_DB, true);
setIgnoreFlag = bundle.getBoolean(SET_IGNORE_FLAG, false);
tagsWrapper.setVisibility(showTagSelection ? View.VISIBLE : View.GONE);
@ -276,7 +281,7 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
taskToDelete = task.getId();
}
EventBus.getDefault().post(new DeleteTaskCommand(taskToDelete));
EventBus.getDefault().post(new DeleteTaskCommand(taskToDelete, setIgnoreFlag));
}).setNegativeButton(getString(R.string.no), (dialog, which) -> {
dialog.dismiss();
}).show());
@ -909,6 +914,7 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
if (TaskFormActivity.this.task.getId() == null) {
event.created = true;
}
event.ignoreEvent = setIgnoreFlag;
event.task = TaskFormActivity.this.task;
EventBus.getDefault().post(event);

View file

@ -19,9 +19,12 @@ import com.habitrpg.android.habitica.ui.viewHolders.tasks.RewardViewHolder;
import com.habitrpg.android.habitica.ui.viewHolders.tasks.TodoViewHolder;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
import java.util.List;
import rx.functions.Action1;
public class ChallengeTasksRecyclerViewAdapter extends SortableTasksRecyclerViewAdapter<BaseTaskViewHolder> {
public class ChallengeTasksRecyclerViewAdapter
extends SortableTasksRecyclerViewAdapter<BaseTaskViewHolder> {
public static final String TASK_TYPE_ADD_ITEM = "ADD_ITEM";
private static final int TYPE_HEADER = 0;
@ -44,7 +47,7 @@ public class ChallengeTasksRecyclerViewAdapter extends SortableTasksRecyclerView
this.taskActionsDisabled = taskActionsDisabled;
}
public void setDailyResetOffset(int newResetOffset){
public void setDailyResetOffset(int newResetOffset) {
dailyResetOffset = newResetOffset;
}
@ -74,7 +77,7 @@ public class ChallengeTasksRecyclerViewAdapter extends SortableTasksRecyclerView
if (task.type.equals(Task.TYPE_REWARD))
return TYPE_REWARD;
if(addItemCallback != null && task.type.equals(TASK_TYPE_ADD_ITEM))
if (addItemCallback != null && task.type.equals(TASK_TYPE_ADD_ITEM))
return TYPE_ADD_ITEM;
return TYPE_HEADER;
@ -84,10 +87,10 @@ public class ChallengeTasksRecyclerViewAdapter extends SortableTasksRecyclerView
addItemCallback = cb;
}
public int addTaskUnder(Task taskToAdd, Task taskAbove){
public int addTaskUnder(Task taskToAdd, Task taskAbove) {
int position = $.findIndex(this.content, t -> t.getId().equals(taskAbove.getId()));
content.add(position+1, taskToAdd);
content.add(position + 1, taskToAdd);
filter();
return position;
@ -122,6 +125,32 @@ public class ChallengeTasksRecyclerViewAdapter extends SortableTasksRecyclerView
return viewHolder;
}
public List<Task> getTaskList(){
return $.map(content, t -> t);
}
/**
* @param task
* @return true if task found&updated
*/
public boolean replaceTask(Task task) {
int i;
for (i = 0; i < this.content.size(); ++i) {
if (content.get(i).getId().equals(task.getId())) {
break;
}
}
if (i < content.size()) {
content.set(i, task);
filter();
return true;
}
return false;
}
public class AddItemViewHolder extends BaseTaskViewHolder {
private Button addBtn;

View file

@ -90,13 +90,9 @@ public abstract class BaseTasksRecyclerViewAdapter<VH extends BaseTaskViewHolder
return LayoutInflater.from(parent.getContext()).inflate(layoutResource, parent, false);
}
/**
* @param task
* @return true if task found&updated
*/
public boolean updateTask(Task task) {
public void updateTask(Task task) {
if (!taskType.equals(task.getType()))
return false;
return;
int i;
for (i = 0; i < this.content.size(); ++i) {
if (content.get(i).getId().equals(task.getId())) {
@ -105,12 +101,8 @@ public abstract class BaseTasksRecyclerViewAdapter<VH extends BaseTaskViewHolder
}
if (i < content.size()) {
content.set(i, task);
filter();
return true;
}
return false;
filter();
}
public void filter() {

View file

@ -202,6 +202,7 @@ public interface ApiClient {
Observable<Void> leaveChallenge(String challengeId, LeaveChallengeBody body);
Observable<Challenge> createChallenge(PostChallenge challenge);
Observable<Void> createChallengeTasks(String challengeId, List<Task> tasks);
Observable<Challenge> updateChallenge(PostChallenge challenge);
Observable<Void> deleteChallenge(String challengeId);

View file

@ -291,6 +291,9 @@ public interface ApiService {
@POST("challenges")
Observable<HabitResponse<Challenge>> createChallenge(@Body PostChallenge challenge);
@POST("tasks/challenge/{challengeId}")
Observable<HabitResponse<Void>> createChallengeTasks(@Path("challengeId") String challengeId, @Body List<Task> tasks);
@PUT("challenges/{challengeId}")
Observable<HabitResponse<Challenge>> updateChallenge(@Path("challengeId") String challengeId, @Body PostChallenge challenge);

View file

@ -15,8 +15,6 @@ public class PostChallenge {
public String description;
public String leaderName;
public String group;
public int prize;

View file

@ -43,7 +43,15 @@ public class ChallengeDeserializer implements JsonDeserializer<Challenge> {
if (profile != null) {
challenge.leaderName = profile.get("name").getAsString();
challenge.leaderId = leaderObj.get("id").getAsString();
JsonElement id = leaderObj.get("id");
if (id == null) {
id = leaderObj.get("_id");
}
if (id != null) {
challenge.leaderId = id.getAsString();
}
}
}
}