Merge branch 'sictiru'

* sictiru:
  V10.2.1b3.
  #1198 Emailing stories
  Update dependencies
  #1199 Add recount before remote sync
  #1396 Navigation gestures vs swipe gestures
  #1401 Target SDK version 30
  #1399 Search for feeds
  Android v10.2.1b2.
  #1392 Collapsing toolbar sticky feed header
This commit is contained in:
Samuel Clay 2021-02-23 14:40:55 -05:00
commit 9566d931d7
24 changed files with 600 additions and 641 deletions

View file

@ -4,7 +4,6 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
@ -133,19 +132,15 @@
android:name=".activity.MuteConfig"
android:launchMode="singleTask"
android:label="@string/mute_sites"/>
<activity
android:name=".activity.SearchForFeeds" android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/>
</activity>
<activity
android:name=".activity.SearchForFeeds"
android:launchMode="singleTop" />
<activity
android:name=".activity.SocialFeedReading"/>
<service
<service
android:name=".service.NBSyncService"
android:permission="android.permission.BIND_JOB_SERVICE" />
<service android:name=".widget.WidgetRemoteViewsService"

View file

@ -1,5 +1,5 @@
buildscript {
ext.kotlin_version = '1.4.20'
ext.kotlin_version = '1.4.30'
repositories {
mavenCentral()
maven {
@ -9,7 +9,7 @@ buildscript {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.1'
classpath 'com.android.tools.build:gradle:4.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
@ -29,7 +29,7 @@ apply plugin: 'checkstyle'
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.fragment:fragment-ktx:1.2.5'
implementation 'androidx.fragment:fragment-ktx:1.3.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
@ -37,20 +37,20 @@ dependencies {
implementation 'com.android.billingclient:billing:3.0.2'
implementation 'nl.dionsegijn:konfetti:1.2.2'
implementation 'com.github.jinatonic.confetti:confetti:1.1.2'
implementation 'com.google.android.play:core:1.9.0'
implementation "com.google.android.material:material:1.2.1"
implementation 'com.google.android.play:core:1.9.1'
implementation "com.google.android.material:material:1.3.0"
implementation "androidx.preference:preference-ktx:1.1.1"
implementation "androidx.browser:browser:1.3.0"
}
android {
compileSdkVersion 29
compileSdkVersion 30
defaultConfig {
applicationId "com.newsblur"
minSdkVersion 21
targetSdkVersion 29
versionCode 180
versionName "10.2.1b1"
targetSdkVersion 30
versionCode 182
versionName "10.2.1b3"
}
compileOptions.with {
sourceCompatibility = JavaVersion.VERSION_1_8

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/gray55"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
</vector>

View file

@ -4,31 +4,97 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/toolbar_newsblur" />
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="16dp"
android:animateLayoutChanges="true"
android:orientation="horizontal">
<ImageView
android:id="@+id/toolbar_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="?attr/homeAsUpIndicator" />
<ImageView
android:id="@+id/toolbar_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="4dp"
android:layout_marginEnd="8dp"
android:src="@drawable/logo" />
<EditText
android:id="@+id/input_search_query"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:autofillHints="@null"
android:background="@null"
android:hint="@string/search_for_feed"
android:imeOptions="actionDone"
android:inputType="textCapSentences|textNoSuggestions"
android:maxLines="1" />
<ImageView
android:id="@+id/clear_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="6dp"
android:src="@drawable/ic_clear"
android:visibility="gone" />
<ProgressBar
android:id="@+id/loading_circle"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="8dp"
android:indeterminate="true"
android:visibility="gone" />
</LinearLayout>
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
style="?listBackground"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
style="?defaultText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/empty_search_notice"
android:textColor="@color/text"
android:textSize="13sp"
android:textSize="16sp"
android:textStyle="italic" />
<ListView
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/feed_result_list"
android:name="com.newsblur.fragment.FolderListFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</RelativeLayout>
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -1,199 +1,197 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
android:layout_height="match_parent">
<!-- The two views in this top FrameLayout are swapped when HTML5 webview custom content wants to be displayed -->
<com.newsblur.view.ReadingScrollView
android:id="@+id/reading_scrollview"
<RelativeLayout
android:id="@+id/reading_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="?readingBackground"
>
android:layout_height="match_parent">
<LinearLayout
<FrameLayout
android:id="@+id/row_item_feed_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:focusable="true"
android:focusableInTouchMode="true"
>
android:minHeight="6dp"
android:paddingTop="4dp"
android:paddingBottom="4dp">
<RelativeLayout
<ImageView
android:id="@+id/reading_feed_icon"
android:layout_width="17dp"
android:layout_height="17dp"
android:layout_marginStart="16dp"
android:contentDescription="@string/description_row_folder_icon" />
<TextView
android:id="@+id/reading_feed_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="8dp"
style="?rowItemHeaderBackground">
android:layout_gravity="center_vertical"
android:layout_marginStart="40dp"
android:ellipsize="end"
android:lines="1"
android:textSize="12sp"
android:textStyle="bold" />
</FrameLayout>
<View
android:id="@+id/item_feed_border"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="@id/row_item_feed_header"
android:background="@color/gray55" />
<com.newsblur.view.ReadingScrollView
android:id="@+id/reading_scrollview"
style="?readingBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/item_feed_border">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/row_item_feed_header"
android:layout_height="wrap_content"
style="?rowItemHeaderBackground"
android:layout_width="match_parent"
android:minHeight="6dp"
android:paddingTop="4dp"
android:paddingBottom="4dp" >
android:layout_height="wrap_content"
android:paddingBottom="8dp">
<ImageView
android:id="@+id/reading_feed_icon"
android:layout_width="17dp"
android:layout_height="17dp"
android:layout_alignParentLeft="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="5dp"
android:contentDescription="@string/description_row_folder_icon" />
<ImageButton
android:id="@+id/story_context_menu_button"
style="?android:attr/actionOverflowButtonStyle"
android:layout_width="34dp"
android:layout_height="34dp"
android:layout_alignParentRight="true"
android:layout_margin="5dp"
android:contentDescription="@string/description_menu" />
<TextView
android:id="@+id/reading_feed_title"
android:id="@+id/reading_item_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="@id/reading_feed_icon"
android:layout_centerVertical="true"
android:ellipsize="end"
android:lines="1"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="10dp"
android:layout_marginRight="16dp"
android:layout_toLeftOf="@id/story_context_menu_button"
android:textSize="17sp" />
<TextView
android:id="@+id/reading_item_date"
style="?readingItemMetadata"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/reading_item_title"
android:layout_alignLeft="@id/reading_item_title"
android:layout_marginTop="8dp"
android:layout_marginRight="12dp"
android:textSize="12sp" />
<TextView
android:id="@+id/reading_item_authors"
style="?readingItemMetadata"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/reading_item_date"
android:layout_toRightOf="@id/reading_item_date"
android:maxLines="1"
android:minWidth="80dp"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/reading_story_changes"
style="?readingItemMetadata"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/reading_item_date"
android:layout_alignLeft="@id/reading_item_title"
android:drawableStart="@drawable/ic_file_edit"
android:drawablePadding="6dp"
android:gravity="center_vertical"
android:paddingTop="8dp"
android:paddingBottom="4dp"
android:text="@string/story_show_changes"
android:textSize="12sp"
android:visibility="gone" />
<com.newsblur.view.FlowLayout
android:id="@+id/reading_item_tags"
android:layout_width="match_parent"
android:layout_height="17dp"
android:layout_below="@id/reading_story_changes"
android:layout_alignLeft="@id/reading_item_title"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp" />
</RelativeLayout>
<View
android:id="@+id/item_feed_border"
style="?itemHeaderDivider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="@id/row_item_feed_header"
android:background="@color/gray55"/>
android:layout_gravity="bottom" />
<ImageButton
android:id="@+id/story_context_menu_button"
android:layout_width="34dp"
android:layout_height="34dp"
android:layout_margin="5dp"
style="?android:attr/actionOverflowButtonStyle"
android:contentDescription="@string/description_menu"
android:layout_below="@id/item_feed_border"
android:layout_alignParentRight="true" />
<include layout="@layout/include_reading_share_bar" />
<TextView
android:id="@+id/reading_item_title"
<View
android:id="@+id/share_bar_underline"
style="?android:divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="16dp"
android:layout_marginTop="10dp"
android:layout_marginLeft="16dp"
android:layout_below="@id/item_feed_border"
android:layout_toLeftOf="@id/story_context_menu_button"
android:textSize="17sp" />
<TextView
android:id="@+id/reading_item_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/reading_item_title"
android:layout_alignLeft="@id/reading_item_title"
android:layout_marginRight="12dp"
android:layout_marginTop="8dp"
style="?readingItemMetadata"
android:textSize="12sp" />
<TextView
android:id="@+id/reading_item_authors"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/reading_item_date"
android:layout_toRightOf="@id/reading_item_date"
android:maxLines="1"
android:minWidth="80dp"
style="?readingItemMetadata"
android:textSize="12sp"
android:textStyle="bold"/>
<TextView
android:id="@+id/reading_story_changes"
style="?readingItemMetadata"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/reading_item_date"
android:layout_alignLeft="@id/reading_item_title"
android:paddingTop="8dp"
android:gravity="center_vertical"
android:paddingBottom="4dp"
android:drawablePadding="6dp"
android:drawableStart="@drawable/ic_file_edit"
android:text="@string/story_show_changes"
android:textSize="12sp"
android:layout_height="3dp"
android:visibility="gone" />
<com.newsblur.view.FlowLayout
android:id="@+id/reading_item_tags"
<TextView
android:id="@+id/reading_textloading"
style="?readingBackground"
android:layout_width="match_parent"
android:layout_height="17dp"
android:layout_alignLeft="@id/reading_item_title"
android:layout_below="@id/reading_story_changes"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp" />
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="@string/orig_text_loading"
android:textSize="16sp"
android:textStyle="italic"
android:visibility="gone" />
</RelativeLayout>
<TextView
android:id="@+id/reading_textmodefailed"
style="?readingBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="@string/orig_text_failed"
android:textSize="16sp"
android:textStyle="italic"
android:visibility="gone" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="bottom"
style="?itemHeaderDivider" />
<com.newsblur.view.NewsblurWebview
android:id="@+id/reading_webview"
style="?readingBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="12dp"
android:layout_marginRight="10dp"
android:scrollbars="none" />
<include layout="@layout/include_reading_share_bar" />
<include layout="@layout/include_reading_item_comment" />
<View
android:id="@+id/share_bar_underline"
android:layout_width="match_parent"
android:layout_height="3dp"
style="?android:divider"
android:visibility="gone" />
</LinearLayout>
<TextView
android:id="@+id/reading_textloading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
style="?readingBackground"
android:gravity="center_horizontal"
android:text="@string/orig_text_loading"
android:textSize="16sp"
android:textStyle="italic"
android:visibility="gone"
/>
</com.newsblur.view.ReadingScrollView>
<TextView
android:id="@+id/reading_textmodefailed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
style="?readingBackground"
android:gravity="center_horizontal"
android:text="@string/orig_text_failed"
android:textSize="16sp"
android:textStyle="italic"
android:visibility="gone"
/>
<com.newsblur.view.NewsblurWebview
android:id="@+id/reading_webview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?readingBackground"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="12dp"
android:scrollbars="none"
/>
<include
layout="@layout/include_reading_item_comment" />
</LinearLayout>
</com.newsblur.view.ReadingScrollView>
</RelativeLayout>
<FrameLayout
android:id="@+id/custom_view_container"

View file

@ -1,83 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?layoutBackground"
android:focusable="false">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent" >
<View
android:id="@+id/row_result_favicon_color"
android:layout_width="8dp"
android:layout_height="match_parent" />
<TextView
android:id="@+id/row_item_sidebar"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginTop="12dp"
android:layout_toRightOf="@id/row_result_favicon_color" />
<ImageView
android:id="@+id/row_result_feedicon"
android:layout_width="21dp"
android:layout_height="21dp"
android:layout_marginTop="10dp"
android:paddingBottom="4dp"
android:paddingTop="2dp"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:layout_toRightOf="@id/row_item_sidebar" />
<TextView
android:id="@+id/row_result_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_toRightOf="@id/row_result_feedicon"
android:layout_alignBottom="@id/row_result_feedicon"
android:ellipsize="end"
android:singleLine="true"
android:textStyle="bold"
style="?defaultText"
android:textSize="15sp" />
<TextView
android:id="@+id/row_result_tagline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/row_result_feedicon"
android:layout_below="@id/row_result_feedicon"
android:layout_marginRight="8dp"
android:paddingTop="8dp"
style="?defaultText"
android:textSize="20sp" />
<TextView
android:id="@+id/row_result_subscribercount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="8dp"
android:paddingTop="8dp"
style="?defaultText"
android:textSize="15sp" />
<TextView
android:id="@+id/row_result_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/row_result_feedicon"
android:layout_below="@id/row_result_tagline"
android:layout_marginRight="8dp"
android:paddingTop="8dp"
android:paddingBottom="12dp"
style="?defaultText"
android:textSize="13sp" />
</RelativeLayout>
</LinearLayout>

View file

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="?layoutBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:paddingHorizontal="16dp"
android:paddingVertical="8dp">
<ImageView
android:id="@+id/img_feed_icon"
android:layout_width="21dp"
android:layout_height="21dp"
android:src="@drawable/world" />
<TextView
android:id="@+id/text_title"
style="?defaultText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_toLeftOf="@+id/text_subscription_count"
android:layout_toRightOf="@id/img_feed_icon"
android:ellipsize="end"
android:singleLine="true"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/text_tagline"
style="?defaultText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/img_feed_icon"
android:layout_alignLeft="@id/img_feed_icon"
android:layout_marginTop="8dp"
android:textSize="14sp" />
<TextView
android:id="@+id/text_subscription_count"
style="?defaultText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:textSize="14sp" />
<TextView
android:id="@+id/row_result_address"
style="?defaultText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/text_tagline"
android:layout_alignLeft="@id/img_feed_icon"
android:layout_marginTop="4dp"
android:textSize="13sp" />
</RelativeLayout>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/menu_search"
android:icon="@drawable/ic_menu_search_gray55"
android:title="@string/menu_search"
app:showAsAction="always" />
</menu>

View file

@ -15,7 +15,7 @@
<string name="login_retrieving_feeds">Retrieving feeds…</string>
<string name="login_next">Next</string>
<string name="title_feed_search">Search for feeds</string>
<string name="search_for_feed">Search for feeds</string>
<string name="loading">Loading…</string>
<string name="orig_text_loading">Fetching story text…</string>
@ -56,7 +56,7 @@
<string name="top_level">TOP LEVEL</string>
<string name="send_brief">%1$s %2$s</string>
<string name="send_full">%1$s \n\n\"%2$s\" \n\n%3$s \n\n--\nShared with NewsBlur.com</string>
<string name="send_full">%1$s \n\%2$s \n\n%3$s \n\n—\nShared with NewsBlur.com</string>
<string name="share_comment_hint">Comment (Optional)</string>
<string name="share_newsblur">Share \"%s\" to your Blurblog?</string>
<string name="share_this">SHARE</string>
@ -200,11 +200,9 @@
<string name="story_hide_changes">Hide Story Changes</string>
<string name="story_changes_loading">Story Changes Loading ...</string>
<string name="your_feeds_search_hint">Search your feeds</string>
<string name="feed_search_hint">Search term or feed URL</string>
<string name="story_search_hint">Search for stories</string>
<string name="empty_search_notice">Type a search term to begin</string>
<string name="menu_add_feed">Add new feed</string>
<string name="menu_search">Search</string>
<string name="adding_feed_progress">Adding feed…</string>
<string name="add_folder_name">Please enter folder name</string>
<string name="add_new_folder">+ Add new folder</string>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/newsblur"
android:hint="@string/feed_search_hint" >
</searchable>

View file

@ -1,67 +0,0 @@
package com.newsblur.activity;
import java.util.List;
import com.newsblur.R;
import com.newsblur.domain.FeedResult;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.util.Base64;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class FeedSearchResultAdapter extends ArrayAdapter<FeedResult>{
private LayoutInflater inflater;
private Context context;
public FeedSearchResultAdapter(Context context, int resource, int textViewResourceId, List<FeedResult> items) {
super(context, resource, textViewResourceId, items);
this.context = context;
inflater = ((Activity) context).getLayoutInflater();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v;
if (convertView != null) {
v = convertView;
} else {
v = inflater.inflate(R.layout.row_feedresult, null);
}
FeedResult result = getItem(position);
ImageView favicon = (ImageView) v.findViewById(R.id.row_result_feedicon);
Bitmap bitmap = null;
if (!TextUtils.isEmpty(result.favicon)) {
final byte[] data = Base64.decode(result.favicon, Base64.DEFAULT);
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
if (bitmap == null) {
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.world);
}
favicon.setImageBitmap(bitmap);
((TextView) v.findViewById(R.id.row_result_title)).setText(result.label);
((TextView) v.findViewById(R.id.row_result_tagline)).setText(result.tagline);
if (!TextUtils.isEmpty(result.url)) {
((TextView) v.findViewById(R.id.row_result_address)).setText(result.url);
} else {
v.findViewById(R.id.row_result_address).setVisibility(View.GONE);
}
((TextView) v.findViewById(R.id.row_result_subscribercount)).setText(result.numberOfSubscriber + " subscribers");
return v;
}
}

View file

@ -0,0 +1,94 @@
package com.newsblur.activity
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.text.TextUtils
import android.util.Base64
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.newsblur.R
import com.newsblur.databinding.ViewFeedSearchRowBinding
import com.newsblur.domain.FeedResult
internal class FeedSearchAdapter(private val onClickListener: OnFeedSearchResultClickListener) : RecyclerView.Adapter<FeedSearchAdapter.ViewHolder>() {
private val resultsList: MutableList<FeedResult> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.view_feed_search_row, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val result = resultsList[position]
var bitmap: Bitmap? = null
if (!TextUtils.isEmpty(result.favicon)) {
val data = Base64.decode(result.favicon, Base64.DEFAULT)
bitmap = BitmapFactory.decodeByteArray(data, 0, data.size)
}
bitmap?.let {
holder.binding.imgFeedIcon.setImageBitmap(bitmap)
}
holder.binding.textTitle.text = result.label
holder.binding.textTagline.text = result.tagline
val subscribersCountText = holder.binding.root.context.resources.getString(R.string.feed_subscribers, result.numberOfSubscriber)
holder.binding.textSubscriptionCount.text = subscribersCountText
if (!TextUtils.isEmpty(result.url)) {
holder.binding.rowResultAddress.text = result.url
holder.binding.rowResultAddress.visibility = View.VISIBLE
} else {
holder.binding.rowResultAddress.visibility = View.GONE
}
holder.itemView.setOnClickListener {
onClickListener.onFeedSearchResultClickListener(result)
}
}
override fun getItemCount(): Int = resultsList.size
fun replaceAll(results: Array<FeedResult>) {
val newResultsList: List<FeedResult> = results.toList()
val diffCallback = ResultDiffCallback(resultsList, newResultsList)
val diffResult = DiffUtil.calculateDiff(diffCallback)
resultsList.clear()
resultsList.addAll(newResultsList)
diffResult.dispatchUpdatesTo(this)
}
internal class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val binding: ViewFeedSearchRowBinding = ViewFeedSearchRowBinding.bind(itemView)
}
internal class ResultDiffCallback(private val oldList: List<FeedResult>,
private val newList: List<FeedResult>) : DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldFeedResult = oldList[oldItemPosition]
val newFeedResult = newList[newItemPosition]
return oldFeedResult.label == newFeedResult.label &&
oldFeedResult.numberOfSubscriber == newFeedResult.numberOfSubscriber
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldFeedResult = oldList[oldItemPosition]
val newFeedResult = newList[newItemPosition]
return oldFeedResult.label == newFeedResult.label
&& oldFeedResult.tagline == newFeedResult.tagline
}
override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size
}
interface OnFeedSearchResultClickListener {
fun onFeedSearchResultClickListener(result: FeedResult)
}
}

View file

@ -3,7 +3,6 @@ package com.newsblur.activity;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentActivity;
import android.widget.Toast;
import com.newsblur.util.FeedUtils;

View file

@ -16,8 +16,6 @@ import androidx.viewpager.widget.ViewPager;
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;

View file

@ -1,164 +0,0 @@
package com.newsblur.activity;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import androidx.fragment.app.DialogFragment;
import androidx.loader.app.LoaderManager;
import androidx.loader.app.LoaderManager.LoaderCallbacks;
import androidx.loader.content.Loader;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.newsblur.R;
import com.newsblur.domain.FeedResult;
import com.newsblur.fragment.AddFeedFragment;
import com.newsblur.network.SearchAsyncTaskLoader;
import com.newsblur.network.SearchLoaderResponse;
import com.newsblur.util.UIUtils;
// TODO: this activity's use of the inbuilt activity search facility as well as an improper use of a loader to
// make network requests makes it easily lose state, lack non-legacy progress indication, and generally
// buggy. a normal layout and a proper use of sync for search results should be implemented.
public class SearchForFeeds extends NbActivity implements LoaderCallbacks<SearchLoaderResponse>, OnItemClickListener, AddFeedFragment.AddFeedProgressListener {
private static final Set<String> SUPPORTED_URL_PROTOCOLS = new HashSet<String>();
static {
SUPPORTED_URL_PROTOCOLS.add("http");
SUPPORTED_URL_PROTOCOLS.add("https");
}
private ListView resultsList;
private Loader<SearchLoaderResponse> searchLoader;
private FeedSearchResultAdapter adapter;
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.activity_feed_search);
UIUtils.setupToolbar(this, R.drawable.logo, getString(R.string.title_feed_search), true);
TextView emptyView = (TextView) findViewById(R.id.empty_view);
resultsList = (ListView) findViewById(R.id.feed_result_list);
resultsList.setEmptyView(emptyView);
resultsList.setOnItemClickListener(this);
resultsList.setItemsCanFocus(false);
searchLoader = LoaderManager.getInstance(this).initLoader(0, new Bundle(), this);
onSearchRequested();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.search, menu);
return true;
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
// test to see if a feed URL was passed rather than a search term
if (tryAddByURL(query)) { return; }
Bundle bundle = new Bundle();
bundle.putString(SearchAsyncTaskLoader.SEARCH_TERM, query);
searchLoader = LoaderManager.getInstance(this).restartLoader(0, bundle, this);
searchLoader.forceLoad();
}
}
/**
* See if the text entered in the query field was actually a URL so we can skip the
* search step and just let users who know feed URLs directly subscribe.
*/
private boolean tryAddByURL(String s) {
URL u = null;
try {
u = new URL(s);
} catch (MalformedURLException mue) {
; // this just signals that the string wasn't a URL, we will return
}
if (u == null) { return false; }
if (! SUPPORTED_URL_PROTOCOLS.contains(u.getProtocol())) { return false; };
if ((u.getHost() == null) || (u.getHost().trim().isEmpty())) { return false; }
DialogFragment addFeedFragment = AddFeedFragment.newInstance(s, s);
addFeedFragment.show(getSupportFragmentManager(), "dialog");
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_search) {
onSearchRequested();
return true;
} else if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public Loader<SearchLoaderResponse> onCreateLoader(int loaderId, Bundle bundle) {
String searchTerm = bundle.getString(SearchAsyncTaskLoader.SEARCH_TERM);
return new SearchAsyncTaskLoader(this, searchTerm);
}
@Override
public void onLoadFinished(Loader<SearchLoaderResponse> loader, SearchLoaderResponse results) {
if(!results.hasError()) {
adapter = new FeedSearchResultAdapter(this, 0, 0, results.getResults());
resultsList.setAdapter(adapter);
} else {
String message = results.getErrorMessage() == null ? "Error" : results.getErrorMessage();
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onLoaderReset(Loader<SearchLoaderResponse> loader) {
}
@Override
public void onItemClick(AdapterView<?> arg0, View view, int position, long id) {
FeedResult result = adapter.getItem(position);
DialogFragment addFeedFragment = AddFeedFragment.newInstance(result.url, result.label);
addFeedFragment.show(getSupportFragmentManager(), "dialog");
}
@Override
public void addFeedStarted() {
runOnUiThread(new Runnable() {
public void run() {
// TODO: this UI should offer some progress indication, since the add API call can block for several seconds
}
});
}
}

View file

@ -0,0 +1,149 @@
package com.newsblur.activity
import android.os.AsyncTask
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import androidx.fragment.app.DialogFragment
import com.newsblur.activity.FeedSearchAdapter.OnFeedSearchResultClickListener
import com.newsblur.databinding.ActivityFeedSearchBinding
import com.newsblur.domain.FeedResult
import com.newsblur.fragment.AddFeedFragment
import com.newsblur.fragment.AddFeedFragment.AddFeedProgressListener
import com.newsblur.network.APIManager
import java.net.MalformedURLException
import java.net.URL
import java.util.*
class SearchForFeeds : NbActivity(), OnFeedSearchResultClickListener, AddFeedProgressListener {
private val supportedUrlProtocols: MutableSet<String> = HashSet(2)
init {
supportedUrlProtocols.add("http")
supportedUrlProtocols.add("https")
}
private lateinit var adapter: FeedSearchAdapter
private lateinit var binding: ActivityFeedSearchBinding
private lateinit var apiManager: APIManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityFeedSearchBinding.inflate(layoutInflater)
setContentView(binding.root)
setupViews()
setupListeners()
apiManager = APIManager(this)
binding.inputSearchQuery.requestFocus()
}
override fun onFeedSearchResultClickListener(result: FeedResult) {
showAddFeedDialog(result.url, result.label)
}
override fun addFeedStarted() {
// loading views handled by AddFeedFragment
}
private fun setupViews() {
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayShowTitleEnabled(false)
supportActionBar?.setDisplayShowHomeEnabled(false)
adapter = FeedSearchAdapter(this)
binding.feedResultList.adapter = adapter
}
private fun setupListeners() {
binding.toolbarArrow.setOnClickListener { finish() }
binding.toolbarIcon.setOnClickListener { finish() }
binding.clearText.setOnClickListener { binding.inputSearchQuery.setText("") }
binding.inputSearchQuery.addTextChangedListener(object : TextWatcher {
private val handler = Handler(Looper.getMainLooper())
private var searchQueryRunnable: Runnable? = null
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable) {
searchQueryRunnable?.let { handler.removeCallbacks(it) }
searchQueryRunnable = Runnable {
if (tryAddByURL(s.toString())) {
return@Runnable
}
syncClearIconVisibility(s)
if (s.isNotEmpty()) searchQuery(s)
else syncSearchResults(arrayOf())
}
handler.postDelayed(searchQueryRunnable!!, 350)
}
})
}
private fun searchQuery(query: Editable) {
object : AsyncTask<Void?, Void?, Array<FeedResult>?>() {
override fun onPreExecute() {
super.onPreExecute()
binding.loadingCircle.visibility = View.VISIBLE
binding.clearText.visibility = View.GONE
}
override fun doInBackground(vararg params: Void?): Array<FeedResult>? {
return apiManager.searchForFeed(query.toString())
}
override fun onPostExecute(result: Array<FeedResult>?) {
binding.loadingCircle.visibility = View.GONE
binding.clearText.visibility = View.VISIBLE
syncSearchResults(result ?: arrayOf())
}
}.execute()
}
private fun syncClearIconVisibility(query: Editable) {
binding.clearText.visibility = if (query.isNotEmpty()) View.VISIBLE else View.GONE
}
private fun syncSearchResults(results: Array<FeedResult>) {
adapter.replaceAll(results)
}
/**
* See if the text entered in the query field was actually a URL so we can skip the
* search step and just let users who know feed URLs directly subscribe.
*/
private fun tryAddByURL(s: String): Boolean {
var u: URL? = null
try {
u = URL(s)
} catch (mue: MalformedURLException) {
// this just signals that the string wasn't a URL, we will return
}
if (u == null) {
return false
}
if (!supportedUrlProtocols.contains(u.protocol)) {
return false
}
if (u.host == null || u.host.trim().isEmpty()) {
return false
}
showAddFeedDialog(s, s)
return true
}
private fun showAddFeedDialog(feedUrl: String, feedLabel: String) {
val addFeedFragment: DialogFragment = AddFeedFragment.newInstance(feedUrl, feedLabel)
addFeedFragment.show(supportFragmentManager, "dialog")
}
}

View file

@ -704,18 +704,19 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if ((e1.getX() > 10f) && // the gesture should not start too close to the left edge and
((e2.getX()-e1.getX()) > 50f) && // move horizontally to the right and
(Math.abs(e1.getY()-e2.getY()) < 25f) // have minimal vertical travel, so we don't capture scrolling gestures
) {
float displayWidthPx = UIUtils.getDisplayWidthPx(context);
float edgeWithNavGesturesPaddingPx = UIUtils.dp2px(context, 40);
float rightEdgeNavGesturePaddingPx = displayWidthPx - edgeWithNavGesturesPaddingPx;
if (e1.getX() > edgeWithNavGesturesPaddingPx && // the gesture should not start too close to the left edge and
e2.getX() - e1.getX() > 50f && // move horizontally to the right and
Math.abs(distanceY) < 25f) { // have minimal vertical travel, so we don't capture scrolling gestures
vh.gestureL2R = true;
vh.gestureDebounce = true;
return true;
}
if ((e1.getX() > 10f) && // the gesture should not start too close to the left edge and
((e1.getX()-e2.getX()) > 50f) && // move horizontally to the left and
(Math.abs(e1.getY()-e2.getY()) < 25f) // have minimal vertical travel, so we don't capture scrolling gestures
) {
if (e1.getX() < rightEdgeNavGesturePaddingPx && // the gesture should not start too close to the right edge and
e1.getX() - e2.getX() > 50f && // move horizontally to the left and
Math.abs(distanceY) < 25f) { // have minimal vertical travel, so we don't capture scrolling gestures
vh.gestureR2L = true;
vh.gestureDebounce = true;
return true;

View file

@ -28,7 +28,6 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.webkit.WebView.HitTestResult;
import android.widget.ImageView;
import android.widget.TextView;
import com.newsblur.R;
@ -52,7 +51,6 @@ import com.newsblur.util.PrefsUtils;
import com.newsblur.util.StoryChangesState;
import com.newsblur.util.StoryUtils;
import com.newsblur.util.UIUtils;
import com.newsblur.view.ReadingScrollView;
import java.util.HashMap;
import java.util.regex.Matcher;
@ -66,12 +64,10 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
public static final String READING_FONT_CHANGED = "readingFontChanged";
public Story story;
private FeedSet fs;
private LayoutInflater inflater;
private String feedColor, feedTitle, feedFade, feedBorder, feedIconUrl, faviconText;
private Classifier classifier;
private BroadcastReceiver textSizeReceiver, readingFontReceiver;
private boolean displayFeedDetails;
private View view;
private UserDetails user;
private DefaultFeedView selectedFeedView;
private boolean textViewUnavailable;
@ -163,7 +159,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
getActivity().unregisterReceiver(textSizeReceiver);
getActivity().unregisterReceiver(readingFontReceiver);
binding.readingWebview.setOnTouchListener(null);
view.setOnTouchListener(null);
binding.getRoot().setOnTouchListener(null);
getActivity().getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(null);
super.onDestroy();
}
@ -184,8 +180,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
this.inflater = inflater;
view = inflater.inflate(R.layout.fragment_readingitem, null);
View view = inflater.inflate(R.layout.fragment_readingitem, container, false);
binding = FragmentReadingitemBinding.bind(view);
itemCommentBinding = IncludeReadingItemCommentBinding.bind(binding.getRoot());
@ -196,7 +191,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
registerForContextMenu(binding.readingWebview);
binding.readingWebview.setCustomViewLayout(binding.customViewContainer);
binding.readingWebview.setWebviewWrapperLayout(binding.readingScrollview);
binding.readingWebview.setWebviewWrapperLayout(binding.readingContainer);
binding.readingWebview.setBackgroundColor(Color.TRANSPARENT);
binding.readingWebview.fragment = this;
binding.readingWebview.activity = activity;
@ -206,8 +201,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
updateSaveButton();
setupItemCommentsAndShares();
ReadingScrollView scrollView = (ReadingScrollView) view.findViewById(R.id.reading_scrollview);
scrollView.registerScrollChangeListener(activity);
binding.readingScrollview.registerScrollChangeListener(activity);
return view;
}
@ -417,15 +411,10 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
}
private void setupItemCommentsAndShares() {
new SetupCommentSectionTask(this, view, inflater, story).execute();
new SetupCommentSectionTask(this, binding.getRoot(), getLayoutInflater(), story).execute();
}
private void setupItemMetadata() {
View feedHeader = view.findViewById(R.id.row_item_feed_header);
View feedHeaderBorder = view.findViewById(R.id.item_feed_border);
TextView itemDate = (TextView) view.findViewById(R.id.reading_item_date);
ImageView feedIcon = (ImageView) view.findViewById(R.id.reading_feed_icon);
if ((feedColor == null) ||
(feedFade == null) ||
TextUtils.equals(feedColor, "null") ||
@ -440,8 +429,8 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
Color.parseColor("#" + feedFade),
};
GradientDrawable gradient = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, colors);
UIUtils.setViewBackground(feedHeader, gradient);
feedHeaderBorder.setBackgroundColor(Color.parseColor("#" + feedBorder));
UIUtils.setViewBackground(binding.rowItemFeedHeader, gradient);
binding.itemFeedBorder.setBackgroundColor(Color.parseColor("#" + feedBorder));
if (TextUtils.equals(faviconText, "black")) {
binding.readingFeedTitle.setTextColor(UIUtils.getColor(getActivity(), R.color.text));
@ -453,13 +442,13 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
if (!displayFeedDetails) {
binding.readingFeedTitle.setVisibility(View.GONE);
feedIcon.setVisibility(View.GONE);
binding.readingFeedIcon.setVisibility(View.GONE);
} else {
FeedUtils.iconLoader.displayImage(feedIconUrl, feedIcon, 0, false);
FeedUtils.iconLoader.displayImage(feedIconUrl, binding.readingFeedIcon, 0, false);
binding.readingFeedTitle.setText(feedTitle);
}
itemDate.setText(StoryUtils.formatLongDate(getActivity(), story.timestamp));
binding.readingItemDate.setText(StoryUtils.formatLongDate(getActivity(), story.timestamp));
if (story.tags.length <= 0) {
binding.readingItemTags.setVisibility(View.GONE);
@ -510,7 +499,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
// TODO: these textviews with compound images are buggy, but stubbed in to let colourblind users
// see what is going on. these should be replaced with proper Chips when the v28 Chip lib
// is in full release.
View v = inflater.inflate(R.layout.tag_view, null);
View v = getLayoutInflater().inflate(R.layout.tag_view, null);
TextView tagText = (TextView) v.findViewById(R.id.tag_text);
tagText.setText(tag);

View file

@ -1,36 +0,0 @@
package com.newsblur.network;
import java.util.ArrayList;
import android.content.Context;
import androidx.loader.content.AsyncTaskLoader;
import com.newsblur.domain.FeedResult;
public class SearchAsyncTaskLoader extends AsyncTaskLoader<SearchLoaderResponse> {
public static final String SEARCH_TERM = "searchTerm";
private String searchTerm;
private APIManager apiManager;
public SearchAsyncTaskLoader(Context context, String searchTerm) {
super(context);
this.searchTerm = searchTerm;
apiManager = new APIManager(context);
}
@Override
public SearchLoaderResponse loadInBackground() {
ArrayList<FeedResult> list = new ArrayList<FeedResult>();
FeedResult[] results = apiManager.searchForFeed(searchTerm);
if (results != null) {
for (FeedResult result : results) {
list.add(result);
}
}
SearchLoaderResponse response = new SearchLoaderResponse(list);
return response;
}
}

View file

@ -1,30 +0,0 @@
package com.newsblur.network;
import java.util.ArrayList;
import com.newsblur.domain.FeedResult;
public class SearchLoaderResponse extends BaseLoaderResponse {
private ArrayList<FeedResult> results;
/**
* Use to indicate there was a problem w/ the search
*
* @param errorMessage
*/
public SearchLoaderResponse(String errorMessage) {
super(errorMessage);
results = new ArrayList<FeedResult>(0);
}
public SearchLoaderResponse(ArrayList<FeedResult> results) {
this.results = results;
}
public ArrayList<FeedResult> getResults() {
return results;
}
}

View file

@ -258,8 +258,8 @@ public class FeedUtils {
Set<FeedSet> impactedFeeds = dbHelper.setStoryReadState(story, read);
NbActivity.updateAllActivities(NbActivity.UPDATE_STORY);
triggerSync(context);
NBSyncService.addRecountCandidates(impactedFeeds);
triggerSync(context);
}
/**
@ -398,23 +398,24 @@ public class FeedUtils {
}
public static void sendStoryBrief(Story story, Context context) {
if (story == null ) { return; }
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
if (story == null) return;
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_SUBJECT, UIUtils.fromHtml(story.title).toString());
intent.putExtra(Intent.EXTRA_TEXT, String.format(context.getResources().getString(R.string.send_brief), new Object[]{UIUtils.fromHtml(story.title), story.permalink}));
intent.putExtra(Intent.EXTRA_SUBJECT, story.title);
intent.putExtra(Intent.EXTRA_TEXT, String.format(context.getResources().getString(R.string.send_brief), story.title, story.permalink));
context.startActivity(Intent.createChooser(intent, "Send using"));
}
public static void sendStoryFull(Story story, Context context) {
if (story == null ) { return; }
String body = getStoryContent(story.storyHash);
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
if (story == null) return;
String body = getStoryText(story.storyHash);
if (TextUtils.isEmpty(body)) body = getStoryContent(story.storyHash);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_SUBJECT, UIUtils.fromHtml(story.title).toString());
intent.putExtra(Intent.EXTRA_TEXT, String.format(context.getResources().getString(R.string.send_full), new Object[]{story.permalink, UIUtils.fromHtml(story.title), UIUtils.fromHtml(body)}));
intent.putExtra(Intent.EXTRA_SUBJECT, story.title);
intent.putExtra(Intent.EXTRA_TEXT, String.format(context.getResources().getString(R.string.send_full), story.title, story.permalink, UIUtils.fromHtml(body)));
context.startActivity(Intent.createChooser(intent, "Send using"));
}

View file

@ -4,7 +4,6 @@ import java.io.File;
import java.util.Map;
import static android.graphics.Bitmap.Config.ARGB_8888;
import static com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS;
import static com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL;
import static com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP;
@ -182,6 +181,10 @@ public class UIUtils {
return ((float) px) / context.getResources().getDisplayMetrics().density;
}
public static float getDisplayWidthPx(Context context) {
return context.getResources().getDisplayMetrics().widthPixels;
}
/**
* Sets the alpha of a view, totally hiding the view if the alpha is so low
* as to be invisible, but also obeying intended visibility.
@ -218,7 +221,7 @@ public class UIUtils {
// enabled scrolling app bar only for reading
if (activity instanceof Reading) {
AppBarLayout.LayoutParams p = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
p.setScrollFlags(SCROLL_FLAG_SCROLL | SCROLL_FLAG_ENTER_ALWAYS | SCROLL_FLAG_SNAP);
p.setScrollFlags(SCROLL_FLAG_SCROLL | SCROLL_FLAG_SNAP);
toolbar.setLayoutParams(p);
}

View file

@ -8,9 +8,11 @@ import android.view.MenuItem;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.widget.AppCompatEditText;
import com.newsblur.R;
public class SelectOnlyEditText extends EditText {
public class SelectOnlyEditText extends AppCompatEditText {
private Context context;
private boolean forceSelection = false;
@ -31,11 +33,6 @@ public class SelectOnlyEditText extends EditText {
this.context = context;
}
public SelectOnlyEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
this.context = context;
}
public void disableActionMenu() {
this.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
@ -61,6 +58,7 @@ public class SelectOnlyEditText extends EditText {
@Override
protected void onSelectionChanged(int start, int end) {
super.onSelectionChanged(start, end);
if (forceSelection && (start == end)) {
selectAll();
if (context != null) {

View file

@ -8,7 +8,6 @@ import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import com.newsblur.R;
import com.newsblur.util.Log;
import com.newsblur.util.PrefsUtils;