package org.wikipedia.feed.announcement;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import org.wikipedia.dataclient.WikiSite;
import org.wikipedia.dataclient.retrofit.RetrofitFactory;
import org.wikipedia.feed.dataclient.FeedClient;
import org.wikipedia.feed.model.Card;
import org.wikipedia.settings.Prefs;
import org.wikipedia.util.GeoUtil;
import org.wikipedia.util.log.L;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import static org.wikipedia.Constants.ACCEPT_HEADER_PREFIX;
public class AnnouncementClient implements FeedClient {
private static final String PLATFORM_CODE = "AndroidApp";
@Nullable private Call<AnnouncementList> call;
@Override
public void request(@NonNull Context context, @NonNull WikiSite wiki, int age, @NonNull Callback cb) {
cancel();
String endpoint = String.format(Locale.ROOT, Prefs.getRestbaseUriFormat(), wiki.scheme(),
wiki.authority());
Retrofit retrofit = RetrofitFactory.newInstance(endpoint, wiki);
Service service = retrofit.create(Service.class);
call = request(service);
call.enqueue(new CallbackAdapter(cb));
}
@Override
public void cancel() {
if (call == null) {
return;
}
call.cancel();
call = null;
}
@VisibleForTesting
interface Service {
/**
* Gets a list of announcements that are currently in effect.
*/
@NonNull
@Headers(ACCEPT_HEADER_PREFIX + "announcements/0.1.0\"")
@GET("feed/announcements")
Call<AnnouncementList> get();
}
@VisibleForTesting
@NonNull
Call<AnnouncementList> request(@NonNull Service service) {
return service.get();
}
@VisibleForTesting
static class CallbackAdapter implements retrofit2.Callback<AnnouncementList> {
@NonNull private final Callback cb;
CallbackAdapter(@NonNull Callback cb) {
this.cb = cb;
}
@Override public void onResponse(Call<AnnouncementList> call,
Response<AnnouncementList> response) {
List<Card> cards = new ArrayList<>();
AnnouncementList content = response.body();
if (content != null) {
cards.addAll(buildCards(content.items()));
}
cb.success(cards);
}
@Override public void onFailure(Call<AnnouncementList> call, Throwable caught) {
L.v(caught);
cb.error(caught);
}
}
@VisibleForTesting
static List<Card> buildCards(@NonNull List<Announcement> announcements) {
List<Card> cards = new ArrayList<>();
String country = GeoUtil.getGeoIPCountry();
Date now = new Date();
for (Announcement announcement : announcements) {
if (shouldShow(announcement, country, now)) {
switch (announcement.type()) {
case Announcement.SURVEY:
cards.add(new SurveyCard(announcement));
break;
case Announcement.FUNDRAISING:
cards.add(new FundraisingCard(announcement));
break;
default:
cards.add(new AnnouncementCard(announcement));
break;
}
}
}
return cards;
}
@VisibleForTesting
static boolean shouldShow(@Nullable Announcement announcement,
@Nullable String country,
@NonNull Date date) {
if (announcement == null
|| !announcement.platforms().contains(PLATFORM_CODE)
|| TextUtils.isEmpty(country)
|| !announcement.countries().contains(country)
|| (announcement.startTime() != null && announcement.startTime().after(date))
|| (announcement.endTime() != null && announcement.endTime().before(date))) {
return false;
}
return true;
}
}