mirror of https://github.com/readrops/Readrops.git
Adding Item view activity with very basic collapsing toolbar layout and webview to render item html content. Big improvements needed.
This commit is contained in:
parent
659eeaa48b
commit
9042b9a039
Binary file not shown.
|
@ -41,7 +41,7 @@ dependencies {
|
||||||
implementation 'com.github.bumptech.glide:glide:4.8.0'
|
implementation 'com.github.bumptech.glide:glide:4.8.0'
|
||||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
|
||||||
implementation "com.github.bumptech.glide:okhttp3-integration:4.8.0"
|
implementation "com.github.bumptech.glide:okhttp3-integration:4.8.0"
|
||||||
implementation ("com.github.bumptech.glide:recyclerview-integration:4.8.0") {
|
implementation("com.github.bumptech.glide:recyclerview-integration:4.8.0") {
|
||||||
// Excludes the support library because it's already included by Glide.
|
// Excludes the support library because it's already included by Glide.
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,4 @@ dependencies {
|
||||||
implementation 'org.jsoup:jsoup:1.11.3'
|
implementation 'org.jsoup:jsoup:1.11.3'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
package="com.readrops.app">
|
package="com.readrops.app">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
@ -13,12 +13,10 @@
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:ignore="GoogleAppIndexingWarning"
|
android:usesCleartextTraffic="true"
|
||||||
android:usesCleartextTraffic="true">
|
tools:ignore="GoogleAppIndexingWarning">
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
|
||||||
<activity android:name=".MainActivity"
|
|
||||||
android:theme="@style/AppTheme.NoActionBar">
|
android:theme="@style/AppTheme.NoActionBar">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
@ -26,5 +24,10 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity android:name=".ItemActivity"
|
||||||
|
android:theme="@style/AppTheme.NoActionBar">
|
||||||
|
|
||||||
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -6,7 +6,6 @@ import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.support.annotation.IdRes;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.support.design.widget.TextInputEditText;
|
import android.support.design.widget.TextInputEditText;
|
||||||
|
@ -19,16 +18,11 @@ import android.widget.Button;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.readrops.app.utils.Utils;
|
||||||
import com.readrops.readropslibrary.HtmlParser;
|
import com.readrops.readropslibrary.HtmlParser;
|
||||||
import com.readrops.readropslibrary.ParsingResult;
|
import com.readrops.readropslibrary.ParsingResult;
|
||||||
|
|
||||||
import org.jsoup.HttpStatusException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.SocketTimeoutException;
|
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.nio.charset.MalformedInputException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.readrops.app;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
|
||||||
|
import com.readrops.app.database.entities.Item;
|
||||||
|
import com.readrops.readropslibrary.ParsingResult;
|
||||||
|
|
||||||
|
public class BasedRepository extends ARepository {
|
||||||
|
|
||||||
|
protected BasedRepository(Application application) {
|
||||||
|
super(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveData<Item> getItemById(int id) {
|
||||||
|
return database.itemDao().getItemById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sync() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addFeed(ParsingResult result) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteFeed(Item item) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveFeed(Item item) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.readrops.app;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.ViewModelProvider;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.support.design.widget.CollapsingToolbarLayout;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import com.readrops.app.utils.GlideApp;
|
||||||
|
import com.readrops.app.utils.Utils;
|
||||||
|
import com.readrops.readropslibrary.Utils.LibUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
|
public class ItemActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
private ItemViewModel viewModel;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_item);
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
int itemId = intent.getIntExtra("itemId", 0);
|
||||||
|
String imageUrl = intent.getStringExtra("imageUrl");
|
||||||
|
|
||||||
|
Toolbar toolbar = findViewById(R.id.collasping_layout_toolbar);
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
|
if (getSupportActionBar() != null)
|
||||||
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
|
CollapsingToolbarLayout toolbarLayout = findViewById(R.id.collapsing_layout);
|
||||||
|
toolbarLayout.setTitle("");
|
||||||
|
|
||||||
|
ImageView imageView = findViewById(R.id.collapsing_layout_image);
|
||||||
|
|
||||||
|
GlideApp.with(this)
|
||||||
|
.load(imageUrl)
|
||||||
|
.into(imageView);
|
||||||
|
|
||||||
|
WebView webView = findViewById(R.id.item_webview);
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()).create(ItemViewModel.class);
|
||||||
|
viewModel.getItemById(itemId).observe(this, item -> {
|
||||||
|
webView.loadData(item.getContent(), LibUtils.HTML_CONTENT_TYPE, "utf-8");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.readrops.app;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.arch.lifecycle.AndroidViewModel;
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.readrops.app.database.Database;
|
||||||
|
import com.readrops.app.database.entities.Item;
|
||||||
|
|
||||||
|
public class ItemViewModel extends AndroidViewModel {
|
||||||
|
|
||||||
|
BasedRepository repository;
|
||||||
|
|
||||||
|
public ItemViewModel(@NonNull Application application) {
|
||||||
|
super(application);
|
||||||
|
|
||||||
|
repository = new BasedRepository(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveData<Item> getItemById(int id) {
|
||||||
|
return repository.getItemById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import android.util.Patterns;
|
||||||
import com.readrops.app.database.ItemWithFeed;
|
import com.readrops.app.database.ItemWithFeed;
|
||||||
import com.readrops.app.database.entities.Feed;
|
import com.readrops.app.database.entities.Feed;
|
||||||
import com.readrops.app.database.entities.Item;
|
import com.readrops.app.database.entities.Item;
|
||||||
|
import com.readrops.app.utils.Utils;
|
||||||
import com.readrops.readropslibrary.HtmlParser;
|
import com.readrops.readropslibrary.HtmlParser;
|
||||||
import com.readrops.readropslibrary.ParsingResult;
|
import com.readrops.readropslibrary.ParsingResult;
|
||||||
import com.readrops.readropslibrary.QueryCallback;
|
import com.readrops.readropslibrary.QueryCallback;
|
||||||
|
@ -28,7 +29,6 @@ import org.jsoup.Jsoup;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
@ -203,8 +203,16 @@ public class LocalFeedRepository extends ARepository implements QueryCallback {
|
||||||
for (Item dbItem : items) {
|
for (Item dbItem : items) {
|
||||||
if (!Boolean.valueOf(database.itemDao().guidExist(dbItem.getGuid()))) {
|
if (!Boolean.valueOf(database.itemDao().guidExist(dbItem.getGuid()))) {
|
||||||
if (dbItem.getDescription() != null) {
|
if (dbItem.getDescription() != null) {
|
||||||
if (dbItem.getImageLink() == null)
|
|
||||||
dbItem.setImageLink(HtmlParser.getDescImageLink(dbItem.getDescription(), feed.getSiteUrl()));
|
if (dbItem.getImageLink() == null) {
|
||||||
|
String imageUrl = HtmlParser.getDescImageLink(dbItem.getDescription(), feed.getSiteUrl());
|
||||||
|
if (imageUrl != null) {
|
||||||
|
dbItem.setImageLink(imageUrl);
|
||||||
|
|
||||||
|
if (dbItem.getContent() != null) // removing cover image in content if found in description
|
||||||
|
dbItem.setContent(HtmlParser.deleteCoverImage(dbItem.getContent()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dbItem.setDescription(Jsoup.parse(dbItem.getDescription()).text());
|
dbItem.setDescription(Jsoup.parse(dbItem.getDescription()).text());
|
||||||
}
|
}
|
||||||
|
@ -224,23 +232,11 @@ public class LocalFeedRepository extends ARepository implements QueryCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
private @ColorInt int getFaviconColor(String favUrl) throws IOException {
|
private @ColorInt int getFaviconColor(String favUrl) throws IOException {
|
||||||
Bitmap favicon = getFaviconFromUrl(favUrl);
|
Bitmap favicon = Utils.getImageFromUrl(favUrl);
|
||||||
Palette palette = Palette.from(favicon).generate();
|
Palette palette = Palette.from(favicon).generate();
|
||||||
|
|
||||||
return palette.getDominantSwatch().getRgb();
|
return palette.getDominantSwatch().getRgb();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bitmap getFaviconFromUrl(String url) throws IOException {
|
|
||||||
OkHttpClient okHttpClient = new OkHttpClient();
|
|
||||||
Request request = new Request.Builder().url(url).build();
|
|
||||||
|
|
||||||
Response response = okHttpClient.newCall(request).execute();
|
|
||||||
|
|
||||||
if (response.isSuccessful()) {
|
|
||||||
InputStream inputStream = response.body().byteStream();
|
|
||||||
return BitmapFactory.decodeStream(inputStream);
|
|
||||||
} else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.readrops.app;
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.arch.lifecycle.ViewModelProvider;
|
import android.arch.lifecycle.ViewModelProvider;
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.design.widget.NavigationView;
|
import android.support.design.widget.NavigationView;
|
||||||
|
@ -123,6 +124,13 @@ public class MainActivity extends AppCompatActivity implements SimpleCallback, S
|
||||||
|
|
||||||
ViewPreloadSizeProvider preloadSizeProvider = new ViewPreloadSizeProvider();
|
ViewPreloadSizeProvider preloadSizeProvider = new ViewPreloadSizeProvider();
|
||||||
adapter = new MainItemListAdapter(GlideApp.with(this), preloadSizeProvider);
|
adapter = new MainItemListAdapter(GlideApp.with(this), preloadSizeProvider);
|
||||||
|
adapter.setOnItemClickListener(itemWithFeed -> {
|
||||||
|
Intent intent = new Intent(this, ItemActivity.class);
|
||||||
|
intent.putExtra("itemId", itemWithFeed.getItem().getId());
|
||||||
|
intent.putExtra("imageUrl", itemWithFeed.getItem().getImageLink());
|
||||||
|
|
||||||
|
startActivity(intent);
|
||||||
|
});
|
||||||
|
|
||||||
RecyclerViewPreloader<String> preloader = new RecyclerViewPreloader<String>(Glide.with(this), adapter, preloadSizeProvider, 10);
|
RecyclerViewPreloader<String> preloader = new RecyclerViewPreloader<String>(Glide.with(this), adapter, preloadSizeProvider, 10);
|
||||||
recyclerView.addOnScrollListener(preloader);
|
recyclerView.addOnScrollListener(preloader);
|
||||||
|
|
|
@ -31,4 +31,7 @@ public interface ItemDao {
|
||||||
|
|
||||||
@Insert
|
@Insert
|
||||||
void insertAll(List<Item> items);
|
void insertAll(List<Item> items);
|
||||||
|
|
||||||
|
@Query("Select * from Item Where id = :id")
|
||||||
|
LiveData<Item> getItemById(int id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
package com.readrops.app.utils;
|
package com.readrops.app.utils;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
public final class Utils {
|
public final class Utils {
|
||||||
|
|
||||||
public static final String HTTP_PREFIX = "http://";
|
public static final String HTTP_PREFIX = "http://";
|
||||||
|
@ -22,4 +31,18 @@ public final class Utils {
|
||||||
toast.show();
|
toast.show();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Bitmap getImageFromUrl(String url) throws IOException {
|
||||||
|
OkHttpClient okHttpClient = new OkHttpClient();
|
||||||
|
Request request = new Request.Builder().url(url).build();
|
||||||
|
|
||||||
|
Response response = okHttpClient.newCall(request).execute();
|
||||||
|
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
InputStream inputStream = response.body().byteStream();
|
||||||
|
return BitmapFactory.decodeStream(inputStream);
|
||||||
|
} else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
tools:context=".ItemActivity">
|
||||||
|
|
||||||
|
<android.support.design.widget.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:theme="@style/Widget.AppCompat.Light.ActionBar">
|
||||||
|
|
||||||
|
<android.support.design.widget.CollapsingToolbarLayout
|
||||||
|
android:id="@+id/collapsing_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:contentScrim="?attr/colorPrimary"
|
||||||
|
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/collapsing_layout_image"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
app:layout_collapseMode="parallax" />
|
||||||
|
|
||||||
|
<android.support.v7.widget.Toolbar
|
||||||
|
android:id="@+id/collasping_layout_toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
app:layout_collapseMode="pin"
|
||||||
|
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
|
||||||
|
|
||||||
|
</android.support.design.widget.CollapsingToolbarLayout>
|
||||||
|
|
||||||
|
</android.support.design.widget.AppBarLayout>
|
||||||
|
|
||||||
|
<android.support.v4.widget.NestedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
|
||||||
|
<WebView
|
||||||
|
android:id="@+id/item_webview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</android.support.v4.widget.NestedScrollView>
|
||||||
|
|
||||||
|
</android.support.design.widget.CoordinatorLayout>
|
|
@ -111,4 +111,14 @@ public final class HtmlParser {
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String deleteCoverImage(String content) {
|
||||||
|
Document document = Jsoup.parse(content);
|
||||||
|
Elements elements = document.select("img");
|
||||||
|
|
||||||
|
if (!elements.isEmpty())
|
||||||
|
elements.first().remove();
|
||||||
|
|
||||||
|
return document.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue