mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-09-18 21:50:56 +00:00
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:
commit
9566d931d7
24 changed files with 600 additions and 641 deletions
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
9
clients/android/NewsBlur/res/drawable/ic_clear.xml
Normal file
9
clients/android/NewsBlur/res/drawable/ic_clear.xml
Normal 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>
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
57
clients/android/NewsBlur/res/layout/view_feed_search_row.xml
Normal file
57
clients/android/NewsBlur/res/layout/view_feed_search_row.xml
Normal 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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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"));
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue