JavaFX/model/NewsListModel.java

218 lines
6.3 KiB
Java

package model;
import java.util.ArrayList;
import java.util.HashMap;
import org.json.JSONArray;
import org.json.JSONObject;
import Classes.ApiCall;
import Classes.Category;
import Classes.Event;
import Classes.SortTypes;
import Classes.api.fetchArticles;
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;
private String APIKey; // Clé d'API
private Category cat = Category.all; // catégorie choise parl'utilisateur
private Boolean isRetreivingSources = false; // est ce que le modele est en train de récupérer les sources
private Boolean apiError = false; // est ce que l'api a rencontré une erreur
private ArrayList<String> sources; // liste des sources
private HashMap<String,EventObserver> observers; // liste des observers
private ArrayList<NewsModel> news; // liste des news finale
private SortTypes sortType = SortTypes.relevancy; // critère de tri
private String query = ""; // critère de recherche de l'utilisateur
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.clear();
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(String errDesc) {
//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) {
//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;
}
//on créer l'URL de l'appel
String lang = LangModel.getInstance().getToLang().name();
String URL = "http://beta.newsapi.org/v2/everything?apiKey="+this.APIKey+"&language="+lang+"&q="+q+"&sortBy="+this.sortType.name();
//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 fetchArticles(this, q)
);
//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
+"&q="+q+"&sortBy="+NewsListModel.this.sortType.name();
//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);
}
}
public void setQuery(String query){
this.query = query;
}
public void setNews(ArrayList<NewsModel> news){
this.news = news;
}
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);
}
}