Skip to content

Show campaigns on home screen #2108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/src/main/java/fr/free/nrw/commons/BasePresenter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package fr.free.nrw.commons;

/**
* Base presenter, enforcing contracts to atach and detach view
*/
public interface BasePresenter {
/**
* Until a view is attached, it is open to listen events from the presenter
*/
void onAttachView(MvpView view);

/**
* Detaching a view makes sure that the view no more receives events from the presenter
*/
void onDetachView();
}
8 changes: 8 additions & 0 deletions app/src/main/java/fr/free/nrw/commons/MvpView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package fr.free.nrw.commons;

/**
* Base interface for all the views
*/
public interface MvpView {
void showMessage(String message);
}
55 changes: 55 additions & 0 deletions app/src/main/java/fr/free/nrw/commons/campaigns/Campaign.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package fr.free.nrw.commons.campaigns;

import com.google.gson.annotations.SerializedName;

/**
* A data class to hold a campaign
*/
public class Campaign {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add Javadocs for all the new classes and methods. :) I guess there isn't really a need to have them for every single getter and setter method in this particular class (since they are fairly self-explanatory), but there should still at least be a Javadoc for the class itself. And the methods in the other classes would need them.

Copy link
Collaborator Author

@ashishkumar468 ashishkumar468 Dec 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I was gonna, have added a lot of classes :P, will do it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


@SerializedName("title") private String title;
@SerializedName("description") private String description;
@SerializedName("startDate") private String startDate;
@SerializedName("endDate") private String endDate;
@SerializedName("link") private String link;

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public String getStartDate() {
return startDate;
}

public void setStartDate(String startDate) {
this.startDate = startDate;
}

public String getEndDate() {
return endDate;
}

public void setEndDate(String endDate) {
this.endDate = endDate;
}

public String getLink() {
return link;
}

public void setLink(String link) {
this.link = link;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package fr.free.nrw.commons.campaigns;

import com.google.gson.annotations.SerializedName;

/**
* A data class to hold the campaign configs
*/
class CampaignConfig {

@SerializedName("showOnlyLiveCampaigns") private boolean showOnlyLiveCampaigns;
@SerializedName("sortBy") private String sortBy;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package fr.free.nrw.commons.campaigns;

import com.google.gson.annotations.SerializedName;
import java.util.List;

/**
* Data class to hold the response from the campaigns api
*/
public class CampaignResponseDTO {

@SerializedName("config")
private CampaignConfig campaignConfig;

@SerializedName("campaigns")
private List<Campaign> campaigns;

public CampaignConfig getCampaignConfig() {
return campaignConfig;
}

public List<Campaign> getCampaigns() {
return campaigns;
}
}
110 changes: 110 additions & 0 deletions app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package fr.free.nrw.commons.campaigns;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.utils.SwipableCardView;
import fr.free.nrw.commons.utils.ViewUtil;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
* A view which represents a single campaign
*/
public class CampaignView extends SwipableCardView {
Campaign campaign = null;
private ViewHolder viewHolder;

public CampaignView(@NonNull Context context) {
super(context);
init();
}

public CampaignView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}

public CampaignView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

public void setCampaign(Campaign campaign) {
this.campaign = campaign;
if (campaign != null) {
this.setVisibility(View.VISIBLE);
viewHolder.init();
} else {
this.setVisibility(View.GONE);
}
}

@Override public boolean onSwipe(View view) {
view.setVisibility(View.GONE);
((MainActivity) getContext()).prefs.edit()
.putBoolean("displayCampaignsCardView", false)
.apply();
ViewUtil.showLongToast(getContext(),
getResources().getString(R.string.nearby_campaign_dismiss_message));
return true;
}

private void init() {
View rootView = inflate(getContext(), R.layout.layout_campagin, this);
viewHolder = new ViewHolder(rootView);
setOnClickListener(view -> {
if (campaign != null) {
showCampaignInBrowser(campaign.getLink());
}
});
}

/**
* open the url associated with the campaign in the system's default browser
*/
private void showCampaignInBrowser(String link) {
Intent view = new Intent();
view.setAction(Intent.ACTION_VIEW);
view.setData(Uri.parse(link));
getContext().startActivity(view);
}

public class ViewHolder {

@BindView(R.id.tv_title) TextView tvTitle;
@BindView(R.id.tv_description) TextView tvDescription;
@BindView(R.id.tv_dates) TextView tvDates;

public ViewHolder(View itemView) {
ButterKnife.bind(this, itemView);
}

public void init() {
if (campaign != null) {
tvTitle.setText(campaign.getTitle());
tvDescription.setText(campaign.getDescription());
SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat outputDateFormat = new SimpleDateFormat("dd MMM");
try {
Date startDate = inputDateFormat.parse(campaign.getStartDate());
Date endDate = inputDateFormat.parse(campaign.getEndDate());
tvDates.setText(String.format("%1s - %2s", outputDateFormat.format(startDate),
outputDateFormat.format(endDate)));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package fr.free.nrw.commons.campaigns;

import android.util.Log;
import fr.free.nrw.commons.BasePresenter;
import fr.free.nrw.commons.MvpView;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
import io.reactivex.Single;
import io.reactivex.SingleObserver;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
* The presenter for the campaigns view, fetches the campaigns from the api and informs the view on
* success and error
*/
public class CampaignsPresenter implements BasePresenter {
private final String TAG = "#CampaignsPresenter#";
private ICampaignsView view;
private MediaWikiApi mediaWikiApi;
private Disposable disposable;
private Campaign campaign;

@Override public void onAttachView(MvpView view) {
this.view = (ICampaignsView) view;
this.mediaWikiApi = ((ICampaignsView) view).getMediaWikiApi();
}

@Override public void onDetachView() {
this.view = null;
disposable.dispose();
}

/**
* make the api call to fetch the campaigns
*/
public void getCampaigns() {
if (view != null && mediaWikiApi != null) {
//If we already have a campaign, lets not make another call
if (this.campaign != null) {
view.showCampaigns(campaign);
return;
}
Single<CampaignResponseDTO> campaigns = mediaWikiApi.getCampaigns();
campaigns.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribeWith(new SingleObserver<CampaignResponseDTO>() {

@Override public void onSubscribe(Disposable d) {
disposable = d;
}

@Override public void onSuccess(CampaignResponseDTO campaignResponseDTO) {
List<Campaign> campaigns = campaignResponseDTO.getCampaigns();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
if (campaigns == null || campaigns.isEmpty()) {
Log.e(TAG, "The campaigns list is empty");
view.showCampaigns(null);
}
Collections.sort(campaigns, (campaign, t1) -> {
Date date1, date2;
try {
date1 = dateFormat.parse(campaign.getStartDate());
date2 = dateFormat.parse(t1.getStartDate());
} catch (ParseException e) {
e.printStackTrace();
return -1;
}
return date1.compareTo(date2);
});
Date campaignEndDate = null;
try {
campaignEndDate = dateFormat.parse(campaigns.get(0).getEndDate());
} catch (ParseException e) {
e.printStackTrace();
}
if (campaignEndDate == null) {
view.showCampaigns(null);
} else if (campaignEndDate.compareTo(new Date()) > 0) {
campaign = campaigns.get(0);
view.showCampaigns(campaign);
} else {
Log.e(TAG, "The campaigns has already finished");
view.showCampaigns(null);
}
}

@Override public void onError(Throwable e) {
Log.e(TAG, "could not fetch campaigns: " + e.getMessage());
}
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package fr.free.nrw.commons.campaigns;

import fr.free.nrw.commons.MvpView;
import fr.free.nrw.commons.mwapi.MediaWikiApi;

/**
* Interface which defines the view contracts of the campaign view
*/
public interface ICampaignsView extends MvpView {
MediaWikiApi getMediaWikiApi();

void showCampaigns(Campaign campaign);
}
Loading