2017-11-15 21:53:52 +00:00
|
|
|
package model;
|
|
|
|
|
2017-11-21 07:34:05 +00:00
|
|
|
import java.io.UnsupportedEncodingException;
|
2017-11-15 21:53:52 +00:00
|
|
|
import java.text.ParseException;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Date;
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
|
|
|
import org.json.JSONArray;
|
|
|
|
import org.json.JSONException;
|
|
|
|
import org.json.JSONObject;
|
|
|
|
|
|
|
|
import Classes.ApiCall;
|
|
|
|
import Classes.Category;
|
|
|
|
import Classes.Event;
|
|
|
|
import Classes.SortTypes;
|
|
|
|
import Interfaces.Callback;
|
|
|
|
import Interfaces.DelayedCallback;
|
|
|
|
import Interfaces.EventObserver;
|
|
|
|
import Interfaces.Observable;
|
|
|
|
import javafx.util.Pair;
|
|
|
|
|
|
|
|
public class NewsListModel implements Observable{
|
|
|
|
|
|
|
|
//instance du singleton
|
|
|
|
private static NewsListModel instance;
|
|
|
|
|
|
|
|
//Clé d'API
|
|
|
|
private String APIKey;
|
|
|
|
//catégorie choise parl'utilisateur
|
|
|
|
private Category cat = Category.all;
|
|
|
|
//est ce que le modele est en train de récupérer les sources
|
|
|
|
private Boolean isRetreivingSources = false;
|
|
|
|
//est ce que l'api a rencontré une erreur
|
|
|
|
private Boolean apiError = false;
|
|
|
|
//liste des sources
|
|
|
|
private ArrayList<String> sources;
|
|
|
|
//liste des observers
|
|
|
|
private HashMap<String,EventObserver> observers;
|
|
|
|
//liste des news finale
|
|
|
|
private ArrayList<NewsModel> news;
|
|
|
|
//critère de tri
|
|
|
|
private SortTypes sortType = SortTypes.relevancy;
|
|
|
|
//critère de recherche de l'utilisateur
|
|
|
|
private String query = "";
|
|
|
|
|
|
|
|
private NewsListModel(String APIKey) {
|
|
|
|
this.APIKey = APIKey;
|
|
|
|
//comme la liste des sources retournée par l'API est de 20 éléments max, pas la peine de déclarer une arraylist sans borne
|
|
|
|
this.sources = new ArrayList<String>(20);
|
|
|
|
this.observers = new HashMap<String,EventObserver>();
|
|
|
|
this.news = new ArrayList<NewsModel>();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static NewsListModel getInstance() {
|
|
|
|
if(NewsListModel.instance == null) {
|
|
|
|
NewsListModel.instance = new NewsListModel("0e72f765c5c84313ae31a5a7e9e61735");
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewsListModel.instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setCategory(Category cat) {
|
|
|
|
|
|
|
|
if(cat == Category.all) {
|
|
|
|
this.sources = null;
|
|
|
|
this.cat = cat;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//on vide la liste des sources
|
|
|
|
this.sources = new ArrayList<String>(20);
|
|
|
|
this.cat = cat;
|
|
|
|
//on créé l'URL d'appel de l'API
|
|
|
|
String lang = LangModel.getInstance().getToLang().name();
|
|
|
|
String URL = "http://beta.newsapi.org/v2/sources?language="+lang;
|
|
|
|
|
|
|
|
//on rajoute la catégorie
|
|
|
|
if(cat != Category.all) {
|
|
|
|
URL += "&category="+cat.name();
|
|
|
|
}
|
|
|
|
|
|
|
|
//on rajoute la clé d'api
|
|
|
|
URL += "&apiKey="+this.APIKey;
|
|
|
|
|
|
|
|
//création de l'appel
|
|
|
|
ApiCall api = new ApiCall(URL,"GET",new Callback() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onSuccess(JSONObject response) {
|
|
|
|
//on récupère toutes les sources (dans la limite de 20 sources)
|
|
|
|
JSONArray arr = response.getJSONArray("sources");
|
|
|
|
for(int i = 0;i<arr.length() && i<20;i++) {
|
|
|
|
NewsListModel.this.sources.add(((JSONObject)arr.get(i)).getString("id"));
|
|
|
|
}
|
|
|
|
NewsListModel.this.isRetreivingSources = false;
|
|
|
|
NewsListModel.this.apiError = false;
|
|
|
|
//tout s'est bien passé, on peut notifier du succès
|
|
|
|
NewsListModel.this.notifyObservers(new Event("NewsModel","SourcesUpdated"));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onError() {
|
|
|
|
//on notifie de l'échec et on garde en mémoire le fait que l'on a échoué (afin d'annuler la recherche de news qui va suivre)
|
|
|
|
NewsListModel.this.isRetreivingSources = false;
|
|
|
|
NewsListModel.this.apiError = true;
|
|
|
|
NewsListModel.this.notifyObservers(new Event("NewsModel","SourcesUpdateFailed"));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
this.isRetreivingSources = true;
|
|
|
|
api.send();
|
|
|
|
}
|
|
|
|
|
|
|
|
public Category getCategory() {
|
|
|
|
return this.cat;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void query(String q) {
|
2017-12-13 15:05:02 +00:00
|
|
|
//si recherche vide
|
|
|
|
if(q.isEmpty()) {
|
|
|
|
this.news = new ArrayList<NewsModel>();
|
|
|
|
NewsListModel.this.notifyObservers(new Event("NewsModel","NewsQuerySuccess"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-15 21:53:52 +00:00
|
|
|
//si la recherche de source s'est fini avec une erreur, pas la peine de chercher des articles
|
|
|
|
if(this.apiError) {
|
|
|
|
NewsListModel.this.notifyObservers(new Event("NewsModel","NewsQueryFailed"));
|
|
|
|
this.apiError = false;
|
|
|
|
return;
|
|
|
|
}
|
2017-11-21 07:34:05 +00:00
|
|
|
|
|
|
|
final String encodedQuery;
|
|
|
|
try {
|
|
|
|
encodedQuery = java.net.URLEncoder.encode(q,"UTF-8");
|
|
|
|
} catch (UnsupportedEncodingException e1) {
|
|
|
|
this.notifyObservers(new Event("NewsModel","NewsQueryFailed"));
|
|
|
|
return;
|
|
|
|
}
|
2017-11-15 21:53:52 +00:00
|
|
|
//on créer l'URL de l'appel
|
|
|
|
String lang = LangModel.getInstance().getToLang().name();
|
2017-11-21 07:34:05 +00:00
|
|
|
String URL = "http://beta.newsapi.org/v2/everything?apiKey="+this.APIKey+"&language="+lang+"&q="+encodedQuery+"&sortBy="+this.sortType.name();
|
2017-11-15 21:53:52 +00:00
|
|
|
|
|
|
|
//on ajoute la liste des sources a l'URL de la requete
|
|
|
|
if(NewsListModel.this.sources != null && NewsListModel.this.sources.size() != 0) {
|
|
|
|
String sources = "&sources=";
|
|
|
|
for(String s : NewsListModel.this.sources) {
|
|
|
|
sources += s+",";
|
|
|
|
}
|
|
|
|
//on enlève la dernière virgule
|
|
|
|
sources = sources.replaceAll(",$", "");
|
|
|
|
URL += sources;
|
|
|
|
}
|
|
|
|
|
|
|
|
ApiCall api = new ApiCall(URL,"GET",new Callback() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onSuccess(JSONObject response) {
|
|
|
|
//on parcours le JSON en créant les objets NewsModel corespondant
|
|
|
|
NewsListModel.this.news = new ArrayList<NewsModel>();
|
|
|
|
JSONArray arr = response.getJSONArray("articles");
|
|
|
|
for(int i = 0;i<arr.length();i++) {
|
|
|
|
JSONObject jsonNews = (JSONObject)arr.get(i);
|
|
|
|
NewsModel news = new NewsModel();
|
2017-11-19 13:44:40 +00:00
|
|
|
|
2017-11-15 21:53:52 +00:00
|
|
|
news.setAuthor(jsonNews.getString("author"))
|
|
|
|
.setDescription(jsonNews.getString("description"))
|
|
|
|
.setTitle(jsonNews.getString("title"))
|
|
|
|
.setNewsURL(jsonNews.getString("url"))
|
|
|
|
.setImageURL(jsonNews.getString("urlToImage"))
|
2017-11-19 13:44:40 +00:00
|
|
|
.setSource(jsonNews.getJSONObject("source").getString("name"))
|
|
|
|
.addTag(NewsListModel.this.cat);
|
2017-11-15 21:53:52 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
news.setDate(jsonNews.getString("publishedAt"));
|
|
|
|
}catch (ParseException e) {
|
|
|
|
news.setDate(new Date());
|
|
|
|
}
|
|
|
|
|
|
|
|
NewsListModel.this.news.add(news);
|
|
|
|
}
|
|
|
|
|
|
|
|
NewsListModel.this.query = q;
|
|
|
|
//ne pas oublier d'enlever l'api des observer, sinon il y a des risques de récurrence
|
|
|
|
NewsListModel.this.removeObserver("newsApiCall");
|
|
|
|
NewsListModel.this.notifyObservers(new Event("NewsModel","NewsQuerySuccess"));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onError() {
|
|
|
|
//L'appel a échoué :(
|
|
|
|
System.out.println("Error");
|
|
|
|
NewsListModel.this.removeObserver("newsApiCall");
|
|
|
|
NewsListModel.this.notifyObservers(new Event("NewsModel","NewsQueryFailed"));
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
//on delay uniquement si on est en train de récupérer les sources
|
|
|
|
if(this.isRetreivingSources) {
|
|
|
|
api.setAsDelayedCall("NewsModel", "SourcesUpdated", new DelayedCallback() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Pair<String, HashMap<String, String>> call() {
|
|
|
|
//si l'appel d'api précédent a échoué, on fait échouer l'appel actuel avec une URL vide
|
|
|
|
if(NewsListModel.this.apiError) {
|
|
|
|
//on reset la variable d'erreur pour que l'utilisateur puisse re-essayer plus tard
|
|
|
|
NewsListModel.this.apiError = false;
|
|
|
|
return new Pair<String,HashMap<String,String>>("",null);
|
|
|
|
}
|
|
|
|
|
|
|
|
String lang = LangModel.getInstance().getToLang().name();
|
|
|
|
String URL = "http://beta.newsapi.org/v2/everything?apiKey="+NewsListModel.this.APIKey+"&language="+lang
|
2017-11-21 07:34:05 +00:00
|
|
|
+"&q="+encodedQuery+"&sortBy="+NewsListModel.this.sortType.name();
|
2017-11-15 21:53:52 +00:00
|
|
|
|
|
|
|
//on ajoute la liste des sources a l'URL de la requete
|
|
|
|
if(NewsListModel.this.sources != null && NewsListModel.this.sources.size() != 0) {
|
|
|
|
String sources = "&sources=";
|
|
|
|
for(String s : NewsListModel.this.sources) {
|
|
|
|
sources += s+",";
|
|
|
|
}
|
|
|
|
//on enlève la dernière virgule
|
|
|
|
sources = sources.replaceAll(",$", "");
|
|
|
|
URL += sources;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Pair<String,HashMap<String,String>>(URL,null);
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
this.addObserver("newsApiCall",api);
|
|
|
|
}
|
|
|
|
|
|
|
|
api.send();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setSortType(SortTypes t) {
|
|
|
|
this.sortType = t;
|
|
|
|
this.query(this.query);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void notifyObservers(Event e) {
|
|
|
|
for(Object key : this.observers.keySet().toArray()) {
|
|
|
|
this.observers.get(key).handleEvent(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-12 14:02:37 +00:00
|
|
|
|
|
|
|
public String getQuery() {
|
|
|
|
return this.query;
|
|
|
|
}
|
|
|
|
|
2017-11-15 21:53:52 +00:00
|
|
|
public ArrayList<NewsModel> getNews(){
|
|
|
|
return this.news;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void addObserver(String key, EventObserver o) {
|
|
|
|
this.observers.put(key, o);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void removeObserver(String key) {
|
|
|
|
this.observers.remove(key);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|