Update challenge / -tasks

This commit is contained in:
Negue 2017-04-22 14:24:18 +02:00
parent 8ccc323417
commit 13c7b1ee42
11 changed files with 350 additions and 102 deletions

View file

@ -5,9 +5,15 @@
<item
android:id="@+id/action_leave"
android:actionViewClass="android.widget.ImageButton"
android:icon="@drawable/leave_light"
android:title="@string/leave"
app:showAsAction="always"
android:actionViewClass="android.widget.ImageButton"/>
app:showAsAction="always" />
<group
android:id="@+id/challenge_edit_action_group">
<item
android:id="@+id/action_edit"
android:title="@string/edit_challenge" />
</group>
</menu>

View file

@ -562,4 +562,5 @@
<string name="tasks">Tasks</string>
<string name="create_challenge">Create challenge</string>
<string name="tavern">Tavern</string>
<string name="edit_challenge">Edit Challenge</string>
</resources>

View file

@ -818,8 +818,14 @@ public class ApiClientImpl implements Action1<Throwable>, ApiClient {
return apiService.createChallenge(challenge).compose(configureApiCallObserver());
}
@Override
public Observable<Void> createChallengeTasks(String challengeId, List<Task> tasks) {
public Observable<Task> createChallengeTask(String challengeId, Task task) {
return apiService.createChallengeTask(challengeId, task).compose(configureApiCallObserver());
}
@Override
public Observable<List<Task>> createChallengeTasks(String challengeId, List<Task> tasks) {
return apiService.createChallengeTasks(challengeId, tasks).compose(configureApiCallObserver());
}

View file

@ -3,13 +3,28 @@ 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 com.magicmicky.habitrpgwrapper.lib.models.tasks.TaskList;
import java.util.List;
import rx.Observable;
public interface ChallengeRepository extends BaseRepository {
Observable<Challenge> getChallenge(String challengeId);
Observable<TaskList> getChallengeTasks(String challengeId);
Observable<Challenge> createChallenge(PostChallenge challenge, List<Task> taskList);
Observable<Challenge> updateChallenge(PostChallenge challenge, List<Task> taskList);
/**
*
* @param challenge
* @param fullTaskList lists all tasks of the current challenge, to create the taskOrders
* @param addedTaskList only the tasks to be added online
* @param updatedTaskList only the updated ones
* @param removedTaskList tasks that has be to be removed
* @return
*/
Observable<Challenge> updateChallenge(PostChallenge challenge, List<Task> fullTaskList,
List<Task> addedTaskList, List<Task> updatedTaskList, List<String> removedTaskList);
Observable<Void> deleteChallenge(String challengeId);
}

View file

@ -7,12 +7,15 @@ 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.TaskList;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.TasksOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import rx.Observable;
import rx.schedulers.Schedulers;
public class ChallengeRepositoryImpl extends BaseRepositoryImpl<ChallengeLocalRepository> implements ChallengeRepository {
@ -22,16 +25,25 @@ public class ChallengeRepositoryImpl extends BaseRepositoryImpl<ChallengeLocalRe
}
@Override
public Observable<Challenge> createChallenge(PostChallenge challenge, List<Task> taskList) {
public Observable<Challenge> getChallenge(String challengeId) {
return apiClient.getChallenge(challengeId);
}
@Override
public Observable<TaskList> getChallengeTasks(String challengeId) {
return apiClient.getChallengeTasks(challengeId);
}
private TasksOrder getTaskOrders(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()){
for (Map.Entry<String, List<Task>> entry : stringListMap.entrySet()) {
List<String> taskIdList = $.map(entry.getValue(), t -> t.getId());
switch(entry.getKey()) {
switch (entry.getKey()) {
case Task.TYPE_HABIT:
tasksOrder.setHabits(taskIdList);
break;
@ -47,23 +59,61 @@ public class ChallengeRepositoryImpl extends BaseRepositoryImpl<ChallengeLocalRe
}
}
challenge.tasksOrder = tasksOrder;
return tasksOrder;
}
private Observable addChallengeTasks(String challengeId, List<Task> addedTaskList) {
if (addedTaskList.size() == 1) {
return apiClient.createChallengeTask(challengeId, addedTaskList.get(0));
} else {
return apiClient.createChallengeTasks(challengeId, addedTaskList);
}
}
@Override
public Observable<Challenge> createChallenge(PostChallenge challenge, List<Task> taskList) {
challenge.tasksOrder = getTaskOrders(taskList);
return Observable.create(subscriber -> {
apiClient.createChallenge(challenge).subscribe(challenge1 -> {
apiClient.createChallengeTasks(challenge1.id, taskList).subscribe(tasks -> {
addChallengeTasks(challenge1.id, taskList).subscribe(task -> {
subscriber.onNext(challenge1);
subscriber.onCompleted();
}, throwable ->
subscriber.onError(throwable));
}, throwable ->
subscriber.onError(throwable));
}, throwable -> subscriber.onError((Throwable) throwable));
}, throwable -> subscriber.onError(throwable));
});
}
@Override
public Observable<Challenge> updateChallenge(PostChallenge challenge, List<Task> taskList) {
return apiClient.updateChallenge(challenge);
public Observable<Challenge> updateChallenge(PostChallenge challenge, List<Task> fullTaskList,
List<Task> addedTaskList, List<Task> updatedTaskList, List<String> removedTaskList) {
ArrayList<Observable> observablesToWait = new ArrayList<>($.map(updatedTaskList, t -> apiClient.updateTask(t.getId(), t)));
observablesToWait.addAll($.map(removedTaskList, apiClient::deleteTask));
if (addedTaskList.size() != 0) {
observablesToWait.add(addChallengeTasks(challenge.id, addedTaskList));
}
challenge.tasksOrder = getTaskOrders(fullTaskList);
return Observable.create(subscriber -> {
Observable.from(observablesToWait)
.flatMap(task -> task.subscribeOn(Schedulers.computation()))
.toList()
.subscribe(o -> {
apiClient.updateChallenge(challenge)
.subscribe(challenge1 -> {
subscriber.onNext(challenge1);
subscriber.onCompleted();
}, throwable -> subscriber.onError(throwable));
});
});
}
@Override

View file

@ -1,11 +1,16 @@
package com.habitrpg.android.habitica.data.local;
import com.magicmicky.habitrpgwrapper.lib.models.Challenge;
import com.magicmicky.habitrpgwrapper.lib.models.Group;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
import java.util.List;
import rx.Observable;
public interface ChallengeLocalRepository extends BaseLocalRepository {
Observable<Challenge> getChallenge(String id);
Observable<List<Task>> getTasks(Challenge challenge);
void setUsersGroups(List<Group> group);

View file

@ -1,7 +1,9 @@
package com.habitrpg.android.habitica.data.local.implementation;
import com.habitrpg.android.habitica.data.local.ChallengeLocalRepository;
import com.magicmicky.habitrpgwrapper.lib.models.Challenge;
import com.magicmicky.habitrpgwrapper.lib.models.Group;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
import com.raizlabs.android.dbflow.runtime.transaction.BaseTransaction;
import com.raizlabs.android.dbflow.runtime.transaction.TransactionListener;
import com.raizlabs.android.dbflow.sql.builder.Condition;
@ -14,6 +16,33 @@ import rx.Observable;
public class DbFlowChallengeLocalRepository implements ChallengeLocalRepository {
@Override
public Observable<Challenge> getChallenge(String id) {
return Observable.create(subscriber -> {
new Select().from(Challenge.class).where(Condition.column("id").is(id)).async().querySingle(new TransactionListener<Challenge>() {
@Override
public void onResultReceived(Challenge result) {
subscriber.onNext(result);
subscriber.onCompleted();
}
@Override
public boolean onReady(BaseTransaction<Challenge> transaction) {
return false;
}
@Override
public boolean hasResult(BaseTransaction<Challenge> transaction, Challenge result) {
return true;
}
});
});
}
@Override
public Observable<List<Task>> getTasks(Challenge challenge) {
return null;
}
@Override
public void setUsersGroups(List<Group> groups) {

View file

@ -34,11 +34,13 @@ import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import android.app.AlertDialog;
import android.content.Intent;
import android.databinding.ObservableArrayList;
import android.databinding.ObservableList;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
@ -103,6 +105,7 @@ public class ChallengeDetailActivity extends BaseActivity {
private Challenge challenge;
@Override
protected int getLayoutResId() {
return R.layout.activity_challenge_detail;
@ -112,6 +115,11 @@ public class ChallengeDetailActivity extends BaseActivity {
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_challenge_details, menu);
if(!challenge.leaderId.equals(HabiticaApplication.User.getId())){
menu.setGroupVisible(R.id.challenge_edit_action_group, false);
}
return true;
}
@ -225,6 +233,7 @@ public class ChallengeDetailActivity extends BaseActivity {
ChallengeViewHolder challengeViewHolder = new ChallengeViewHolder(findViewById(R.id.challenge_header));
challengeViewHolder.bind(challenge);
}
@Override
@ -240,11 +249,23 @@ public class ChallengeDetailActivity extends BaseActivity {
return true;
case R.id.action_edit:
openChallengeEditActivity();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void openChallengeEditActivity(){
Intent intent = new Intent(this, CreateChallengeActivity.class);
intent.putExtra(CreateChallengeActivity.CHALLENGE_ID_KEY, challenge.id);
startActivity(intent);
}
private void showChallengeLeaveDialog(){
new AlertDialog.Builder(this)
.setTitle(this.getString(R.string.challenge_leave_title))

View file

@ -31,7 +31,6 @@ 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;
@ -40,6 +39,7 @@ import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
@ -49,6 +49,7 @@ import butterknife.BindView;
import butterknife.OnClick;
public class CreateChallengeActivity extends BaseActivity {
public static final String CHALLENGE_ID_KEY = "challengeId";
@BindView(R.id.create_challenge_title)
EditText create_challenge_title;
@ -77,18 +78,30 @@ public class CreateChallengeActivity extends BaseActivity {
private ChallengeTasksRecyclerViewAdapter challengeTasks;
private GroupArrayAdapter locationAdapter;
private String challengeId;
private boolean editMode;
private HashMap<String, Task> addedTasks = new HashMap<>();
private HashMap<String, Task> updatedTasks = new HashMap<>();
private HashMap<String, Task> removedTasks = new HashMap<>();
// Add {*} Items
Task addHabit;
Task addDaily;
Task addTodo;
Task addReward;
private GroupArrayAdapter locationAdapter;
@Override
protected int getLayoutResId() {
return R.layout.activity_create_challenge;
}
@Override
protected void injectActivity(AppComponent component) {
component.inject(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
@ -99,50 +112,98 @@ public class CreateChallengeActivity extends BaseActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_save) {
saveChallenge();
if(editMode){
updateChallenge();
} else {
createChallenge();
}
}
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);
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
if(bundle != null) {
challengeId = bundle.getString(CHALLENGE_ID_KEY, null);
}
EventBus.getDefault().register(this);
fillControls();
if (challengeId != null) {
fillControlsByChallenge();
}
}
@Subscribe
public void onEvent(DeleteTaskCommand deleteTask) {
String taskIdToDelete = deleteTask.TaskIdToDelete;
challengeTasks.removeTask(taskIdToDelete);
if(editMode){
if(addedTasks.containsKey(taskIdToDelete)){
addedTasks.remove(taskIdToDelete);
} else{
removedTasks.put(taskIdToDelete, null);
if(updatedTasks.containsKey(taskIdToDelete)){
updatedTasks.remove(taskIdToDelete);
}
}
}
}
@Subscribe
public void onEvent(TaskTappedEvent tappedEvent) {
openNewTaskActivity(tappedEvent.Task);
}
@Subscribe
public void onEvent(TaskSaveEvent saveEvent) {
if (saveEvent.task.getId() == null) {
saveEvent.task.setId(UUID.randomUUID().toString());
}
addOrUpdateTaskInList(saveEvent.task);
}
@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);
}
private void fillControls() {
Resources resources = getResources();
ActionBar supportActionBar = getSupportActionBar();
if (supportActionBar != null) {
supportActionBar.setIcon(R.drawable.ic_close_white_24dp);
supportActionBar.setDisplayShowHomeEnabled(true);
supportActionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
supportActionBar.setTitle(R.string.create_challenge);
supportActionBar.setTitle("");
supportActionBar.setBackgroundDrawable(new ColorDrawable(resources.getColor(R.color.brand_200)));
supportActionBar.setElevation(0);
}
@ -198,6 +259,47 @@ public class CreateChallengeActivity extends BaseActivity {
create_challenge_task_list.setLayoutManager(new LinearLayoutManager(this));
}
private static Task createTask(String taskType, String taskName) {
Task t = new Task();
t.setId(UUID.randomUUID().toString());
t.setType(taskType);
t.setText(taskName);
if (taskType.equals(Task.TYPE_HABIT)) {
t.setUp(true);
t.setDown(false);
}
return t;
}
private void fillControlsByChallenge() {
challengeRepository.getChallenge(challengeId).subscribe(challenge -> {
create_challenge_title.setText(challenge.name);
create_challenge_description.setText(challenge.description);
create_challenge_tag.setText(challenge.shortName);
create_challenge_prize.setText(challenge.prize + "");
for (int i = 0; i < locationAdapter.getCount(); i++) {
Group group = locationAdapter.getItem(i);
if (group.id == challenge.groupId) {
challenge_location_spinner.setSelection(i);
break;
}
}
challengeRepository.getChallengeTasks(challengeId).subscribe(tasks -> {
tasks.tasks.forEach((s, task) -> addOrUpdateTaskInList(task));
}, Throwable::printStackTrace, () -> {
// activate editMode to track taskChanges
editMode = true;
});
});
}
private void openNewTaskActivity(String type) {
Bundle bundle = new Bundle();
bundle.putString(TaskFormActivity.TASK_TYPE_KEY, type);
@ -240,26 +342,65 @@ public class CreateChallengeActivity extends BaseActivity {
startActivityForResult(intent, 1);
}
@Subscribe
public void onEvent(DeleteTaskCommand deleteTask) {
challengeTasks.removeTask(deleteTask.TaskIdToDelete);
private PostChallenge getChallengeData(){
PostChallenge c = new PostChallenge();
int locationPos = challenge_location_spinner.getSelectedItemPosition();
Group locationGroup = locationAdapter.getItem(locationPos);
if(challengeId != null){
c.id = challengeId;
}
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());
return c;
}
@Subscribe
public void onEvent(TaskTappedEvent tappedEvent) {
openNewTaskActivity(tappedEvent.Task);
private void createChallenge() {
PostChallenge c = getChallengeData();
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
});
}
@Subscribe
public void onEvent(TaskSaveEvent saveEvent) {
private void updateChallenge() {
PostChallenge c = getChallengeData();
if (saveEvent.task.getId() == null)
saveEvent.task.setId(UUID.randomUUID().toString());
List<Task> taskList = challengeTasks.getTaskList();
taskList.remove(addHabit);
taskList.remove(addDaily);
taskList.remove(addTodo);
taskList.remove(addReward);
if (!challengeTasks.replaceTask(saveEvent.task)) {
challengeRepository.updateChallenge(c, taskList, new ArrayList<>(addedTasks.values()),
new ArrayList<>(updatedTasks.values()),
new ArrayList<>(removedTasks.keySet())
).subscribe(createdChallenge -> {
finish();
}, throwable -> {
// UHOH
});
}
private void addOrUpdateTaskInList(Task task) {
if (!challengeTasks.replaceTask(task)) {
Task taskAbove;
switch (saveEvent.task.getType()) {
switch (task.getType()) {
case Task.TYPE_HABIT:
taskAbove = addHabit;
break;
@ -274,31 +415,20 @@ public class CreateChallengeActivity extends BaseActivity {
break;
}
challengeTasks.addTaskUnder(saveEvent.task, taskAbove);
challengeTasks.addTaskUnder(task, taskAbove);
if(editMode){
addedTasks.put(task.getId(), task);
}
} else {
// don't need to add the task to updatedTasks if its already been added right now
if(editMode && !addedTasks.containsKey(task.getId()))
{
updatedTasks.put(task.getId(), task);
}
}
}
private static Task createTask(String taskType, String taskName) {
Task t = new Task();
t.setId(UUID.randomUUID().toString());
t.setType(taskType);
t.setText(taskName);
t.setNotes("example " + taskType + " notes");
if (taskType.equals(Task.TYPE_HABIT)) {
t.setUp(true);
t.setDown(false);
}
return t;
}
@Override
protected void injectActivity(AppComponent component) {
component.inject(this);
}
private class GroupArrayAdapter extends ArrayAdapter<Group> {
public GroupArrayAdapter(@NonNull Context context) {
super(context, android.R.layout.simple_spinner_item);
@ -319,24 +449,4 @@ 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

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

View file

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