Simple email application for Android. Original source code: https://framagit.org/dystopia-project/simple-email
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 lines
9.3 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. package eu.faircode.email;
  2. /*
  3. This file is part of FairEmail.
  4. FairEmail is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. NetGuard is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with NetGuard. If not, see <http://www.gnu.org/licenses/>.
  14. Copyright 2018 by Marcel Bokhorst (M66B)
  15. */
  16. import android.content.Context;
  17. import android.content.Intent;
  18. import android.graphics.Typeface;
  19. import android.util.Log;
  20. import android.view.LayoutInflater;
  21. import android.view.View;
  22. import android.view.ViewGroup;
  23. import android.widget.ImageView;
  24. import android.widget.TextView;
  25. import java.text.Collator;
  26. import java.util.ArrayList;
  27. import java.util.Collections;
  28. import java.util.Comparator;
  29. import java.util.List;
  30. import java.util.Locale;
  31. import androidx.annotation.NonNull;
  32. import androidx.localbroadcastmanager.content.LocalBroadcastManager;
  33. import androidx.recyclerview.widget.DiffUtil;
  34. import androidx.recyclerview.widget.ListUpdateCallback;
  35. import androidx.recyclerview.widget.RecyclerView;
  36. public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder> {
  37. private Context context;
  38. private List<TupleFolderEx> all = new ArrayList<>();
  39. private List<TupleFolderEx> filtered = new ArrayList<>();
  40. public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
  41. View itemView;
  42. ImageView ivEdit;
  43. TextView tvName;
  44. TextView tvMessages;
  45. TextView tvType;
  46. TextView tvAfter;
  47. ImageView ivSync;
  48. ImageView ivState;
  49. TextView tvError;
  50. ViewHolder(View itemView) {
  51. super(itemView);
  52. this.itemView = itemView;
  53. ivEdit = itemView.findViewById(R.id.ivEdit);
  54. tvName = itemView.findViewById(R.id.tvName);
  55. tvMessages = itemView.findViewById(R.id.tvMessages);
  56. tvType = itemView.findViewById(R.id.tvType);
  57. tvAfter = itemView.findViewById(R.id.tvAfter);
  58. ivSync = itemView.findViewById(R.id.ivSync);
  59. tvError = itemView.findViewById(R.id.tvError);
  60. ivState = itemView.findViewById(R.id.ivState);
  61. }
  62. private void wire(boolean properties) {
  63. itemView.setOnClickListener(this);
  64. if (properties)
  65. ivEdit.setOnClickListener(this);
  66. }
  67. private void unwire() {
  68. itemView.setOnClickListener(null);
  69. }
  70. private void bindTo(TupleFolderEx folder) {
  71. boolean outbox = EntityFolder.OUTBOX.equals(folder.type);
  72. ivEdit.setVisibility(outbox ? View.INVISIBLE : View.VISIBLE);
  73. String name = Helper.localizeFolderName(context, folder.name);
  74. if (folder.unseen > 0)
  75. tvName.setText(context.getString(R.string.title_folder_unseen, name, folder.unseen));
  76. else
  77. tvName.setText(name);
  78. tvName.setTypeface(null, folder.unseen > 0 ? Typeface.BOLD : Typeface.NORMAL);
  79. tvName.setTextColor(Helper.resolveColor(context, folder.unseen > 0 ? R.attr.colorUnread : android.R.attr.textColorSecondary));
  80. tvMessages.setText(Integer.toString(folder.messages));
  81. int resid = context.getResources().getIdentifier(
  82. "title_folder_" + folder.type.toLowerCase(),
  83. "string",
  84. context.getPackageName());
  85. tvType.setText(resid > 0 ? context.getString(resid) : folder.type);
  86. tvAfter.setText(Integer.toString(folder.after));
  87. tvAfter.setVisibility(folder.synchronize ? View.VISIBLE : View.INVISIBLE);
  88. ivSync.setVisibility(folder.synchronize ? View.VISIBLE : View.INVISIBLE);
  89. if ("connected".equals(folder.state))
  90. ivState.setImageResource(R.drawable.baseline_cloud_24);
  91. else if ("connecting".equals(folder.state))
  92. ivState.setImageResource(R.drawable.baseline_cloud_queue_24);
  93. else
  94. ivState.setImageResource(R.drawable.baseline_cloud_off_24);
  95. ivState.setVisibility(folder.synchronize || outbox ? View.VISIBLE : View.INVISIBLE);
  96. tvError.setText(folder.error);
  97. tvError.setVisibility(folder.error == null ? View.GONE : View.VISIBLE);
  98. }
  99. @Override
  100. public void onClick(View view) {
  101. int pos = getAdapterPosition();
  102. if (pos == RecyclerView.NO_POSITION)
  103. return;
  104. TupleFolderEx folder = filtered.get(pos);
  105. if (view.getId() == R.id.ivEdit) {
  106. if (!EntityFolder.OUTBOX.equals(folder.type)) {
  107. LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
  108. lbm.sendBroadcast(
  109. new Intent(ActivityView.ACTION_EDIT_FOLDER)
  110. .putExtra("id", folder.id));
  111. }
  112. } else {
  113. LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
  114. lbm.sendBroadcast(
  115. new Intent(ActivityView.ACTION_VIEW_MESSAGES)
  116. .putExtra("folder", folder.id));
  117. }
  118. }
  119. }
  120. AdapterFolder(Context context) {
  121. this.context = context;
  122. setHasStableIds(true);
  123. }
  124. public void set(@NonNull List<TupleFolderEx> folders) {
  125. Log.i(Helper.TAG, "Set folders=" + folders.size());
  126. final Collator collator = Collator.getInstance(Locale.getDefault());
  127. collator.setStrength(Collator.SECONDARY); // Case insensitive, process accents etc
  128. Collections.sort(folders, new Comparator<TupleFolderEx>() {
  129. @Override
  130. public int compare(TupleFolderEx f1, TupleFolderEx f2) {
  131. int s = Integer.compare(
  132. EntityFolder.FOLDER_SORT_ORDER.indexOf(f1.type),
  133. EntityFolder.FOLDER_SORT_ORDER.indexOf(f2.type));
  134. if (s != 0)
  135. return s;
  136. int c = -f1.synchronize.compareTo(f2.synchronize);
  137. if (c != 0)
  138. return c;
  139. return collator.compare(
  140. f1.name == null ? "" : f1.name,
  141. f2.name == null ? "" : f2.name);
  142. }
  143. });
  144. all.clear();
  145. all.addAll(folders);
  146. DiffUtil.DiffResult diff = DiffUtil.calculateDiff(new MessageDiffCallback(filtered, all));
  147. filtered.clear();
  148. filtered.addAll(all);
  149. diff.dispatchUpdatesTo(new ListUpdateCallback() {
  150. @Override
  151. public void onInserted(int position, int count) {
  152. Log.i(Helper.TAG, "Inserted @" + position + " #" + count);
  153. }
  154. @Override
  155. public void onRemoved(int position, int count) {
  156. Log.i(Helper.TAG, "Removed @" + position + " #" + count);
  157. }
  158. @Override
  159. public void onMoved(int fromPosition, int toPosition) {
  160. Log.i(Helper.TAG, "Moved " + fromPosition + ">" + toPosition);
  161. }
  162. @Override
  163. public void onChanged(int position, int count, Object payload) {
  164. Log.i(Helper.TAG, "Changed @" + position + " #" + count);
  165. }
  166. });
  167. diff.dispatchUpdatesTo(AdapterFolder.this);
  168. }
  169. private class MessageDiffCallback extends DiffUtil.Callback {
  170. private List<TupleFolderEx> prev;
  171. private List<TupleFolderEx> next;
  172. MessageDiffCallback(List<TupleFolderEx> prev, List<TupleFolderEx> next) {
  173. this.prev = prev;
  174. this.next = next;
  175. }
  176. @Override
  177. public int getOldListSize() {
  178. return prev.size();
  179. }
  180. @Override
  181. public int getNewListSize() {
  182. return next.size();
  183. }
  184. @Override
  185. public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
  186. TupleFolderEx f1 = prev.get(oldItemPosition);
  187. TupleFolderEx f2 = next.get(newItemPosition);
  188. return f1.id.equals(f2.id);
  189. }
  190. @Override
  191. public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
  192. TupleFolderEx f1 = prev.get(oldItemPosition);
  193. TupleFolderEx f2 = next.get(newItemPosition);
  194. return f1.equals(f2);
  195. }
  196. }
  197. @Override
  198. public long getItemId(int position) {
  199. return filtered.get(position).id;
  200. }
  201. @Override
  202. public int getItemCount() {
  203. return filtered.size();
  204. }
  205. @Override
  206. @NonNull
  207. public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
  208. return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_folder, parent, false));
  209. }
  210. @Override
  211. public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
  212. holder.unwire();
  213. TupleFolderEx folder = filtered.get(position);
  214. holder.bindTo(folder);
  215. holder.wire(folder.account != null);
  216. }
  217. }