diff options
Diffstat (limited to 'org.fox.ttrss/src/main/java/org')
10 files changed, 332 insertions, 44 deletions
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/Application.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/Application.java index dd134e8c..94857855 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/Application.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/Application.java @@ -10,6 +10,9 @@ import org.fox.ttrss.types.ArticleList; import androidx.annotation.NonNull; import androidx.annotation.Nullable; + +import java.util.LinkedHashMap; + import icepick.Icepick; public class Application extends android.app.Application { @@ -21,6 +24,8 @@ public class Application extends android.app.Application { public int m_selectedArticleId; public String m_sessionId; public int m_apiLevel; + public LinkedHashMap<String, String> m_customSortModes = new LinkedHashMap<String, String>(); + public static Application getInstance(){ return m_singleton; } @@ -50,6 +55,7 @@ public class Application extends android.app.Application { out.putString("gs:sessionId", m_sessionId); out.putInt("gs:apiLevel", m_apiLevel); out.putInt("gs:selectedArticleId", m_selectedArticleId); + out.putSerializable("gs:customSortTypes", m_customSortModes); } public void load(Bundle in) { @@ -57,6 +63,12 @@ public class Application extends android.app.Application { m_sessionId = in.getString("gs:sessionId"); m_apiLevel = in.getInt("gs:apiLevel"); m_selectedArticleId = in.getInt("gs:selectedArticleId"); + + try { + m_customSortModes = (LinkedHashMap<String, String>) in.getSerializable("gs:customSortTypes"); + } catch (Exception e) { + e.printStackTrace(); + } } } diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticleFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticleFragment.java index ed961e38..d75a4e5a 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticleFragment.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticleFragment.java @@ -2,7 +2,11 @@ package org.fox.ttrss; import android.annotation.SuppressLint; import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; import android.content.SharedPreferences; +import android.content.res.Resources; import android.graphics.Color; import android.net.Uri; import android.os.Build; @@ -23,6 +27,7 @@ import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebView.HitTestResult; import android.webkit.WebViewClient; +import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -210,6 +215,70 @@ public class ArticleFragment extends StateSavedFragment { } + final ImageView scoreView = view.findViewById(R.id.score); + + if (scoreView != null) { + setScoreImage(scoreView, m_article.score); + + Resources.Theme theme = m_activity.getTheme(); + TypedValue tv = new TypedValue(); + theme.resolveAttribute(R.attr.headlineTitleHighScoreUnreadTextColor, tv, true); + int titleHighScoreUnreadColor = tv.data; + + if (m_article.score > Article.SCORE_HIGH) + scoreView.setColorFilter(titleHighScoreUnreadColor); + else + scoreView.setColorFilter(null); + + if (m_activity.getApiLevel() >= 16) { + scoreView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + final EditText edit = new EditText(getActivity()); + edit.setText(String.valueOf(m_article.score)); + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) + .setTitle(R.string.score_for_this_article) + .setPositiveButton(R.string.set_score, + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + + try { + int newScore = Integer.parseInt(edit.getText().toString()); + + m_article.score = newScore; + + m_activity.saveArticleScore(m_article); + + setScoreImage(scoreView, newScore); + } catch (NumberFormatException e) { + m_activity.toast(R.string.score_invalid); + e.printStackTrace(); + } + } + }) + .setNegativeButton(getString(R.string.cancel), + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + + // + + } + }).setView(edit); + + Dialog dialog = builder.create(); + dialog.show(); + } + }); + } + } + ImageView attachments = view.findViewById(R.id.attachments); if (attachments != null) { @@ -360,6 +429,20 @@ public class ArticleFragment extends StateSavedFragment { return view; } + private void setScoreImage(ImageView scoreView, int score) { + TypedValue tv = new TypedValue(); + int scoreAttr = R.attr.ic_action_trending_flat; + + if (m_article.score > 0) + scoreAttr = R.attr.ic_action_trending_up; + else if (m_article.score < 0) + scoreAttr = R.attr.ic_action_trending_down; + + m_activity.getTheme().resolveAttribute(scoreAttr, tv, true); + + scoreView.setImageResource(tv.resourceId); + } + protected void renderContent(Bundle savedInstanceState) { if (!isAdded() || m_web == null) return; diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java index b92324da..672da44e 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java @@ -43,6 +43,7 @@ import android.view.ViewTreeObserver; import android.view.WindowManager; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.CheckBox; +import android.widget.EditText; import android.widget.ImageView; import android.widget.ListView; import android.widget.PopupMenu; @@ -704,6 +705,7 @@ public class HeadlinesFragment extends StateSavedFragment { public TextView titleView; public TextView feedTitleView; public ImageView markedView; + public ImageView scoreView; public ImageView publishedView; public TextView excerptView; public ImageView flavorImageView; @@ -747,6 +749,7 @@ public class HeadlinesFragment extends StateSavedFragment { feedTitleView = v.findViewById(R.id.feed_title); markedView = v.findViewById(R.id.marked); + scoreView = v.findViewById(R.id.score); publishedView = v.findViewById(R.id.published); excerptView = v.findViewById(R.id.excerpt); flavorImageView = v.findViewById(R.id.flavor_image); @@ -1034,6 +1037,72 @@ public class HeadlinesFragment extends StateSavedFragment { }); } + if (holder.scoreView != null) { + TypedValue tv = new TypedValue(); + int scoreAttr = R.attr.ic_action_trending_flat; + + if (article.score > 0) + scoreAttr = R.attr.ic_action_trending_up; + else if (article.score < 0) + scoreAttr = R.attr.ic_action_trending_down; + + m_activity.getTheme().resolveAttribute(scoreAttr, tv, true); + + holder.scoreView.setImageResource(tv.resourceId); + + if (article.score > Article.SCORE_HIGH) + holder.scoreView.setColorFilter(titleHighScoreUnreadColor); + else + holder.scoreView.setColorFilter(null); + + if (m_activity.getApiLevel() >= 16) { + holder.scoreView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + final EditText edit = new EditText(getActivity()); + edit.setText(String.valueOf(article.score)); + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) + .setTitle(R.string.score_for_this_article) + .setPositiveButton(R.string.set_score, + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + + try { + int newScore = Integer.parseInt(edit.getText().toString()); + + article.score = newScore; + + m_activity.saveArticleScore(article); + + m_adapter.notifyItemChanged(m_list.getChildPosition(holder.view)); + } catch (NumberFormatException e) { + m_activity.toast(R.string.score_invalid); + e.printStackTrace(); + } + } + }) + .setNegativeButton(getString(R.string.cancel), + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + + // + + } + }).setView(edit); + + Dialog dialog = builder.create(); + dialog.show(); + } + }); + } + } if (holder.publishedView != null) { TypedValue tv = new TypedValue(); @@ -1662,9 +1731,9 @@ public class HeadlinesFragment extends StateSavedFragment { // store original color origTitleColors[viewType] = Integer.valueOf(tv.getCurrentTextColor()); - if (score < -500) { + if (score < Article.SCORE_LOW) { tv.setPaintFlags(tv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); - } else if (score > 500) { + } else if (score > Article.SCORE_HIGH) { tv.setTextColor(titleHighScoreUnreadColor); tv.setPaintFlags(tv.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG); } else { diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/MasterActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/MasterActivity.java index 121b836c..f7681e42 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/MasterActivity.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/MasterActivity.java @@ -26,6 +26,7 @@ import org.fox.ttrss.types.FeedCategory; import java.util.Date; import java.util.HashMap; +import java.util.LinkedHashMap; import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.widget.Toolbar; @@ -367,45 +368,43 @@ public class MasterActivity extends OnlineActivity implements HeadlinesEventList case R.id.headlines_toggle_sort_order: Dialog dialog = new Dialog(this); - String sortMode = getSortMode(); + LinkedHashMap<String, String> sortModes = getSortModes(); - int selectedIndex = 0; + CharSequence[] sortTitles = sortModes.values().toArray(new CharSequence[0]); + final CharSequence[] sortNames = sortModes.keySet().toArray(new CharSequence[0]); - if (sortMode.equals("feed_dates")) { - selectedIndex = 1; - } else if (sortMode.equals("date_reverse")) { - selectedIndex = 2; - } else if (sortMode.equals("title")) { - selectedIndex = 3; - } + String currentMode = getSortMode(); + + int i = 0; + int selectedIndex = 0; + + for (CharSequence tmp : sortNames) { + if (tmp.equals(currentMode)) { + selectedIndex = i; + break; + } + + ++i; + } AlertDialog.Builder builder = new AlertDialog.Builder(this) .setTitle(getString(R.string.headlines_sort_articles_title)) .setSingleChoiceItems( - new String[] { - getString(R.string.headlines_sort_default), - getString(R.string.headlines_sort_newest_first), - getString(R.string.headlines_sort_oldest_first), - getString(R.string.headlines_sort_title) - }, + sortTitles, selectedIndex, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - switch (which) { - case 0: - setSortMode("default"); - break; - case 1: - setSortMode("feed_dates"); - break; - case 2: - setSortMode("date_reverse"); - break; - case 3: - setSortMode("title"); - break; - } + + try { +// Log.d(TAG, "sort selected index:" + which + ": " + sortNames[which]); + + setSortMode((String)sortNames[which]); + + } catch (IndexOutOfBoundsException e) { + e.printStackTrace(); + } + dialog.cancel(); refresh(); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/OnlineActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/OnlineActivity.java index e8559d3e..f513173a 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/OnlineActivity.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/OnlineActivity.java @@ -1,5 +1,6 @@ package org.fox.ttrss; +import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.AlertDialog; import android.app.Dialog; @@ -31,6 +32,8 @@ import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; +import com.github.javiersantos.appupdater.AppUpdater; +import com.github.javiersantos.appupdater.enums.UpdateFrom; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -48,7 +51,9 @@ import org.fox.ttrss.util.ImageCacheService; import java.lang.reflect.Type; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import androidx.appcompat.view.ActionMode; import androidx.appcompat.widget.Toolbar; @@ -256,11 +261,20 @@ public class OnlineActivity extends CommonActivity { switchOfflineSuccess(); } else { checkTrial(false); + checkUpdates(); m_headlinesActionModeCallback = new HeadlinesActionModeCallback(); } } + protected void checkUpdates() { + if (BuildConfig.DEBUG || BuildConfig.ENABLE_UPDATER) { + new AppUpdater(this) + .setUpdateFrom(UpdateFrom.JSON) + .setUpdateJSON(String.format("https://srv.tt-rss.org/fdroid/updates/%1$s.json", this.getPackageName())) + .start(); + } + } protected void switchOffline() { AlertDialog.Builder builder = new AlertDialog.Builder(this) @@ -1164,24 +1178,28 @@ public class OnlineActivity extends CommonActivity { initMenu(); - List<PackageInfo> pkgs = getPackageManager() - .getInstalledPackages(0); - - for (PackageInfo p : pkgs) { - if ("org.fox.ttrss.key".equals(p.packageName)) { - Log.d(TAG, "license apk found"); - menu.findItem(R.id.donate).setVisible(false); - break; + if (BuildConfig.ENABLE_TRIAL && !BuildConfig.DEBUG) { + List<PackageInfo> pkgs = getPackageManager() + .getInstalledPackages(0); + + for (PackageInfo p : pkgs) { + if ("org.fox.ttrss.key".equals(p.packageName)) { + Log.d(TAG, "license apk found"); + menu.findItem(R.id.donate).setVisible(false); + break; + } } + } else { + menu.findItem(R.id.donate).setVisible(false); } - + return true; } public int getApiLevel() { return Application.getInstance().m_apiLevel; } - + protected void setApiLevel(int apiLevel) { Application.getInstance().m_apiLevel = apiLevel; } @@ -1208,6 +1226,27 @@ public class OnlineActivity extends CommonActivity { req.execute(map); } + public void saveArticleScore(final Article article) { + ApiRequest req = new ApiRequest(getApplicationContext()) { + protected void onPostExecute(JsonElement result) { + //toast(article.marked ? R.string.notify_article_marked : R.string.notify_article_unmarked); + invalidateOptionsMenu(); + } + }; + + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "updateArticle"); + put("article_ids", String.valueOf(article.id)); + put("data", String.valueOf(article.score)); + put("field", "4"); + } + }; + + req.execute(map); + } + public void saveArticleMarked(final Article article) { ApiRequest req = new ApiRequest(getApplicationContext()) { protected void onPostExecute(JsonElement result) { @@ -1291,8 +1330,45 @@ public class OnlineActivity extends CommonActivity { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { + ArticlePager ap = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_LEFT: + if (ap != null && ap.isAdded()) { + ap.selectArticle(false); + return true; + } + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (ap != null && ap.isAdded()) { + ap.selectArticle(true); + return true; + } + break; + case KeyEvent.KEYCODE_ESCAPE: + moveTaskToBack(true); + return true; + case KeyEvent.KEYCODE_O: + if (ap != null && ap.getSelectedArticle() != null) { + openUri(Uri.parse(ap.getSelectedArticle().link)); + return true; + } + break; + case KeyEvent.KEYCODE_R: + refresh(); + return true; + case KeyEvent.KEYCODE_U: + if (ap != null && ap.getSelectedArticle() != null) { + Article a = ap.getSelectedArticle(); + a.unread = !a.unread; + saveArticleUnread(a); + if (hf != null) hf.notifyUpdated(); + } + return true; + } + if (m_prefs.getBoolean("use_volume_keys", false)) { - ArticlePager ap = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); if (ap != null && ap.isAdded()) { switch (keyCode) { @@ -1506,6 +1582,7 @@ public class OnlineActivity extends CommonActivity { } @SuppressWarnings("unchecked") + @SuppressLint("StaticFieldLeak") protected void onPostExecute(JsonElement result) { if (result != null) { try { @@ -1521,6 +1598,20 @@ public class OnlineActivity extends CommonActivity { if (apiLevel != null) { setApiLevel(apiLevel.getAsInt()); Log.d(TAG, "Received API level: " + getApiLevel()); + + // get custom sort from configuration object + if (getApiLevel() >= 17) { + + // daemon_is_running, icons_dir, etc... + JsonObject config = content.get("config").getAsJsonObject(); + + Type hashType = new TypeToken<Map<String, String>>(){}.getType(); + Map<String, String> customSortTypes = new Gson().fromJson(config.get("custom_sort_types"), hashType); + + setCustomSortModes(customSortTypes); + + Log.d(TAG, "test"); + } if (m_listener != null) { m_listener.OnLoginSuccess(); @@ -1602,7 +1693,20 @@ public class OnlineActivity extends CommonActivity { } - public String getSortMode() { + public LinkedHashMap<String, String> getSortModes() { + LinkedHashMap<String, String> tmp = new LinkedHashMap<String, String>(); + + tmp.put("default", getString(R.string.headlines_sort_default)); + tmp.put("feed_dates", getString(R.string.headlines_sort_newest_first)); + tmp.put("date_reverse", getString(R.string.headlines_sort_oldest_first)); + tmp.put("title", getString(R.string.headlines_sort_title)); + + tmp.putAll(Application.getInstance().m_customSortModes); + + return tmp; + } + + public String getSortMode() { return m_prefs.getString("headlines_sort_mode", "default"); } @@ -1612,6 +1716,11 @@ public class OnlineActivity extends CommonActivity { editor.apply(); } + private synchronized void setCustomSortModes(Map<String, String> modes) { + Application.getInstance().m_customSortModes.clear(); + Application.getInstance().m_customSortModes.putAll(modes); + } + public void setViewMode(String viewMode) { SharedPreferences.Editor editor = m_prefs.edit(); editor.putString("view_mode", viewMode); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineArticleFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineArticleFragment.java index 441ec62b..a3b152a7 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineArticleFragment.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineArticleFragment.java @@ -235,6 +235,11 @@ public class OfflineArticleFragment extends Fragment { } + ImageView score = view.findViewById(R.id.score); + + if (score != null) { + score.setVisibility(View.GONE); + } ImageView attachments = view.findViewById(R.id.attachments); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineHeadlinesFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineHeadlinesFragment.java index 3d9e1229..470b0aac 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineHeadlinesFragment.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineHeadlinesFragment.java @@ -505,6 +505,7 @@ public class OfflineHeadlinesFragment extends Fragment implements OnItemClickLis public View flavorImageOverflow; public View headlineHeader; public ImageView attachmentsView; + public ImageView scoreView; public ArticleViewHolder(View v) { @@ -549,6 +550,7 @@ public class OfflineHeadlinesFragment extends Fragment implements OnItemClickLis headlineHeader = v.findViewById(R.id.headline_header); flavorImageOverflow = v.findViewById(R.id.gallery_overflow); attachmentsView = v.findViewById(R.id.attachments); + scoreView = v.findViewById(R.id.score); } } @@ -794,6 +796,10 @@ public class OfflineHeadlinesFragment extends Fragment implements OnItemClickLis holder.attachmentsView.setVisibility(View.GONE); } + if (holder.scoreView != null) { + holder.scoreView.setVisibility(View.GONE); + } + if (holder.markedView != null) { TypedValue tv = new TypedValue(); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineMasterActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineMasterActivity.java index cdaa794e..0a3b6378 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineMasterActivity.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineMasterActivity.java @@ -25,6 +25,8 @@ import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; +import java.util.HashMap; + public class OfflineMasterActivity extends OfflineActivity implements OfflineHeadlinesEventListener { private final String TAG = this.getClass().getSimpleName(); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/types/Article.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/types/Article.java index a11cd0ac..2daaba49 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/types/Article.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/types/Article.java @@ -21,6 +21,9 @@ public class Article implements Parcelable { public static final int FLAVOR_KIND_VIDEO = 2; public static final int FLAVOR_KIND_YOUTUBE = 3; + public static final int SCORE_LOW = -500; + public static final int SCORE_HIGH = 500; + public int id; public boolean unread; public boolean marked; diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/util/ImageCacheService.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/ImageCacheService.java index f07e23c2..24a7a732 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/util/ImageCacheService.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/ImageCacheService.java @@ -132,7 +132,7 @@ public class ImageCacheService extends IntentService { digest.update(s.getBytes()); byte messageDigest[] = digest.digest(); - StringBuffer hexString = new StringBuffer(); + StringBuilder hexString = new StringBuilder(); for (int i=0; i<messageDigest.length; i++) hexString.append(Integer.toHexString(0xFF & messageDigest[i])); |