package com.kelin.mvvmlight.zhihu.news;
import android.app.Fragment;
import android.databinding.ObservableArrayList;
import android.databinding.ObservableBoolean;
import android.databinding.ObservableList;
import android.support.v4.util.Pair;
import android.widget.Toast;
import com.kelin.mvvmlight.BR;
import com.kelin.mvvmlight.base.ViewModel;
import com.kelin.mvvmlight.command.ReplyCommand;
import com.kelin.mvvmlight.messenger.Messenger;
import com.kelin.mvvmlight.zhihu.R;
import com.kelin.mvvmlight.zhihu.ZhiHuApp;
import com.kelin.mvvmlight.zhihu.retrofit.RetrofitProvider;
import com.trello.rxlifecycle.FragmentLifecycleProvider;
import java.util.Calendar;
import me.tatarka.bindingcollectionadapter.BaseItemViewSelector;
import me.tatarka.bindingcollectionadapter.ItemView;
import me.tatarka.bindingcollectionadapter.ItemViewSelector;
import rx.Notification;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import rx.subjects.BehaviorSubject;
/**
* Created by kelin on 16-4-25.
*/
public class NewsViewModel implements ViewModel {
public static final String TOKEN_TOP_NEWS_FINISH = "token_top_news_finish" + ZhiHuApp.sPackageName;
//context
private Fragment fragment;
/**
* model
*/
private NewsService.News news;
private TopNewsService.News topNews;
/*
data for presenter
*/
// viewModel for RecyclerView
public final ObservableList<NewItemViewModel> itemViewModel = new ObservableArrayList<>();
// view layout for RecyclerView
public final ItemViewSelector<NewItemViewModel> itemView = new BaseItemViewSelector<NewItemViewModel>() {
@Override
public void select(ItemView itemView, int position, NewItemViewModel itemViewModel) {
itemView.set(BR.viewModel, itemViewModel.storiesBean.getExtraField() != null ? R.layout.listitem_news_header : R.layout.listitem_news);
}
@Override
public int viewTypeCount() {
return 2;
}
};
//collection of view style,wrap to a class to manage conveniently!
public final ViewStyle viewStyle = new ViewStyle();
public class ViewStyle {
public final ObservableBoolean isRefreshing = new ObservableBoolean(true);
public final ObservableBoolean progressRefreshing = new ObservableBoolean(true);
}
/**
* command
*/
public final ReplyCommand onRefreshCommand = new ReplyCommand<>(() -> {
Observable.just(Calendar.getInstance())
.doOnNext(c -> c.add(Calendar.DAY_OF_MONTH, 1))
.map(c -> NewsListHelper.DAY_FORMAT.format(c.getTime()))
.subscribe(d -> loadTopNews(d));
});
/**
* @param p count of listview items,is unused here!
* @params,funciton when return true,the callback just can be invoked!
*/
public final ReplyCommand<Integer> onLoadMoreCommand = new ReplyCommand<>((p) -> {
loadNewsList(news.getDate());
});
public NewsViewModel(Fragment fragment) {
this.fragment = fragment;
BehaviorSubject<Notification<NewsService.News>> subject = BehaviorSubject.create();
subject.filter(Notification::isOnNext)
.subscribe(n -> Toast.makeText(fragment.getActivity(), "load finish!", Toast.LENGTH_SHORT).show());
Observable.just(Calendar.getInstance())
.doOnNext(c -> c.add(Calendar.DAY_OF_MONTH, 1))
.map(c -> NewsListHelper.DAY_FORMAT.format(c.getTime()))
.subscribe(d -> loadTopNews(d));
}
private void loadNewsList(String date) {
viewStyle.isRefreshing.set(true);
Observable<Notification<NewsService.News>> newsListOb =
RetrofitProvider.getInstance().create(NewsService.class)
.getNewsList(date)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(((FragmentLifecycleProvider) fragment).bindToLifecycle())
.materialize().share();
newsListOb.filter(Notification::isOnNext)
.map(n -> n.getValue())
.filter(m -> !m.getStories().isEmpty())
.doOnNext(m -> Observable.just(m.getDate()).map(d -> new NewsService.News.StoriesBean.ExtraField(true, d))
.map(d -> new NewsService.News.StoriesBean(d))
.subscribe(d -> itemViewModel.add(new NewItemViewModel(fragment.getActivity(), d))))
.doOnNext(m -> news = m)
.doAfterTerminate(()-> viewStyle.isRefreshing.set(false))
.flatMap(m -> Observable.from(m.getStories()))
.subscribe(i -> itemViewModel.add(new NewItemViewModel(fragment.getActivity(), i)));
NewsListHelper.dealWithResponseError(newsListOb.filter(Notification::isOnError)
.map(n -> n.getThrowable()));
}
private void loadTopNews(String date) {
viewStyle.isRefreshing.set(true);
Observable<TopNewsService.News> topNewsOb =
RetrofitProvider.getInstance().create(TopNewsService.class)
.getTopNewsList()
.compose(((FragmentLifecycleProvider) fragment).bindToLifecycle());
Observable<NewsService.News> newsListOb =
RetrofitProvider.getInstance().create(NewsService.class)
.getNewsList(date)
.compose(((FragmentLifecycleProvider) fragment).bindToLifecycle());
Observable<Notification<Pair<TopNewsService.News, NewsService.News>>> combineRequestOb = Observable.combineLatest(topNewsOb, newsListOb, Pair::new)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.materialize().share();
combineRequestOb.filter(Notification::isOnNext)
.map(n -> n.getValue())
.map(p -> p.first)
.filter(m -> !m.getTop_stories().isEmpty())
.doOnNext(m -> Observable.just(NewsListHelper.isTomorrow(date)).filter(b -> b).subscribe(b -> itemViewModel.clear()))
.subscribe(m -> Messenger.getDefault().send(m, TOKEN_TOP_NEWS_FINISH));
combineRequestOb.filter(Notification::isOnNext)
.map(n -> n.getValue())
.map(p -> p.second).filter(m -> !m.getStories().isEmpty())
.doOnNext(m -> news = m)
.flatMap(m -> Observable.from(m.getStories()))
.subscribe(i -> itemViewModel.add(new NewItemViewModel(fragment.getActivity(), i)));
combineRequestOb.subscribe((n) -> {
viewStyle.isRefreshing.set(false);
viewStyle.progressRefreshing.set(false);
});
NewsListHelper.dealWithResponseError(combineRequestOb.filter(Notification::isOnError)
.map(n -> n.getThrowable()));
}
}