diff options
55 files changed, 1030 insertions, 2792 deletions
diff --git a/org.fox.ttrss/build.gradle b/org.fox.ttrss/build.gradle index c8d9b3d5..7ffaf523 100755 --- a/org.fox.ttrss/build.gradle +++ b/org.fox.ttrss/build.gradle @@ -16,6 +16,9 @@ android { versionCode getGitVersionCode() versionName getVersion() vectorDrawables.useSupportLibrary = true + manifestPlaceholders = [ + appIcon: "@mipmap/ic_launcher" + ] } signingConfigs { @@ -36,8 +39,20 @@ android { } buildTypes { + debug { + minifyEnabled false + versionNameSuffix "-debug" + applicationIdSuffix ".debug" + debuggable true + resValue "string", "app_name", "Tiny Tiny RSS (debug)" + manifestPlaceholders = [ + appIcon: "@mipmap/ic_launcher_variant" + ] + } + release { minifyEnabled false + versionNameSuffix "-release-unsigned" proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' } @@ -46,7 +61,18 @@ android { versionNameSuffix "-signed" proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' signingConfig signingConfigs.signed - matchingFallbacks = ['release'] + } + + branch { + minifyEnabled false + versionNameSuffix "-signed-branch" + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + signingConfig signingConfigs.signed + applicationIdSuffix ".branch" + resValue "string", "app_name", "Tiny Tiny RSS (branch)" + manifestPlaceholders = [ + appIcon: "@mipmap/ic_launcher_variant" + ] } } namespace 'org.fox.ttrss' diff --git a/org.fox.ttrss/src/main/AndroidManifest.xml b/org.fox.ttrss/src/main/AndroidManifest.xml index feb8a2e1..3388d515 100755 --- a/org.fox.ttrss/src/main/AndroidManifest.xml +++ b/org.fox.ttrss/src/main/AndroidManifest.xml @@ -17,7 +17,7 @@ android:name=".Application" android:allowBackup="true" android:hardwareAccelerated="true" - android:icon="@mipmap/ic_launcher" + android:icon="${appIcon}" android:label="@string/app_name" android:networkSecurityConfig="@xml/network_security_config" > @@ -217,7 +217,7 @@ <provider android:name="androidx.core.content.FileProvider" - android:authorities="org.fox.ttrss.SharedFileProvider" + android:authorities="${applicationId}.SharedFileProvider" android:exported="false" android:grantUriPermissions="true"> <meta-data diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiCommon.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiCommon.java index 75963c96..adc0881d 100644 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiCommon.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiCommon.java @@ -41,13 +41,16 @@ public class ApiCommon { void setLastErrorMessage(String message); } - public enum ApiError { NO_ERROR, HTTP_UNAUTHORIZED, HTTP_FORBIDDEN, HTTP_NOT_FOUND, + public enum ApiError { + SUCCESS, UNKNOWN_ERROR, HTTP_UNAUTHORIZED, HTTP_FORBIDDEN, HTTP_NOT_FOUND, HTTP_SERVER_ERROR, HTTP_OTHER_ERROR, SSL_REJECTED, SSL_HOSTNAME_REJECTED, PARSE_ERROR, IO_ERROR, OTHER_ERROR, API_DISABLED, API_UNKNOWN, LOGIN_FAILED, INVALID_URL, API_INCORRECT_USAGE, NETWORK_UNAVAILABLE, API_UNKNOWN_METHOD } public static int getErrorMessage(ApiError error) { switch (error) { - case NO_ERROR: + case SUCCESS: + return R.string.error_success; + case UNKNOWN_ERROR: return R.string.error_unknown; case HTTP_UNAUTHORIZED: return R.string.error_http_unauthorized; @@ -154,6 +157,7 @@ public class ApiCommon { switch (statusCode) { case API_STATUS_OK: + caller.setLastError(ApiError.SUCCESS); return result.getAsJsonObject().get("content"); case API_STATUS_ERR: JsonObject contentObj = resultObj.get("content").getAsJsonObject(); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiLoader.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiLoader.java index 259d7a28..8d83e7bd 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiLoader.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiLoader.java @@ -27,7 +27,7 @@ public class ApiLoader extends AsyncTaskLoader<JsonElement> implements ApiCommon super(context); m_context = context; - m_lastError = ApiError.NO_ERROR; + m_lastError = ApiError.UNKNOWN_ERROR; m_params = params; } diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiRequest.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiRequest.java index 409047f0..ba8dad20 100644 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiRequest.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiRequest.java @@ -21,7 +21,7 @@ public class ApiRequest extends AsyncTask<HashMap<String,String>, Integer, JsonE public ApiRequest(Context context) { m_context = context; - m_lastError = ApiError.NO_ERROR; + m_lastError = ApiError.UNKNOWN_ERROR; } @SuppressLint("NewApi") 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 07f1a3b5..75542e3c 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 @@ -1,5 +1,8 @@ package org.fox.ttrss; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.os.Bundle; import org.fox.ttrss.types.ArticleList; @@ -8,22 +11,28 @@ import java.util.HashMap; import java.util.LinkedHashMap; public class Application extends android.app.Application { - private static Application m_singleton; + public static final int LOADER_HEADLINES = 0; + public static final int LOADER_FEEDS = 1; + public static final int LOADER_CATS = 2; - // this is the only instance of a (large) object which contains all currently loaded articles and is - // used by all fragments and activities concurrently - private final ArticleList m_articles = new ArticleList(); + private static Application m_singleton; private String m_sessionId; private int m_apiLevel; public LinkedHashMap<String, String> m_customSortModes = new LinkedHashMap<>(); + ConnectivityManager m_cmgr; + ArticleModel m_articleModel; public static Application getInstance(){ return m_singleton; } public static ArticleList getArticles() { - return getInstance().m_articles; + return getInstance().m_articleModel.getArticles().getValue(); + } + + public static ArticleModel getArticlesModel() { + return getInstance().m_articleModel; } @Override @@ -31,6 +40,8 @@ public class Application extends android.app.Application { super.onCreate(); m_singleton = this; + m_cmgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + m_articleModel = new ArticleModel(this); } public String getSessionId() { @@ -68,6 +79,14 @@ public class Application extends android.app.Application { m_customSortModes.clear(); m_customSortModes.putAll(tmp); } - + } + + public boolean isWifiConnected() { + NetworkInfo wifi = m_cmgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + + if (wifi != null) + return wifi.isConnected(); + + return false; } } 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 3ee42976..8794e653 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 @@ -157,7 +157,7 @@ public class ArticleFragment extends androidx.fragment.app.Fragment { View noteContainer = view.findViewById(R.id.note_container); if (note != null && noteContainer != null) { - if (m_article.note != null && !m_article.note.isEmpty()) { + if (!m_article.note.isEmpty()) { note.setTextSize(TypedValue.COMPLEX_UNIT_SP, m_articleSmallFontSize); note.setText(m_article.note); noteContainer.setVisibility(View.VISIBLE); @@ -259,7 +259,7 @@ public class ArticleFragment extends androidx.fragment.app.Fragment { String linkHexColor = String.format("#%06X", (0xFFFFFF & tvColorPrimary.data)); cssOverride += " a:link {color: "+linkHexColor+";} a:visited { color: "+linkHexColor+";}"; - String articleContent = m_article.content != null ? m_article.content : ""; + String articleContent = m_article.content; ws.setJavaScriptEnabled(false); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticleModel.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticleModel.java new file mode 100644 index 00000000..80467f63 --- /dev/null +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticleModel.java @@ -0,0 +1,315 @@ +package org.fox.ttrss; + +import android.app.Application; +import android.content.SharedPreferences; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.preference.PreferenceManager; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; + +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.ArticleList; +import org.fox.ttrss.types.Feed; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class ArticleModel extends AndroidViewModel implements ApiCommon.ApiCaller { + private final String TAG = this.getClass().getSimpleName(); + private final MutableLiveData<ArticleList> m_articles = new MutableLiveData<>(new ArticleList()); + private SharedPreferences m_prefs; + private final int m_responseCode = 0; + protected String m_responseMessage; + private int m_apiStatusCode = 0; + + private String m_lastErrorMessage; + private ApiCommon.ApiError m_lastError; + private Feed m_feed; + private int m_firstId; + private String m_searchQuery = ""; + private boolean m_firstIdChanged; + private int m_offset; + private int m_amountLoaded; + private int m_resizeWidth; + private boolean m_append; + private boolean m_lazyLoadEnabled = true; + private boolean m_loadingInProgress; + private ExecutorService m_executor; + private Handler m_mainHandler = new Handler(Looper.getMainLooper()); + private MutableLiveData<Long> m_lastUpdate = new MutableLiveData<>(Long.valueOf(0)); + + public ArticleModel(@NonNull Application application) { + super(application); + + m_prefs = PreferenceManager.getDefaultSharedPreferences(application); + + // do we need concurrency or not? + m_executor = Executors.newSingleThreadExecutor(); + } + + public LiveData<Long> getUpdatesData() { + return m_lastUpdate; + } + + public LiveData<ArticleList> getArticles() { + return m_articles; + } + + + public void update(int position, Article article) { + m_articles.getValue().set(position, article); + m_articles.postValue(m_articles.getValue()); + } + + public void update(ArticleList articles) { + m_articles.postValue(articles); + } + + public void startLoading(boolean append, @NonNull Feed feed, int resizeWidth) { + Log.d(TAG, "startLoading append=" + append); + + m_resizeWidth = resizeWidth; + + if (!append) { + m_append = false; + m_lazyLoadEnabled = true; + m_feed = feed; + + loadInBackground(); + } else if (feed != m_feed || m_lazyLoadEnabled && !m_loadingInProgress) { + m_append = true; + m_feed = feed; + + loadInBackground(); + } else { + m_articles.postValue(m_articles.getValue()); + } + } + + private void loadInBackground() { + Log.d(TAG, this + " loadInBackground append=" + m_append + " offset=" + m_offset); + + ArticleList articlesWork = new ArticleList(m_articles.getValue()); + + m_loadingInProgress = true; + + final int skip = getSkip(m_append, articlesWork); + final boolean allowForceUpdate = org.fox.ttrss.Application.getInstance().getApiLevel() >= 9 && + !m_feed.is_cat && m_feed.id > 0 && !m_append && skip == 0; + + HashMap<String,String> params = new HashMap<>(); + + params.put("op", "getHeadlines"); + params.put("sid", org.fox.ttrss.Application.getInstance().getSessionId()); + params.put("feed_id", String.valueOf(m_feed.id)); + params.put("show_excerpt", "true"); + params.put("excerpt_length", String.valueOf(CommonActivity.EXCERPT_MAX_LENGTH)); + params.put("show_content", "true"); + params.put("include_attachments", "true"); + params.put("view_mode", m_prefs.getString("view_mode", "adaptive")); + params.put("limit", m_prefs.getString("headlines_request_size", "15")); + params.put("skip", String.valueOf(skip)); + params.put("include_nested", "true"); + params.put("has_sandbox", "true"); + params.put("order_by", m_prefs.getString("headlines_sort_mode", "default")); + + if (m_prefs.getBoolean("enable_image_downsampling", false)) { + if (m_prefs.getBoolean("always_downsample_images", false) || !org.fox.ttrss.Application.getInstance().isWifiConnected()) { + params.put("resize_width", String.valueOf(m_resizeWidth)); + } + } + + if (m_feed.is_cat) + params.put("is_cat", "true"); + + if (allowForceUpdate) { + params.put("force_update", "true"); + } + + if (m_searchQuery != null && !m_searchQuery.isEmpty()) { + params.put("search", m_searchQuery); + params.put("search_mode", ""); + params.put("match_on", "both"); + } + + if (m_firstId > 0) + params.put("check_first_id", String.valueOf(m_firstId)); + + if (org.fox.ttrss.Application.getInstance().getApiLevel() >= 12) { + params.put("include_header", "true"); + } + + Log.d(TAG, "firstId=" + m_firstId + " append=" + m_append + " skip=" + skip + " localSize=" + articlesWork.size()); + + m_executor.execute(() -> { + JsonElement result = ApiCommon.performRequest(getApplication(), params, this); + + Log.d(TAG, "got result=" + result); + + if (result != null) { + try { + JsonArray content = result.getAsJsonArray(); + if (content != null) { + final List<Article> articlesJson; + final JsonObject header; + + if (org.fox.ttrss.Application.getInstance().getApiLevel() >= 12) { + header = content.get(0).getAsJsonObject(); + + m_firstIdChanged = header.get("first_id_changed") != null; + + try { + m_firstId = header.get("first_id").getAsInt(); + } catch (NumberFormatException e) { + m_firstId = 0; + } + + Log.d(TAG, this + " firstID=" + m_firstId + " firstIdChanged=" + m_firstIdChanged); + + Type listType = new TypeToken<List<Article>>() {}.getType(); + articlesJson = new Gson().fromJson(content.get(1), listType); + } else { + Type listType = new TypeToken<List<Article>>() {}.getType(); + articlesJson = new Gson().fromJson(content, listType); + } + + if (!m_append) + articlesWork.clear(); + + m_amountLoaded = articlesJson.size(); + + for (Article article : articlesJson) + if (!articlesWork.containsId(article.id)) { + article.collectMediaInfo(); + article.cleanupExcerpt(); + article.fixNullFields(); + articlesWork.add(article); + } + + if (m_firstIdChanged) { + Log.d(TAG, "first id changed, disabling lazy load"); + m_lazyLoadEnabled = false; + } + + if (m_amountLoaded < Integer.parseInt(m_prefs.getString("headlines_request_size", "15"))) { + Log.d(TAG, this + " amount loaded "+m_amountLoaded+" < request size, disabling lazy load"); + m_lazyLoadEnabled = false; + } + + m_offset += m_amountLoaded; + m_loadingInProgress = false; + + Log.d(TAG, this + " loaded headlines=" + m_amountLoaded + " resultingLocalSize=" + articlesWork.size()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + m_mainHandler.post(() -> { + m_articles.setValue(articlesWork); + m_lastUpdate.setValue(System.currentTimeMillis()); + }); + }); + + m_loadingInProgress = false; + + } + + private int getSkip(boolean append, ArticleList articles) { + int skip = 0; + + if (append) { + // adaptive, all_articles, marked, published, unread + String viewMode = m_prefs.getString("view_mode", "adaptive"); + + int numUnread = Math.toIntExact(articles.getUnreadCount()); + int numAll = Math.toIntExact(articles.size()); + + if ("marked".equals(viewMode)) { + skip = numAll; + } else if ("published".equals(viewMode)) { + skip = numAll; + } else if ("unread".equals(viewMode)) { + skip = numUnread; + } else if (m_searchQuery != null && !m_searchQuery.isEmpty()) { + skip = numAll; + } else if ("adaptive".equals(viewMode)) { + skip = numUnread > 0 ? numUnread : numAll; + } else { + skip = numAll; + } + } + + return skip; + } + + @Override + public void setStatusCode(int statusCode) { + m_apiStatusCode = statusCode; + } + + @Override + public void setLastError(ApiCommon.ApiError lastError) { + m_lastError = lastError; + } + + @Override + public void setLastErrorMessage(String message) { + m_lastErrorMessage = message; + } + + public boolean getFirstIdChanged() { + return m_firstIdChanged; + } + + public boolean getAppend() { + return m_append; + } + + public void setSearchQuery(String searchQuery) { + m_searchQuery = searchQuery; + } + + public String getSearchQuery() { + return m_searchQuery; + } + + public int getOffset() { + return m_offset; + } + + public boolean lazyLoadEnabled() { + return m_lazyLoadEnabled; + } + + public int getErrorMessage() { + return ApiCommon.getErrorMessage(m_lastError); + } + + ApiCommon.ApiError getLastError() { + return m_lastError; + } + + String getLastErrorMessage() { + return m_lastErrorMessage; + } + + public boolean isLoading() { + return m_loadingInProgress; + } +} diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticlePager.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticlePager.java index da9dc8f3..cf43f4f0 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticlePager.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticlePager.java @@ -2,10 +2,7 @@ package org.fox.ttrss; import android.annotation.SuppressLint; import android.app.Activity; -import android.content.SharedPreferences; -import android.os.BadParcelableException; import android.os.Bundle; -import android.os.Handler; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -13,65 +10,44 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; -import androidx.preference.PreferenceManager; -import androidx.viewpager2.adapter.FragmentStateAdapter; import androidx.viewpager2.widget.ViewPager2; -import com.google.android.material.snackbar.Snackbar; -import com.google.gson.JsonElement; - import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.ArticleList; import org.fox.ttrss.types.Feed; -import org.fox.ttrss.util.HeadlinesRequest; - -import java.util.HashMap; +import org.fox.ttrss.util.DiffFragmentStateAdapter; +import org.fox.ttrss.util.ArticleDiffItemCallback; public class ArticlePager extends androidx.fragment.app.Fragment { - private final String TAG = "ArticlePager"; + private final String TAG = this.getClass().getSimpleName(); private PagerAdapter m_adapter; private HeadlinesEventListener m_listener; private int m_articleId; private OnlineActivity m_activity; - private String m_searchQuery = ""; private Feed m_feed; - private SharedPreferences m_prefs; - private int m_firstId = 0; - private boolean m_refreshInProgress; - private boolean m_lazyLoadDisabled; private ViewPager2 m_pager; - private static class PagerAdapter extends FragmentStateAdapter { - - public PagerAdapter(FragmentActivity fa) { - super(fa); + private static class PagerAdapter extends DiffFragmentStateAdapter<Article> { + + public PagerAdapter(@NonNull Fragment fragment) { + super(fragment, new ArticleDiffItemCallback()); + } + + private void syncToSharedArticles() { + submitList(new ArticleList(Application.getArticles())); } @Override @NonNull public Fragment createFragment(int position) { - try { - Article article = Application.getArticles().get(position); - - if (article != null) { - ArticleFragment af = new ArticleFragment(); - af.initialize(article); - - return af; - } - } catch (IndexOutOfBoundsException e) { - e.printStackTrace(); - } + Article article = getItem(position); - return null; - } + ArticleFragment af = new ArticleFragment(); + af.initialize(article); - @Override - public int getItemCount() { - return Application.getArticles().size(); + return af; } - } public void initialize(int articleId, Feed feed) { @@ -79,17 +55,12 @@ public class ArticlePager extends androidx.fragment.app.Fragment { m_feed = feed; } - public void setSearchQuery(String searchQuery) { - m_searchQuery = searchQuery; - } - @Override public void onSaveInstanceState(Bundle out) { super.onSaveInstanceState(out); out.putInt("m_articleId", m_articleId); out.putParcelable("m_feed", m_feed); - out.putInt("m_firstId", m_firstId); } @Override @@ -99,7 +70,6 @@ public class ArticlePager extends androidx.fragment.app.Fragment { if (savedInstanceState != null) { m_articleId = savedInstanceState.getInt("m_articleId"); m_feed = savedInstanceState.getParcelable("m_feed"); - m_firstId = savedInstanceState.getInt("m_firstId"); } setRetainInstance(true); @@ -109,36 +79,42 @@ public class ArticlePager extends androidx.fragment.app.Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_article_pager, container, false); - m_adapter = new PagerAdapter(getActivity()); + m_adapter = new PagerAdapter(this); + m_adapter.submitList(Application.getArticles()); + + ArticleModel model = Application.getArticlesModel(); + + // deal with further updates + model.getArticles().observe(getActivity(), articles -> { + Log.d(TAG, "observed article list size=" + articles.size()); + m_adapter.submitList(articles); + }); m_pager = view.findViewById(R.id.article_pager); - int position = Application.getArticles().getPositionById(m_articleId); - m_listener.onArticleSelected(Application.getArticles().getById(m_articleId), false); m_pager.setAdapter(m_adapter); m_pager.setOffscreenPageLimit(3); - m_pager.setCurrentItem(position, false); + int position = Application.getArticles().getPositionById(m_articleId); + + if (position != -1) + m_pager.setCurrentItem(position, false); + m_pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { Log.d(TAG, "onPageSelected: " + position); - final Article article = Application.getArticles().get(position); - - if (article != null) { - m_articleId = article.id; - - new Handler().postDelayed(() -> m_listener.onArticleSelected(article, false), 250); + // wtf + if (position != -1) { + Article article = Application.getArticles().get(position); - //Log.d(TAG, "Page #" + position + "/" + m_adapter.getCount()); + if (article != null) { + m_articleId = article.id; - if (!m_refreshInProgress && !m_lazyLoadDisabled && (m_activity.isSmallScreen() || m_activity.isPortrait()) && position >= m_adapter.getItemCount() - 5) { - Log.d(TAG, "loading more articles..."); - - new Handler().postDelayed(() -> refresh(true), 100); + m_listener.onArticleSelected(article, false); } } } @@ -146,170 +122,19 @@ public class ArticlePager extends androidx.fragment.app.Fragment { return view; } - - protected void refresh(final boolean append) { - - if (!append) { - m_lazyLoadDisabled = false; - } - - m_refreshInProgress = true; - - @SuppressLint("StaticFieldLeak") HeadlinesRequest req = new HeadlinesRequest(getActivity().getApplicationContext(), m_activity, Application.getArticles()) { - @Override - protected void onPostExecute(JsonElement result) { - if (isDetached() || !isAdded()) return; - - if (!append) { - m_pager.setCurrentItem(0, false); - Application.getArticles().clear(); - } - - super.onPostExecute(result); - - m_refreshInProgress = false; - - if (result != null) { - - if (m_firstIdChanged) { - m_lazyLoadDisabled = true; - } - - if (m_firstIdChanged && !(m_activity instanceof DetailActivity && !m_activity.isPortrait())) { - //m_activity.toast(R.string.headlines_row_top_changed); - - Snackbar.make(getView(), R.string.headlines_row_top_changed, Snackbar.LENGTH_LONG) - .setAction(R.string.reload, v -> refresh(false)).show(); - } - - if (m_amountLoaded < Integer.parseInt(m_prefs.getString("headlines_request_size", "15"))) { - m_lazyLoadDisabled = true; - } - - ArticlePager.this.m_firstId = m_firstId; - - try { - m_adapter.notifyDataSetChanged(); - } catch (BadParcelableException e) { - if (getActivity() != null) { - getActivity().finish(); - return; - } - } - - if (!Application.getArticles().isEmpty()) { - if (Application.getArticles().getById(m_articleId) == null) { - Article article = Application.getArticles().get(0); - - m_articleId = article.id; - m_listener.onArticleSelected(article, false); - } - } - - } else { - m_lazyLoadDisabled = true; - - if (m_lastError == ApiCommon.ApiError.LOGIN_FAILED) { - m_activity.login(true); - } else { - m_activity.toast(getErrorMessage()); - } - } - } - }; - - final Feed feed = m_feed; - - final String sessionId = m_activity.getSessionId(); - int skip = 0; - - if (append) { - // adaptive, all_articles, marked, published, unread - String viewMode = m_activity.getViewMode(); - int numUnread = 0; - int numAll = Application.getArticles().size(); - - for (Article a : Application.getArticles()) { - if (a.unread) ++numUnread; - } - - if ("marked".equals(viewMode)) { - skip = numAll; - } else if ("published".equals(viewMode)) { - skip = numAll; - } else if ("unread".equals(viewMode)) { - skip = numUnread; - } else if (m_searchQuery != null && !m_searchQuery.isEmpty()) { - skip = numAll; - } else if ("adaptive".equals(viewMode)) { - skip = numUnread > 0 ? numUnread : numAll; - } else { - skip = numAll; - } - } - - final int fskip = skip; - - req.setOffset(skip); - - HashMap<String,String> map = new HashMap<>(); - map.put("op", "getHeadlines"); - map.put("sid", sessionId); - map.put("feed_id", String.valueOf(feed.id)); - map.put("show_excerpt", "true"); - map.put("excerpt_length", String.valueOf(CommonActivity.EXCERPT_MAX_LENGTH)); - map.put("show_content", "true"); - map.put("include_attachments", "true"); - map.put("limit", m_prefs.getString("headlines_request_size", "15")); - map.put("offset", String.valueOf(0)); - map.put("view_mode", m_activity.getViewMode()); - map.put("skip", String.valueOf(fskip)); - map.put("include_nested", "true"); - map.put("has_sandbox", "true"); - map.put("order_by", m_activity.getSortMode()); - - if (feed.is_cat) map.put("is_cat", "true"); - - if (m_searchQuery != null && !m_searchQuery.isEmpty()) { - map.put("search", m_searchQuery); - map.put("search_mode", ""); - map.put("match_on", "both"); - } - - if (m_firstId > 0) map.put("check_first_id", String.valueOf(m_firstId)); - - if (m_activity.getApiLevel() >= 12) { - map.put("include_header", "true"); - } - - if (m_prefs.getBoolean("enable_image_downsampling", false)) { - if (m_prefs.getBoolean("always_downsample_images", false) || !m_activity.isWifiConnected()) { - map.put("resize_width", String.valueOf(m_activity.getResizeWidth())); - } - } - - Log.d(TAG, "[AP] request more headlines, firstId=" + m_firstId); - req.execute(map); - } - @Override public void onAttach(@NonNull Activity activity) { super.onAttach(activity); m_listener = (HeadlinesEventListener)activity; m_activity = (OnlineActivity)activity; - - m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); } @SuppressLint("NewApi") @Override public void onResume() { super.onResume(); - - //if (m_adapter != null) m_adapter.notifyDataSetChanged(); - m_activity.invalidateOptionsMenu(); } @@ -317,7 +142,8 @@ public class ArticlePager extends androidx.fragment.app.Fragment { if (m_pager != null && articleId != m_articleId) { int position = Application.getArticles().getPositionById(articleId); - m_pager.setCurrentItem(position, false); + if (position != -1) + m_pager.setCurrentItem(position, false); } } @@ -345,7 +171,13 @@ public class ArticlePager extends androidx.fragment.app.Fragment { return m_articleId; } - public void notifyUpdated() { - m_adapter.notifyDataSetChanged(); + public void notifyItemChanged(int position) { + if (m_adapter != null) + m_adapter.notifyItemChanged(position); + } + + public void syncToSharedArticles() { + if (m_adapter != null) + m_adapter.syncToSharedArticles(); } } diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/BaseFeedlistFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/BaseFeedlistFragment.java index 86a31465..b37f7386 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/BaseFeedlistFragment.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/BaseFeedlistFragment.java @@ -17,7 +17,7 @@ import java.net.URL; public abstract class BaseFeedlistFragment extends androidx.fragment.app.Fragment { abstract public void refresh(); - public void initDrawerHeader(LayoutInflater inflater, View view, ListView list, final CommonActivity activity, final SharedPreferences prefs, boolean isRoot) { + public void initDrawerHeader(LayoutInflater inflater, View view, ListView list, final CommonActivity activity, final SharedPreferences prefs) { View layout = inflater.inflate(R.layout.drawer_header, list, false); list.addHeaderView(layout, null, false); @@ -62,9 +62,7 @@ public abstract class BaseFeedlistFragment extends androidx.fragment.app.Fragmen text.setText(R.string.unread_only); ImageView icon = rowToggle.findViewById(R.id.icon); - TypedValue tv = new TypedValue(); - getActivity().getTheme().resolveAttribute(R.attr.ic_filter_variant, tv, true); - icon.setImageResource(tv.resourceId); + icon.setImageResource(R.drawable.baseline_filter_alt_24); final SwitchCompat rowSwitch = rowToggle.findViewById(R.id.row_switch); rowSwitch.setChecked(activity.getUnreadOnly()); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/CommonActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/CommonActivity.java index cdc261b7..97e356c4 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/CommonActivity.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/CommonActivity.java @@ -15,8 +15,6 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -66,7 +64,6 @@ public class CommonActivity extends AppCompatActivity implements SharedPreferenc public final static String FRAG_ARTICLE = "article"; public final static String FRAG_FEEDS = "feeds"; public final static String FRAG_CATS = "cats"; - public final static String FRAG_DIALOG = "dialog"; public final static String THEME_DEFAULT = "THEME_FOLLOW_DEVICE"; @@ -74,7 +71,6 @@ public class CommonActivity extends AppCompatActivity implements SharedPreferenc public final static String NOTIFICATION_CHANNEL_PRIORITY = "channel_priority"; public static final int EXCERPT_MAX_LENGTH = 256; - public static final int EXCERPT_MAX_QUERY_LENGTH = 2048; public static final int LABEL_BASE_INDEX = -1024; public static final int PENDING_INTENT_CHROME_SHARE = 1; @@ -330,22 +326,6 @@ public class CommonActivity extends AppCompatActivity implements SharedPreferenc }); } - protected void preloadUriIfAllowed(Uri uri) { - boolean enableCustomTabs = m_prefs.getBoolean("enable_custom_tabs", true); - - if (m_customTabClient != null && enableCustomTabs) { - ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo info = cm.getActiveNetworkInfo(); - - if (info != null && info.isConnected() && info.getType() == ConnectivityManager.TYPE_WIFI) { - CustomTabsSession session = getCustomTabSession(); - session.mayLaunchUrl(uri, null, null); - - //toast("Preloading: " + uri.toString()); - } - } - } - protected Intent getShareIntent(String text, String subject) { Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("text/plain"); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/DetailActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/DetailActivity.java index 6558c2d1..bca2aa40 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/DetailActivity.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/DetailActivity.java @@ -6,7 +6,6 @@ import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; -import android.os.Handler; import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -94,7 +93,7 @@ public class DetailActivity extends OnlineActivity implements HeadlinesEventList saveArticleUnread(article); if (hf != null) { - hf.notifyUpdated(); + hf.notifyItemChanged(Application.getArticles().indexOf(article)); } } } @@ -149,17 +148,16 @@ public class DetailActivity extends OnlineActivity implements HeadlinesEventList FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); - final HeadlinesFragment hf = new HeadlinesFragment(); + HeadlinesFragment hf = new HeadlinesFragment(); hf.initialize(feed, openedArticleId, true); hf.setSearchQuery(searchQuery); ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES); - ArticlePager af = new ArticlePager(); - af.initialize(openedArticleId, feed); - af.setSearchQuery(searchQuery); + ArticlePager ap = new ArticlePager(); + ap.initialize(openedArticleId, feed); - ft.replace(R.id.article_fragment, af, FRAG_ARTICLE); + ft.replace(R.id.article_fragment, ap, FRAG_ARTICLE); ft.commit(); @@ -199,8 +197,8 @@ public class DetailActivity extends OnlineActivity implements HeadlinesEventList menu.findItem(R.id.article_set_score).setIcon(R.drawable.baseline_trending_flat_24); } - menu.findItem(R.id.toggle_unread).setIcon(selectedArticle.unread ? R.drawable.baseline_drafts_24 : - R.drawable.baseline_email_24); + menu.findItem(R.id.toggle_unread).setIcon(selectedArticle.unread ? R.drawable.baseline_email_24 : + R.drawable.baseline_drafts_24); menu.findItem(R.id.toggle_attachments).setVisible(selectedArticle.attachments != null && !selectedArticle.attachments.isEmpty()); } @@ -261,7 +259,7 @@ public class DetailActivity extends OnlineActivity implements HeadlinesEventList } @Override - public void onArticleListSelectionChange(ArticleList m_selectedArticles) { + public void onArticleListSelectionChange() { invalidateOptionsMenu(); } @@ -271,35 +269,23 @@ public class DetailActivity extends OnlineActivity implements HeadlinesEventList } @Override - public void onArticleSelected(final Article article, boolean open) { - - if (article == null) return; - + public void onArticleSelected(Article article, boolean open) { + if (article.unread) { article.unread = false; saveArticleUnread(article); } - try { - preloadUriIfAllowed(Uri.parse(article.link)); - } catch (Exception e) { - e.printStackTrace(); - } - if (!getSupportActionBar().isShowing()) getSupportActionBar().show(); - if (open) { - - new Handler().postDelayed(() -> { - ArticlePager ap = (ArticlePager) DetailActivity.this.getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); - - if (ap != null) { - ap.setActiveArticleId(article.id); - } - }, 250); + ArticlePager ap = (ArticlePager) DetailActivity.this.getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + if (open) { + if (ap != null) { + ap.setActiveArticleId(article.id); + } } else { - HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); if (hf != null) { hf.setActiveArticleId(article.id); } @@ -313,11 +299,11 @@ public class DetailActivity extends OnlineActivity implements HeadlinesEventList HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); ArticlePager ap = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); - if (ap != null) { - ap.notifyUpdated(); + if (ap != null) { + ap.syncToSharedArticles(); } - if (hf != null) { + /* if (hf != null) { Article article = Application.getArticles().getById(hf.getActiveArticleId()); if (article == null && !Application.getArticles().isEmpty()) { @@ -335,7 +321,7 @@ public class DetailActivity extends OnlineActivity implements HeadlinesEventList ft.replace(R.id.article_fragment, af, FRAG_ARTICLE); ft.commitAllowingStateLoss(); } - } + } */ } @Override diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedCategoriesFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedCategoriesFragment.java index 08a656e4..34127013 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedCategoriesFragment.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedCategoriesFragment.java @@ -62,9 +62,9 @@ public class FeedCategoriesFragment extends BaseFeedlistFragment implements OnIt params.put("op", "getCategories"); params.put("sid", sessionId); params.put("enable_nested", "true"); - if (unreadOnly) { - params.put("unread_only", String.valueOf(unreadOnly)); - } + + if (unreadOnly) + params.put("unread_only", "true"); return new ApiLoader(getContext(), params); } @@ -288,7 +288,7 @@ public class FeedCategoriesFragment extends BaseFeedlistFragment implements OnIt m_list = view.findViewById(R.id.feeds); m_adapter = new FeedCategoryListAdapter(getActivity(), R.layout.feeds_row, m_cats); - initDrawerHeader(inflater, view, m_list, m_activity, m_prefs, true); + initDrawerHeader(inflater, view, m_list, m_activity, m_prefs); m_list.setAdapter(m_adapter); m_list.setOnItemClickListener(this); @@ -312,7 +312,7 @@ public class FeedCategoriesFragment extends BaseFeedlistFragment implements OnIt public void onResume() { super.onResume(); - LoaderManager.getInstance(this).initLoader(0, null, this).forceLoad(); + LoaderManager.getInstance(this).initLoader(Application.LOADER_CATS, null, this).forceLoad(); m_activity.invalidateOptionsMenu(); } @@ -324,7 +324,7 @@ public class FeedCategoriesFragment extends BaseFeedlistFragment implements OnIt if (m_swipeLayout != null) m_swipeLayout.setRefreshing(true); - LoaderManager.getInstance(this).restartLoader(0, null, this).forceLoad(); + LoaderManager.getInstance(this).restartLoader(Application.LOADER_CATS, null, this).forceLoad(); } private class FeedCategoryListAdapter extends ArrayAdapter<FeedCategory> { @@ -376,10 +376,7 @@ public class FeedCategoriesFragment extends BaseFeedlistFragment implements OnIt ImageView icon = v.findViewById(R.id.icon); if (icon != null) { - TypedValue tv = new TypedValue(); - - m_activity.getTheme().resolveAttribute(R.attr.ic_folder_outline, tv, true); - icon.setImageResource(tv.resourceId); + icon.setImageResource(R.drawable.baseline_folder_open_24); } diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java index 495180bb..c198343d 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java @@ -327,7 +327,7 @@ public class FeedsFragment extends BaseFeedlistFragment implements OnItemClickLi m_list = view.findViewById(R.id.feeds); - initDrawerHeader(inflater, view, m_list, m_activity, m_prefs, !m_enableParentBtn); + initDrawerHeader(inflater, view, m_list, m_activity, m_prefs); if (m_enableParentBtn) { View layout = inflater.inflate(R.layout.feeds_goback, m_list, false); @@ -366,7 +366,7 @@ public class FeedsFragment extends BaseFeedlistFragment implements OnItemClickLi public void onResume() { super.onResume(); - LoaderManager.getInstance(this).initLoader(0, null, this).forceLoad(); + LoaderManager.getInstance(this).initLoader(Application.LOADER_FEEDS, null, this).forceLoad(); m_activity.invalidateOptionsMenu(); } @@ -404,7 +404,7 @@ public class FeedsFragment extends BaseFeedlistFragment implements OnItemClickLi m_swipeLayout.setRefreshing(true); } - LoaderManager.getInstance(this).restartLoader(0, null, this).forceLoad(); + LoaderManager.getInstance(this).restartLoader(Application.LOADER_FEEDS, null, this).forceLoad(); } private class FeedListAdapter extends ArrayAdapter<Feed> { @@ -462,34 +462,23 @@ public class FeedsFragment extends BaseFeedlistFragment implements OnItemClickLi ImageView icon = v.findViewById(R.id.icon); if (icon != null) { - TypedValue tv = new TypedValue(); - if (feed.id == 0 && !feed.is_cat) { - m_activity.getTheme().resolveAttribute(R.attr.ic_archive, tv, true); - icon.setImageResource(tv.resourceId); + icon.setImageResource(R.drawable.baseline_archive_24); } else if (feed.id == -1 && !feed.is_cat) { - m_activity.getTheme().resolveAttribute(R.attr.ic_star, tv, true); - icon.setImageResource(tv.resourceId); + icon.setImageResource(R.drawable.baseline_star_24); } else if (feed.id == -2 && !feed.is_cat) { - m_activity.getTheme().resolveAttribute(R.attr.ic_rss_box, tv, true); - icon.setImageResource(tv.resourceId); + icon.setImageResource(R.drawable.rss); } else if (feed.id == -3 && !feed.is_cat) { - m_activity.getTheme().resolveAttribute(R.attr.ic_fresh, tv, true); - icon.setImageResource(tv.resourceId); + icon.setImageResource(R.drawable.baseline_local_fire_department_24); } else if (feed.id == -4 && !feed.is_cat) { - m_activity.getTheme().resolveAttribute(R.attr.ic_inbox, tv, true); - icon.setImageResource(tv.resourceId); + icon.setImageResource(R.drawable.baseline_inbox_24); } else if (feed.id == -6 && !feed.is_cat) { - m_activity.getTheme().resolveAttribute(R.attr.ic_restore, tv, true); - icon.setImageResource(tv.resourceId); + icon.setImageResource(R.drawable.baseline_restore_24); } else if (feed.is_cat) { - m_activity.getTheme().resolveAttribute(R.attr.ic_folder_outline, tv, true); - icon.setImageResource(tv.resourceId); + icon.setImageResource(R.drawable.baseline_folder_open_24); } else { - m_activity.getTheme().resolveAttribute(R.attr.ic_rss_box, tv, true); - icon.setImageResource(tv.resourceId); + icon.setImageResource(R.drawable.rss); } - } TextView tt = v.findViewById(R.id.title); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesEventListener.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesEventListener.java index 5494bb2b..27e00bbf 100644 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesEventListener.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesEventListener.java @@ -4,7 +4,7 @@ import org.fox.ttrss.types.Article; import org.fox.ttrss.types.ArticleList; public interface HeadlinesEventListener { - void onArticleListSelectionChange(ArticleList m_selectedArticles); + void onArticleListSelectionChange(); void onArticleSelected(Article article); void onArticleSelected(Article article, boolean open); void onHeadlinesLoaded(boolean appended); 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 ad023a7e..fbcf0b4c 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 @@ -1,6 +1,5 @@ package org.fox.ttrss; -import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; import android.content.Context; @@ -15,6 +14,7 @@ import android.media.MediaPlayer; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.text.Html; @@ -46,11 +46,13 @@ import android.widget.TextView; import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityOptionsCompat; +import androidx.core.content.ContextCompat; import androidx.core.view.ViewCompat; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.ListAdapter; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -65,14 +67,13 @@ import com.bumptech.glide.request.target.Target; import com.google.android.material.button.MaterialButton; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.snackbar.Snackbar; -import com.google.gson.JsonElement; import org.fox.ttrss.glide.ProgressTarget; import org.fox.ttrss.types.Article; import org.fox.ttrss.types.ArticleList; import org.fox.ttrss.types.Attachment; import org.fox.ttrss.types.Feed; -import org.fox.ttrss.util.HeadlinesRequest; +import org.fox.ttrss.util.ArticleDiffItemCallback; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; @@ -81,11 +82,19 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.TimeZone; +import java.util.stream.Collectors; import jp.wasabeef.glide.transformations.CropCircleTransformation; public class HeadlinesFragment extends androidx.fragment.app.Fragment { + private boolean m_isLazyLoading; + + public void notifyItemChanged(int position) { + if (m_adapter != null) + m_adapter.notifyItemChanged(position); + } + public enum ArticlesSelection { ALL, NONE, UNREAD } public static final int FLAVOR_IMG_MIN_SIZE = 128; @@ -96,9 +105,6 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { private Feed m_feed; private int m_activeArticleId; private String m_searchQuery = ""; - private boolean m_refreshInProgress = false; - private int m_firstId = 0; - private boolean m_lazyLoadDisabled = false; private SharedPreferences m_prefs; @@ -114,14 +120,12 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { private MediaPlayer m_mediaPlayer; private TextureView m_activeTexture; - public ArticleList getSelectedArticles() { - ArticleList tmp = new ArticleList(); - - for (Article a : Application.getArticles()) { - if (a.selected) tmp.add(a); - } + protected static HashMap<Integer, Integer> m_flavorHeightsCache = new HashMap<>(); - return tmp; + public ArticleList getSelectedArticles() { + return Application.getArticles() + .stream() + .filter(a -> a.selected).collect(Collectors.toCollection(ArticleList::new)); } public void initialize(Feed feed) { @@ -186,19 +190,24 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { private void catchupAbove(Article article) { ArticleList tmp = new ArticleList(); - for (Article a : Application.getArticles()) { + ArticleList articles = Application.getArticles(); + for (Article a : articles) { if (article.equalsById(a)) break; if (a.unread) { a.unread = false; tmp.add(a); + + int position = articles.getPositionById(a.id); + + if (position != -1) + m_adapter.notifyItemChanged(position); } } if (!tmp.isEmpty()) { m_activity.setArticlesUnread(tmp, Article.UPDATE_SET_FALSE); - m_adapter.notifyDataSetChanged(); } } @@ -250,8 +259,6 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { m_feed = savedInstanceState.getParcelable("m_feed"); m_activeArticleId = savedInstanceState.getInt("m_activeArticleId"); m_searchQuery = savedInstanceState.getString("m_searchQuery"); - m_firstId = savedInstanceState.getInt("m_firstId"); - m_lazyLoadDisabled = savedInstanceState.getBoolean("m_lazyLoadDisabled"); m_compactLayoutMode = savedInstanceState.getBoolean("m_compactLayoutMode"); } @@ -267,13 +274,12 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { out.putParcelable("m_feed", m_feed); out.putInt("m_activeArticleId", m_activeArticleId); out.putString("m_searchQuery", m_searchQuery); - out.putInt("m_firstId", m_firstId); - out.putBoolean("m_lazyLoadDisabled", m_lazyLoadDisabled); out.putBoolean("m_compactLayoutMode", m_compactLayoutMode); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + Log.d(TAG, "onCreateView"); String headlineMode = m_prefs.getString("headline_mode", "HL_DEFAULT"); @@ -287,7 +293,7 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { m_swipeLayout = view.findViewById(R.id.headlines_swipe_container); - m_swipeLayout.setOnRefreshListener(() -> refresh(false, true)); + m_swipeLayout.setOnRefreshListener(() -> refresh(false)); m_list = view.findViewById(R.id.headlines_list); registerForContextMenu(m_list); @@ -296,11 +302,14 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { m_list.setLayoutManager(m_layoutManager); m_list.setItemAnimator(new DefaultItemAnimator()); - m_adapter = new ArticleListAdapter(Application.getArticles()); - + m_adapter = new ArticleListAdapter(); m_list.setAdapter(m_adapter); - if (m_prefs.getBoolean("headlines_swipe_to_dismiss", true) && !m_prefs.getBoolean("headlines_mark_read_scroll", false) ) { + if (savedInstanceState == null && Application.getArticles().isEmpty()) { + refresh(false); + } + + if (m_prefs.getBoolean("headlines_swipe_to_dismiss", true) /*&& !m_prefs.getBoolean("headlines_mark_read_scroll", false) */) { ItemTouchHelper swipeHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) { @@ -345,8 +354,10 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { wasUnread = false; } - Application.getArticles().remove(adapterPosition); - m_adapter.notifyItemRemoved(adapterPosition); + ArticleList tmpRemove = new ArticleList(Application.getArticles()); + tmpRemove.remove(adapterPosition); + + Application.getArticlesModel().update(tmpRemove); Snackbar.make(m_list, R.string.headline_undo_row_prompt, Snackbar.LENGTH_LONG) .setAction(getString(R.string.headline_undo_row_button), v -> { @@ -356,9 +367,10 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { m_activity.saveArticleUnread(article); } - Application.getArticles().add(adapterPosition, article); - m_adapter.notifyItemInserted(adapterPosition); - m_adapter.notifyItemRangeChanged(adapterPosition, 1); + ArticleList tmpInsert = new ArticleList(Application.getArticles()); + tmpInsert.add(adapterPosition, article); + + Application.getArticlesModel().update(tmpInsert); }).show(); } @@ -378,17 +390,22 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); - if (newState == RecyclerView.SCROLL_STATE_IDLE && m_prefs.getBoolean("headlines_mark_read_scroll", false)) { - if (!m_readArticles.isEmpty()) { - m_activity.toggleArticlesUnread(m_readArticles); + ArticleModel model = Application.getArticlesModel(); + + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + if (!m_readArticles.isEmpty() && !m_isLazyLoading && !model.isLoading() && m_prefs.getBoolean("headlines_mark_read_scroll", false)) { + Log.d(TAG, "marking articles as read, count=" + m_readArticles.size()); - for (Article a : m_readArticles) + m_activity.setArticlesUnread(m_readArticles, Article.UPDATE_SET_FALSE); + + for (Article a : m_readArticles) { a.unread = false; - if (m_feed != null) - m_feed.unread -= m_readArticles.size(); + int position = Application.getArticles().getPositionById(a.id); - m_adapter.notifyDataSetChanged(); + if (position != -1) + m_adapter.notifyItemChanged(position); + } m_readArticles.clear(); @@ -407,27 +424,33 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { // Log.d(TAG, "onScrolled: FVI=" + firstVisibleItem + " LVI=" + lastVisibleItem); if (m_prefs.getBoolean("headlines_mark_read_scroll", false)) { - for (int i = 0; i < firstVisibleItem; i++) { try { Article article = Application.getArticles().get(i); - if (article.unread && !m_readArticles.contains(article)) { - Log.d(TAG, "adding to mark read=" + article.title); - + if (article.unread && !m_readArticles.contains(article)) m_readArticles.add(article); - } + } catch (IndexOutOfBoundsException e) { e.printStackTrace(); } } - } - if (!m_refreshInProgress && !m_lazyLoadDisabled && lastVisibleItem >= Application.getArticles().size() - 5) { - m_refreshInProgress = true; - new Handler().postDelayed(() -> refresh(true), 100); + // Log.d(TAG, "pending to auto mark as read count=" + m_readArticles.size()); } + ArticleModel model = Application.getArticlesModel(); + + if (dy > 0 && !m_isLazyLoading && !model.isLoading() && model.lazyLoadEnabled() && + lastVisibleItem >= Application.getArticles().size() - 5) { + + Log.d(TAG, "attempting to lazy load more articles..."); + + m_isLazyLoading = true; + + // this has to be dispatched delayed, consequent adapter updates are forbidden in scroll handler + new Handler().postDelayed(() -> refresh(true), 250); + } } }); @@ -435,7 +458,60 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { m_activity.setTitle(m_feed.title); } - Log.d(TAG, "onCreateView, feed=" + m_feed); + ArticleModel model = Application.getArticlesModel(); + + // this gets notified on network update + model.getUpdatesData().observe(getActivity(), lastUpdate -> { + if (lastUpdate > 0) { + ArticleList tmp = new ArticleList(model.getArticles().getValue()); + + Log.d(TAG, "observed last update=" + lastUpdate + " article count=" + tmp.size()); + + if (m_prefs.getBoolean("headlines_mark_read_scroll", false)) + tmp.add(new Article(Article.TYPE_AMR_FOOTER)); + + final boolean appended = model.getAppend(); + + m_adapter.submitList(tmp, () -> { + if (!appended) + m_list.scrollToPosition(0); + + if (m_swipeLayout != null) + m_swipeLayout.setRefreshing(false); + + m_isLazyLoading = false; + + m_listener.onHeadlinesLoaded(appended); + m_listener.onArticleListSelectionChange(); + }); + + if (model.getFirstIdChanged()) + Snackbar.make(getView(), R.string.headlines_row_top_changed, Snackbar.LENGTH_LONG) + .setAction(R.string.reload, v -> refresh(false)).show(); + + if (model.getLastError() == ApiCommon.ApiError.LOGIN_FAILED) { + m_activity.login(); + } else if (model.getLastError() != null && model.getLastError() != ApiCommon.ApiError.SUCCESS) { + if (model.getLastErrorMessage() != null) { + m_activity.toast(m_activity.getString(model.getErrorMessage()) + "\n" + model.getLastErrorMessage()); + } else { + m_activity.toast(model.getErrorMessage()); + } + } + } + }); + + // loaded articles might get modified for all sorts of reasons + model.getArticles().observe(getActivity(), articles -> { + Log.d(TAG, "observed article list size=" + articles.size()); + + ArticleList tmp = new ArticleList(articles); + + if (m_prefs.getBoolean("headlines_mark_read_scroll", false)) + tmp.add(new Article(Article.TYPE_AMR_FOOTER)); + + m_adapter.submitList(tmp); + }); return view; } @@ -444,9 +520,12 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { public void onResume() { super.onResume(); - if (Application.getArticles().isEmpty()) { - refresh(false); - } else { + Log.d(TAG, "onResume"); + + syncToSharedArticles(); + + // we only set this in detail activity + if (m_activeArticleId > 0) { Article activeArticle = Application.getArticles().getById(m_activeArticleId); if (activeArticle != null) @@ -464,183 +543,21 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { m_listener = (HeadlinesEventListener) activity; } - public void refresh(boolean append) { - refresh(append, false); - } - - public void refresh(final boolean append, boolean userInitiated) { - Application.getArticles().stripFooters(); - m_adapter.notifyDataSetChanged(); - - if (!append) m_lazyLoadDisabled = false; - - if (m_activity != null && isAdded() && m_feed != null) { - m_refreshInProgress = true; - - if (m_swipeLayout != null) m_swipeLayout.setRefreshing(true); - - if (!append) { - m_activity.getSupportActionBar().show(); - Application.getArticles().clear(); - m_adapter.notifyDataSetChanged(); - } else if (!(m_activity instanceof DetailActivity)) { - // detail activity does not use footers because it would break 1-to-1 mapping with pager view - // pager will need to work on a footerless subset of shared article view before this is possible - Application.getArticles().add(new Article(Article.TYPE_LOADMORE)); - m_adapter.notifyDataSetChanged(); - } - - final String sessionId = m_activity.getSessionId(); - final boolean isCat = m_feed.is_cat; - - @SuppressLint("StaticFieldLeak") HeadlinesRequest req = new HeadlinesRequest(getActivity().getApplicationContext(), m_activity, Application.getArticles()) { - @Override - protected void onPostExecute(JsonElement result) { - if (isDetached() || !isAdded()) return; - - super.onPostExecute(result); - - if (m_swipeLayout != null) m_swipeLayout.setRefreshing(false); - - m_refreshInProgress = false; - - if (result != null) { - - // is this needed? - if (!Application.getArticles().containsId(m_activeArticleId)) - m_activeArticleId = 0; - - if (m_firstIdChanged) { - m_lazyLoadDisabled = true; - - Log.d(TAG, "first id changed, disabling lazy load"); - - // article pager deals with this in tablet landscape view - if (m_activity.isSmallScreen() || !m_activity.isPortrait()) { - Snackbar.make(getView(), R.string.headlines_row_top_changed, Snackbar.LENGTH_LONG) - .setAction(R.string.reload, v -> refresh(false)).show(); - } - } - - if (m_amountLoaded < Integer.parseInt(m_prefs.getString("headlines_request_size", "15"))) { - // Log.d(TAG, "amount loaded "+m_amountLoaded+" < request size, disabling lazy load"); - m_lazyLoadDisabled = true; - } - - HeadlinesFragment.this.m_firstId = m_firstId; - - m_adapter.notifyDataSetChanged(); - m_listener.onHeadlinesLoaded(append); - - } else { - m_lazyLoadDisabled = true; - - if (m_lastError == ApiCommon.ApiError.LOGIN_FAILED) { - m_activity.login(true); - } else { - if (m_lastErrorMessage != null) { - m_activity.toast(getString(getErrorMessage()) + "\n" + m_lastErrorMessage); - } else { - m_activity.toast(getErrorMessage()); - } - } - } - - // detail activity does not use footers (see above) - if (!(m_activity instanceof DetailActivity)) { - Application.getArticles().add(new Article(Article.TYPE_AMR_FOOTER)); - m_adapter.notifyDataSetChanged(); - } - } - }; - - final int skip = getSkip(append); - - final boolean allowForceUpdate = m_activity.getApiLevel() >= 9 && - !m_feed.is_cat && m_feed.id > 0 && !append && userInitiated && - skip == 0; - - Log.d(TAG, "allowForceUpdate=" + allowForceUpdate + " userInitiated=" + userInitiated + " skip=" + skip); - - req.setOffset(skip); - - HashMap<String,String> map = new HashMap<>(); - map.put("op", "getHeadlines"); - map.put("sid", sessionId); - map.put("feed_id", String.valueOf(m_feed.id)); - map.put("show_excerpt", "true"); - map.put("excerpt_length", String.valueOf(CommonActivity.EXCERPT_MAX_LENGTH)); - map.put("show_content", "true"); - map.put("include_attachments", "true"); - map.put("view_mode", m_activity.getViewMode()); - map.put("limit", m_prefs.getString("headlines_request_size", "15")); - map.put("offset", String.valueOf(0)); - map.put("skip", String.valueOf(skip)); - map.put("include_nested", "true"); - map.put("has_sandbox", "true"); - map.put("order_by", m_activity.getSortMode()); - - if (m_prefs.getBoolean("enable_image_downsampling", false)) { - if (m_prefs.getBoolean("always_downsample_images", false) || !m_activity.isWifiConnected()) { - map.put("resize_width", String.valueOf(m_activity.getResizeWidth())); - } - } - - if (isCat) map.put("is_cat", "true"); + public void refresh(final boolean append) { + ArticleModel model = Application.getArticlesModel(); - if (allowForceUpdate) { - map.put("force_update", "true"); - } - - if (m_searchQuery != null && !m_searchQuery.isEmpty()) { - map.put("search", m_searchQuery); - map.put("search_mode", ""); - map.put("match_on", "both"); - } - - if (m_firstId > 0) map.put("check_first_id", String.valueOf(m_firstId)); - - if (m_activity.getApiLevel() >= 12) { - map.put("include_header", "true"); - } - - Log.d(TAG, "[HP] request more headlines, firstId=" + m_firstId); - - req.execute(map); - } - } + if (!append) + m_activeArticleId = -1; - private int getSkip(boolean append) { - int skip = 0; - - if (append) { - // adaptive, all_articles, marked, published, unread - String viewMode = m_activity.getViewMode(); - - int numUnread = Math.toIntExact(Application.getArticles().getUnreadCount()); - int numAll = Math.toIntExact(Application.getArticles().getSizeWithoutFooters()); - - if ("marked".equals(viewMode)) { - skip = numAll; - } else if ("published".equals(viewMode)) { - skip = numAll; - } else if ("unread".equals(viewMode)) { - skip = numUnread; - } else if (m_searchQuery != null && !m_searchQuery.isEmpty()) { - skip = numAll; - } else if ("adaptive".equals(viewMode)) { - skip = numUnread > 0 ? numUnread : numAll; - } else { - skip = numAll; - } - } + if (m_swipeLayout != null) + m_swipeLayout.setRefreshing(true); - return skip; + model.setSearchQuery(getSearchQuery()); + model.startLoading(append, m_feed, m_activity.getResizeWidth()); } static class ArticleViewHolder extends RecyclerView.ViewHolder { public View view; - public Article article; public TextView titleView; public TextView feedTitleView; @@ -664,6 +581,7 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { public TextureView flavorVideoView; public MaterialButton attachmentsView; public ProgressTarget<String, GlideDrawable> flavorProgressTarget; + int articleId; public ArticleViewHolder(View v) { super(v); @@ -674,7 +592,7 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { View flavorImage = view.findViewById(R.id.flavor_image); if (flavorImage != null) { - article.flavorViewHeight = flavorImage.getMeasuredHeight(); + HeadlinesFragment.m_flavorHeightsCache.put(articleId, flavorImage.getMeasuredHeight()); } return true; @@ -705,6 +623,7 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { if (flavorImageView != null && flavorImageLoadingBar != null) { flavorProgressTarget = new FlavorProgressTarget<>(new GlideDrawableImageViewTarget(flavorImageView), flavorImageLoadingBar); } + } public void clearAnimation() { @@ -739,15 +658,12 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { } } - private class ArticleListAdapter extends RecyclerView.Adapter<ArticleViewHolder> { - private final ArticleList items; - + private class ArticleListAdapter extends ListAdapter<Article, ArticleViewHolder> { public static final int VIEW_NORMAL = 0; public static final int VIEW_UNREAD = 1; public static final int VIEW_ACTIVE = 2; public static final int VIEW_ACTIVE_UNREAD = 3; - public static final int VIEW_LOADMORE = 4; - public static final int VIEW_AMR_FOOTER = 5; + public static final int VIEW_AMR_FOOTER = 4; public static final int VIEW_COUNT = VIEW_AMR_FOOTER + 1; @@ -779,9 +695,8 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { return false; } - public ArticleListAdapter(ArticleList items) { - super(); - this.items = items; + public ArticleListAdapter() { + super(new ArticleDiffItemCallback()); Display display = m_activity.getWindowManager().getDefaultDisplay(); Point size = new Point(); @@ -803,9 +718,6 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { case VIEW_AMR_FOOTER: layoutId = R.layout.headlines_footer; break; - case VIEW_LOADMORE: - layoutId = R.layout.headlines_row_loadmore; - break; case VIEW_UNREAD: layoutId = m_compactLayoutMode ? R.layout.headlines_row_compact_unread : R.layout.headlines_row_unread; break; @@ -826,12 +738,12 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { @Override public void onBindViewHolder(final ArticleViewHolder holder, int position) { - holder.article = items.get(position); - int headlineFontSize = m_prefs.getInt("headlines_font_size_sp_int", 13); int headlineSmallFontSize = Math.max(10, Math.min(18, headlineFontSize - 2)); - final Article article = holder.article; + Article article = getItem(position); + + holder.articleId = article.id; if (article.id == Article.TYPE_AMR_FOOTER && m_prefs.getBoolean("headlines_mark_read_scroll", false)) { WindowManager wm = (WindowManager) m_activity.getSystemService(Context.WINDOW_SERVICE); @@ -854,9 +766,10 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { // only set active article when it makes sense (in DetailActivity) if (getActivity() instanceof DetailActivity) { - m_activeArticleId = article.id; - m_adapter.notifyDataSetChanged(); - } + m_activeArticleId = article.id; + + m_adapter.notifyItemChanged(position); + } }); // block footer clicks to make button/selection clicking easier @@ -867,18 +780,18 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { } if (holder.textImage != null) { - updateTextCheckedState(holder, article); + updateTextCheckedState(holder, position); holder.textImage.setOnClickListener(view -> { - Log.d(TAG, "textImage : onclicked"); + Article selectedArticle = getItem(position); - article.selected = !article.selected; + Log.d(TAG, "textImage onClick pos=" + position + " article=" + article); - updateTextCheckedState(holder, article); + selectedArticle.selected = !selectedArticle.selected; - m_listener.onArticleListSelectionChange(getSelectedArticles()); + updateTextCheckedState(holder, position); - Log.d(TAG, "num selected: " + getSelectedArticles().size()); + m_listener.onArticleListSelectionChange(); }); ViewCompat.setTransitionName(holder.textImage, "gallery:" + article.flavorImageUri); @@ -915,47 +828,40 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { TypedValue tvTertiary = new TypedValue(); m_activity.getTheme().resolveAttribute(R.attr.colorTertiary, tvTertiary, true); + ColorStateList colorTertiary = ColorStateList.valueOf(ContextCompat.getColor(m_activity, tvTertiary.resourceId)); + TypedValue tvPrimary = new TypedValue(); m_activity.getTheme().resolveAttribute(R.attr.colorPrimary, tvPrimary, true); - if (holder.markedView != null) { - TypedValue tv = new TypedValue(); - m_activity.getTheme().resolveAttribute(article.marked ? R.attr.ic_star : R.attr.ic_star_outline, tv, true); - - holder.markedView.setIconResource(tv.resourceId); + ColorStateList colorPrimary = ColorStateList.valueOf(ContextCompat.getColor(m_activity, tvPrimary.resourceId)); - - if (article.marked) - holder.markedView.setIconTint(ColorStateList.valueOf(tvTertiary.data)); - else - holder.markedView.setIconTint(ColorStateList.valueOf(tvPrimary.data)); + if (holder.markedView != null) { + holder.markedView.setIconResource(article.marked ? R.drawable.baseline_star_24 : R.drawable.baseline_star_outline_24); + holder.markedView.setIconTint(article.marked ? colorTertiary : colorPrimary); holder.markedView.setOnClickListener(v -> { - article.marked = !article.marked; - - m_adapter.notifyItemChanged(m_list.getChildAdapterPosition(holder.view)); + Article selectedArticle = new Article(getItem(position)); + selectedArticle.marked = !selectedArticle.marked; - m_activity.saveArticleMarked(article); + m_activity.saveArticleMarked(selectedArticle); + Application.getArticlesModel().update(position, selectedArticle); }); } if (holder.scoreView != null) { - TypedValue tv = new TypedValue(); - int scoreAttr = R.attr.ic_action_trending_flat; + int scoreDrawable = R.drawable.baseline_trending_flat_24; if (article.score > 0) - scoreAttr = R.attr.ic_action_trending_up; + scoreDrawable = R.drawable.baseline_trending_up_24; else if (article.score < 0) - scoreAttr = R.attr.ic_action_trending_down; + scoreDrawable = R.drawable.baseline_trending_down_24; - m_activity.getTheme().resolveAttribute(scoreAttr, tv, true); - - holder.scoreView.setIconResource(tv.resourceId); + holder.scoreView.setIconResource(scoreDrawable); if (article.score > Article.SCORE_HIGH) - holder.scoreView.setIconTint(ColorStateList.valueOf(tvTertiary.data)); + holder.scoreView.setIconTint(colorTertiary); else - holder.scoreView.setIconTint(ColorStateList.valueOf(tvPrimary.data)); + holder.scoreView.setIconTint(colorPrimary); if (m_activity.getApiLevel() >= 16) { holder.scoreView.setOnClickListener(v -> { @@ -985,21 +891,21 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { } if (holder.publishedView != null) { - TypedValue tv = new TypedValue(); - m_activity.getTheme().resolveAttribute(R.attr.ic_rss_box, tv, true); - holder.publishedView.setIconResource(tv.resourceId); + // otherwise we just use tinting in actionbar + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + holder.publishedView.setIconResource(article.published ? R.drawable.rss_box : R.drawable.rss); + } - if (article.published) - holder.publishedView.setIconTint(ColorStateList.valueOf(tvTertiary.data)); - else - holder.publishedView.setIconTint(ColorStateList.valueOf(tvPrimary.data)); + holder.publishedView.setIconTint(article.published ? colorTertiary : colorPrimary); holder.publishedView.setOnClickListener(v -> { - article.published = !article.published; - m_adapter.notifyItemChanged(m_list.getChildAdapterPosition(holder.view)); + Article selectedArticle = new Article(getItem(position)); + selectedArticle.published = !selectedArticle.published; - m_activity.saveArticlePublished(article); + m_activity.saveArticlePublished(selectedArticle); + + Application.getArticlesModel().update(position, selectedArticle); }); } @@ -1061,6 +967,7 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { holder.flavorVideoKindView.setVisibility(View.GONE); holder.flavorImageOverflow.setVisibility(View.GONE); holder.flavorVideoView.setVisibility(View.GONE); + holder.flavorImageHolder.setVisibility(View.GONE); Glide.clear(holder.flavorImageView); @@ -1124,10 +1031,17 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { holder.flavorImageView.setVisibility(View.VISIBLE); holder.flavorImageView.setMaxHeight((int)(m_screenHeight * 0.6f)); + // only show holder if we're about to display a picture + holder.flavorImageHolder.setVisibility(View.VISIBLE); + // prevent lower listiew entries from jumping around if this row is modified - if (article.flavorViewHeight > 0) { - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) holder.flavorImageView.getLayoutParams(); - lp.height = article.flavorViewHeight; + if (m_flavorHeightsCache.containsKey(article.id)) { + int cachedHeight = m_flavorHeightsCache.get(article.id); + + if (cachedHeight > 0) { + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) holder.flavorImageView.getLayoutParams(); + lp.height = cachedHeight; + } } holder.flavorProgressTarget.setModel(article.flavorImageUri); @@ -1320,18 +1234,19 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { if (holder.selectionBoxView != null) { holder.selectionBoxView.setChecked(article.selected); holder.selectionBoxView.setOnClickListener(view -> { - CheckBox cb = (CheckBox)view; + Article currentArticle = getItem(position); - article.selected = cb.isChecked(); + Log.d(TAG, "selectionCb onClick pos=" + position + " article=" + article); + + CheckBox cb = (CheckBox)view; - m_listener.onArticleListSelectionChange(getSelectedArticles()); + currentArticle.selected = cb.isChecked(); - Log.d(TAG, "num selected: " + getSelectedArticles().size()); + m_listener.onArticleListSelectionChange(); }); } if (holder.menuButtonView != null) { - holder.menuButtonView.setOnClickListener(v -> { PopupMenu popup = new PopupMenu(getActivity(), v); @@ -1341,7 +1256,8 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { popup.getMenu().findItem(R.id.article_set_labels).setEnabled(m_activity.getApiLevel() >= 1); popup.getMenu().findItem(R.id.article_edit_note).setEnabled(m_activity.getApiLevel() >= 1); - popup.setOnMenuItemClickListener(item -> onArticleMenuItemSelected(item, article, + popup.setOnMenuItemClickListener(item -> onArticleMenuItemSelected(item, + getItem(position), m_list.getChildAdapterPosition(holder.view))); popup.show(); @@ -1351,12 +1267,10 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { @Override public int getItemViewType(int position) { - Article a = items.get(position); + Article a = getItem(position); if (a.id == Article.TYPE_AMR_FOOTER) { return VIEW_AMR_FOOTER; - } else if (a.id == Article.TYPE_LOADMORE) { - return VIEW_LOADMORE; } else if (a.id == m_activeArticleId && a.unread) { return VIEW_ACTIVE_UNREAD; } else if (a.id == m_activeArticleId) { @@ -1368,12 +1282,9 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { } } - @Override - public int getItemCount() { - return items.size(); - } + private void updateTextCheckedState(final ArticleViewHolder holder, int position) { + Article article = getItem(position); - private void updateTextCheckedState(final ArticleViewHolder holder, final Article article) { String tmp = !article.title.isEmpty() ? article.title.substring(0, 1).toUpperCase() : "?"; if (article.selected) { @@ -1508,47 +1419,60 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { } } - public void notifyUpdated() { - m_adapter.notifyDataSetChanged(); - } - public void scrollToArticle(Article article) { scrollToArticleId(article.id); } public void scrollToArticleId(int id) { - m_list.scrollToPosition(Application.getArticles().getPositionById(id)); + int position = Application.getArticles().getPositionById(id); + + if (position != -1) + m_list.scrollToPosition(position); } public void setActiveArticleId(int articleId) { if (m_list != null && articleId != m_activeArticleId) { + ArticleList articles = Application.getArticles(); + + int oldPosition = articles.getPositionById(m_activeArticleId); + int newPosition = articles.getPositionById(articleId); + m_activeArticleId = articleId; - m_adapter.notifyDataSetChanged(); + + if (oldPosition != -1) + m_adapter.notifyItemChanged(oldPosition); + + m_adapter.notifyItemChanged(newPosition); scrollToArticleId(articleId); + + if (newPosition >= articles.size() - 5) + new Handler().postDelayed(() -> refresh(true), 0); } } public void setSelection(ArticlesSelection select) { - for (Article a : Application.getArticles()) - a.selected = false; + ArticleList articlesWithoutFooters = Application.getArticles().getWithoutFooters(); - if (select != ArticlesSelection.NONE) { - for (Article a : Application.getArticles()) { - if (select == ArticlesSelection.ALL || select == ArticlesSelection.UNREAD && a.unread) { - a.selected = true; - } - } - } + for (Article a : articlesWithoutFooters) { + if (select == ArticlesSelection.ALL || select == ArticlesSelection.UNREAD && a.unread) { + a.selected = true; - if (m_adapter != null) { - m_adapter.notifyDataSetChanged(); - } - } + int position = Application.getArticles().getPositionById(a.id); + + if (position != -1) + m_adapter.notifyItemChanged(position); + + } else if (a.selected) { + a.selected = false; + + int position = Application.getArticles().getPositionById(a.id); - public int getActiveArticleId() { - return m_activeArticleId; + if (position != -1) + m_adapter.notifyItemChanged(position); + } + } } public String getSearchQuery() { @@ -1559,10 +1483,7 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { if (!m_searchQuery.equals(query)) { m_searchQuery = query; - // could be called before fragment view has been initialized - if (m_list != null) { - refresh(false); - } + refresh(false); } } @@ -1577,4 +1498,15 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment { releaseSurface(); } + private void syncToSharedArticles() { + ArticleList tmp = new ArticleList(); + + tmp.addAll(Application.getArticles()); + + if (m_prefs.getBoolean("headlines_mark_read_scroll", false)) + tmp.add(new Article(Article.TYPE_AMR_FOOTER)); + + m_adapter.submitList(tmp); + } + } 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 9430ddc2..458f1f76 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 @@ -164,7 +164,7 @@ public class MasterActivity extends OnlineActivity implements HeadlinesEventList FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); - if (m_prefs.getBoolean("enable_cats", false)) { + if (m_prefs.getBoolean("enable_cats", true)) { ft.replace(R.id.feeds_fragment, new FeedCategoriesFragment(), FRAG_CATS); } else { ft.replace(R.id.feeds_fragment, new FeedsFragment(), FRAG_FEEDS); @@ -445,7 +445,7 @@ public class MasterActivity extends OnlineActivity implements HeadlinesEventList } @Override - public void onArticleListSelectionChange(ArticleList m_selectedArticles) { + public void onArticleListSelectionChange() { invalidateOptionsMenu(); } @@ -476,7 +476,7 @@ public class MasterActivity extends OnlineActivity implements HeadlinesEventList // we use shared article list, but detail activity does not use special footers // we will append those back (if needed) in onActivityResult() - Application.getArticles().stripFooters(); + // Application.getArticles().stripFooters(); startActivityForResult(intent, HEADLINES_REQUEST); overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left); @@ -520,19 +520,19 @@ public class MasterActivity extends OnlineActivity implements HeadlinesEventList protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (requestCode == HEADLINES_REQUEST) { - - // we add back footers stripped when this was passed to DetailActivity - Application.getArticles().add(new Article(Article.TYPE_AMR_FOOTER)); + Log.d(TAG, "onActivityResult:" + requestCode + " "+ resultCode + " " + data); + if (requestCode == HEADLINES_REQUEST) { HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); if (hf != null) { - hf.notifyUpdated(); + // data might be null if detailactivity crashed + if (data != null) { + int activeArticleId = data.getIntExtra("activeArticleId", 0); - // this makes position in headlines in master activity (not quite) randomly jump around when returning - // even if active article hasn't been changed, i guess keeping it as-is is a lesser evil? - hf.scrollToArticleId(data.getIntExtra("activeArticleId", 0)); + Log.d(TAG, "got back from detail activity, scrolling to id=" + activeArticleId); + hf.scrollToArticleId(activeArticleId); + } } } } 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 92a3f219..ffca776b 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 @@ -5,12 +5,15 @@ import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.ColorStateList; import android.graphics.Point; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.util.Log; +import android.util.TypedValue; import android.view.Display; import android.view.KeyEvent; import android.view.Menu; @@ -23,6 +26,7 @@ import android.widget.TextView; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.view.ActionMode; import androidx.appcompat.widget.Toolbar; +import androidx.core.content.ContextCompat; import androidx.preference.PreferenceManager; import com.google.android.material.dialog.MaterialAlertDialogBuilder; @@ -391,6 +395,7 @@ public class OnlineActivity extends CommonActivity { } else if (itemId == R.id.search) { if (hf != null) { final EditText edit = new EditText(this); + edit.setText(hf.getSearchQuery()); MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this) .setTitle(R.string.search) @@ -561,28 +566,37 @@ public class OnlineActivity extends CommonActivity { if (ap != null) { Article selectedArticle = Application.getArticles().getById(ap.getSelectedArticleId()); - if (selectedArticle != null) - setArticleScore(selectedArticle); + if (selectedArticle != null) { + setArticleScore(selectedArticle); + + hf.notifyItemChanged(Application.getArticles().indexOf(selectedArticle)); + } } return true; } else if (itemId == R.id.toggle_marked) { if (ap != null) { Article selectedArticle = Application.getArticles().getById(ap.getSelectedArticleId()); - selectedArticle.marked = !selectedArticle.marked; - saveArticleMarked(selectedArticle); + if (selectedArticle != null) { + selectedArticle.marked = !selectedArticle.marked; + + saveArticleMarked(selectedArticle); - if (hf != null) hf.notifyUpdated(); + hf.notifyItemChanged(Application.getArticles().indexOf(selectedArticle)); + } } return true; } else if (itemId == R.id.toggle_unread) { if (ap != null) { Article selectedArticle = Application.getArticles().getById(ap.getSelectedArticleId()); - selectedArticle.unread = !selectedArticle.unread; - saveArticleUnread(selectedArticle); + if (selectedArticle != null) { + selectedArticle.unread = !selectedArticle.unread; + + saveArticleUnread(selectedArticle); - if (hf != null) hf.notifyUpdated(); + hf.notifyItemChanged(Application.getArticles().indexOf(selectedArticle)); + } } return true; } else if (itemId == R.id.selection_toggle_unread) { @@ -590,11 +604,13 @@ public class OnlineActivity extends CommonActivity { ArticleList selected = hf.getSelectedArticles(); if (!selected.isEmpty()) { - for (Article a : selected) + for (Article a : selected) { a.unread = !a.unread; + hf.notifyItemChanged(Application.getArticles().indexOf(a)); + } + toggleArticlesUnread(selected); - hf.notifyUpdated(); invalidateOptionsMenu(); } } @@ -604,11 +620,13 @@ public class OnlineActivity extends CommonActivity { ArticleList selected = hf.getSelectedArticles(); if (!selected.isEmpty()) { - for (Article a : selected) + for (Article a : selected) { a.marked = !a.marked; + hf.notifyItemChanged(Application.getArticles().indexOf(a)); + } + toggleArticlesMarked(selected); - hf.notifyUpdated(); invalidateOptionsMenu(); } } @@ -618,24 +636,26 @@ public class OnlineActivity extends CommonActivity { ArticleList selected = hf.getSelectedArticles(); if (!selected.isEmpty()) { - for (Article a : selected) + for (Article a : selected) { a.published = !a.published; + hf.notifyItemChanged(Application.getArticles().indexOf(a)); + } + toggleArticlesPublished(selected); - hf.notifyUpdated(); invalidateOptionsMenu(); } } return true; } else if (itemId == R.id.toggle_published) { - if (ap != null) { + if (ap != null && hf != null) { Article selectedArticle = Application.getArticles().getById(ap.getSelectedArticleId()); if (selectedArticle != null) { selectedArticle.published = !selectedArticle.published; saveArticlePublished(selectedArticle); - if (hf != null) hf.notifyUpdated(); + hf.notifyItemChanged(Application.getArticles().indexOf(selectedArticle)); } } return true; @@ -688,12 +708,17 @@ public class OnlineActivity extends CommonActivity { if (a.unread) { a.unread = false; tmp.add(a); + + if (hf != null) { + int position = Application.getArticles().indexOf(a); + + hf.notifyItemChanged(position); + } } } if (!tmp.isEmpty()) { setArticlesUnread(tmp, Article.UPDATE_SET_FALSE); - hf.notifyUpdated(); invalidateOptionsMenu(); } } @@ -713,11 +738,15 @@ public class OnlineActivity extends CommonActivity { saveArticleNote(article, note); - HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); - if (hf != null) hf.notifyUpdated(); + int position = Application.getArticles().getPositionById(article.id); + + if (position != -1) { + HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + if (hf != null) hf.notifyItemChanged(position); - ArticlePager ap = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); - if (ap != null) ap.notifyUpdated(); + ArticlePager ap = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + if (ap != null) ap.notifyItemChanged(position); + } }); builder.setNegativeButton(R.string.dialog_cancel, (dialog, which) -> { @@ -839,7 +868,8 @@ public class OnlineActivity extends CommonActivity { protected void setApiLevel(int apiLevel) { Application.getInstance().setApiLevel(apiLevel); } - + + // TODO switch to setArticleField() public void saveArticleUnread(final Article article) { ApiRequest req = new ApiRequest(getApplicationContext()) { protected void onPostExecute(JsonElement result) { @@ -853,11 +883,12 @@ public class OnlineActivity extends CommonActivity { map.put("op", "updateArticle"); map.put("article_ids", String.valueOf(article.id)); map.put("mode", article.unread ? "1" : "0"); - map.put("field", "2"); + map.put("field", String.valueOf(Article.UPDATE_FIELD_UNREAD)); req.execute(map); } + // TODO switch to setArticleField() public void saveArticleScore(final Article article) { ApiRequest req = new ApiRequest(getApplicationContext()) { protected void onPostExecute(JsonElement result) { @@ -871,11 +902,12 @@ public class OnlineActivity extends CommonActivity { map.put("op", "updateArticle"); map.put("article_ids", String.valueOf(article.id)); map.put("data", String.valueOf(article.score)); - map.put("field", "4"); + map.put("field", String.valueOf(Article.UPDATE_FIELD_SCORE)); req.execute(map); } + // TODO switch to setArticleField() public void saveArticleMarked(final Article article) { ApiRequest req = new ApiRequest(getApplicationContext()) { protected void onPostExecute(JsonElement result) { @@ -889,11 +921,12 @@ public class OnlineActivity extends CommonActivity { map.put("op", "updateArticle"); map.put("article_ids", String.valueOf(article.id)); map.put("mode", article.marked ? "1" : "0"); - map.put("field", "0"); + map.put("field", String.valueOf(Article.UPDATE_FIELD_MARKED)); req.execute(map); } + // TODO switch to setArticleField() public void saveArticlePublished(final Article article) { ApiRequest req = new ApiRequest(getApplicationContext()) { @@ -908,11 +941,12 @@ public class OnlineActivity extends CommonActivity { map.put("op", "updateArticle"); map.put("article_ids", String.valueOf(article.id)); map.put("mode", article.published ? "1" : "0"); - map.put("field", "1"); + map.put("field", String.valueOf(Article.UPDATE_FIELD_PUBLISHED)); req.execute(map); } + // TODO switch to setArticleField() public void saveArticleNote(final Article article, final String note) { ApiRequest req = new ApiRequest(getApplicationContext()) { protected void onPostExecute(JsonElement result) { @@ -926,7 +960,7 @@ public class OnlineActivity extends CommonActivity { map.put("article_ids", String.valueOf(article.id)); map.put("mode", "1"); map.put("data", note); - map.put("field", "3"); + map.put("field", String.valueOf(Article.UPDATE_FIELD_NOTE)); req.execute(map); } @@ -1005,7 +1039,8 @@ article.score = Integer.parseInt(edit.getText().toString()); if (selectedArticle != null) { selectedArticle.unread = !selectedArticle.unread; saveArticleUnread(selectedArticle); - if (hf != null) hf.notifyUpdated(); + + hf.notifyItemChanged(Application.getArticles().indexOf(selectedArticle)); } } return true; @@ -1081,8 +1116,6 @@ article.score = Integer.parseInt(edit.getText().toString()); } public void setArticlesUnread(final ArticleList articles, int mode) { - ApiRequest req = new ApiRequest(getApplicationContext()); - setArticleField(articles, Article.UPDATE_FIELD_UNREAD, mode); } @@ -1099,11 +1132,19 @@ article.score = Integer.parseInt(edit.getText().toString()); protected void onPostExecute(JsonElement result) { Log.d(TAG, "setArticleField operation complete"); - HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); - if (hf != null) hf.notifyUpdated(); + // currently this is generally handled before operation completes (but after POJO is modified) + /* HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); ArticlePager ap = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); - if (ap != null) ap.notifyUpdated(); + + for (Article a : articles) { + int position = Application.getArticles().getPositionById(a.id); + + if (position != -1) { + if (hf != null) hf.notifyItemChanged(position); + if (ap != null) ap.notifyItemChanged(position); + } + } */ } }; @@ -1144,11 +1185,30 @@ article.score = Integer.parseInt(edit.getText().toString()); Article article = Application.getArticles().getById(ap.getSelectedArticleId()); if (article != null) { + m_menu.findItem(R.id.toggle_marked).setIcon(article.marked ? R.drawable.baseline_star_24 : R.drawable.baseline_star_outline_24); - m_menu.findItem(R.id.toggle_published).setIcon(article.published ? R.drawable.baseline_check_box_24 : - R.drawable.baseline_rss_feed_24); + // TODO we probably shouldn't do this all the time + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + TypedValue tvTertiary = new TypedValue(); + getTheme().resolveAttribute(R.attr.colorTertiary, tvTertiary, true); + + ColorStateList colorStateTertiary = ColorStateList.valueOf(ContextCompat.getColor(this, tvTertiary.resourceId)); + + TypedValue tvNormal = new TypedValue(); + getTheme().resolveAttribute(R.attr.colorControlNormal, tvNormal, true); + + ColorStateList colorStateNormal = ColorStateList.valueOf(ContextCompat.getColor(this, tvNormal.resourceId)); + + m_menu.findItem(R.id.toggle_published).setIconTintList(article.published ? colorStateTertiary : colorStateNormal); + m_menu.findItem(R.id.toggle_marked).setIconTintList(article.marked ? colorStateTertiary : colorStateNormal); + + } else { + m_menu.findItem(R.id.toggle_published).setIcon(article.published ? R.drawable.rss_box : + R.drawable.baseline_rss_feed_24); + } + } } @@ -1189,12 +1249,6 @@ article.score = Integer.parseInt(edit.getText().toString()); if (hf != null) { hf.refresh(false); } - - ArticlePager af = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); - - if (af != null) { - af.refresh(false); - } } } @@ -1363,15 +1417,6 @@ article.score = Integer.parseInt(edit.getText().toString()); return m_lastImageHitTestUrl; } - public boolean isWifiConnected() { - NetworkInfo wifi = m_cmgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI); - - if (wifi != null) - return wifi.isConnected(); - - return false; - } - public int getResizeWidth() { Display display = getWindowManager().getDefaultDisplay(); Point size = new Point(); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/share/CommonActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/share/CommonActivity.java index 63458532..9c9187d9 100644 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/share/CommonActivity.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/share/CommonActivity.java @@ -10,7 +10,6 @@ public class CommonActivity extends Activity { private final String TAG = this.getClass().getSimpleName(); private boolean m_smallScreenMode = true; - private boolean m_compatMode = false; protected void setSmallScreen(boolean smallScreen) { Log.d(TAG, "m_smallScreenMode=" + smallScreen); @@ -27,23 +26,10 @@ public class CommonActivity extends Activity { toast.show(); } - @Override - public void onCreate(Bundle savedInstanceState) { - m_compatMode = android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB; - - Log.d(TAG, "m_compatMode=" + m_compatMode); - - super.onCreate(savedInstanceState); - } - public boolean isSmallScreen() { return m_smallScreenMode; } - public boolean isCompatMode() { - return m_compatMode; - } - public boolean isPortrait() { Display display = getWindowManager().getDefaultDisplay(); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/share/ShareActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/share/ShareActivity.java index 3a1553b6..66a77aef 100644 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/share/ShareActivity.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/share/ShareActivity.java @@ -86,7 +86,7 @@ public class ShareActivity extends CommonShareActivity { protected void onPostExecute(JsonElement result) { setProgressBarIndeterminateVisibility(false); - if (m_lastError != ApiCommon.ApiError.NO_ERROR) { + if (m_lastError != ApiCommon.ApiError.UNKNOWN_ERROR) { toast(getErrorMessage()); } else { toast(R.string.share_article_posted); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/share/SubscribeActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/share/SubscribeActivity.java index e71583d3..82e2d52d 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/share/SubscribeActivity.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/share/SubscribeActivity.java @@ -157,7 +157,7 @@ public class SubscribeActivity extends CommonShareActivity { protected void onPostExecute(JsonElement result) { m_progressBar.setVisibility(View.INVISIBLE); - if (m_lastError != ApiCommon.ApiError.NO_ERROR) { + if (m_lastError != ApiCommon.ApiError.UNKNOWN_ERROR) { toast(getErrorMessage()); } else { try { @@ -259,7 +259,7 @@ public class SubscribeActivity extends CommonShareActivity { protected void onPostExecute(JsonElement result) { m_progressBar.setVisibility(View.INVISIBLE); - if (m_lastError != ApiCommon.ApiError.NO_ERROR) { + if (m_lastError != ApiCommon.ApiError.UNKNOWN_ERROR) { toast(getErrorMessage()); } else { JsonArray content = result.getAsJsonArray(); 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 7d476ad6..f0795dd8 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 @@ -14,7 +14,6 @@ import java.util.regex.Pattern; // TODO: serialize Labels public class Article implements Parcelable { - public static final int TYPE_LOADMORE = -1; public static final int TYPE_AMR_FOOTER = -2; public static final int FLAVOR_KIND_ALBUM = 1; @@ -69,9 +68,8 @@ public class Article implements Parcelable { transient public String flavorStreamUri; transient public String youtubeVid; transient public List<Element> mediaList = new ArrayList<>(); - transient public int flavorViewHeight; - public Article(Parcel in) { + public Article(Parcel in) { readFromParcel(in); } @@ -194,8 +192,44 @@ public class Article implements Parcelable { public Article(int id) { this.id = id; this.title = "ID:" + id; - this.link = ""; - this.tags = new ArrayList<>(); + fixNullFields(); + } + + public Article(Article clone) { + id = clone.id; + unread = clone.unread; + marked = clone.marked; + published = clone.published; + score = clone.score; + updated = clone.updated; + is_updated = clone.is_updated; + title = clone.title; + link = clone.link; + feed_id = clone.feed_id; + tags = clone.tags; + attachments = clone.attachments; + content = clone.content; + excerpt = clone.excerpt; + labels = clone.labels; + feed_title = clone.feed_title; + comments_count = clone.comments_count; + comments_link = clone.comments_link; + always_display_attachments = clone.always_display_attachments; + author = clone.author; + note = clone.note; + selected = clone.selected; + flavor_image = clone.flavor_image; + flavor_stream = clone.flavor_stream; + flavor_kind = clone.flavor_kind; + site_url = clone.site_url; + + articleDoc = clone.articleDoc; + flavorImage = clone.flavorImage; + + flavorImageUri = clone.flavorImageUri; + flavorStreamUri = clone.flavorStreamUri; + youtubeVid = clone.youtubeVid; + mediaList = new ArrayList<>(clone.mediaList); } @Override @@ -262,13 +296,9 @@ public class Article implements Parcelable { } public boolean equalsById(Article article) { - if (article != null && id == article.id) { - return true; - } else { - return false; - } + return article != null && id == article.id; } - + @SuppressWarnings("rawtypes") public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @@ -280,4 +310,14 @@ public class Article implements Parcelable { return new Article[size]; } }; + + /** set fields which might be missing during JSON deserialization to sane values */ + public void fixNullFields() { + if (note == null) note = ""; + if (link == null) link = ""; + if (tags == null) tags = new ArrayList<>(); + if (note == null) note = ""; + if (excerpt == null) excerpt = ""; + if (content == null) content = ""; + } } diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/types/ArticleList.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/types/ArticleList.java index 873b311b..6724acb0 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/types/ArticleList.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/types/ArticleList.java @@ -1,8 +1,5 @@ package org.fox.ttrss.types; -import android.os.Parcel; -import android.os.Parcelable; - import java.util.ListIterator; import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; @@ -26,6 +23,10 @@ public class ArticleList extends CopyOnWriteArrayList<Article> { public ArticleList() { } + public ArticleList(ArticleList clone) { + this.addAll(clone); + } + public ArticleList getWithoutFooters() { return this.stream().filter(a -> { return a.id > 0; }).collect(Collectors.toCollection(ArticleList::new)); } @@ -34,22 +35,6 @@ public class ArticleList extends CopyOnWriteArrayList<Article> { return this.stream().filter(a -> { return a.unread; }).count(); } - public long getSizeWithoutFooters() { - return this.stream().filter(a -> { return a.id > 0; }).count(); - } - - /** strips all trailing items with negative IDs (Article.TYPE_LOADMORE, Article.TYPE_AMR_FOOTER) */ - public void stripFooters() { - for (ListIterator<Article> iterator = this.listIterator(size()); iterator.hasPrevious();) { - final Article article = iterator.previous(); - - if (article.id < 0) - this.remove(article); - else - break; - } - } - public int getPositionById(int id) { for (int i = 0; i < size(); i++) { if (get(i).id == id) { diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/util/ArticleDiffItemCallback.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/ArticleDiffItemCallback.java new file mode 100644 index 00000000..b037eea0 --- /dev/null +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/ArticleDiffItemCallback.java @@ -0,0 +1,21 @@ +package org.fox.ttrss.util; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DiffUtil; + +import org.fox.ttrss.types.Article; + +public class ArticleDiffItemCallback extends DiffUtil.ItemCallback<Article> { + private final String TAG = this.getClass().getSimpleName(); + @Override + public boolean areItemsTheSame(@NonNull Article a1, @NonNull Article a2) { + return a1.id == a2.id; + } + + @Override + public boolean areContentsTheSame(@NonNull Article a1, @NonNull Article a2) { + return a1.id == a2.id && a1.unread == a2.unread && a1.marked == a2.marked + && a1.selected == a2.selected && a1.published == a2.published + && a1.note.equals(a2.note); + } +} diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/util/DiffFragmentStateAdapter.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/DiffFragmentStateAdapter.java new file mode 100644 index 00000000..c423b02d --- /dev/null +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/DiffFragmentStateAdapter.java @@ -0,0 +1,54 @@ +package org.fox.ttrss.util; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.lifecycle.Lifecycle; +import androidx.recyclerview.widget.AsyncListDiffer; +import androidx.recyclerview.widget.DiffUtil; +import androidx.viewpager2.adapter.FragmentStateAdapter; + +import java.util.List; + +// https://gist.github.com/Gnzlt/7e8a23ba0c3b046ed33c824b284d7270 +public abstract class DiffFragmentStateAdapter<T> extends FragmentStateAdapter { + + private final AsyncListDiffer<T> differ; + + protected DiffFragmentStateAdapter(FragmentActivity fragmentActivity, DiffUtil.ItemCallback<T> diffCallback) { + super(fragmentActivity); + differ = new AsyncListDiffer<>(this, diffCallback); + } + + protected DiffFragmentStateAdapter(Fragment fragment, DiffUtil.ItemCallback<T> diffCallback) { + super(fragment); + differ = new AsyncListDiffer<>(this, diffCallback); + } + + protected DiffFragmentStateAdapter(FragmentManager fragmentManager, Lifecycle lifecycle, DiffUtil.ItemCallback<T> diffCallback) { + super(fragmentManager, lifecycle); + differ = new AsyncListDiffer<>(this, diffCallback); + } + + public void submitList(List<T> list, Runnable commitCallback) { + differ.submitList(list, commitCallback); + } + + public void submitList(List<T> list) { + differ.submitList(list, null); + } + + public List<T> getCurrentList() { + return differ.getCurrentList(); + } + + protected T getItem(int position) { + return differ.getCurrentList().get(position); + } + + @Override + public int getItemCount() { + return differ.getCurrentList().size(); + } +} + diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/util/HeadlinesRequest.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/HeadlinesRequest.java deleted file mode 100755 index 82698ffb..00000000 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/util/HeadlinesRequest.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.fox.ttrss.util; - -import android.content.Context; -import android.util.Log; - -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.reflect.TypeToken; - -import org.fox.ttrss.ApiCommon; -import org.fox.ttrss.ApiRequest; -import org.fox.ttrss.Application; -import org.fox.ttrss.OnlineActivity; -import org.fox.ttrss.types.Article; -import org.fox.ttrss.types.ArticleList; - -import java.lang.reflect.Type; -import java.util.List; - -public class HeadlinesRequest extends ApiRequest { - private final String TAG = this.getClass().getSimpleName(); - - private int m_offset = 0; - private final OnlineActivity m_activity; - protected boolean m_firstIdChanged = false; - protected int m_firstId = 0; - protected int m_amountLoaded = 0; - - public HeadlinesRequest(Context context, OnlineActivity activity, ArticleList articles) { - super(context); - - m_activity = activity; - } - - protected void onPostExecute(JsonElement result) { - if (result != null) { - try { - JsonArray content = result.getAsJsonArray(); - if (content != null) { - final List<Article> articlesJson; - final JsonObject header; - - if (m_activity.getApiLevel() >= 12) { - header = content.get(0).getAsJsonObject(); - - //Log.d(TAG, "headerID:" + header.get("top_id_changed")); - - m_firstIdChanged = header.get("first_id_changed") != null; - try { - m_firstId = header.get("first_id").getAsInt(); - } catch (NumberFormatException e) { - m_firstId = 0; - } - - Log.d(TAG, "firstID=" + m_firstId + " firstIdChanged=" + m_firstIdChanged); - - Type listType = new TypeToken<List<Article>>() {}.getType(); - articlesJson = new Gson().fromJson(content.get(1), listType); - } else { - Type listType = new TypeToken<List<Article>>() {}.getType(); - articlesJson = new Gson().fromJson(content, listType); - } - - ArticleList articles = Application.getArticles(); - - if (m_offset == 0) - articles.clear(); - else - articles.stripFooters(); - - m_amountLoaded = articlesJson.size(); - - for (Article f : articlesJson) - if (!articles.containsId(f.id)) { - f.collectMediaInfo(); - f.cleanupExcerpt(); - articles.add(f); - } - - return; - } - - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (m_lastError == ApiCommon.ApiError.LOGIN_FAILED) { - m_activity.login(); - } else { - - if (m_lastErrorMessage != null) { - m_activity.toast(m_activity.getString(getErrorMessage()) + "\n" + m_lastErrorMessage); - } else { - m_activity.toast(getErrorMessage()); - } - //m_activity.setLoadingStatus(getErrorMessage(), false); - } - } - - public void setOffset(int skip) { - m_offset = skip; - } -} diff --git a/org.fox.ttrss/src/main/res/drawable/ic_launcher_background_variant.xml b/org.fox.ttrss/src/main/res/drawable/ic_launcher_background_variant.xml new file mode 100644 index 00000000..749ffa26 --- /dev/null +++ b/org.fox.ttrss/src/main/res/drawable/ic_launcher_background_variant.xml @@ -0,0 +1,42 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="51.06383" + android:viewportHeight="51.06383"> + <group android:translateX="-10.468085" + android:translateY="-10.468085"> + <path + android:pathData="M-9.8995,-7.7102h94.3666v92.4381h-94.3666z" + android:fillColor="#5c5c5c" + android:strokeColor="#00000000" + android:fillAlpha="1"/> + <path + android:pathData="M5.668,58.0128a8.3196,8.3198 0,1 0,16.6393 0a8.3196,8.3198 0,1 0,-16.6393 0z" + android:strokeAlpha="1" + android:strokeWidth="0.69765961" + android:fillColor="#808080" + android:strokeColor="#00000000" + android:fillAlpha="1"/> + <path + android:pathData="m45.8796,66.3326 l-11.7862,0A28.4254,28.426 0,0 0,5.668 37.9066l0,-11.7864A40.2116,40.2124 0,0 1,45.8796 66.3326Z" + android:strokeAlpha="1" + android:strokeWidth="0.69765961" + android:fillColor="#808080" + android:strokeColor="#00000000" + android:fillAlpha="1"/> + <path + android:pathData="M54.1992,66.3326A48.5312,48.5322 0,0 0,5.668 17.8004l0,-12.1331a60.6653,60.6641 90,0 1,60.6641 60.6653z" + android:strokeAlpha="1" + android:strokeWidth="2.01254654" + android:fillColor="#808080" + android:strokeColor="#00000000" + android:fillAlpha="1"/> + <path + android:pathData="M54.1992,66.3326A48.5312,48.5322 0,0 0,5.668 17.8004l0,-12.1331a60.6653,60.6641 90,0 1,60.6641 60.6653z" + android:strokeAlpha="1" + android:strokeWidth="2.01254654" + android:fillColor="#808080" + android:strokeColor="#00000000" + android:fillAlpha="1"/> + </group> +</vector> diff --git a/org.fox.ttrss/src/main/res/drawable/rss.xml b/org.fox.ttrss/src/main/res/drawable/rss.xml new file mode 100644 index 00000000..f97e14a2 --- /dev/null +++ b/org.fox.ttrss/src/main/res/drawable/rss.xml @@ -0,0 +1 @@ +<!-- drawable/rss.xml --><vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"><path android:fillColor="#000000" android:pathData="M6.18,15.64A2.18,2.18 0 0,1 8.36,17.82C8.36,19 7.38,20 6.18,20C5,20 4,19 4,17.82A2.18,2.18 0 0,1 6.18,15.64M4,4.44A15.56,15.56 0 0,1 19.56,20H16.73A12.73,12.73 0 0,0 4,7.27V4.44M4,10.1A9.9,9.9 0 0,1 13.9,20H11.07A7.07,7.07 0 0,0 4,12.93V10.1Z" /></vector>
\ No newline at end of file diff --git a/org.fox.ttrss/src/main/res/drawable/rss_box.xml b/org.fox.ttrss/src/main/res/drawable/rss_box.xml new file mode 100644 index 00000000..45b40cea --- /dev/null +++ b/org.fox.ttrss/src/main/res/drawable/rss_box.xml @@ -0,0 +1 @@ +<!-- drawable/rss_box.xml --><vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"><path android:fillColor="#000000" android:pathData="M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3M7.5,15A1.5,1.5 0 0,0 6,16.5A1.5,1.5 0 0,0 7.5,18A1.5,1.5 0 0,0 9,16.5A1.5,1.5 0 0,0 7.5,15M6,10V12A6,6 0 0,1 12,18H14A8,8 0 0,0 6,10M6,6V8A10,10 0 0,1 16,18H18A12,12 0 0,0 6,6Z" /></vector>
\ No newline at end of file diff --git a/org.fox.ttrss/src/main/res/layout-sw600dp-land/activity_detail.xml b/org.fox.ttrss/src/main/res/layout-sw600dp-land/activity_detail.xml index 59c1b086..823afb9b 100644 --- a/org.fox.ttrss/src/main/res/layout-sw600dp-land/activity_detail.xml +++ b/org.fox.ttrss/src/main/res/layout-sw600dp-land/activity_detail.xml @@ -54,7 +54,7 @@ <FrameLayout android:layout_width="match_parent" android:id="@+id/article_fragment" - app:layout_behavior=".util.DetailActivityScrollingViewBehavior" + app:layout_behavior="org.fox.ttrss.util.DetailActivityScrollingViewBehavior" android:layout_height="match_parent"/> <com.google.android.material.bottomappbar.BottomAppBar diff --git a/org.fox.ttrss/src/main/res/layout-sw600dp-land/activity_master.xml b/org.fox.ttrss/src/main/res/layout-sw600dp-land/activity_master.xml index b6a6f19d..63b8c3e2 100644 --- a/org.fox.ttrss/src/main/res/layout-sw600dp-land/activity_master.xml +++ b/org.fox.ttrss/src/main/res/layout-sw600dp-land/activity_master.xml @@ -61,7 +61,7 @@ android:id="@+id/headlines_fragment" android:layout_width="match_parent" android:layout_height="wrap_content" - app:layout_behavior=".util.FabAwareScrollingViewBehavior" /> + app:layout_behavior="org.fox.ttrss.util.FabAwareScrollingViewBehavior" /> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/master_fab" diff --git a/org.fox.ttrss/src/main/res/layout/activity_gallery.xml b/org.fox.ttrss/src/main/res/layout/activity_gallery.xml index f44bb74b..b0f67761 100644 --- a/org.fox.ttrss/src/main/res/layout/activity_gallery.xml +++ b/org.fox.ttrss/src/main/res/layout/activity_gallery.xml @@ -17,7 +17,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="0" - app:icon="?ic_dots_vertical" + app:icon="@drawable/baseline_more_vert_24" android:layout_alignParentRight="true" android:layout_marginTop="48dp" app:iconTint="?colorTertiary" /> diff --git a/org.fox.ttrss/src/main/res/layout/feeds_goback.xml b/org.fox.ttrss/src/main/res/layout/feeds_goback.xml index f4c580a3..75ba8fe1 100755 --- a/org.fox.ttrss/src/main/res/layout/feeds_goback.xml +++ b/org.fox.ttrss/src/main/res/layout/feeds_goback.xml @@ -20,7 +20,7 @@ android:layout_height="21dp" android:layout_weight="0" android:scaleType="fitXY" - android:src="?ic_go_back" + android:src="@drawable/baseline_arrow_back_24" app:tint="?colorTertiary" /> <TextView diff --git a/org.fox.ttrss/src/main/res/layout/feeds_row.xml b/org.fox.ttrss/src/main/res/layout/feeds_row.xml index 32e20c26..0f9c4e54 100755 --- a/org.fox.ttrss/src/main/res/layout/feeds_row.xml +++ b/org.fox.ttrss/src/main/res/layout/feeds_row.xml @@ -23,7 +23,7 @@ android:layout_weight="0" android:scaleType="fitXY" app:tint="?colorOnPrimaryContainer" - android:src="?ic_rss_box" /> + android:src="@drawable/rss" /> <TextView android:id="@+id/title" diff --git a/org.fox.ttrss/src/main/res/layout/feeds_row_selected.xml b/org.fox.ttrss/src/main/res/layout/feeds_row_selected.xml index c12c732d..031c2116 100755 --- a/org.fox.ttrss/src/main/res/layout/feeds_row_selected.xml +++ b/org.fox.ttrss/src/main/res/layout/feeds_row_selected.xml @@ -29,7 +29,7 @@ android:layout_weight="0" android:scaleType="fitXY" app:tint="?colorOnTertiaryContainer" - android:src="?ic_rss_box" /> + android:src="@drawable/rss" /> <TextView android:id="@+id/title" diff --git a/org.fox.ttrss/src/main/res/layout/feeds_row_toggle.xml b/org.fox.ttrss/src/main/res/layout/feeds_row_toggle.xml index d4451bbe..ad76bca5 100755 --- a/org.fox.ttrss/src/main/res/layout/feeds_row_toggle.xml +++ b/org.fox.ttrss/src/main/res/layout/feeds_row_toggle.xml @@ -20,7 +20,7 @@ android:layout_weight="0" android:scaleType="fitXY" app:tint="?colorOnPrimaryContainer" - android:src="?ic_rss_box" /> + android:src="@drawable/rss_box" /> <TextView android:id="@+id/title" diff --git a/org.fox.ttrss/src/main/res/layout/fragment_headlines.xml b/org.fox.ttrss/src/main/res/layout/fragment_headlines.xml index 2783a1e4..647c3ae9 100755 --- a/org.fox.ttrss/src/main/res/layout/fragment_headlines.xml +++ b/org.fox.ttrss/src/main/res/layout/fragment_headlines.xml @@ -12,7 +12,6 @@ <org.fox.ttrss.util.ContextMenuRecyclerView android:id="@+id/headlines_list" android:background="?colorSurfaceContainer" - android:drawSelectorOnTop="true" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent" /> diff --git a/org.fox.ttrss/src/main/res/layout/headlines_row.xml b/org.fox.ttrss/src/main/res/layout/headlines_row.xml index 52bbae56..3659589d 100755 --- a/org.fox.ttrss/src/main/res/layout/headlines_row.xml +++ b/org.fox.ttrss/src/main/res/layout/headlines_row.xml @@ -212,7 +212,7 @@ android:layout_weight="0" android:paddingLeft="4dp" android:paddingRight="4dp" - app:icon="?ic_action_trending_flat" /> + app:icon="@drawable/baseline_trending_flat_24" /> <com.google.android.material.button.MaterialButton style="?attr/materialIconButtonStyle" @@ -222,7 +222,7 @@ android:layout_weight="0" android:paddingLeft="4dp" android:paddingRight="4dp" - app:icon="?ic_attachment" /> + app:icon="@drawable/baseline_attachment_24" /> <com.google.android.material.button.MaterialButton style="?attr/materialIconButtonStyle" @@ -232,7 +232,7 @@ android:layout_weight="0" android:paddingLeft="4dp" android:paddingRight="4dp" - app:icon="?ic_star_outline" /> + app:icon="@drawable/baseline_star_outline_24" /> <com.google.android.material.button.MaterialButton style="?attr/materialIconButtonStyle" @@ -242,7 +242,7 @@ android:layout_weight="0" android:paddingLeft="4dp" android:paddingRight="4dp" - app:icon="?ic_rss_box" /> + app:icon="@drawable/rss" /> <com.google.android.material.button.MaterialButton style="?attr/materialIconButtonStyle" @@ -252,7 +252,7 @@ android:layout_weight="0" android:paddingLeft="4dp" android:paddingRight="4dp" - app:icon="?ic_dots_vertical" /> + app:icon="@drawable/baseline_more_vert_24" /> </LinearLayout> </TableRow> </TableLayout> diff --git a/org.fox.ttrss/src/main/res/layout/headlines_row_compact.xml b/org.fox.ttrss/src/main/res/layout/headlines_row_compact.xml index 352aad91..7090668a 100755 --- a/org.fox.ttrss/src/main/res/layout/headlines_row_compact.xml +++ b/org.fox.ttrss/src/main/res/layout/headlines_row_compact.xml @@ -103,6 +103,6 @@ android:layout_gravity="end" android:layout_height="24dp" android:layout_weight="0.5" - app:icon="?ic_star_outline" /> + app:icon="@drawable/baseline_star_outline_24" /> </LinearLayout> </LinearLayout>
\ No newline at end of file diff --git a/org.fox.ttrss/src/main/res/layout/headlines_row_compact_active.xml b/org.fox.ttrss/src/main/res/layout/headlines_row_compact_active.xml index 5721dcb8..72ae99b8 100755 --- a/org.fox.ttrss/src/main/res/layout/headlines_row_compact_active.xml +++ b/org.fox.ttrss/src/main/res/layout/headlines_row_compact_active.xml @@ -101,8 +101,9 @@ style="?attr/materialIconButtonStyle" android:layout_width="wrap_content" android:paddingEnd="0dp" + android:layout_gravity="end" android:layout_height="24dp" android:layout_weight="0.5" - app:icon="?ic_star_outline" /> + app:icon="@drawable/baseline_star_outline_24" /> </LinearLayout> </LinearLayout>
\ No newline at end of file diff --git a/org.fox.ttrss/src/main/res/layout/headlines_row_compact_active_unread.xml b/org.fox.ttrss/src/main/res/layout/headlines_row_compact_active_unread.xml index 06813e04..b2b3a21e 100755 --- a/org.fox.ttrss/src/main/res/layout/headlines_row_compact_active_unread.xml +++ b/org.fox.ttrss/src/main/res/layout/headlines_row_compact_active_unread.xml @@ -105,6 +105,6 @@ android:layout_gravity="end" android:layout_height="24dp" android:layout_weight="0.5" - app:icon="?ic_star_outline" /> + app:icon="@drawable/baseline_star_outline_24" /> </LinearLayout> </LinearLayout>
\ No newline at end of file diff --git a/org.fox.ttrss/src/main/res/layout/headlines_row_compact_unread.xml b/org.fox.ttrss/src/main/res/layout/headlines_row_compact_unread.xml index 6aa1bdcd..2fbbe062 100755 --- a/org.fox.ttrss/src/main/res/layout/headlines_row_compact_unread.xml +++ b/org.fox.ttrss/src/main/res/layout/headlines_row_compact_unread.xml @@ -105,6 +105,6 @@ android:layout_gravity="end" android:layout_height="24dp" android:layout_weight="0.5" - app:icon="?ic_star_outline" /> + app:icon="@drawable/baseline_star_outline_24" /> </LinearLayout> </LinearLayout>
\ No newline at end of file diff --git a/org.fox.ttrss/src/main/res/layout/headlines_row_unread.xml b/org.fox.ttrss/src/main/res/layout/headlines_row_unread.xml index 4b20d9cb..3365f476 100755 --- a/org.fox.ttrss/src/main/res/layout/headlines_row_unread.xml +++ b/org.fox.ttrss/src/main/res/layout/headlines_row_unread.xml @@ -212,7 +212,7 @@ android:layout_weight="0" android:paddingLeft="4dp" android:paddingRight="4dp" - app:icon="?ic_action_trending_flat" /> + app:icon="@drawable/baseline_trending_flat_24" /> <com.google.android.material.button.MaterialButton style="?attr/materialIconButtonStyle" @@ -222,7 +222,7 @@ android:layout_weight="0" android:paddingLeft="4dp" android:paddingRight="4dp" - app:icon="?ic_attachment" /> + app:icon="@drawable/baseline_attachment_24" /> <com.google.android.material.button.MaterialButton style="?attr/materialIconButtonStyle" @@ -232,7 +232,7 @@ android:layout_weight="0" android:paddingLeft="4dp" android:paddingRight="4dp" - app:icon="?ic_star_outline" /> + app:icon="@drawable/baseline_star_outline_24" /> <com.google.android.material.button.MaterialButton style="?attr/materialIconButtonStyle" @@ -242,7 +242,7 @@ android:layout_weight="0" android:paddingLeft="4dp" android:paddingRight="4dp" - app:icon="?ic_rss_box" /> + app:icon="@drawable/rss" /> <com.google.android.material.button.MaterialButton style="?attr/materialIconButtonStyle" @@ -252,7 +252,7 @@ android:layout_weight="0" android:paddingLeft="4dp" android:paddingRight="4dp" - app:icon="?ic_dots_vertical" /> + app:icon="@drawable/baseline_more_vert_24" /> </LinearLayout> </TableRow> </TableLayout> diff --git a/org.fox.ttrss/src/main/res/layout/layout_detail_phone.xml b/org.fox.ttrss/src/main/res/layout/layout_detail_phone.xml index 55a6ba77..4e75d44b 100644 --- a/org.fox.ttrss/src/main/res/layout/layout_detail_phone.xml +++ b/org.fox.ttrss/src/main/res/layout/layout_detail_phone.xml @@ -14,7 +14,7 @@ <FrameLayout android:id="@+id/article_fragment" - app:layout_behavior=".util.DetailActivityScrollingViewBehavior" + app:layout_behavior="org.fox.ttrss.util.DetailActivityScrollingViewBehavior" android:layout_width="match_parent" android:layout_height="match_parent"> </FrameLayout> diff --git a/org.fox.ttrss/src/main/res/layout/layout_master_phone.xml b/org.fox.ttrss/src/main/res/layout/layout_master_phone.xml index b4cb6b59..e32d5fbe 100644 --- a/org.fox.ttrss/src/main/res/layout/layout_master_phone.xml +++ b/org.fox.ttrss/src/main/res/layout/layout_master_phone.xml @@ -29,7 +29,7 @@ <FrameLayout android:id="@+id/headlines_fragment" - app:layout_behavior=".util.FabAwareScrollingViewBehavior" + app:layout_behavior="org.fox.ttrss.util.FabAwareScrollingViewBehavior" android:layout_width="match_parent" android:layout_height="wrap_content"/> diff --git a/org.fox.ttrss/src/main/res/mipmap-anydpi-v26/ic_launcher_variant.xml b/org.fox.ttrss/src/main/res/mipmap-anydpi-v26/ic_launcher_variant.xml new file mode 100644 index 00000000..d49922f9 --- /dev/null +++ b/org.fox.ttrss/src/main/res/mipmap-anydpi-v26/ic_launcher_variant.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@drawable/ic_launcher_background_variant"/> + <foreground android:drawable="@drawable/ic_launcher_foreground"/> +</adaptive-icon>
\ No newline at end of file diff --git a/org.fox.ttrss/src/main/res/values-night/themes.xml b/org.fox.ttrss/src/main/res/values-night/themes.xml index 7d54a029..e11ef016 100644 --- a/org.fox.ttrss/src/main/res/values-night/themes.xml +++ b/org.fox.ttrss/src/main/res/values-night/themes.xml @@ -3,29 +3,6 @@ <item name="windowActionModeOverlay">true</item> <item name="preferenceTheme">@style/AppPreferenceThemeOverlay</item> - <item name="ic_rss_box">@drawable/baseline_rss_feed_24</item> - <item name="ic_checkbox_marked">@drawable/baseline_check_box_24</item> - <item name="ic_star">@drawable/baseline_star_24</item> - <item name="ic_star_outline">@drawable/baseline_star_outline_24</item> - <item name="ic_share">@drawable/baseline_share_24</item> - <item name="ic_inbox">@drawable/baseline_inbox_24</item> - <item name="ic_go_back">@drawable/baseline_arrow_back_24</item> - <item name="ic_settings">@drawable/baseline_settings_24</item> - <item name="ic_filter_variant">@drawable/baseline_filter_alt_24</item> - <item name="ic_cloud_download">@drawable/baseline_cloud_download_24</item> - <item name="ic_cloud_upload">@drawable/baseline_cloud_upload_24</item> - <item name="ic_archive">@drawable/baseline_archive_24</item> - <item name="ic_fresh">@drawable/baseline_local_fire_department_24</item> - <item name="ic_restore">@drawable/baseline_restore_24</item> - <item name="ic_folder_outline">@drawable/baseline_folder_open_24</item> - <item name="ic_dots_vertical">@drawable/baseline_more_vert_24</item> - <item name="ic_dots_vertical_circle">@drawable/outline_more_24</item> - <item name="ic_attachment">@drawable/baseline_attachment_24</item> - <item name="ic_attachment_vert">@drawable/baseline_attach_file_24</item> - <item name="ic_action_trending_up">@drawable/baseline_trending_up_24</item> - <item name="ic_action_trending_flat">@drawable/baseline_trending_flat_24</item> - <item name="ic_action_trending_down">@drawable/baseline_trending_down_24</item> - <item name="colorPrimary">@color/md_theme_primary</item> <item name="colorOnPrimary">@color/md_theme_onPrimary</item> <item name="colorPrimaryContainer">@color/md_theme_primaryContainer</item> diff --git a/org.fox.ttrss/src/main/res/values/attrs.xml b/org.fox.ttrss/src/main/res/values/attrs.xml index daf2323c..55344e51 100755 --- a/org.fox.ttrss/src/main/res/values/attrs.xml +++ b/org.fox.ttrss/src/main/res/values/attrs.xml @@ -1,29 +1,3 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <attr name="ic_rss_box" format="reference"/> - <attr name="ic_checkbox_marked" format="reference" /> - <attr name="ic_star" format="reference" /> - <attr name="ic_star_outline" format="reference" /> - <attr name="ic_share" format="reference" /> - <attr name="ic_go_back" format="reference" /> - <attr name="ic_settings" format="reference" /> - <attr name="ic_filter_variant" format="reference" /> - <attr name="ic_cloud_download" format="reference" /> - <attr name="ic_cloud_upload" format="reference" /> - <attr name="ic_archive" format="reference" /> - <attr name="ic_fresh" format="reference" /> - <attr name="ic_folder_outline" format="reference" /> - <attr name="ic_dots_vertical" format="reference" /> - <attr name="ic_dots_vertical_circle" format="reference" /> - <attr name="ic_attachment" format="reference" /> - <attr name="ic_attachment_vert" format="reference" /> - <declare-styleable name="ScrimInsetsView"> - <attr format="reference|color" name="insetForeground"> - </attr></declare-styleable> - <attr name="drawer_header" format="reference" /> - <attr name="ic_restore" format="reference" /> - <attr name="ic_inbox" format="reference" /> - <attr name="ic_action_trending_up" format="reference" /> - <attr name="ic_action_trending_flat" format="reference" /> - <attr name="ic_action_trending_down" format="reference" /> </resources>
\ No newline at end of file diff --git a/org.fox.ttrss/src/main/res/values/strings.xml b/org.fox.ttrss/src/main/res/values/strings.xml index 6a67013a..fb7e6309 100755 --- a/org.fox.ttrss/src/main/res/values/strings.xml +++ b/org.fox.ttrss/src/main/res/values/strings.xml @@ -303,4 +303,5 @@ <string name="check_for_updates">Check for updates</string> <string name="dont_open_anything">Nothing</string> <string name="open_on_startup">Open on startup</string> + <string name="error_success">Operation completed successfully</string> </resources> diff --git a/org.fox.ttrss/src/main/res/values/themes.xml b/org.fox.ttrss/src/main/res/values/themes.xml index 68a57811..15be8c17 100644 --- a/org.fox.ttrss/src/main/res/values/themes.xml +++ b/org.fox.ttrss/src/main/res/values/themes.xml @@ -4,29 +4,6 @@ <item name="windowActionModeOverlay">true</item> <item name="preferenceTheme">@style/AppPreferenceThemeOverlay</item> - <item name="ic_rss_box">@drawable/baseline_rss_feed_24</item> - <item name="ic_checkbox_marked">@drawable/baseline_check_box_24</item> - <item name="ic_star">@drawable/baseline_star_24</item> - <item name="ic_star_outline">@drawable/baseline_star_outline_24</item> - <item name="ic_share">@drawable/baseline_share_24</item> - <item name="ic_inbox">@drawable/baseline_inbox_24</item> - <item name="ic_go_back">@drawable/baseline_arrow_back_24</item> - <item name="ic_settings">@drawable/baseline_settings_24</item> - <item name="ic_filter_variant">@drawable/baseline_filter_alt_24</item> - <item name="ic_cloud_download">@drawable/baseline_cloud_download_24</item> - <item name="ic_cloud_upload">@drawable/baseline_cloud_upload_24</item> - <item name="ic_archive">@drawable/baseline_archive_24</item> - <item name="ic_fresh">@drawable/baseline_local_fire_department_24</item> - <item name="ic_restore">@drawable/baseline_restore_24</item> - <item name="ic_folder_outline">@drawable/baseline_folder_open_24</item> - <item name="ic_dots_vertical">@drawable/baseline_more_vert_24</item> - <item name="ic_dots_vertical_circle">@drawable/outline_more_24</item> - <item name="ic_attachment">@drawable/baseline_attachment_24</item> - <item name="ic_attachment_vert">@drawable/baseline_attach_file_24</item> - <item name="ic_action_trending_up">@drawable/baseline_trending_up_24</item> - <item name="ic_action_trending_flat">@drawable/baseline_trending_flat_24</item> - <item name="ic_action_trending_down">@drawable/baseline_trending_down_24</item> - <item name="colorPrimary">@color/md_theme_primary</item> <item name="colorOnPrimary">@color/md_theme_onPrimary</item> <item name="colorPrimaryContainer">@color/md_theme_primaryContainer</item> diff --git a/org.fox.ttrss/src/main/res/xml/preferences.xml b/org.fox.ttrss/src/main/res/xml/preferences.xml index 81fbd5f1..8d064587 100755 --- a/org.fox.ttrss/src/main/res/xml/preferences.xml +++ b/org.fox.ttrss/src/main/res/xml/preferences.xml @@ -44,7 +44,7 @@ android:title="@string/sort_feeds_by_unread" /> <SwitchPreferenceCompat - android:defaultValue="false" + android:defaultValue="true" android:key="enable_cats" android:title="@string/enable_cats" /> @@ -108,7 +108,6 @@ <SwitchPreferenceCompat android:defaultValue="true" - android:dependency="headlines_mark_read_scroll" android:key="headlines_swipe_to_dismiss" android:summary="@string/pref_headlines_swipe_to_dismiss_long" android:title="@string/pref_headlines_swipe_to_dismiss" /> diff --git a/org.fox.ttrss/src_drawable/s_dashclock.svg b/org.fox.ttrss/src_drawable/s_dashclock.svg deleted file mode 100644 index f4be84f9..00000000 --- a/org.fox.ttrss/src_drawable/s_dashclock.svg +++ /dev/null @@ -1,1071 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="72" - height="72" - id="svg2985" - version="1.1" - inkscape:version="0.48.4 r9939" - inkscape:export-filename="C:\Users\fox\workspace\Tiny-Tiny-RSS-for-Honeycomb\res\drawable-xhdpi\dashclock.png" - inkscape:export-xdpi="120" - inkscape:export-ydpi="120" - sodipodi:docname="s_dashclock.svg"> - <defs - id="defs2987"> - <filter - id="filter4035" - inkscape:label="Glow" - inkscape:menu="Shadows and Glows" - inkscape:menu-tooltip="Glow of object's own color at the edges" - color-interpolation-filters="sRGB"> - <feGaussianBlur - id="feGaussianBlur4037" - stdDeviation="5" - result="result91" /> - <feComposite - id="feComposite4039" - in2="result91" - in="SourceGraphic" - operator="over" /> - </filter> - <filter - id="filter4044" - inkscape:label="Drop shadow" - width="1.5" - height="1.5" - x="-.25" - y="-.25"> - <feGaussianBlur - id="feGaussianBlur4046" - in="SourceAlpha" - stdDeviation="2" - result="blur" /> - <feColorMatrix - id="feColorMatrix4048" - result="bluralpha" - type="matrix" - values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0 " /> - <feOffset - id="feOffset4050" - in="bluralpha" - dx="1" - dy="1" - result="offsetBlur" /> - <feMerge - id="feMerge4052"> - <feMergeNode - id="feMergeNode4054" - in="offsetBlur" /> - <feMergeNode - id="feMergeNode4056" - in="SourceGraphic" /> - </feMerge> - </filter> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient3890" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" - gradientUnits="userSpaceOnUse" /> - <linearGradient - id="RSSg" - y2="225.94" - x2="225.94" - y1="30.059999" - x1="30.059999" - gradientUnits="userSpaceOnUse"> - <stop - id="stop3838" - stop-color="#E3702D" - offset="0.0" /> - <stop - id="stop3840" - stop-color="#EA7D31" - offset="0.1071" /> - <stop - id="stop3842" - stop-color="#F69537" - offset="0.3503" /> - <stop - id="stop3844" - stop-color="#FB9E3A" - offset="0.5" /> - <stop - id="stop3846" - stop-color="#EA7C31" - offset="0.7016" /> - <stop - id="stop3848" - stop-color="#DE642B" - offset="0.8866" /> - <stop - id="stop3850" - stop-color="#D95B29" - offset="1.0" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient5363" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" - gradientUnits="userSpaceOnUse" /> - <linearGradient - id="linearGradient3277" - y2="225.94" - x2="225.94" - y1="30.059999" - x1="30.059999" - gradientUnits="userSpaceOnUse"> - <stop - id="stop3279" - stop-color="#E3702D" - offset="0.0" /> - <stop - id="stop3281" - stop-color="#EA7D31" - offset="0.1071" /> - <stop - id="stop3283" - stop-color="#F69537" - offset="0.3503" /> - <stop - id="stop3285" - stop-color="#FB9E3A" - offset="0.5" /> - <stop - id="stop3287" - stop-color="#EA7C31" - offset="0.7016" /> - <stop - id="stop3289" - stop-color="#DE642B" - offset="0.8866" /> - <stop - id="stop3291" - stop-color="#D95B29" - offset="1.0" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient5668" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - id="linearGradient3294" - y2="225.94" - x2="225.94" - y1="30.059999" - x1="30.059999" - gradientUnits="userSpaceOnUse"> - <stop - id="stop3296" - stop-color="#E3702D" - offset="0.0" /> - <stop - id="stop3298" - stop-color="#EA7D31" - offset="0.1071" /> - <stop - id="stop3300" - stop-color="#F69537" - offset="0.3503" /> - <stop - id="stop3302" - stop-color="#FB9E3A" - offset="0.5" /> - <stop - id="stop3304" - stop-color="#EA7C31" - offset="0.7016" /> - <stop - id="stop3306" - stop-color="#DE642B" - offset="0.8866" /> - <stop - id="stop3308" - stop-color="#D95B29" - offset="1.0" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient5670" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - id="linearGradient3311" - y2="225.94" - x2="225.94" - y1="30.059999" - x1="30.059999" - gradientUnits="userSpaceOnUse"> - <stop - id="stop3313" - stop-color="#E3702D" - offset="0.0" /> - <stop - id="stop3315" - stop-color="#EA7D31" - offset="0.1071" /> - <stop - id="stop3317" - stop-color="#F69537" - offset="0.3503" /> - <stop - id="stop3319" - stop-color="#FB9E3A" - offset="0.5" /> - <stop - id="stop3321" - stop-color="#EA7C31" - offset="0.7016" /> - <stop - id="stop3323" - stop-color="#DE642B" - offset="0.8866" /> - <stop - id="stop3325" - stop-color="#D95B29" - offset="1.0" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient5652" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - id="linearGradient3328" - y2="225.94" - x2="225.94" - y1="30.059999" - x1="30.059999" - gradientUnits="userSpaceOnUse"> - <stop - id="stop3330" - stop-color="#E3702D" - offset="0.0" /> - <stop - id="stop3332" - stop-color="#EA7D31" - offset="0.1071" /> - <stop - id="stop3334" - stop-color="#F69537" - offset="0.3503" /> - <stop - id="stop3336" - stop-color="#FB9E3A" - offset="0.5" /> - <stop - id="stop3338" - stop-color="#EA7C31" - offset="0.7016" /> - <stop - id="stop3340" - stop-color="#DE642B" - offset="0.8866" /> - <stop - id="stop3342" - stop-color="#D95B29" - offset="1.0" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient5654" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - id="linearGradient3345" - y2="225.94" - x2="225.94" - y1="30.059999" - x1="30.059999" - gradientUnits="userSpaceOnUse"> - <stop - id="stop3347" - stop-color="#E3702D" - offset="0.0" /> - <stop - id="stop3349" - stop-color="#EA7D31" - offset="0.1071" /> - <stop - id="stop3351" - stop-color="#F69537" - offset="0.3503" /> - <stop - id="stop3353" - stop-color="#FB9E3A" - offset="0.5" /> - <stop - id="stop3355" - stop-color="#EA7C31" - offset="0.7016" /> - <stop - id="stop3357" - stop-color="#DE642B" - offset="0.8866" /> - <stop - id="stop3359" - stop-color="#D95B29" - offset="1.0" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient5656" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - id="linearGradient3362" - y2="225.94" - x2="225.94" - y1="30.059999" - x1="30.059999" - gradientUnits="userSpaceOnUse"> - <stop - id="stop3364" - stop-color="#E3702D" - offset="0.0" /> - <stop - id="stop3366" - stop-color="#EA7D31" - offset="0.1071" /> - <stop - id="stop3368" - stop-color="#F69537" - offset="0.3503" /> - <stop - id="stop3370" - stop-color="#FB9E3A" - offset="0.5" /> - <stop - id="stop3372" - stop-color="#EA7C31" - offset="0.7016" /> - <stop - id="stop3374" - stop-color="#DE642B" - offset="0.8866" /> - <stop - id="stop3376" - stop-color="#D95B29" - offset="1.0" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient5658" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - id="linearGradient3379" - y2="225.94" - x2="225.94" - y1="30.059999" - x1="30.059999" - gradientUnits="userSpaceOnUse"> - <stop - id="stop3381" - stop-color="#E3702D" - offset="0.0" /> - <stop - id="stop3383" - stop-color="#EA7D31" - offset="0.1071" /> - <stop - id="stop3385" - stop-color="#F69537" - offset="0.3503" /> - <stop - id="stop3387" - stop-color="#FB9E3A" - offset="0.5" /> - <stop - id="stop3389" - stop-color="#EA7C31" - offset="0.7016" /> - <stop - id="stop3391" - stop-color="#DE642B" - offset="0.8866" /> - <stop - id="stop3393" - stop-color="#D95B29" - offset="1.0" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient5664" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - id="linearGradient3396" - y2="225.94" - x2="225.94" - y1="30.059999" - x1="30.059999" - gradientUnits="userSpaceOnUse"> - <stop - id="stop3398" - stop-color="#E3702D" - offset="0.0" /> - <stop - id="stop3400" - stop-color="#EA7D31" - offset="0.1071" /> - <stop - id="stop3402" - stop-color="#F69537" - offset="0.3503" /> - <stop - id="stop3404" - stop-color="#FB9E3A" - offset="0.5" /> - <stop - id="stop3406" - stop-color="#EA7C31" - offset="0.7016" /> - <stop - id="stop3408" - stop-color="#DE642B" - offset="0.8866" /> - <stop - id="stop3410" - stop-color="#D95B29" - offset="1.0" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient5666" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - id="linearGradient3413" - y2="225.94" - x2="225.94" - y1="30.059999" - x1="30.059999" - gradientUnits="userSpaceOnUse"> - <stop - id="stop3415" - stop-color="#E3702D" - offset="0.0" /> - <stop - id="stop3417" - stop-color="#EA7D31" - offset="0.1071" /> - <stop - id="stop3419" - stop-color="#F69537" - offset="0.3503" /> - <stop - id="stop3421" - stop-color="#FB9E3A" - offset="0.5" /> - <stop - id="stop3423" - stop-color="#EA7C31" - offset="0.7016" /> - <stop - id="stop3425" - stop-color="#DE642B" - offset="0.8866" /> - <stop - id="stop3427" - stop-color="#D95B29" - offset="1.0" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient5660" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - id="linearGradient3430" - y2="225.94" - x2="225.94" - y1="30.059999" - x1="30.059999" - gradientUnits="userSpaceOnUse"> - <stop - id="stop3432" - stop-color="#E3702D" - offset="0.0" /> - <stop - id="stop3434" - stop-color="#EA7D31" - offset="0.1071" /> - <stop - id="stop3436" - stop-color="#F69537" - offset="0.3503" /> - <stop - id="stop3438" - stop-color="#FB9E3A" - offset="0.5" /> - <stop - id="stop3440" - stop-color="#EA7C31" - offset="0.7016" /> - <stop - id="stop3442" - stop-color="#DE642B" - offset="0.8866" /> - <stop - id="stop3444" - stop-color="#D95B29" - offset="1.0" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient5662" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - id="linearGradient3447" - y2="225.94" - x2="225.94" - y1="30.059999" - x1="30.059999" - gradientUnits="userSpaceOnUse"> - <stop - id="stop3449" - stop-color="#E3702D" - offset="0.0" /> - <stop - id="stop3451" - stop-color="#EA7D31" - offset="0.1071" /> - <stop - id="stop3453" - stop-color="#F69537" - offset="0.3503" /> - <stop - id="stop3455" - stop-color="#FB9E3A" - offset="0.5" /> - <stop - id="stop3457" - stop-color="#EA7C31" - offset="0.7016" /> - <stop - id="stop3459" - stop-color="#DE642B" - offset="0.8866" /> - <stop - id="stop3461" - stop-color="#D95B29" - offset="1.0" /> - </linearGradient> - <linearGradient - y2="211.27248" - x2="217.63582" - y1="39.288776" - x1="46.536098" - gradientUnits="userSpaceOnUse" - id="linearGradient3469" - xlink:href="#RSSg" - inkscape:collect="always" /> - <linearGradient - y2="125.5" - x2="220.00627" - y1="125.5" - x1="42.993729" - gradientUnits="userSpaceOnUse" - id="linearGradient3471" - xlink:href="#RSSg" - inkscape:collect="always" /> - <filter - color-interpolation-filters="sRGB" - id="filter5699" - inkscape:label="Drop shadow" - width="1.5" - height="1.5" - x="-0.25" - y="-0.25"> - <feGaussianBlur - id="feGaussianBlur5701" - in="SourceAlpha" - stdDeviation="2" - result="blur" /> - <feColorMatrix - id="feColorMatrix5703" - result="bluralpha" - type="matrix" - values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0 " /> - <feOffset - id="feOffset5705" - in="bluralpha" - dx="2" - dy="2" - result="offsetBlur" /> - <feMerge - id="feMerge5707"> - <feMergeNode - id="feMergeNode5709" - in="offsetBlur" /> - <feMergeNode - id="feMergeNode5711" - in="SourceGraphic" /> - </feMerge> - </filter> - <filter - id="filter3293" - inkscape:label="Drop shadow" - width="1.5" - height="1.5" - x="-.25" - y="-.25"> - <feGaussianBlur - id="feGaussianBlur3295" - in="SourceAlpha" - stdDeviation="3" - result="blur" /> - <feColorMatrix - id="feColorMatrix3297" - result="bluralpha" - type="matrix" - values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.75 0 " /> - <feOffset - id="feOffset3299" - in="bluralpha" - dx="1" - dy="1" - result="offsetBlur" /> - <feMerge - id="feMerge3301"> - <feMergeNode - id="feMergeNode3303" - in="offsetBlur" /> - <feMergeNode - id="feMergeNode3305" - in="SourceGraphic" /> - </feMerge> - </filter> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4512" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4514" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4516" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4518" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4520" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4522" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4524" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4526" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4528" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4530" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4532" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4534" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4549" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4551" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4553" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4555" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4557" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4559" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4561" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4563" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4565" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4567" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4572" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" - gradientTransform="matrix(0.34665172,0,0,0.34665859,-9.5847012,-7.505653)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4574" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" - gradientTransform="matrix(0.34665172,0,0,0.34665859,-9.5847012,-7.505653)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4577" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" - gradientTransform="matrix(0.34665172,0,0,0.34665859,-9.5847012,-7.505653)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4579" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" - gradientTransform="matrix(0.34665172,0,0,0.34665859,-9.5847012,-7.505653)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4581" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4583" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4585" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4587" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4590" - gradientUnits="userSpaceOnUse" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" - gradientTransform="matrix(0.34665172,0,0,0.34665859,-9.5847012,-15.505653)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4592" - gradientUnits="userSpaceOnUse" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" - gradientTransform="matrix(0.34665172,0,0,0.34665859,-9.5847012,-15.505653)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4676" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.34665172,0,0,0.34665859,-9.5847012,-7.505653)" - x1="46.536098" - y1="39.288776" - x2="217.63582" - y2="211.27248" /> - <linearGradient - inkscape:collect="always" - xlink:href="#RSSg" - id="linearGradient4678" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.34665172,0,0,0.34665859,-9.5847012,-7.505653)" - x1="42.993729" - y1="125.5" - x2="220.00627" - y2="125.5" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#000000" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:zoom="7.7781746" - inkscape:cx="49.788136" - inkscape:cy="31.375346" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:document-units="px" - inkscape:grid-bbox="true" - inkscape:snap-page="false" - inkscape:window-width="1280" - inkscape:window-height="961" - inkscape:window-x="1592" - inkscape:window-y="-8" - inkscape:window-maximized="1" /> - <metadata - id="metadata2990"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - id="layer1" - inkscape:label="Layer 1" - inkscape:groupmode="layer" - transform="translate(0,8)"> - <path - style="fill:#5693fd;fill-opacity:1;stroke:none" - d="m 10.457912,43.891242 c -5.3345941,0 -9.68712703,4.316148 -9.68712703,9.650846 0,5.334697 4.35253293,9.687127 9.68712703,9.687127 3.621444,0 6.763753,-2.021498 8.417279,-4.970548 -1.332101,-1.326573 -2.33102,-2.941902 -2.90251,-4.716579 -0.552565,-1.715836 -0.798196,-3.532842 -0.79819,-5.442206 -1.2e-5,-0.630425 0.02748,-1.310797 0.108844,-2.031757 0.02951,-0.261496 0.07199,-0.533671 0.108844,-0.798191 -1.447954,-0.866201 -3.124315,-1.378692 -4.934267,-1.378692 z" - id="circle26" - inkscape:connector-curvature="0" /> - <path - style="fill:#5693fd;fill-opacity:1;stroke:none" - d="m 0.77078497,16.535086 0,13.678078 A 33.002051,33.002704 0 0 1 17.750468,34.929743 l 2.35829,-9.505721 -4.861704,0 -3.845826,0 1.015878,-3.7007 0.979597,-3.410449 A 46.685828,46.686752 0 0 0 0.77078497,16.535086 z M 39.990951,37.904815 39.337886,40.517074 c -0.08277,0.45381 -0.244611,0.952443 -0.362813,1.451255 -0.09989,0.421337 -0.134677,0.849362 -0.217689,1.269848 -0.08663,0.438515 -0.2221,0.845213 -0.290251,1.233567 -0.05306,0.302702 0,0.488934 0,0.507939 -1.1e-5,0.297438 0.0012,0.391421 0,0.435377 -0.055,-0.05926 0.482688,0.217695 1.741506,0.217688 0.228753,0 0.649652,-0.02893 1.233567,-0.108844 0.588536,-0.08053 1.214979,-0.189057 1.85035,-0.326532 0.164221,-0.03553 0.310568,-0.07416 0.471658,-0.108844 a 46.685828,46.686752 0 0 0 -3.773263,-7.183713 z m 7.365119,21.913951 -0.07256,0.253969 -1.523818,0.50794 c -0.770442,0.252811 -1.647848,0.498277 -2.648541,0.725627 -1.006346,0.228619 -2.097133,0.425988 -3.265323,0.616784 -1.18131,0.192927 -2.400678,0.344324 -3.664419,0.471657 -0.825434,0.08317 -1.630649,0.144805 -2.430852,0.181407 a 33.002051,33.002704 0 0 1 0.03628,0.653065 l 13.678078,0 A 46.685828,46.686752 0 0 0 47.35607,59.818766 z" - id="path28" - inkscape:connector-curvature="0" /> - <path - style="fill:#5693fd;fill-opacity:1;stroke:none" - d="m 0.77078497,-7.229215 0,14.1134548 A 56.344965,56.346082 0 0 1 15.9364,8.9522782 l 0.108844,-0.3990952 2.213164,0 5.913864,0 2.249445,-8.78009268 0.435377,-1.77778732 0.217688,-0.036281 A 70.431206,70.432601 0 0 0 0.77078497,-7.229215 z M 57.11576,21.070257 l -0.507939,1.814069 -0.616783,2.10432 -2.176883,0 -10.666724,0 -0.217688,0.907034 A 56.344965,56.346082 0 0 1 57.11576,63.229215 l 14.113455,0 A 70.431206,70.432601 0 0 0 57.11576,21.070257 z" - id="path30" - inkscape:connector-curvature="0" /> - <path - inkscape:connector-curvature="0" - id="path4547" - style="font-size:87.69078827px;font-style:oblique;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#5693fd;fill-opacity:1;stroke:none;font-family:Segoe UI;-inkscape-font-specification:Segoe UI Bold Oblique" - d="m 53.804356,22.086365 -12.933871,0 -4.437563,17.489747 c -0.07218,0.395786 -0.162374,0.821991 -0.270583,1.278625 -0.108252,0.45667 -0.207472,0.913316 -0.297641,1.36995 -0.09022,0.456669 -0.171393,0.89049 -0.243525,1.301462 -0.07218,0.410996 -0.108252,0.753492 -0.108229,1.027466 -2.5e-5,1.217754 0.360753,2.115825 1.082332,2.694237 0.721529,0.578436 1.912093,0.867653 3.571696,0.867642 0.432905,1.1e-5 0.98309,-0.04563 1.650558,-0.136999 0.667406,-0.09137 1.352883,-0.21309 2.05643,-0.365321 0.703484,-0.152196 1.379941,-0.312032 2.029374,-0.479483 0.649365,-0.167429 1.172492,-0.312032 1.569382,-0.433809 l -2.651715,10.685637 c -0.649432,0.213102 -1.443141,0.426216 -2.381131,0.639306 -0.938051,0.213114 -1.966266,0.410996 -3.084647,0.593657 -1.118437,0.182649 -2.281943,0.33488 -3.490522,0.456646 -1.208628,0.121777 -2.390173,0.18266 -3.544639,0.18266 -2.741927,0 -5.032861,-0.296822 -6.87281,-0.890478 -1.839977,-0.593645 -3.310144,-1.415612 -4.410505,-2.465914 -1.100379,-1.050291 -1.87605,-2.275638 -2.327014,-3.676041 -0.450979,-1.400391 -0.676465,-2.922561 -0.676458,-4.566507 -7e-6,-0.487088 0.03607,-1.050291 0.10824,-1.689609 0.07215,-0.639307 0.171363,-1.293835 0.297641,-1.963605 0.126262,-0.669737 0.270577,-1.347103 0.432933,-2.032095 0.162343,-0.684969 0.315673,-1.316672 0.459992,-1.895107 l 4.437563,-17.992067 -8.550427,0 3.030532,-10.639977 8.171609,0 2.814064,-10.95963491 18.020835,-3.74454209 -3.625814,14.704177 13.150339,0 z" /> - </g> -</svg> diff --git a/org.fox.ttrss/src_drawable/s_drawer_header.svg b/org.fox.ttrss/src_drawable/s_drawer_header.svg deleted file mode 100644 index d613c406..00000000 --- a/org.fox.ttrss/src_drawable/s_drawer_header.svg +++ /dev/null @@ -1,257 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="300" - height="120" - viewBox="0 0 300.00001 120.00001" - id="svg2" - version="1.1" - inkscape:version="0.91 r13725" - sodipodi:docname="s_drawer_header.svg" - inkscape:export-filename="C:\Users\fox\Projects\tt-rss-android\org.fox.ttrss\src\main\res\drawable-xxhdpi\drawer_header.png" - inkscape:export-xdpi="307.5" - inkscape:export-ydpi="307.5"> - <defs - id="defs4"> - <filter - style="color-interpolation-filters:sRGB" - inkscape:label="Drop Shadow" - id="filter4210"> - <feFlood - flood-opacity="0.321569" - flood-color="rgb(0,0,0)" - result="flood" - id="feFlood4212" /> - <feComposite - in="flood" - in2="SourceGraphic" - operator="in" - result="composite1" - id="feComposite4214" /> - <feGaussianBlur - in="composite1" - stdDeviation="2" - result="blur" - id="feGaussianBlur4216" /> - <feOffset - dx="0" - dy="0" - result="offset" - id="feOffset4218" /> - <feComposite - in="SourceGraphic" - in2="offset" - operator="over" - result="composite2" - id="feComposite4220" /> - </filter> - <filter - style="color-interpolation-filters:sRGB" - inkscape:label="Drop Shadow" - id="filter4222"> - <feFlood - flood-opacity="0.321569" - flood-color="rgb(0,0,0)" - result="flood" - id="feFlood4224" /> - <feComposite - in="flood" - in2="SourceGraphic" - operator="in" - result="composite1" - id="feComposite4226" /> - <feGaussianBlur - in="composite1" - stdDeviation="2" - result="blur" - id="feGaussianBlur4228" /> - <feOffset - dx="0" - dy="0" - result="offset" - id="feOffset4230" /> - <feComposite - in="SourceGraphic" - in2="offset" - operator="over" - result="composite2" - id="feComposite4232" /> - </filter> - <filter - style="color-interpolation-filters:sRGB" - inkscape:label="Drop Shadow" - id="filter4234"> - <feFlood - flood-opacity="0.321569" - flood-color="rgb(0,0,0)" - result="flood" - id="feFlood4236" /> - <feComposite - in="flood" - in2="SourceGraphic" - operator="in" - result="composite1" - id="feComposite4238" /> - <feGaussianBlur - in="composite1" - stdDeviation="2" - result="blur" - id="feGaussianBlur4240" /> - <feOffset - dx="0" - dy="0" - result="offset" - id="feOffset4242" /> - <feComposite - in="SourceGraphic" - in2="offset" - operator="over" - result="composite2" - id="feComposite4244" /> - </filter> - <filter - style="color-interpolation-filters:sRGB" - inkscape:label="Drop Shadow" - id="filter4306"> - <feFlood - flood-opacity="0.611765" - flood-color="rgb(0,0,0)" - result="flood" - id="feFlood4308" /> - <feComposite - in="flood" - in2="SourceGraphic" - operator="in" - result="composite1" - id="feComposite4310" /> - <feGaussianBlur - in="composite1" - stdDeviation="6" - result="blur" - id="feGaussianBlur4312" /> - <feOffset - dx="0" - dy="0" - result="offset" - id="feOffset4314" /> - <feComposite - in="SourceGraphic" - in2="offset" - operator="over" - result="composite2" - id="feComposite4316" /> - </filter> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#000000" - borderopacity="1" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="2.8" - inkscape:cx="107.011" - inkscape:cy="70.376366" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - units="px" - borderlayer="true" - inkscape:window-width="1920" - inkscape:window-height="1137" - inkscape:window-x="-8" - inkscape:window-y="-8" - inkscape:window-maximized="1" /> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(0,-932.36214)"> - <path - style="fill:#c6e3f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 96.7857,905.93357 63.21428,60.35714 -55.35714,95.71429 -32.857141,-1.0714 z" - id="path4208" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccccc" /> - <path - style="fill:#1d6185;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 198.57141,994.505 64.64286,68.9286 -126.78572,-2.5 z" - id="path4162" - inkscape:connector-curvature="0" /> - <path - style="fill:#2374a1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4234)" - d="M 219.2857,1007.3621 71.071414,1113.0764 161.78572,948.79071 Z" - id="path4154" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccc" /> - <path - style="fill:#ab2f08;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 58.214271,1057.3621 -62.1428577,0.3572 -0.7142858,-157.14287 24.6428575,-0.71429 z" - id="path4160" - inkscape:connector-curvature="0" /> - <path - style="fill:#f4511e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4222)" - d="M 100.71427,895.93357 71.071414,1111.6478 3.2142708,895.93357 Z" - id="path4156" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccc" /> - <path - style="fill:#257eae;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4306)" - d="m 83.571414,898.07643 163.214276,159.99997 63.21429,-0.7143 -3.57143,-161.42853 z" - id="path4142" - inkscape:connector-curvature="0" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m -1.4285867,895.93357 -1.0714286,-5" - id="path4158" - inkscape:connector-curvature="0" /> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect4164" - width="65.35714" - height="202.85715" - x="-66.428589" - y="888.43359" /> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect4164-4" - width="65.357147" - height="202.85718" - x="300.89288" - y="875.93353" /> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect4164-41" - width="364.28574" - height="81.428589" - x="-36.250019" - y="1053.7908" /> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect4164-41-3" - width="364.28577" - height="81.428596" - x="-23.571449" - y="820.2193" /> - </g> -</svg> diff --git a/org.fox.ttrss/src_drawable/s_drawer_header_amber.svg b/org.fox.ttrss/src_drawable/s_drawer_header_amber.svg deleted file mode 100644 index 9c83cf7f..00000000 --- a/org.fox.ttrss/src_drawable/s_drawer_header_amber.svg +++ /dev/null @@ -1,257 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="300" - height="120" - viewBox="0 0 300.00001 120.00001" - id="svg2" - version="1.1" - inkscape:version="0.92.3 (2405546, 2018-03-11)" - sodipodi:docname="s_drawer_header_dark.svg" - inkscape:export-filename="C:\Users\andrew\Projects\tt-rss-android\org.fox.ttrss\src\main\res\drawable-xxhdpi\drawer_header_dark.png" - inkscape:export-xdpi="307.20001" - inkscape:export-ydpi="307.20001"> - <defs - id="defs4"> - <filter - style="color-interpolation-filters:sRGB" - inkscape:label="Drop Shadow" - id="filter4210"> - <feFlood - flood-opacity="0.321569" - flood-color="rgb(0,0,0)" - result="flood" - id="feFlood4212" /> - <feComposite - in="flood" - in2="SourceGraphic" - operator="in" - result="composite1" - id="feComposite4214" /> - <feGaussianBlur - in="composite1" - stdDeviation="2" - result="blur" - id="feGaussianBlur4216" /> - <feOffset - dx="0" - dy="0" - result="offset" - id="feOffset4218" /> - <feComposite - in="SourceGraphic" - in2="offset" - operator="over" - result="composite2" - id="feComposite4220" /> - </filter> - <filter - style="color-interpolation-filters:sRGB" - inkscape:label="Drop Shadow" - id="filter4222"> - <feFlood - flood-opacity="0.321569" - flood-color="rgb(0,0,0)" - result="flood" - id="feFlood4224" /> - <feComposite - in="flood" - in2="SourceGraphic" - operator="in" - result="composite1" - id="feComposite4226" /> - <feGaussianBlur - in="composite1" - stdDeviation="2" - result="blur" - id="feGaussianBlur4228" /> - <feOffset - dx="0" - dy="0" - result="offset" - id="feOffset4230" /> - <feComposite - in="SourceGraphic" - in2="offset" - operator="over" - result="composite2" - id="feComposite4232" /> - </filter> - <filter - style="color-interpolation-filters:sRGB" - inkscape:label="Drop Shadow" - id="filter4234"> - <feFlood - flood-opacity="0.321569" - flood-color="rgb(0,0,0)" - result="flood" - id="feFlood4236" /> - <feComposite - in="flood" - in2="SourceGraphic" - operator="in" - result="composite1" - id="feComposite4238" /> - <feGaussianBlur - in="composite1" - stdDeviation="2" - result="blur" - id="feGaussianBlur4240" /> - <feOffset - dx="0" - dy="0" - result="offset" - id="feOffset4242" /> - <feComposite - in="SourceGraphic" - in2="offset" - operator="over" - result="composite2" - id="feComposite4244" /> - </filter> - <filter - style="color-interpolation-filters:sRGB" - inkscape:label="Drop Shadow" - id="filter4306"> - <feFlood - flood-opacity="0.611765" - flood-color="rgb(0,0,0)" - result="flood" - id="feFlood4308" /> - <feComposite - in="flood" - in2="SourceGraphic" - operator="in" - result="composite1" - id="feComposite4310" /> - <feGaussianBlur - in="composite1" - stdDeviation="6" - result="blur" - id="feGaussianBlur4312" /> - <feOffset - dx="0" - dy="0" - result="offset" - id="feOffset4314" /> - <feComposite - in="SourceGraphic" - in2="offset" - operator="over" - result="composite2" - id="feComposite4316" /> - </filter> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#000000" - borderopacity="1" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="2.8" - inkscape:cx="95.509823" - inkscape:cy="76.447795" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - units="px" - borderlayer="true" - inkscape:window-width="1920" - inkscape:window-height="1170" - inkscape:window-x="0" - inkscape:window-y="0" - inkscape:window-maximized="1" /> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(0,-932.36214)"> - <path - style="fill:#eed5b2;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 96.7857,905.93357 63.21428,60.35714 -55.35714,95.71429 -32.857141,-1.0714 z" - id="path4208" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccccc" /> - <path - style="fill:#624318;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 198.57141,994.505 64.64286,68.9286 -126.78572,-2.5 z" - id="path4162" - inkscape:connector-curvature="0" /> - <path - style="fill:#a0712c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4234)" - d="M 219.2857,1007.3621 71.071414,1113.0764 161.78572,948.79071 Z" - id="path4154" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccc" /> - <path - style="fill:#ab2f08;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 58.214271,1057.3621 -62.1428577,0.3572 -0.7142858,-157.14287 24.6428575,-0.71429 z" - id="path4160" - inkscape:connector-curvature="0" /> - <path - style="fill:#f4511e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4222)" - d="M 100.71427,895.93357 71.071414,1111.6478 3.2142708,895.93357 Z" - id="path4156" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccc" /> - <path - style="fill:#b87d2c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4306)" - d="m 83.571414,898.07643 163.214276,159.99997 63.21429,-0.7143 -3.57143,-161.42853 z" - id="path4142" - inkscape:connector-curvature="0" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m -1.4285867,895.93357 -1.0714286,-5" - id="path4158" - inkscape:connector-curvature="0" /> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect4164" - width="65.35714" - height="202.85715" - x="-66.428589" - y="888.43359" /> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect4164-4" - width="65.357147" - height="202.85718" - x="300.89288" - y="875.93353" /> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect4164-41" - width="364.28574" - height="81.428589" - x="-36.250019" - y="1053.7908" /> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect4164-41-3" - width="364.28577" - height="81.428596" - x="-23.571449" - y="820.2193" /> - </g> -</svg> diff --git a/org.fox.ttrss/src_drawable/s_drawer_header_dark.svg b/org.fox.ttrss/src_drawable/s_drawer_header_dark.svg deleted file mode 100644 index 45c92e72..00000000 --- a/org.fox.ttrss/src_drawable/s_drawer_header_dark.svg +++ /dev/null @@ -1,257 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="300" - height="120" - viewBox="0 0 300.00001 120.00001" - id="svg2" - version="1.1" - inkscape:version="0.92.3 (2405546, 2018-03-11)" - sodipodi:docname="s_drawer_header_dark.svg" - inkscape:export-filename="/home/fox/Projects/tt-rss-android/org.fox.ttrss/src/main/res/drawable-hdpi/drawer_header_amber.png" - inkscape:export-xdpi="192" - inkscape:export-ydpi="192"> - <defs - id="defs4"> - <filter - style="color-interpolation-filters:sRGB" - inkscape:label="Drop Shadow" - id="filter4210"> - <feFlood - flood-opacity="0.321569" - flood-color="rgb(0,0,0)" - result="flood" - id="feFlood4212" /> - <feComposite - in="flood" - in2="SourceGraphic" - operator="in" - result="composite1" - id="feComposite4214" /> - <feGaussianBlur - in="composite1" - stdDeviation="2" - result="blur" - id="feGaussianBlur4216" /> - <feOffset - dx="0" - dy="0" - result="offset" - id="feOffset4218" /> - <feComposite - in="SourceGraphic" - in2="offset" - operator="over" - result="composite2" - id="feComposite4220" /> - </filter> - <filter - style="color-interpolation-filters:sRGB" - inkscape:label="Drop Shadow" - id="filter4222"> - <feFlood - flood-opacity="0.321569" - flood-color="rgb(0,0,0)" - result="flood" - id="feFlood4224" /> - <feComposite - in="flood" - in2="SourceGraphic" - operator="in" - result="composite1" - id="feComposite4226" /> - <feGaussianBlur - in="composite1" - stdDeviation="2" - result="blur" - id="feGaussianBlur4228" /> - <feOffset - dx="0" - dy="0" - result="offset" - id="feOffset4230" /> - <feComposite - in="SourceGraphic" - in2="offset" - operator="over" - result="composite2" - id="feComposite4232" /> - </filter> - <filter - style="color-interpolation-filters:sRGB" - inkscape:label="Drop Shadow" - id="filter4234"> - <feFlood - flood-opacity="0.321569" - flood-color="rgb(0,0,0)" - result="flood" - id="feFlood4236" /> - <feComposite - in="flood" - in2="SourceGraphic" - operator="in" - result="composite1" - id="feComposite4238" /> - <feGaussianBlur - in="composite1" - stdDeviation="2" - result="blur" - id="feGaussianBlur4240" /> - <feOffset - dx="0" - dy="0" - result="offset" - id="feOffset4242" /> - <feComposite - in="SourceGraphic" - in2="offset" - operator="over" - result="composite2" - id="feComposite4244" /> - </filter> - <filter - style="color-interpolation-filters:sRGB" - inkscape:label="Drop Shadow" - id="filter4306"> - <feFlood - flood-opacity="0.611765" - flood-color="rgb(0,0,0)" - result="flood" - id="feFlood4308" /> - <feComposite - in="flood" - in2="SourceGraphic" - operator="in" - result="composite1" - id="feComposite4310" /> - <feGaussianBlur - in="composite1" - stdDeviation="6" - result="blur" - id="feGaussianBlur4312" /> - <feOffset - dx="0" - dy="0" - result="offset" - id="feOffset4314" /> - <feComposite - in="SourceGraphic" - in2="offset" - operator="over" - result="composite2" - id="feComposite4316" /> - </filter> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#000000" - borderopacity="1" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="2.8" - inkscape:cx="95.15268" - inkscape:cy="76.447795" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - units="px" - borderlayer="true" - inkscape:window-width="1920" - inkscape:window-height="1170" - inkscape:window-x="0" - inkscape:window-y="0" - inkscape:window-maximized="1" /> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(0,-932.36214)"> - <path - style="fill:#eed5b2;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 96.7857,905.93357 63.21428,60.35714 -55.35714,95.71429 -32.857141,-1.0714 z" - id="path4208" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccccc" /> - <path - style="fill:#624318;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 198.57141,994.505 64.64286,68.9286 -126.78572,-2.5 z" - id="path4162" - inkscape:connector-curvature="0" /> - <path - style="fill:#a0712c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4234)" - d="M 219.2857,1007.3621 71.071414,1113.0764 161.78572,948.79071 Z" - id="path4154" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccc" /> - <path - style="fill:#ab2f08;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 58.214271,1057.3621 -62.1428577,0.3572 -0.7142858,-157.14287 24.6428575,-0.71429 z" - id="path4160" - inkscape:connector-curvature="0" /> - <path - style="fill:#f4511e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4222)" - d="M 100.71427,895.93357 71.071414,1111.6478 3.2142708,895.93357 Z" - id="path4156" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccc" /> - <path - style="fill:#b87d2c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4306)" - d="m 83.571414,898.07643 163.214276,159.99997 63.21429,-0.7143 -3.57143,-161.42853 z" - id="path4142" - inkscape:connector-curvature="0" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m -1.4285867,895.93357 -1.0714286,-5" - id="path4158" - inkscape:connector-curvature="0" /> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect4164" - width="65.35714" - height="202.85715" - x="-66.428589" - y="888.43359" /> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect4164-4" - width="65.357147" - height="202.85718" - x="300.89288" - y="875.93353" /> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect4164-41" - width="364.28574" - height="81.428589" - x="-36.250019" - y="1053.7908" /> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect4164-41-3" - width="364.28577" - height="81.428596" - x="-23.571449" - y="820.2193" /> - </g> -</svg> |