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:
Shinokuni 2019-02-07 18:33:55 +00:00
parent 659eeaa48b
commit 9042b9a039
13 changed files with 245 additions and 33 deletions

View File

@ -41,7 +41,7 @@ dependencies {
implementation 'com.github.bumptech.glide:glide: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: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.
transitive = false
}
@ -58,6 +58,4 @@ dependencies {
implementation 'org.jsoup:jsoup:1.11.3'
}

View File

@ -4,7 +4,7 @@
package="com.readrops.app">
<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
android:allowBackup="true"
@ -13,12 +13,10 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning"
android:usesCleartextTraffic="true">
<activity android:name=".MainActivity"
android:usesCleartextTraffic="true"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".MainActivity"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -26,5 +24,10 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ItemActivity"
android:theme="@style/AppTheme.NoActionBar">
</activity>
</application>
</manifest>

View File

@ -6,7 +6,6 @@ import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.design.widget.TextInputEditText;
@ -19,16 +18,11 @@ import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.readrops.app.utils.Utils;
import com.readrops.readropslibrary.HtmlParser;
import com.readrops.readropslibrary.ParsingResult;
import org.jsoup.HttpStatusException;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.charset.MalformedInputException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;

View File

@ -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) {
}
}

View File

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

View File

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

View File

@ -12,6 +12,7 @@ import android.util.Patterns;
import com.readrops.app.database.ItemWithFeed;
import com.readrops.app.database.entities.Feed;
import com.readrops.app.database.entities.Item;
import com.readrops.app.utils.Utils;
import com.readrops.readropslibrary.HtmlParser;
import com.readrops.readropslibrary.ParsingResult;
import com.readrops.readropslibrary.QueryCallback;
@ -28,7 +29,6 @@ import org.jsoup.Jsoup;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.TreeMap;
@ -203,8 +203,16 @@ public class LocalFeedRepository extends ARepository implements QueryCallback {
for (Item dbItem : items) {
if (!Boolean.valueOf(database.itemDao().guidExist(dbItem.getGuid()))) {
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());
}
@ -224,23 +232,11 @@ public class LocalFeedRepository extends ARepository implements QueryCallback {
}
private @ColorInt int getFaviconColor(String favUrl) throws IOException {
Bitmap favicon = getFaviconFromUrl(favUrl);
Bitmap favicon = Utils.getImageFromUrl(favUrl);
Palette palette = Palette.from(favicon).generate();
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;
}
}

View File

@ -2,6 +2,7 @@ package com.readrops.app;
import android.app.Dialog;
import android.arch.lifecycle.ViewModelProvider;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
@ -123,6 +124,13 @@ public class MainActivity extends AppCompatActivity implements SimpleCallback, S
ViewPreloadSizeProvider preloadSizeProvider = new ViewPreloadSizeProvider();
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);
recyclerView.addOnScrollListener(preloader);

View File

@ -31,4 +31,7 @@ public interface ItemDao {
@Insert
void insertAll(List<Item> items);
@Query("Select * from Item Where id = :id")
LiveData<Item> getItemById(int id);
}

View File

@ -1,10 +1,19 @@
package com.readrops.app.utils;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
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 static final String HTTP_PREFIX = "http://";
@ -22,4 +31,18 @@ public final class Utils {
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;
}
}

View File

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

View File

@ -111,4 +111,14 @@ public final class HtmlParser {
else
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();
}
}