Java tutorial
/* * Copyright 2015 Anael Mobilia * * This file is part of NextINpact-Unofficial. * * NextINpact-Unofficial is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * NextINpact-Unofficial is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NextINpact-Unofficial. If not, see <http://www.gnu.org/licenses/> */ package com.pcinpact; import java.io.File; import java.util.ArrayList; import java.util.Collections; import com.pcinpact.adapters.ItemsAdapter; import com.pcinpact.database.DAO; import com.pcinpact.downloaders.AsyncHTMLDownloader; import com.pcinpact.downloaders.AsyncImageDownloader; import com.pcinpact.downloaders.RefreshDisplayInterface; import com.pcinpact.items.ArticleItem; import com.pcinpact.items.Item; import com.pcinpact.items.SectionItem; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.graphics.Bitmap; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.Window; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ListView; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; public class ListeArticlesActivity extends ActionBarActivity implements RefreshDisplayInterface, OnItemClickListener { // les articles private ArrayList<ArticleItem> mesArticles = new ArrayList<ArticleItem>(); // itemAdapter private ItemsAdapter monItemsAdapter; // La BDD private DAO monDAO; // Nombre de DL en cours private int DLinProgress = 0; // Ressources sur les lments graphiques private Menu monMenu; private ListView monListView; private SwipeRefreshLayout monSwipeRefreshLayout; private TextView headerTextView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); // On dfinit la vue setContentView(R.layout.liste_articles); // On rcupre les lments monListView = (ListView) this.findViewById(R.id.listeArticles); monSwipeRefreshLayout = (SwipeRefreshLayout) this.findViewById(R.id.swipe_container); headerTextView = (TextView) findViewById(R.id.header_text); setSupportProgressBarIndeterminateVisibility(false); // onRefresh monSwipeRefreshLayout.setOnRefreshListener(new OnRefreshListener() { @Override public void onRefresh() { telechargeListeArticles(); } }); monItemsAdapter = new ItemsAdapter(this, mesArticles); monListView.setAdapter(monItemsAdapter); monListView.setOnItemClickListener(this); // On active le SwipeRefreshLayout uniquement si on est en haut de la listview monListView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { int topRowVerticalPosition; if (monListView == null || monListView.getChildCount() == 0) { topRowVerticalPosition = 0; } else { topRowVerticalPosition = monListView.getChildAt(0).getTop(); } monSwipeRefreshLayout.setEnabled(topRowVerticalPosition >= 0); } }); // J'active la BDD monDAO = DAO.getInstance(getApplicationContext()); // Je charge mes articles mesArticles.addAll(monDAO.chargerArticlesTriParDate()); // Mise jour de l'affichage monItemsAdapter.updateListeItems(prepareAffichage()); // Message d'accueil pour la premire utilisation final SharedPreferences mesPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); // Est-ce la premiere utilisation de l'application ? Boolean premiereUtilisation = mesPrefs.getBoolean(getString(R.string.idOptionPremierLancementApplication), getResources().getBoolean(R.bool.defautOptionPremierLancementApplication)); // Si premire utilisation : on affiche un disclaimer if (premiereUtilisation) { AlertDialog.Builder builder = new AlertDialog.Builder(this); // Titre builder.setTitle(getResources().getString(R.string.app_name)); // Contenu builder.setMessage(getResources().getString(R.string.disclaimerContent)); // Bouton d'action builder.setCancelable(false); builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { // Enregistrement que le message a dj t affich Editor editor = mesPrefs.edit(); editor.putBoolean(getString(R.string.idOptionPremierLancementApplication), false); editor.commit(); // Affichage de l'cran de configuration de l'application Intent intentOptions = new Intent(getApplicationContext(), OptionsActivity.class); startActivity(intentOptions); } }); // On cre & affiche builder.create().show(); // Lancement d'un tlchargement des articles telechargeListeArticles(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Je garde le menu pour pouvoir l'animer aprs monMenu = menu; // Je charge mon menu dans l'actionBar MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main_activity_actions, monMenu); // Je lance l'animation si un DL est dj en cours if (DLinProgress != 0) { // Hack : il n'y avait pas d'accs la GUI sur onCreate DLinProgress--; nouveauChargementGUI(); } return super.onCreateOptionsMenu(monMenu); } /** * Gestion du clic sur un article => l'ouvrir */ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ArticleItem monArticle = (ArticleItem) monItemsAdapter.getItem(position); Intent monIntent = new Intent(getApplicationContext(), ArticleActivity.class); monIntent.putExtra("ARTICLE_ID", monArticle.getID()); startActivity(monIntent); } /** * Ouverture du menu de l'action bar l'utilisation du bouton menu */ @Override public boolean onKeyUp(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_MENU: monMenu.performIdentifierAction(R.id.action_overflow, 0); return true; } return super.onKeyUp(keyCode, event); } /** * Gestion des clic dans le menu d'options de l'activit */ @Override public boolean onOptionsItemSelected(final MenuItem pItem) { switch (pItem.getItemId()) { // Rafraichir la liste des articles case R.id.action_refresh: telechargeListeArticles(); return true; // Menu Options case R.id.action_settings: // Je lance l'activit options Intent intentOptions = new Intent(getApplicationContext(), OptionsActivity.class); startActivity(intentOptions); return true; // A propos case R.id.action_about: Intent intentAbout = new Intent(getApplicationContext(), AboutActivity.class); startActivity(intentAbout); return true; default: return super.onOptionsItemSelected(pItem); } } /** * Nettoyage du cache */ @Override protected void onDestroy() { // Prfrences de l'utilisateur SharedPreferences mesPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); // Nombre d'articles conserver int maLimite = Integer.parseInt(mesPrefs.getString(getString(R.string.idOptionNbArticles), getString(R.string.defautOptionNbArticles))); mesArticles = monDAO.chargerArticlesTriParDate(); // Je protge les images prsentes dans les articles conserver ArrayList<String> imagesLegit = new ArrayList<String>(); for (int i = 0; i < maLimite && i < mesArticles.size(); i++) { imagesLegit.add(mesArticles.get(i).getImageName()); } // Je ne conserve que les n premiers articles for (int i = maLimite; i < mesArticles.size(); i++) { ArticleItem article = mesArticles.get(i); // Suppression en DB monDAO.supprimerArticle(article); // DEBUG if (Constantes.DEBUG) { Log.w("ListeArticlesActivity", "Cache : suppression de " + article.getTitre()); } // Suppression des commentaires de l'article monDAO.supprimerCommentaire(article.getID()); // Suppression de la miniature, uniquement si plus utilise if (!imagesLegit.contains(article.getImageName())) { File monFichier = new File( getApplicationContext().getFilesDir() + Constantes.PATH_IMAGES_MINIATURES, article.getImageName()); monFichier.delete(); } } // Nettoyage des traces des v<1.8.0 // Les fichiers sur stocks en local String[] SavedFiles = getApplicationContext().fileList(); for (String file : SavedFiles) { // Article effacer getApplicationContext().deleteFile(file); } super.onDestroy(); } @SuppressLint("NewApi") private void telechargeListeArticles() { // Uniquement si on est pa&s dj en train de faire un refresh... if (DLinProgress == 0) { // Le retour en GUI nouveauChargementGUI(); // Ma tche de DL AsyncHTMLDownloader monAHD = new AsyncHTMLDownloader(getApplicationContext(), this, Constantes.HTML_LISTE_ARTICLES, Constantes.NEXT_INPACT_URL, monDAO); // Paralllisation des tlchargements pour l'ensemble de l'application if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { monAHD.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { monAHD.execute(); } } } @SuppressLint("NewApi") @Override public void downloadHTMLFini(String uneURL, ArrayList<Item> desItems) { // Si c'est un refresh gnral if (uneURL.equals(Constantes.NEXT_INPACT_URL)) { for (Item unItem : desItems) { // Je l'enregistre en mmoire mesArticles.add((ArticleItem) unItem); // Je lance le tlchargement de sa miniature AsyncImageDownloader monAID = new AsyncImageDownloader(getApplicationContext(), this, Constantes.IMAGE_MINIATURE_ARTICLE, ((ArticleItem) unItem).getURLIllustration()); // Paralllisation des tlchargements pour l'ensemble de l'application if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { monAID.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { monAID.execute(); } nouveauChargementGUI(); // Je lance le tlchargement de son contenu AsyncHTMLDownloader monAHD = new AsyncHTMLDownloader(getApplicationContext(), this, Constantes.HTML_ARTICLE, ((ArticleItem) unItem).getURL(), monDAO); // Paralllisation des tlchargements pour l'ensemble de l'application if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { monAHD.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { monAHD.execute(); } nouveauChargementGUI(); } // Prfrences de l'utilisateur SharedPreferences mesPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); // Nombre d'articles conserver int maLimite = Integer.parseInt(mesPrefs.getString(getString(R.string.idOptionNbArticles), getString(R.string.defautOptionNbArticles))); // Je limie n articles (cf prfrence de l'utilisateur) for (int i = 0; i < (mesArticles.size() - maLimite); i++) { mesArticles.remove(i); } // DEBUG if (Constantes.DEBUG) { Log.w("ListeArticlesActivity", "downloadHTMLFini : " + mesArticles.size() + " articles laisss en mmoire"); } } // gestion du tlchargement GUI finChargementGUI(); } @Override public void downloadImageFini(String uneURL, Bitmap uneImage) { // gestion du tlchargement GUI finChargementGUI(); } /** * Fournit une liste d'articles tris par date + sections * * @return */ private ArrayList<Item> prepareAffichage() { // Tri des Articles par timestamp Collections.sort(mesArticles); ArrayList<Item> monRetour = new ArrayList<Item>(); String jourActuel = ""; for (ArticleItem article : mesArticles) { // Si ce n'est pas la mme journe que l'article prcdent if (!article.getDatePublication().equals(jourActuel)) { // Je met jour ma date jourActuel = article.getDatePublication(); // J'ajoute un sectionItem monRetour.add(new SectionItem(jourActuel)); } // J'ajoute mon article monRetour.add(article); } return monRetour; } /** * Gre les animations de tlchargement */ private void nouveauChargementGUI() { // Si c'est le premier => activation des gri-gri GUI if (DLinProgress == 0) { // DEBUG if (Constantes.DEBUG) { Log.w("nouveauChargementGUI", "Lancement animation"); } // Couleurs du RefreshLayout monSwipeRefreshLayout.setColorSchemeColors(getResources().getColor(R.color.refreshBleu), getResources().getColor(R.color.refreshOrange), getResources().getColor(R.color.refreshBleu), getResources().getColor(R.color.refreshBlanc)); // Animation du RefreshLayout monSwipeRefreshLayout.setRefreshing(true); // Lance la rotation du logo dans le header setSupportProgressBarIndeterminateVisibility(true); // Supprime l'icne refresh dans le header if (monMenu != null) monMenu.findItem(R.id.action_refresh).setVisible(false); } // Je note le tlchargement en cours DLinProgress++; // DEBUG if (Constantes.DEBUG) { Log.w("nouveauChargementGUI", "" + DLinProgress); } } /** * Gre les animations de tlchargement */ private void finChargementGUI() { // Je note la fin du tlchargement DLinProgress--; // Si c'est le premier => activation des gri-gri GUI if (DLinProgress == 0) { // DEBUG if (Constantes.DEBUG) { Log.w("finChargementGUI", "Arrt animation"); } // On stoppe l'animation du SwipeRefreshLayout monSwipeRefreshLayout.setRefreshing(false); // Arrt de la rotation du logo dans le header setSupportProgressBarIndeterminateVisibility(false); // Affiche l'icne refresh dans le header if (monMenu != null) monMenu.findItem(R.id.action_refresh).setVisible(true); // Je met jour les donnes monItemsAdapter.updateListeItems(prepareAffichage()); // Je notifie le changement pour un rafraichissement du contenu monItemsAdapter.notifyDataSetChanged(); } // DEBUG if (Constantes.DEBUG) { Log.w("finChargementGUI", "" + DLinProgress); } } }