package com.kickstarter.viewmodels;
import android.support.annotation.NonNull;
import android.util.Pair;
import com.kickstarter.libs.ActivityViewModel;
import com.kickstarter.libs.Environment;
import com.kickstarter.libs.KoalaContext;
import com.kickstarter.models.Project;
import com.kickstarter.models.Update;
import com.kickstarter.services.ApiClientType;
import com.kickstarter.ui.IntentKey;
import com.kickstarter.ui.activities.ProjectUpdatesActivity;
import okhttp3.Request;
import rx.Observable;
import rx.subjects.BehaviorSubject;
import rx.subjects.PublishSubject;
import static com.kickstarter.libs.rx.transformers.Transformers.neverError;
import static com.kickstarter.libs.rx.transformers.Transformers.takePairWhen;
import static com.kickstarter.libs.rx.transformers.Transformers.takeWhen;
public interface ProjectUpdatesViewModel {
interface Inputs {
/** Call when an external link has been activated. */
void externalLinkActivated();
/** Call when a project update comments uri request has been made. */
void goToCommentsRequest(Request request);
/** Call when a project update uri request has been made. */
void goToUpdateRequest(Request request);
/** Call when a project updates uri request has been made. */
void goToUpdatesRequest(Request request);
}
interface Outputs {
/** Emits an update to start the comments activity with. */
Observable<Update> startCommentsActivity();
/** Emits a project and an update to start the update activity with. */
Observable<Pair<Project, Update>> startUpdateActivity();
/** Emits a url to load in the web view. */
Observable<String> webViewUrl();
}
final class ViewModel extends ActivityViewModel<ProjectUpdatesActivity> implements Inputs, Outputs {
private final ApiClientType client;
public ViewModel(final @NonNull Environment environment) {
super(environment);
this.client = environment.apiClient();
final Observable<Project> project = intent()
.map(i -> i.getParcelableExtra(IntentKey.PROJECT))
.ofType(Project.class)
.take(1);
final Observable<String> initialUpdatesIndexUrl = project
.map(Project::updatesUrl);
final Observable<String> anotherIndexUrl = this.goToUpdatesRequest
.map(request -> request.url().toString());
Observable.merge(initialUpdatesIndexUrl, anotherIndexUrl)
.distinctUntilChanged()
.compose(bindToLifecycle())
.subscribe(this.webViewUrl::onNext);
this.goToCommentsRequest
.map(this::projectUpdateParams)
.switchMap(this::fetchUpdate)
.compose(bindToLifecycle())
.subscribe(this.startCommentsActivity::onNext);
final Observable<Update> goToUpdateRequest = this.goToUpdateRequest
.map(this::projectUpdateParams)
.switchMap(this::fetchUpdate)
.share();
project
.compose(takePairWhen(goToUpdateRequest))
.compose(bindToLifecycle())
.subscribe(this.startUpdateActivity::onNext);
project
.compose(takeWhen(this.externalLinkActivated))
.compose(bindToLifecycle())
.subscribe(p -> this.koala.trackOpenedExternalLink(p, KoalaContext.ExternalLink.PROJECT_UPDATES));
project
.compose(takeWhen(goToUpdateRequest))
.compose(bindToLifecycle())
.subscribe(p -> this.koala.trackViewedUpdate(p, KoalaContext.Update.UPDATES));
project
.take(1)
.compose(bindToLifecycle())
.subscribe(this.koala::trackViewedUpdates);
}
private @NonNull Observable<Update> fetchUpdate(final @NonNull Pair<String, String> projectAndUpdateParams) {
return this.client
.fetchUpdate(projectAndUpdateParams.first, projectAndUpdateParams.second)
.compose(neverError());
}
/**
* Parses a request for project and update params.
*
* @param request Comments or update request.
* @return Pair of project param string and update param string.
*/
private @NonNull Pair<String, String> projectUpdateParams(final @NonNull Request request) {
// todo: build a Navigation helper for better param extraction
final String projectParam = request.url().encodedPathSegments().get(2);
final String updateParam = request.url().encodedPathSegments().get(4);
return Pair.create(projectParam, updateParam);
}
private final PublishSubject<Request> externalLinkActivated = PublishSubject.create();
private final PublishSubject<Request> goToCommentsRequest = PublishSubject.create();
private final PublishSubject<Request> goToUpdateRequest = PublishSubject.create();
private final PublishSubject<Request> goToUpdatesRequest = PublishSubject.create();
private final PublishSubject<Update> startCommentsActivity = PublishSubject.create();
private final PublishSubject<Pair<Project, Update>> startUpdateActivity = PublishSubject.create();
private final BehaviorSubject<String> webViewUrl = BehaviorSubject.create();
public final Inputs inputs = this;
public final Outputs outputs = this;
@Override public void externalLinkActivated() {
this.externalLinkActivated.onNext(null);
}
@Override public void goToCommentsRequest(final @NonNull Request request) {
this.goToCommentsRequest.onNext(request);
}
@Override public void goToUpdateRequest(final @NonNull Request request) {
this.goToUpdateRequest.onNext(request);
}
@Override
public void goToUpdatesRequest(final @NonNull Request request) {
this.goToUpdatesRequest.onNext(request);
}
@Override public @NonNull Observable<Update> startCommentsActivity() {
return this.startCommentsActivity;
}
@Override public @NonNull Observable<Pair<Project, Update>> startUpdateActivity() {
return this.startUpdateActivity;
}
@Override public @NonNull Observable<String> webViewUrl() {
return this.webViewUrl;
}
}
}