Java tutorial
// Copyright (c) 2017-2018, Tom Geiselmann // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software // and associated documentation files (the "Software"), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, merge, publish, distribute, // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or // substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. package com.none.tom.simplerssreader.utils; import android.content.Context; import android.content.SharedPreferences; import android.support.annotation.Nullable; import android.text.TextUtils; import com.google.common.collect.LinkedListMultimap; import com.none.tom.simplerssreader.R; import com.none.tom.simplerssreader.opml.Outline; import com.none.tom.simplerssreader.opml.OutlineGroup; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Set; import java.util.TreeSet; import static com.none.tom.simplerssreader.utils.Constants.KEY_SHARED_PREFERENCES; public class SharedPrefUtils { private static final String KEY_SUBSCRIPTIONS = "key_subscriptions"; private static final String KEY_SUBSCRIPTION_CATEGORIES = "key_subscription_categories"; private static final String KEY_SUBSCRIPTION_URLS = "key_subscription_urls"; private static final String KEY_SUBSCRIPTION_TITLES = "key_subscription_titles"; private static final String KEY_SUBSCRIPTION_IDS = "key_subscription_ids"; private static final String KEY_CURRENT_FEED_POSITION = "key_current_feed_position"; private static final String KEY_PREVIOUS_FEED_POSITION = "key_previous_feed__position"; private static LinkedListMultimap<String, String> sSubscriptions; private static List<List<Object>> sSubscriptionList; private static SharedPreferences sSharedPreferences; @SuppressWarnings("unchecked") public static <T> T get(final Context context, final String key, final Class<T> clazz) { if (clazz.equals(String.class)) { return (T) getSharedPreferences(context).getString(key, null); } return (T) (Integer) getSharedPreferences(context).getInt(key, 0); } public static <T> void put(final Context context, final String key, @Nullable final T value) { final SharedPreferences.Editor preferences = getSharedPreferences(context).edit(); if (value == null || value instanceof String) { preferences.putString(key, (String) value); } else { preferences.putInt(key, (Integer) value); } preferences.apply(); } private static SharedPreferences getSharedPreferences(final Context context) { if (sSharedPreferences == null) { sSharedPreferences = context.getSharedPreferences(KEY_SHARED_PREFERENCES, Context.MODE_PRIVATE); } return sSharedPreferences; } private static LinkedListMultimap<String, String> getSubscriptions(final Context context) { if (sSubscriptions == null) { sSubscriptions = LinkedListMultimap.create(); final String subscriptions = get(context, KEY_SUBSCRIPTIONS, String.class); if (!TextUtils.isEmpty(subscriptions)) { try { final JSONObject JSON = new JSONObject(subscriptions); final JSONArray titlesJSON = JSON.getJSONArray(KEY_SUBSCRIPTION_TITLES); final JSONArray categoriesJSON = JSON.getJSONArray(KEY_SUBSCRIPTION_CATEGORIES); final JSONArray idsJSON = JSON.getJSONArray(KEY_SUBSCRIPTION_IDS); final JSONArray urlsJSON = JSON.getJSONArray(KEY_SUBSCRIPTION_URLS); for (int i = 0; i < titlesJSON.length(); i++) { final String title = titlesJSON.getString(i); sSubscriptions.put(title, categoriesJSON.getString(i)); sSubscriptions.put(title, idsJSON.getString(i)); sSubscriptions.put(title, urlsJSON.getString(i)); } } catch (final JSONException e) { LogUtils.logError(e); } } } return sSubscriptions; } public static String getSubscriptionTitleAt(final Context context, final int position) { final List<String> titles = new ArrayList<>(getSubscriptions(context).asMap().keySet()); if (titles.size() > position) { return titles.get(position); } return null; } public static String getSubscriptionIdAt(final Context context, final int position) { final String title = getSubscriptionTitleAt(context, position); if (!TextUtils.isEmpty(title)) { return getSubscriptions(context).get(title).get(1); } return null; } public static String getSubscriptionUrlAt(final Context context, final int position) { final String title = getSubscriptionTitleAt(context, position); if (!TextUtils.isEmpty(title)) { return getSubscriptions(context).get(title).get(2); } return null; } public static List<String> getSubscriptionTitlesFor(final Context context, final List<Integer> positions) { final List<String> titles = new ArrayList<>(getSubscriptions(context).asMap().keySet()); final List<String> result = new ArrayList<>(positions.size()); for (final int position : positions) { result.add(titles.get(position)); } return result; } public static List<List<Object>> getSubscriptionsFor(final Context context, final String newCategory) { if (sSubscriptionList == null) { final LinkedListMultimap<String, String> subscriptions = getSubscriptions(context); final boolean queryEmpty = TextUtils.isEmpty(newCategory); sSubscriptionList = new ArrayList<>(subscriptions.size()); int i = 0; for (final String title : subscriptions.asMap().keySet()) { final String category = subscriptions.get(title).get(0); if (queryEmpty || newCategory.equals(category)) { if (queryEmpty) { sSubscriptionList.add(Arrays.<Object>asList(title, category)); } else { sSubscriptionList.add(Arrays.<Object>asList(title, category, i)); } } i++; } } return sSubscriptionList; } static List<Object> getSubscriptionsAsOutlines(final Context context, final boolean retainCategories) { final LinkedListMultimap<String, String> subscriptions = getSubscriptions(context); final List<Object> outlines = new ArrayList<>(subscriptions.size()); final LinkedListMultimap<String, Outline> outlineGroups = LinkedListMultimap.create(); for (final String title : subscriptions.asMap().keySet()) { final String category = subscriptions.get(title).get(0); final String xmlUrl = subscriptions.get(title).get(2); final Outline outline = new Outline.Builder().setText(title).setTitle(title).setXmlUrl(xmlUrl).build(); if (retainCategories) { outlineGroups.put(category, outline); } else { outlines.add(outline); } } if (retainCategories) { for (final String category : outlineGroups.asMap().keySet()) { outlines.add(new OutlineGroup.Builder().setText(category).setTitle(category) .addSubOutlines(outlineGroups.get(category)).build()); } } return outlines; } public static String[] getSubscriptionCategories(final Context context, final boolean edit) { final LinkedListMultimap<String, String> subscriptions = getSubscriptions(context); final Set<String> categories = new TreeSet<>(); if (!edit) { categories.add(context.getString(R.string.all_categories)); } else { categories.add(context.getString(R.string.clear_category)); } for (final String title : subscriptions.asMap().keySet()) { categories.add(subscriptions.get(title).get(0)); } return categories.toArray(new String[categories.size()]); } private static int getSubscriptionPositionAfterEdit(final Context context, final String newTitle) { int i = 0; for (final String title : getSubscriptions(context).asMap().keySet()) { if (title.equals(newTitle)) { break; } i++; } return i; } public static int getSubscriptionsCnt(final Context context) { return getSubscriptions(context).asMap().size(); } public static int addSubscription(final Context context, final String title, final String category, final String url) { final LinkedListMultimap<String, String> subscriptions = getSubscriptions(context); final String currentTitle = getCurrentFeedTitle(context); subscriptions.putAll(title, Arrays.asList(category, "", url)); saveSubscriptions(context, subscriptions); return updateCurrentFeedPosition(context, currentTitle); } public static void addSubscriptions(final Context context, final List outlines) { final LinkedListMultimap<String, String> subscriptions = getSubscriptions(context); for (final Object outline : outlines) { if (outline instanceof Outline) { final String text = ((Outline) outline).getText(); final String xmlUrl = ((Outline) outline).getXmlUrl(); final String category = context.getString(R.string.uncategorized); if (!TextUtils.isEmpty(xmlUrl) && !TextUtils.isEmpty(text) && !subscriptions.containsKey(text)) { subscriptions.putAll(text.trim(), Arrays.asList(category, "", xmlUrl)); } } else { for (final Outline subOutline : ((OutlineGroup) outline).getOutlines()) { final String text = subOutline.getText(); final String xmlUrl = subOutline.getXmlUrl(); final String category = ((OutlineGroup) outline).getText(); if (!TextUtils.isEmpty(xmlUrl) && !TextUtils.isEmpty(text) && !subscriptions.containsKey(text)) { subscriptions.putAll(text.trim(), Arrays.asList(category, "", xmlUrl)); } } } } final String currentTitle = getCurrentFeedTitle(context); saveSubscriptions(context, subscriptions); updateCurrentFeedPosition(context, currentTitle); } private static void saveSubscriptions(final Context context, final LinkedListMultimap<String, String> subscriptions) { if (subscriptions != null) { final JSONObject JSON = new JSONObject(); final JSONArray titlesJSON = new JSONArray(); final JSONArray categoriesJSON = new JSONArray(); final JSONArray idsJSON = new JSONArray(); final JSONArray urlsJSON = new JSONArray(); final List<String> titles = new ArrayList<>(subscriptions.asMap().keySet()); Collections.sort(titles); for (final String title : titles) { final Iterator<String> iter = subscriptions.get(title).iterator(); titlesJSON.put(title); categoriesJSON.put(iter.next()); idsJSON.put(iter.next()); urlsJSON.put(iter.next()); } try { JSON.put(KEY_SUBSCRIPTION_TITLES, titlesJSON); JSON.put(KEY_SUBSCRIPTION_CATEGORIES, categoriesJSON); JSON.put(KEY_SUBSCRIPTION_IDS, idsJSON); JSON.put(KEY_SUBSCRIPTION_URLS, urlsJSON); put(context, KEY_SUBSCRIPTIONS, JSON.toString()); } catch (final JSONException e) { LogUtils.logError(e); } } else { put(context, KEY_SUBSCRIPTIONS, null); } sSubscriptions = null; sSubscriptionList = null; } @SuppressWarnings("ConstantConditions") public static void updateSubscriptionUrl(final Context context, final String feedUrl) { final LinkedListMultimap<String, String> subscriptions = getSubscriptions(context); final int position = getCurrentFeedPosition(context); final String title = getSubscriptionTitleAt(context, position); final List<String> values = subscriptions.get(title); values.set(2, feedUrl); subscriptions.replaceValues(title, values); saveSubscriptions(context, subscriptions); } @SuppressWarnings("ConstantConditions") public static void updateSubscriptionIdAt(final Context context, final String id, final int position) { final LinkedListMultimap<String, String> subscriptions = getSubscriptions(context); final String title = getSubscriptionTitleAt(context, position); final List<String> values = subscriptions.get(title); values.set(1, id); subscriptions.replaceValues(title, values); saveSubscriptions(context, subscriptions); } @SuppressWarnings("ConstantConditions") public static void updateSubscriptionCategoryTitleAt(final Context context, final String category, final String newTitle, final int position) { final LinkedListMultimap<String, String> subscriptions = getSubscriptions(context); final String title = getSubscriptionTitleAt(context, position); final List<String> values = subscriptions.get(title); final boolean newCategory = !values.get(0).equals(category); if (newCategory || !newTitle.equals(title)) { if (newCategory) { final List<String> newValues = new ArrayList<>(subscriptions.removeAll(title)); newValues.set(0, category); subscriptions.putAll(newTitle, newValues); } else { subscriptions.putAll(newTitle, subscriptions.removeAll(title)); } saveSubscriptions(context, subscriptions); updateCurrentFeedPosition(context, newTitle); } } public static boolean unsubscribe(final Context context, final List<String> titles) { final LinkedListMultimap<String, String> subscriptions = getSubscriptions(context); if (subscriptions.asMap().size() < 2) { saveSubscriptions(context, null); putCurrentFeedPosition(context, 0); putPreviousFeedPosition(context, 0); return false; } final String currentTitle = getCurrentFeedTitle(context); for (final String title : titles) { subscriptions.removeAll(title); } if (subscriptions.isEmpty()) { saveSubscriptions(context, null); putCurrentFeedPosition(context, 0); putPreviousFeedPosition(context, 0); return false; } saveSubscriptions(context, subscriptions); if (subscriptions.containsKey(currentTitle)) { updateCurrentFeedPosition(context, currentTitle); return false; } return true; } public static void invalidateSubscriptionList() { sSubscriptionList = null; } public static boolean isSubscriptionsEmpty(final Context context) { return getSubscriptions(context).isEmpty(); } public static SearchResults getSearchResultsFor(final Context context, final String query, final int position) { final List<Integer> positions = new ArrayList<>(); final List<LinkedHashMap<Integer, Integer>> indices = new ArrayList<>(); int i = 0; for (final String title : getSubscriptions(context).asMap().keySet()) { if (StringUtils.containsIgnoreCase(title, query)) { indices.add(SearchUtils.getIndicesForQuery(title, query)); positions.add(i); } i++; } return new SearchResults(position, positions, indices); } public static int getCurrentFeedPosition(final Context context) { return get(context, KEY_CURRENT_FEED_POSITION, Integer.class); } public static void putCurrentFeedPosition(final Context context, final int position) { putPreviousFeedPosition(context, getCurrentFeedPosition(context)); put(context, KEY_CURRENT_FEED_POSITION, position); } private static void putPreviousFeedPosition(final Context context, final int position) { put(context, KEY_PREVIOUS_FEED_POSITION, position); } public static int getPreviousFeedPosition(final Context context) { return get(context, KEY_PREVIOUS_FEED_POSITION, Integer.class); } private static int updateCurrentFeedPosition(final Context context, final String title) { if (!TextUtils.isEmpty(title)) { final int position = getSubscriptionPositionAfterEdit(context, title); putCurrentFeedPosition(context, position); return position; } return 0; } public static String getCurrentFeedUrl(final Context context) { return getSubscriptionUrlAt(context, getCurrentFeedPosition(context)); } public static String getCurrentFeedTitle(final Context context) { return getSubscriptionTitleAt(context, getCurrentFeedPosition(context)); } }