#1399 Search for feeds

This commit is contained in:
sictiru 2021-01-16 22:18:08 -08:00
parent fd69353bc8
commit ce0f403b59
13 changed files with 396 additions and 415 deletions

View file

@ -133,19 +133,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

@ -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,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>

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

@ -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

@ -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;
}
}