/* * Copyright 2014, 2015, 2016 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.adapters; import android.content.Context; import android.support.v4.content.ContextCompat; import android.text.Html; import android.text.Spanned; import android.util.Log; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import com.pcinpact.R; import com.pcinpact.adapters.viewholder.ArticleItemViewHolder; import com.pcinpact.adapters.viewholder.CommentaireItemViewHolder; import com.pcinpact.adapters.viewholder.ContenuArticleViewHolder; import com.pcinpact.adapters.viewholder.SectionItemViewHolder; import com.pcinpact.datastorage.ImageProvider; import com.pcinpact.items.ArticleItem; import com.pcinpact.items.CommentaireItem; import com.pcinpact.items.ContenuArticleItem; import com.pcinpact.items.Item; import com.pcinpact.items.SectionItem; import com.pcinpact.parseur.TagHandler; import com.pcinpact.utils.Constantes; import java.util.ArrayList; /** * Adapter pour le rendu des *Item. * * @author Anael */ public class ItemsAdapter extends BaseAdapter { /** * Context de l'application. */ private final Context monContext; /** * Layout inflater. */ private final LayoutInflater monLayoutInflater; /** * Items à afficher. */ private ArrayList<? extends Item> mesItems; /** * Faut-il ne pas réutiliser les vues ? (changement de thème) */ private boolean resetView = false; /** * Constructeur. * * @param unContext Contexte application * @param unLayoutInflater Layout Inflater * @param desItems items à afficher */ public ItemsAdapter(final Context unContext, final LayoutInflater unLayoutInflater, final ArrayList<? extends Item> desItems) { /** * Cf issue #188 : une activité est requise pour que le layoutinflater puisse être associé à une activité => * possibilité de lancer une autre apps * Sinon, crash lors du click sur une URL */ // Je charge le bouzin monContext = unContext; mesItems = desItems; monLayoutInflater = unLayoutInflater; } /** * Réinitialisation forcée des vues (changement de thème) #208 - uniquement pour le moment du changement de thème */ public void setResetView() { resetView = true; } /** * MàJ les données de la liste d'items. * * @param nouveauxItems liste d'items */ public void updateListeItems(final ArrayList<? extends Item> nouveauxItems) { mesItems = nouveauxItems; } @Override public int getCount() { return mesItems.size(); } @Override public Item getItem(int arg0) { return mesItems.get(arg0); } @Override public long getItemId(int arg0) { return arg0; } /** * Nombre de type d'items existants. */ @Override public int getViewTypeCount() { return Item.NOMBRE_DE_TYPES; } /** * Type de l'item à la position (pour définir le bon type de vue à fournir). */ @Override public int getItemViewType(int position) { return mesItems.get(position).getType(); } @Override public View getView(int position, View convertView, ViewGroup parent) { View maView = convertView; // Gestion du recyclage des vues - voir http://android.amberfog.com/?p=296 // Pas de recyclage ou recyclage forcé (changement de thème) if (maView == null || resetView) { // DEBUG if (Constantes.DEBUG) { Log.d("ItemsAdapter", "getView() - nouvelle vue (#" + position + ")"); } // Je crée la vue qui va bien... switch (getItemViewType(position)) { case Item.TYPE_SECTION: // Je charge mon layout maView = monLayoutInflater.inflate(R.layout.liste_articles_item_section, parent, false); // Ses propriétés maView.setOnClickListener(null); maView.setOnLongClickListener(null); // Je crée mon viewHolder SectionItemViewHolder sectionVH = new SectionItemViewHolder(); // Je prépare mon holder sectionVH.sectionView = (TextView) maView.findViewById(R.id.titreSection); // Et l'assigne maView.setTag(sectionVH); break; case Item.TYPE_ARTICLE: // Je charge mon layout maView = monLayoutInflater.inflate(R.layout.liste_articles_item_article, parent, false); // Je crée mon viewHolder ArticleItemViewHolder articleVH = new ArticleItemViewHolder(); // Je prépare mon holder articleVH.relativeLayout = (RelativeLayout) maView.findViewById(R.id.relativeLayoutArticle); articleVH.imageArticle = (ImageView) maView.findViewById(R.id.imageArticle); articleVH.labelAbonne = (TextView) maView.findViewById(R.id.labelAbonne); articleVH.titreArticle = (TextView) maView.findViewById(R.id.titreArticle); articleVH.heureArticle = (TextView) maView.findViewById(R.id.heureArticle); articleVH.sousTitreArticle = (TextView) maView.findViewById(R.id.sousTitreArticle); articleVH.commentairesArticle = (TextView) maView.findViewById(R.id.commentairesArticle); // Et l'assigne maView.setTag(articleVH); break; case Item.TYPE_COMMENTAIRE: // Je charge mon layout maView = monLayoutInflater.inflate(R.layout.commentaires_item_commentaire, parent, false); // Je crée mon viewHolder CommentaireItemViewHolder commentaireVH = new CommentaireItemViewHolder(); // Je prépare mon holder commentaireVH.auteurDateCommentaire = (TextView) maView.findViewById(R.id.auteurDateCommentaire); commentaireVH.numeroCommentaire = (TextView) maView.findViewById(R.id.numeroCommentaire); commentaireVH.commentaire = (TextView) maView.findViewById(R.id.commentaire); // Et l'assigne maView.setTag(commentaireVH); break; case Item.TYPE_CONTENU_ARTICLE: // Je charge mon layout maView = monLayoutInflater.inflate(R.layout.article_texte, parent, false); // Je crée mon viewHolder ContenuArticleViewHolder contenuVH = new ContenuArticleViewHolder(); // Je prépare mon holder contenuVH.contenu = (TextView) maView.findViewById(R.id.texteArticle); // Et l'assigne maView.setTag(contenuVH); break; default: // DEBUG if (Constantes.DEBUG) { Log.e("ItemsAdapter", "getView() - getItemViewType incorrect : " + getItemViewType(position)); } break; } } else { // DEBUG if (Constantes.DEBUG) { // 0...n vs 1...(n+1) Log.d("ItemsAdapter", "getView() - recyclage de la vue (pour #" + (position + 1) + ")"); } } Item i = mesItems.get(position); if (i != null) { switch (i.getType()) { case Item.TYPE_SECTION: // Je charge mon ItemsViewHolder (lien vers les *View) SectionItemViewHolder sectionVH = (SectionItemViewHolder) maView.getTag(); SectionItem si = (SectionItem) i; sectionVH.sectionView.setText(si.getTitre()); // Désactivation de l'effet de click maView.setOnClickListener(null); maView.setOnLongClickListener(null); // On applique le zoom éventuel appliqueZoom(sectionVH.sectionView, Constantes.TEXT_SIZE_MEDIUM); break; case Item.TYPE_ARTICLE: // Je charge mon ItemsViewHolder (lien vers les *View) ArticleItemViewHolder articleVH = (ArticleItemViewHolder) maView.getTag(); /** * Article */ ArticleItem ai = (ArticleItem) i; // Gestion du thème (option utilisateur= Boolean isThemeSombre = Constantes.getOptionBoolean(monContext, R.string.idOptionThemeSombre, R.bool.defautOptionThemeSombre); // L'article est-il déjà lu ? int couleurArticle; if (ai.isLu()) { // Couleur lu // Choix couleur en fonction du thème if (isThemeSombre) { couleurArticle = ContextCompat.getColor(monContext, R.color.articleLu_fonce); } else { couleurArticle = ContextCompat.getColor(monContext, R.color.articleLu_clair); } } else { // Couleur non lu // Choix couleur en fonction du thème if (isThemeSombre) { couleurArticle = ContextCompat.getColor(monContext, R.color.articleNonLu_fonce); } else { couleurArticle = ContextCompat.getColor(monContext, R.color.articleNonLu_clair); } } // Application de la couleur articleVH.relativeLayout.setBackgroundColor(couleurArticle); // Gestion du badge abonné if (ai.isAbonne()) { articleVH.labelAbonne.setVisibility(View.VISIBLE); } else { articleVH.labelAbonne.setVisibility(View.GONE); } // Remplissage des textview articleVH.titreArticle.setText(ai.getTitre()); articleVH.heureArticle.setText(ai.getHeureMinutePublication()); articleVH.sousTitreArticle.setText(ai.getSousTitre()); // Gestion du nombre de commentaires (+ nouveaux) String texteCommentaires = String.valueOf(ai.getNbCommentaires()); boolean nbNouveauComm = Constantes.getOptionBoolean(monContext, R.string.idOptionAfficherNbNouveauComm, R.bool.defautOptionAfficherNbNouveauComm); // Ssi commentaires déjà lus if (nbNouveauComm && ai.getDernierCommLu() > 0) { // Calcul du nb de nouveaux commentaires int nbCommentaires = ai.getNbCommentaires() - ai.getDernierCommLu(); // Affichage seulement si des nouveaux commentaires if (nbCommentaires > 0) { // Insertion dans texte texteCommentaires += " (+" + nbCommentaires + ")"; } } articleVH.commentairesArticle.setText(texteCommentaires); // Gestion de l'image ImageProvider monImageProvider = new ImageProvider(monContext, articleVH.imageArticle, ai.getId()); articleVH.imageArticle.setImageDrawable(monImageProvider.getDrawable(ai.getUrlIllustration())); // On applique le zoom éventuel appliqueZoom(articleVH.titreArticle, Constantes.TEXT_SIZE_SMALL); appliqueZoom(articleVH.heureArticle, Constantes.TEXT_SIZE_SMALL); appliqueZoom(articleVH.sousTitreArticle, Constantes.TEXT_SIZE_SMALL); appliqueZoom(articleVH.commentairesArticle, Constantes.TEXT_SIZE_MICRO); appliqueZoom(articleVH.labelAbonne, Constantes.TEXT_SIZE_SMALL); break; case Item.TYPE_COMMENTAIRE: // Je charge mon ItemsViewHolder (lien vers les *View) CommentaireItemViewHolder commentaireVH = (CommentaireItemViewHolder) maView.getTag(); /** * Commentaire */ CommentaireItem ci = (CommentaireItem) i; // DEBUG if (Constantes.DEBUG) { Log.i("ItemsAdapter", "getView() - Commentaire #" + ci.getId()); } // Remplissage des textview commentaireVH.auteurDateCommentaire.setText(ci.getAuteurDateCommentaire()); commentaireVH.numeroCommentaire.setText(String.valueOf(ci.getId())); Spanned spannedCommentaire = Html.fromHtml(ci.getCommentaire(), new ImageProvider(monContext, commentaireVH.commentaire, ci.getCommentaire(), Constantes.IMAGE_SMILEY, ci.getUuid()), null); commentaireVH.commentaire.setText(spannedCommentaire); // Définition de l'ID du textview (pour gestion callback si dl image) commentaireVH.commentaire.setId(ci.getUuid()); // Liens cliquables ? option utilisateur ! Boolean lienCommentaireClickable = Constantes.getOptionBoolean(monContext, R.string.idOptionLiensDansCommentaires, R.bool.defautOptionLiensDansCommentaires); if (lienCommentaireClickable) { // Active les liens a href commentaireVH.commentaire.setMovementMethod(new GestionLiens()); } else { // Désactivation de l'effet de click maView.setOnClickListener(null); maView.setOnLongClickListener(null); } // On applique le zoom éventuel appliqueZoom(commentaireVH.auteurDateCommentaire, Constantes.TEXT_SIZE_MICRO); appliqueZoom(commentaireVH.numeroCommentaire, Constantes.TEXT_SIZE_MICRO); appliqueZoom(commentaireVH.commentaire, Constantes.TEXT_SIZE_SMALL); break; case Item.TYPE_CONTENU_ARTICLE: // Je charge mon ItemsViewHolder (lien vers les *View) ContenuArticleViewHolder contenuVH = (ContenuArticleViewHolder) maView.getTag(); /** * Contenu */ ContenuArticleItem cai = (ContenuArticleItem) i; // Remplissage des textview Spanned spannedContenu = Html.fromHtml(cai.getContenu(), new ImageProvider(monContext, contenuVH.contenu, cai.getContenu(), Constantes.IMAGE_CONTENU_ARTICLE, cai.getArticleID()), new TagHandler()); contenuVH.contenu.setText(spannedContenu); // Définition de l'ID du textview (pour gestion callback si dl image) contenuVH.contenu.setId(cai.getArticleID()); // Liens cliquables ? option utilisateur ! Boolean lienArticleClickable = Constantes.getOptionBoolean(monContext, R.string.idOptionLiensDansArticles, R.bool.defautOptionLiensDansArticles); if (lienArticleClickable) { // Active les liens a href contenuVH.contenu.setMovementMethod(new GestionLiens()); } else { // Désactivation de l'effet de click maView.setOnClickListener(null); maView.setOnLongClickListener(null); } // On applique le zoom éventuel appliqueZoom(contenuVH.contenu, Constantes.TEXT_SIZE_SMALL); break; default: // DEBUG if (Constantes.DEBUG) { Log.e("ItemsAdapter", "getView() - i.getType() incorrect : " + i.getType()); } break; } } return maView; } /** * Applique un zoom sur une textview. * * @param uneTextView textView cible * @param defaultSize taille par défaut */ private void appliqueZoom(final TextView uneTextView, final int defaultSize) { // Taile par défaut int tailleDefaut = Integer.valueOf(monContext.getResources().getString(R.string.defautOptionZoomTexte)); // L'option selectionnée int tailleUtilisateur = Constantes.getOptionInt(monContext, R.string.idOptionZoomTexte, R.string.defautOptionZoomTexte); float monCoeffZoom = 1; // Faut-il applique un zoom ? if (tailleUtilisateur != tailleDefaut) { monCoeffZoom = (float) tailleUtilisateur / tailleDefaut; } float nouvelleTaille = defaultSize * monCoeffZoom; uneTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, nouvelleTaille); // DEBUG if (Constantes.DEBUG) { Log.d("ItemsAdapter", "appliqueZoom() - " + monCoeffZoom + " - taille originale " + defaultSize + " => " + nouvelleTaille); } } }