From 64fc2ba71b0cc047060a6343c0757e6bec617446 Mon Sep 17 00:00:00 2001 From: David Luhmer Date: Sat, 2 Jan 2021 13:07:10 +0100 Subject: use ViewBinding everywhere and get rid of Butterknife Signed-off-by: David Luhmer --- .../NewsReaderDetailFragment.java | 16 +- .../owncloudnewsreader/NewsReaderListActivity.java | 384 ++++++++++--------- .../adapter/NewsListRecyclerAdapter.java | 96 +++-- .../adapter/ProgressViewHolder.java | 3 +- .../adapter/RecyclerItemClickListener.java | 5 +- .../adapter/RssItemCardViewHolder.java | 78 ++++ .../adapter/RssItemFullTextViewHolder.java | 13 + .../adapter/RssItemHeadlineViewHolder.java | 78 ++++ .../adapter/RssItemTextViewHolder.java | 78 ++++ .../adapter/RssItemThumbnailViewHolder.java | 128 +++++++ .../adapter/RssItemViewHolder.java | 323 ++++++++++++++++ .../adapter/RssItemWebViewHolder.java | 82 ++++ .../owncloudnewsreader/adapter/ViewHolder.java | 413 --------------------- .../owncloudnewsreader/helper/FavIconHandler.java | 27 +- 14 files changed, 1037 insertions(+), 687 deletions(-) create mode 100644 News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemCardViewHolder.java create mode 100644 News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemFullTextViewHolder.java create mode 100644 News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemHeadlineViewHolder.java create mode 100644 News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemTextViewHolder.java create mode 100644 News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemThumbnailViewHolder.java create mode 100644 News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemViewHolder.java create mode 100644 News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemWebViewHolder.java delete mode 100644 News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/ViewHolder.java (limited to 'News-Android-App/src/main/java') diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderDetailFragment.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderDetailFragment.java index 26c1f033..baad3656 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderDetailFragment.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderDetailFragment.java @@ -62,7 +62,7 @@ import java.util.List; import javax.inject.Inject; import de.luhmer.owncloudnewsreader.adapter.NewsListRecyclerAdapter; -import de.luhmer.owncloudnewsreader.adapter.ViewHolder; +import de.luhmer.owncloudnewsreader.adapter.RssItemViewHolder; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm.SORT_DIRECTION; import de.luhmer.owncloudnewsreader.database.model.RssItem; @@ -403,7 +403,7 @@ public class NewsReaderDetailFragment extends Fragment { for (int i = firstVisibleItem; i < firstVisibleItem + numberItemsAhead; i++) { //Log.v(TAG, "Mark item as read: " + i); - ViewHolder vh = (ViewHolder) binding.list.findViewHolderForLayoutPosition(i); + RssItemViewHolder vh = (RssItemViewHolder) binding.list.findViewHolderForLayoutPosition(i); if (vh != null && !vh.shouldStayUnread()) { adapter.changeReadStateOfItem(vh, true); } @@ -416,8 +416,8 @@ public class NewsReaderDetailFragment extends Fragment { for (int i = firstVisibleItem; i <= lastVisibleItem; i++) { RecyclerView.ViewHolder vhTemp = binding.list.findViewHolderForLayoutPosition(i); - if (vhTemp instanceof ViewHolder) { //Check for ViewHolder instance because of ProgressViewHolder - ViewHolder vh = (ViewHolder) vhTemp; + if (vhTemp instanceof RssItemViewHolder) { //Check for ViewHolder instance because of ProgressViewHolder + RssItemViewHolder vh = (RssItemViewHolder) vhTemp; if (!vh.shouldStayUnread()) { adapter.changeReadStateOfItem(vh, true); @@ -616,16 +616,16 @@ public class NewsReaderDetailFragment extends Fragment { swipeAction = mPrefs.getString(SP_SWIPE_RIGHT_ACTION, SP_SWIPE_RIGHT_ACTION_DEFAULT); switch (swipeAction) { case "0": // Open link in browser and mark as read - String currentUrl = ((ViewHolder) viewHolder).getRssItem().getLink(); + String currentUrl = ((RssItemViewHolder) viewHolder).getRssItem().getLink(); Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(currentUrl)); startActivity(browserIntent); - adapter.changeReadStateOfItem((ViewHolder) viewHolder, true); + adapter.changeReadStateOfItem((RssItemViewHolder) viewHolder, true); break; case "1": // Star - adapter.toggleStarredStateOfItem((ViewHolder) viewHolder); + adapter.toggleStarredStateOfItem((RssItemViewHolder) viewHolder); break; case "2": // Read - adapter.toggleReadStateOfItem((ViewHolder) viewHolder); + adapter.toggleReadStateOfItem((RssItemViewHolder) viewHolder); break; default: Log.e(TAG, "Swipe preferences has an invalid value"); diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderListActivity.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderListActivity.java index 7d6feae7..69a5ae06 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderListActivity.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderListActivity.java @@ -81,6 +81,7 @@ import java.lang.reflect.Field; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.concurrent.TimeUnit; import javax.inject.Inject; @@ -89,7 +90,7 @@ import javax.inject.Named; import de.luhmer.owncloudnewsreader.ListView.SubscriptionExpandableListAdapter; import de.luhmer.owncloudnewsreader.adapter.NewsListRecyclerAdapter; import de.luhmer.owncloudnewsreader.adapter.RecyclerItemClickListener; -import de.luhmer.owncloudnewsreader.adapter.ViewHolder; +import de.luhmer.owncloudnewsreader.adapter.RssItemViewHolder; import de.luhmer.owncloudnewsreader.authentication.AccountGeneral; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; import de.luhmer.owncloudnewsreader.database.model.Feed; @@ -150,42 +151,84 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements private ActionBarDrawerToggle drawerToggle; private SearchView mSearchView; - private String mSearchString; - private static final String SEARCH_KEY = "SEARCH_KEY"; + private String mSearchString; + private static final String SEARCH_KEY = "SEARCH_KEY"; - private PublishSubject searchPublishSubject; - private static final int REQUEST_CODE_PERMISSION_DOWNLOAD_WEB_ARCHIVE = 1; + private PublishSubject searchPublishSubject; + private static final int REQUEST_CODE_PERMISSION_DOWNLOAD_WEB_ARCHIVE = 1; private static final int REQUEST_CODE_PERMISSION_LOCATION = 139; - private static final String ID_FEED_STRING = "ID_FEED_STRING"; - private static final String IS_FOLDER_BOOLEAN = "IS_FOLDER_BOOLEAN"; - private static final String OPTIONAL_FOLDER_ID = "OPTIONAL_FOLDER_ID"; - private static final String LIST_ADAPTER_TOTAL_COUNT = "LIST_ADAPTER_TOTAL_COUNT"; - private static final String LIST_ADAPTER_PAGE_COUNT = "LIST_ADAPTER_PAGE_COUNT"; + private static final String ID_FEED_STRING = "ID_FEED_STRING"; + private static final String IS_FOLDER_BOOLEAN = "IS_FOLDER_BOOLEAN"; + private static final String OPTIONAL_FOLDER_ID = "OPTIONAL_FOLDER_ID"; + private static final String LIST_ADAPTER_TOTAL_COUNT = "LIST_ADAPTER_TOTAL_COUNT"; + private static final String LIST_ADAPTER_PAGE_COUNT = "LIST_ADAPTER_PAGE_COUNT"; - @Inject @Named("sharedPreferencesFileName") String sharedPreferencesFileName; + @Inject + @Named("sharedPreferencesFileName") + String sharedPreferencesFileName; - @Override - protected void onCreate(Bundle savedInstanceState) { - ((NewsReaderApplication) getApplication()).getAppComponent().injectActivity(this); - - SharedPreferences defaultValueSp = getSharedPreferences(PreferenceManager.KEY_HAS_SET_DEFAULT_VALUES, Context.MODE_PRIVATE); - if(!defaultValueSp.getBoolean(PreferenceManager.KEY_HAS_SET_DEFAULT_VALUES, false)) { - PreferenceManager.setDefaultValues(this, sharedPreferencesFileName, Context.MODE_PRIVATE, R.xml.pref_data_sync, true); - PreferenceManager.setDefaultValues(this, sharedPreferencesFileName, Context.MODE_PRIVATE, R.xml.pref_display, true); - PreferenceManager.setDefaultValues(this, sharedPreferencesFileName, Context.MODE_PRIVATE, R.xml.pref_general, true); - PreferenceManager.setDefaultValues(this, sharedPreferencesFileName, Context.MODE_PRIVATE, R.xml.pref_notification, true); - } + private View.OnClickListener mSnackbarListener = view -> { + //Toast.makeText(getActivity(), "button 1 pressed", 3000).show(); + updateCurrentRssView(); + }; + + @Override + public void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + + if (drawerToggle != null) { + drawerToggle.syncState(); + } + + // Fragments are not ready when calling the method below in onCreate() + updateButtonLayout(); + + //Start auto sync if enabled + if (mPrefs.getBoolean(SettingsActivity.CB_SYNCONSTARTUP_STRING, false)) { + startSync(); + } + + boolean tabletSize = getResources().getBoolean(R.bool.isTablet); + if (tabletSize) { + showTapLogoToSyncShowcaseView(); + } + + + // In case automatic theme selection based on time is selected, check if location permission + // for twilight manager is given.. otherwise request it + if (isUserLoggedIn() && ThemeChooser.isAutoThemeSelectionEnabled() && ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions( + this, + new String[]{ACCESS_FINE_LOCATION}, + REQUEST_CODE_PERMISSION_LOCATION + ); + } + } + + private boolean isUserLoggedIn() { + return (mPrefs.getString(SettingsActivity.EDT_OWNCLOUDROOTPATH_STRING, null) != null); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + ((NewsReaderApplication) getApplication()).getAppComponent().injectActivity(this); + + SharedPreferences defaultValueSp = getSharedPreferences(PreferenceManager.KEY_HAS_SET_DEFAULT_VALUES, Context.MODE_PRIVATE); + if (!defaultValueSp.getBoolean(PreferenceManager.KEY_HAS_SET_DEFAULT_VALUES, false)) { + PreferenceManager.setDefaultValues(this, sharedPreferencesFileName, Context.MODE_PRIVATE, R.xml.pref_data_sync, true); + PreferenceManager.setDefaultValues(this, sharedPreferencesFileName, Context.MODE_PRIVATE, R.xml.pref_display, true); + PreferenceManager.setDefaultValues(this, sharedPreferencesFileName, Context.MODE_PRIVATE, R.xml.pref_general, true); + PreferenceManager.setDefaultValues(this, sharedPreferencesFileName, Context.MODE_PRIVATE, R.xml.pref_notification, true); + } super.onCreate(savedInstanceState); binding = ActivityNewsreaderBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - if (binding.toolbarLayout.toolbar != null) { - setSupportActionBar(binding.toolbarLayout.toolbar); - } + setSupportActionBar(binding.toolbarLayout.toolbar); initAccountManager(); @@ -230,10 +273,10 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements binding.drawerLayout.addDrawerListener(drawerToggle); - adjustEdgeSizeOfDrawer(); + adjustEdgeSizeOfDrawer(); } setSupportActionBar(binding.toolbarLayout.toolbar); - getSupportActionBar().setDisplayShowHomeEnabled(true); + Objects.requireNonNull(getSupportActionBar()).setDisplayShowHomeEnabled(true); if (drawerToggle != null) { drawerToggle.syncState(); } @@ -241,84 +284,39 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements //AppRater.app_launched(this); //AppRater.rateNow(this); - if (savedInstanceState == null) { //When the app starts (no orientation change) - updateDetailFragment(SubscriptionExpandableListAdapter.SPECIAL_FOLDERS.ALL_UNREAD_ITEMS.getValue(), true, null, true); - } - } - - @Override - public void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - - if (drawerToggle != null) { - drawerToggle.syncState(); - } - - // Fragments are not ready when calling the method below in onCreate() - updateButtonLayout(); - - //Start auto sync if enabled - if (mPrefs.getBoolean(SettingsActivity.CB_SYNCONSTARTUP_STRING, false)) { - startSync(); - } - - boolean tabletSize = getResources().getBoolean(R.bool.isTablet); - if (tabletSize) { - showTapLogoToSyncShowcaseView(); - } - - - // In case automatic theme selection based on time is selected, check if location permission - // for twilight manager is given.. otherwise request it - if(isUserLoggedIn() && ThemeChooser.isAutoThemeSelectionEnabled() && ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions( - this, - new String[]{ ACCESS_FINE_LOCATION }, - REQUEST_CODE_PERMISSION_LOCATION - ); - } - } + if (savedInstanceState == null) { //When the app starts (no orientation change) + updateDetailFragment(SubscriptionExpandableListAdapter.SPECIAL_FOLDERS.ALL_UNREAD_ITEMS.getValue(), true, null, true); + } + } - private boolean isUserLoggedIn() { - return (mPrefs.getString(SettingsActivity.EDT_OWNCLOUDROOTPATH_STRING, null) != null); + @Override + protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { + restoreInstanceState(savedInstanceState); + super.onRestoreInstanceState(savedInstanceState); } @Override - protected void onSaveInstanceState(Bundle outState) { + protected void onSaveInstanceState(@NonNull Bundle outState) { saveInstanceState(outState); super.onSaveInstanceState(outState); } - @Override - protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { - restoreInstanceState(savedInstanceState); - super.onRestoreInstanceState(savedInstanceState); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - if (drawerToggle != null) { - drawerToggle.onConfigurationChanged(newConfig); - } - } - - private void saveInstanceState(Bundle outState) { - NewsReaderDetailFragment ndf = getNewsReaderDetailFragment(); - if (ndf != null) { - outState.putLong(OPTIONAL_FOLDER_ID, ndf.getIdFolder()); - outState.putBoolean(IS_FOLDER_BOOLEAN, ndf.getIdFeed() == null); - outState.putLong(ID_FEED_STRING, ndf.getIdFeed() != null ? ndf.getIdFeed() : ndf.getIdFolder()); - - NewsListRecyclerAdapter adapter = (NewsListRecyclerAdapter) ndf.getRecyclerView().getAdapter(); - if (adapter != null) { - outState.putInt(LIST_ADAPTER_TOTAL_COUNT, adapter.getTotalItemCount()); - outState.putInt(LIST_ADAPTER_PAGE_COUNT, adapter.getCachedPages()); - } - } - if(mSearchView != null) { - mSearchString = mSearchView.getQuery().toString(); - outState.putString(SEARCH_KEY, mSearchString); + private void saveInstanceState(Bundle outState) { + NewsReaderDetailFragment ndf = getNewsReaderDetailFragment(); + if (ndf != null) { + outState.putLong(OPTIONAL_FOLDER_ID, ndf.getIdFolder()); + outState.putBoolean(IS_FOLDER_BOOLEAN, ndf.getIdFeed() == null); + outState.putLong(ID_FEED_STRING, ndf.getIdFeed() != null ? ndf.getIdFeed() : ndf.getIdFolder()); + + NewsListRecyclerAdapter adapter = (NewsListRecyclerAdapter) ndf.getRecyclerView().getAdapter(); + if (adapter != null) { + outState.putInt(LIST_ADAPTER_TOTAL_COUNT, adapter.getTotalItemCount()); + outState.putInt(LIST_ADAPTER_PAGE_COUNT, adapter.getCachedPages()); + } + } + if (mSearchView != null) { + mSearchString = mSearchView.getQuery().toString(); + outState.putString(SEARCH_KEY, mSearchString); } } @@ -327,70 +325,69 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements savedInstanceState.containsKey(IS_FOLDER_BOOLEAN) && savedInstanceState.containsKey(OPTIONAL_FOLDER_ID)) { - NewsListRecyclerAdapter adapter = new NewsListRecyclerAdapter(this, getNewsReaderDetailFragment().binding.list, this, mPostDelayHandler, mPrefs); - - adapter.setTotalItemCount(savedInstanceState.getInt(LIST_ADAPTER_TOTAL_COUNT)); - adapter.setCachedPages(savedInstanceState.getInt(LIST_ADAPTER_PAGE_COUNT)); + NewsListRecyclerAdapter adapter = new NewsListRecyclerAdapter(this, getNewsReaderDetailFragment().binding.list, this, mPostDelayHandler, mPrefs); - getNewsReaderDetailFragment() - .getRecyclerView() - .setAdapter(adapter); + adapter.setTotalItemCount(savedInstanceState.getInt(LIST_ADAPTER_TOTAL_COUNT)); + adapter.setCachedPages(savedInstanceState.getInt(LIST_ADAPTER_PAGE_COUNT)); - updateDetailFragment(savedInstanceState.getLong(ID_FEED_STRING), - savedInstanceState.getBoolean(IS_FOLDER_BOOLEAN), - savedInstanceState.getLong(OPTIONAL_FOLDER_ID), - false); - } - mSearchString = savedInstanceState.getString(SEARCH_KEY, null); - } + getNewsReaderDetailFragment() + .getRecyclerView() + .setAdapter(adapter); + updateDetailFragment(savedInstanceState.getLong(ID_FEED_STRING), + savedInstanceState.getBoolean(IS_FOLDER_BOOLEAN), + savedInstanceState.getLong(OPTIONAL_FOLDER_ID), + false); + } + mSearchString = savedInstanceState.getString(SEARCH_KEY, null); + } - /** - * This method increases the "pull to open drawer" area by three. - * This method should be called only once! - */ - private void adjustEdgeSizeOfDrawer() { - try { - // increase the size of the drag margin to prevent starting a star swipe when - // trying to open the drawer. - Field mDragger = binding.drawerLayout.getClass().getDeclaredField("mLeftDragger"); - mDragger.setAccessible(true); - ViewDragHelper draggerObj = (ViewDragHelper) mDragger.get(binding.drawerLayout); - Field mEdgeSize = draggerObj.getClass().getDeclaredField("mEdgeSize"); - mEdgeSize.setAccessible(true); - int edge = mEdgeSize.getInt(draggerObj); - mEdgeSize.setInt(draggerObj, edge * 3); - } catch (Exception e) { - Log.e(TAG, "Setting edge width of drawer failed..", e); - } - } + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (drawerToggle != null) { + drawerToggle.onConfigurationChanged(newConfig); + } + } - public int getEdgeSizeOfDrawer() { - try { - Field mDragger = binding.drawerLayout.getClass().getDeclaredField("mLeftDragger"); - mDragger.setAccessible(true); - ViewDragHelper draggerObj = (ViewDragHelper) mDragger.get(binding.drawerLayout); - Field mEdgeSize = draggerObj.getClass().getDeclaredField("mEdgeSize"); - mEdgeSize.setAccessible(true); - return mEdgeSize.getInt(draggerObj); - } catch (Exception e) { - Log.e(TAG, "Failed to get edge size of drawer", e); - } - return 0; - } + /** + * This method increases the "pull to open drawer" area by three. + * This method should be called only once! + */ + private void adjustEdgeSizeOfDrawer() { + try { + // increase the size of the drag margin to prevent starting a star swipe when + // trying to open the drawer. + Field mDragger = Objects.requireNonNull(binding.drawerLayout).getClass().getDeclaredField("mLeftDragger"); + mDragger.setAccessible(true); + ViewDragHelper draggerObj = (ViewDragHelper) mDragger.get(binding.drawerLayout); + Field mEdgeSize = Objects.requireNonNull(draggerObj).getClass().getDeclaredField("mEdgeSize"); + mEdgeSize.setAccessible(true); + int edge = mEdgeSize.getInt(draggerObj); + mEdgeSize.setInt(draggerObj, edge * 3); + } catch (Exception e) { + Log.e(TAG, "Setting edge width of drawer failed..", e); + } + } - private void showTapLogoToSyncShowcaseView() { - getSlidingListFragment().showTapLogoToSyncShowcaseView(); - } + private void showTapLogoToSyncShowcaseView() { + getSlidingListFragment().showTapLogoToSyncShowcaseView(); + } - private View.OnClickListener mSnackbarListener = new View.OnClickListener() { - @Override - public void onClick(View view) { - //Toast.makeText(getActivity(), "button 1 pressed", 3000).show(); - updateCurrentRssView(); - } - }; + public int getEdgeSizeOfDrawer() { + try { + Field mDragger = Objects.requireNonNull(binding.drawerLayout).getClass().getDeclaredField("mLeftDragger"); + mDragger.setAccessible(true); + ViewDragHelper draggerObj = (ViewDragHelper) mDragger.get(binding.drawerLayout); + Field mEdgeSize = Objects.requireNonNull(draggerObj).getClass().getDeclaredField("mEdgeSize"); + mEdgeSize.setAccessible(true); + return mEdgeSize.getInt(draggerObj); + } catch (Exception e) { + Log.e(TAG, "Failed to get edge size of drawer", e); + } + return 0; + } /** @@ -598,17 +595,10 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements startDialogFragment(idFeed, false); } - private void startDialogFragment(long idFeed, Boolean isFolder) { DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(getApplicationContext()); - if (isFolder) { - /* - if(idFeed >= 0) { - //currently no actions for folders - //String titel = dbConn.getFolderById(idFeed).getLabel(); - }*/ - } else { + if (!isFolder) { String titel = dbConn.getFeedById(idFeed).getFeedTitle(); String iconurl = dbConn.getFeedById(idFeed).getFaviconUrl(); String feedurl = dbConn.getFeedById(idFeed).getLink(); @@ -660,14 +650,14 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements } - public void UpdateItemList() - { - try { - NewsReaderDetailFragment nrD = getNewsReaderDetailFragment(); - if (nrD != null) - nrD.getRecyclerView().getAdapter().notifyDataSetChanged(); - } catch (Exception ex) { - ex.printStackTrace(); + public void UpdateItemList() { + try { + NewsReaderDetailFragment nrD = getNewsReaderDetailFragment(); + if (nrD != null && nrD.getRecyclerView() != null) { + nrD.getRecyclerView().getAdapter().notifyDataSetChanged(); + } + } catch (Exception ex) { + ex.printStackTrace(); } } @@ -786,14 +776,14 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements public static final int RESULT_ADD_NEW_FEED = 15643; @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(drawerToggle != null && drawerToggle.onOptionsItemSelected(item)) + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + if (drawerToggle != null && drawerToggle.onOptionsItemSelected(item)) return true; switch (item.getItemId()) { case android.R.id.home: - if(handlePodcastBackPressed()) + if (handlePodcastBackPressed()) return true; break; @@ -860,7 +850,6 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements } else { Log.e("Permission error","Asking for permission"); requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.FOREGROUND_SERVICE}, REQUEST_CODE_PERMISSION_DOWNLOAD_WEB_ARCHIVE); - return; } } else { //you dont need to worry about these stuff below api level 23 Log.v("Permission error","You already have the permission"); @@ -1057,23 +1046,22 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements private void resetUiAndStartSync() { getSlidingListFragment().loadOwncloudOrNextcloudBanner(); getSlidingListFragment().reloadAdapter(); - updateCurrentRssView(); - startSync(); - getSlidingListFragment().bindUserInfoToUI(); - } + updateCurrentRssView(); + startSync(); + getSlidingListFragment().bindUserInfoToUI(); + } - private void UpdateListView() - { - getNewsReaderDetailFragment().notifyDataSetChangedOnAdapter(); - } + private void UpdateListView() { + getNewsReaderDetailFragment().notifyDataSetChangedOnAdapter(); + } - @Override - public void onClick(ViewHolder vh, int position) { + @Override + public void onClick(RssItemViewHolder vh, int position) { if (mPrefs.getBoolean(SettingsActivity.CB_SKIP_DETAILVIEW_AND_OPEN_BROWSER_DIRECTLY_STRING, false)) { - String currentUrl = vh.getRssItem().getLink(); + String currentUrl = vh.getRssItem().getLink(); - //Choose Browser based on user settings + //Choose Browser based on user settings //modified copy from NewsDetailFragment.java:loadUrl(String url) int selectedBrowser = Integer.parseInt(mPrefs.getString(SettingsActivity.SP_DISPLAY_BROWSER, "0")); if (selectedBrowser == 0) { // Custom Tabs @@ -1089,7 +1077,7 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements startActivity(browserIntent); } - ((NewsListRecyclerAdapter) getNewsReaderDetailFragment().getRecyclerView().getAdapter()).changeReadStateOfItem(vh, true); + ((NewsListRecyclerAdapter) getNewsReaderDetailFragment().getRecyclerView().getAdapter()).changeReadStateOfItem(vh, true); } else { Intent intentNewsDetailAct = new Intent(this, NewsDetailActivity.class); @@ -1100,18 +1088,18 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements } @Override - public boolean onLongClick(ViewHolder vh, int position) { - RssItem rssItem = vh.getRssItem(); - DialogFragment newFragment = - NewsDetailImageDialogFragment.newInstanceUrl(rssItem.getTitle(), rssItem.getLink()); - FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); - Fragment prev = getSupportFragmentManager().findFragmentByTag("menu_fragment_dialog"); - if (prev != null) { - ft.remove(prev); - } - ft.addToBackStack(null); - newFragment.show(ft, "menu_fragment_dialog"); - return true; + public boolean onLongClick(RssItemViewHolder vh, int position) { + RssItem rssItem = vh.getRssItem(); + DialogFragment newFragment = + NewsDetailImageDialogFragment.newInstanceUrl(rssItem.getTitle(), rssItem.getLink()); + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + Fragment prev = getSupportFragmentManager().findFragmentByTag("menu_fragment_dialog"); + if (prev != null) { + ft.remove(prev); + } + ft.addToBackStack(null); + newFragment.show(ft, "menu_fragment_dialog"); + return true; } @Override diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/NewsListRecyclerAdapter.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/NewsListRecyclerAdapter.java index 1026fd83..f93d2e89 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/NewsListRecyclerAdapter.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/NewsListRecyclerAdapter.java @@ -1,5 +1,6 @@ package de.luhmer.owncloudnewsreader.adapter; +import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.util.Log; @@ -7,6 +8,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; import androidx.fragment.app.FragmentActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -22,6 +24,11 @@ import de.luhmer.owncloudnewsreader.R; import de.luhmer.owncloudnewsreader.SettingsActivity; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; import de.luhmer.owncloudnewsreader.database.model.RssItem; +import de.luhmer.owncloudnewsreader.databinding.SubscriptionDetailListItemCardViewBinding; +import de.luhmer.owncloudnewsreader.databinding.SubscriptionDetailListItemHeadlineBinding; +import de.luhmer.owncloudnewsreader.databinding.SubscriptionDetailListItemTextBinding; +import de.luhmer.owncloudnewsreader.databinding.SubscriptionDetailListItemThumbnailBinding; +import de.luhmer.owncloudnewsreader.databinding.SubscriptionDetailListItemWebLayoutBinding; import de.luhmer.owncloudnewsreader.events.podcast.PodcastCompletedEvent; import de.luhmer.owncloudnewsreader.helper.AsyncTaskHelper; import de.luhmer.owncloudnewsreader.helper.PostDelayHandler; @@ -74,7 +81,7 @@ public class NewsListRecyclerAdapter extends RecyclerView.Adapter { recyclerView .addOnScrollListener(new RecyclerView.OnScrollListener() { @Override - public void onScrolled(RecyclerView recyclerView, + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); @@ -88,15 +95,13 @@ public class NewsListRecyclerAdapter extends RecyclerView.Adapter { Log.v(TAG, "start load more task..."); - recyclerView.post(new Runnable() { - public void run() { - // End has been reached - // Do something - lazyList.add(null); - notifyItemInserted(lazyList.size() - 1); + recyclerView.post(() -> { + // End has been reached + // Do something + lazyList.add(null); + notifyItemInserted(lazyList.size() - 1); - AsyncTaskHelper.StartAsyncTask(new LoadMoreItemsAsyncTask()); - } + AsyncTaskHelper.StartAsyncTask(new LoadMoreItemsAsyncTask()); }); } } @@ -150,50 +155,48 @@ public class NewsListRecyclerAdapter extends RecyclerView.Adapter { } @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @NonNull int viewType) { if (viewType == VIEW_PROG) { View v = LayoutInflater.from(parent.getContext()).inflate( R.layout.progressbar_item, parent, false); - return new ProgressViewHolder(v); } else { - Integer layout = 0; + Context context = parent.getContext(); + RssItemViewHolder viewHolder = null; switch (Integer.parseInt(mPrefs.getString(SettingsActivity.SP_FEED_LIST_LAYOUT, "0"))) { case 0: - layout = R.layout.subscription_detail_list_item_thumbnail; + viewHolder = new RssItemThumbnailViewHolder(SubscriptionDetailListItemThumbnailBinding.inflate(LayoutInflater.from(context), parent, false), mPrefs); break; case 1: + viewHolder = new RssItemTextViewHolder(SubscriptionDetailListItemTextBinding.inflate(LayoutInflater.from(context), parent, false), mPrefs); + break; case 3: - layout = R.layout.subscription_detail_list_item_text; + viewHolder = new RssItemFullTextViewHolder(SubscriptionDetailListItemTextBinding.inflate(LayoutInflater.from(context), parent, false), mPrefs); break; case 2: - layout = R.layout.subscription_detail_list_item_web_layout; + viewHolder = new RssItemWebViewHolder(SubscriptionDetailListItemWebLayoutBinding.inflate(LayoutInflater.from(context), parent, false), mPrefs); break; case 4: - layout = R.layout.subscription_detail_list_item_card_view; + viewHolder = new RssItemCardViewHolder(SubscriptionDetailListItemCardViewBinding.inflate(LayoutInflater.from(context), parent, false), mPrefs); break; case 5: - layout = R.layout.subscription_detail_list_item_headline; + viewHolder = new RssItemHeadlineViewHolder(SubscriptionDetailListItemHeadlineBinding.inflate(LayoutInflater.from(context), parent, false), mPrefs); break; default: Log.e(TAG, "Unknown layout.."); } - View view = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false); - - final ViewHolder holder = new ViewHolder(view, mPrefs); - holder.starImageView.setOnClickListener(view1 -> toggleStarredStateOfItem(holder)); + RssItemViewHolder finalViewHolder = viewHolder; + viewHolder.getStar().setOnClickListener(view1 -> toggleStarredStateOfItem(finalViewHolder)); - holder.setClickListener((RecyclerItemClickListener) activity); - - holder.flPlayPausePodcastWrapper.setOnClickListener(v -> { - if (holder.isPlaying()) { + viewHolder.getPlayPausePodcastWrapper().setOnClickListener(v -> { + if (finalViewHolder.isPlaying()) { playPausePodcastClicked.pausePodcast(); } else { - playPausePodcastClicked.openPodcast(holder.getRssItem()); + playPausePodcastClicked.openPodcast(finalViewHolder.getRssItem()); } }); - + viewHolder.setClickListener((RecyclerItemClickListener) activity); /* // TODO implement option to delete cached podcasts (https://github.com/nextcloud/news-android/issues/742) holder.flPlayPausePodcastWrapper.setOnLongClickListener(v -> { @@ -208,47 +211,48 @@ public class NewsListRecyclerAdapter extends RecyclerView.Adapter { return false; }); */ - - return holder; + return viewHolder; } } @Override - public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) { - if(viewHolder instanceof ProgressViewHolder) { + public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int position) { + if (viewHolder instanceof ProgressViewHolder) { ((ProgressViewHolder) viewHolder).progressBar.setIndeterminate(true); } else { - final ViewHolder holder = (ViewHolder) viewHolder; + final RssItemViewHolder holder = (RssItemViewHolder) viewHolder; RssItem item = lazyList.get(position); - holder.setRssItem(item); + holder.bind(item); holder.setStayUnread(NewsReaderListActivity.stayUnreadItems.contains(item.getId())); //Podcast stuff if (DatabaseConnectionOrm.ALLOWED_PODCASTS_TYPES.contains(item.getEnclosureMime())) { final boolean isPlaying = idOfCurrentlyPlayedPodcast == item.getId(); //Enable podcast buttons in view - holder.flPlayPausePodcastWrapper.setVisibility(View.VISIBLE); + holder.getPlayPausePodcastWrapper().setVisibility(View.VISIBLE); holder.setPlaying(isPlaying); holder.setDownloadPodcastProgressbar(); } else { - holder.flPlayPausePodcastWrapper.setVisibility(View.GONE); + holder.getPlayPausePodcastWrapper().setVisibility(View.GONE); } } } @Override - public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) { - if(holder instanceof ViewHolder) + public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) { + if (holder instanceof RssItemViewHolder) { EventBus.getDefault().unregister(holder); + } } @Override - public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { - if(holder instanceof ViewHolder) + public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) { + if (holder instanceof RssItemViewHolder) { EventBus.getDefault().register(holder); + } } - public void changeReadStateOfItem(ViewHolder viewHolder, boolean isChecked) { + public void changeReadStateOfItem(RssItemViewHolder viewHolder, boolean isChecked) { RssItem rssItem = viewHolder.getRssItem(); if (rssItem.getRead_temp() != isChecked) { // Only perform database operations if really needed rssItem.setRead_temp(isChecked); @@ -263,13 +267,13 @@ public class NewsListRecyclerAdapter extends RecyclerView.Adapter { } } - public void toggleReadStateOfItem(ViewHolder viewHolder) { + public void toggleReadStateOfItem(RssItemViewHolder viewHolder) { RssItem rssItem = viewHolder.getRssItem(); boolean isRead = !rssItem.getRead_temp(); changeReadStateOfItem(viewHolder, isRead); } - public void toggleStarredStateOfItem(ViewHolder viewHolder) { + public void toggleStarredStateOfItem(RssItemViewHolder viewHolder) { RssItem rssItem = viewHolder.getRssItem(); boolean isStarred = !rssItem.getStarred_temp(); rssItem.setStarred_temp(isStarred); @@ -394,16 +398,8 @@ public class NewsListRecyclerAdapter extends RecyclerView.Adapter { DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(activity); List items = dbConn.getCurrentRssItemView(cachedPages++); - /* - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - }*/ - sw.stop(); Log.v(TAG, "Time needed (loading more): " + sw.toString()); - return items; } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/ProgressViewHolder.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/ProgressViewHolder.java index 114a5a8f..a5095230 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/ProgressViewHolder.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/ProgressViewHolder.java @@ -4,6 +4,7 @@ import android.view.View; import android.widget.ProgressBar; import androidx.recyclerview.widget.RecyclerView; + import de.luhmer.owncloudnewsreader.R; public class ProgressViewHolder extends RecyclerView.ViewHolder { @@ -11,6 +12,6 @@ public class ProgressViewHolder extends RecyclerView.ViewHolder { public ProgressViewHolder(View v) { super(v); - progressBar = (ProgressBar) v.findViewById(R.id.progressBar); + progressBar = v.findViewById(R.id.progressBar); } } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RecyclerItemClickListener.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RecyclerItemClickListener.java index cffdee0b..0a19bee2 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RecyclerItemClickListener.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RecyclerItemClickListener.java @@ -1,6 +1,7 @@ package de.luhmer.owncloudnewsreader.adapter; public interface RecyclerItemClickListener { - void onClick(ViewHolder vh, int position); - boolean onLongClick(ViewHolder vh, int position); + void onClick(RssItemViewHolder vh, int position); + + boolean onLongClick(RssItemViewHolder vh, int position); } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemCardViewHolder.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemCardViewHolder.java new file mode 100644 index 00000000..3bc64691 --- /dev/null +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemCardViewHolder.java @@ -0,0 +1,78 @@ +package de.luhmer.owncloudnewsreader.adapter; + +import android.content.SharedPreferences; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; + +import de.luhmer.owncloudnewsreader.database.model.RssItem; +import de.luhmer.owncloudnewsreader.databinding.SubscriptionDetailListItemCardViewBinding; + +public class RssItemCardViewHolder extends RssItemViewHolder { + SubscriptionDetailListItemCardViewBinding binding; + + RssItemCardViewHolder(@NonNull SubscriptionDetailListItemCardViewBinding binding, SharedPreferences sharedPreferences) { + super(binding.getRoot(), sharedPreferences); + this.binding = binding; + } + + @Override + protected ImageView getImageViewFavIcon() { + return binding.imgViewFavIcon; + } + + @Override + protected ImageView getStar() { + return binding.starImageview; + } + + @Override + protected ImageView getPlayPausePodcastButton() { + return binding.podcastWrapper.btnPlayPausePodcast; + } + + @Override + protected View getColorFeed() { + return binding.colorLineFeed; + } + + @Override + protected TextView getTextViewTitle() { + return binding.tvSubscription; + } + + @Override + protected TextView getTextViewSummary() { + return binding.summary; + } + + @Override + protected TextView getTextViewBody() { + return binding.body; + } + + @Override + protected TextView getTextViewItemDate() { + return binding.tvItemDate; + } + + @Override + protected FrameLayout getPlayPausePodcastWrapper() { + return binding.podcastWrapper.flPlayPausePodcastWrapper; + } + + @Override + protected ProgressBar getPodcastDownloadProgress() { + return binding.podcastWrapper.podcastDownloadProgress; + } + + @CallSuper + public void bind(@NonNull RssItem rssItem) { + super.bind(rssItem); + } +} \ No newline at end of file diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemFullTextViewHolder.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemFullTextViewHolder.java new file mode 100644 index 00000000..d8db05d3 --- /dev/null +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemFullTextViewHolder.java @@ -0,0 +1,13 @@ +package de.luhmer.owncloudnewsreader.adapter; + +import android.content.SharedPreferences; + +import androidx.annotation.NonNull; + +import de.luhmer.owncloudnewsreader.databinding.SubscriptionDetailListItemTextBinding; + +public class RssItemFullTextViewHolder extends RssItemTextViewHolder { + RssItemFullTextViewHolder(@NonNull SubscriptionDetailListItemTextBinding binding, SharedPreferences sharedPreferences) { + super(binding, sharedPreferences); + } +} \ No newline at end of file diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemHeadlineViewHolder.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemHeadlineViewHolder.java new file mode 100644 index 00000000..56888c85 --- /dev/null +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemHeadlineViewHolder.java @@ -0,0 +1,78 @@ +package de.luhmer.owncloudnewsreader.adapter; + +import android.content.SharedPreferences; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; + +import de.luhmer.owncloudnewsreader.database.model.RssItem; +import de.luhmer.owncloudnewsreader.databinding.SubscriptionDetailListItemHeadlineBinding; + +public class RssItemHeadlineViewHolder extends RssItemViewHolder { + SubscriptionDetailListItemHeadlineBinding binding; + + RssItemHeadlineViewHolder(@NonNull SubscriptionDetailListItemHeadlineBinding binding, SharedPreferences sharedPreferences) { + super(binding.getRoot(), sharedPreferences); + this.binding = binding; + } + + @Override + protected ImageView getImageViewFavIcon() { + return binding.imgViewFavIcon; + } + + @Override + protected ImageView getStar() { + return binding.starImageview; + } + + @Override + protected ImageView getPlayPausePodcastButton() { + return binding.podcastWrapper.btnPlayPausePodcast; + } + + @Override + protected View getColorFeed() { + return binding.colorLineFeed; + } + + @Override + protected TextView getTextViewTitle() { + return binding.tvSubscription; + } + + @Override + protected TextView getTextViewSummary() { + return binding.summary; + } + + @Override + protected TextView getTextViewBody() { + return null; + } + + @Override + protected TextView getTextViewItemDate() { + return binding.tvItemDate; + } + + @Override + protected FrameLayout getPlayPausePodcastWrapper() { + return binding.podcastWrapper.flPlayPausePodcastWrapper; + } + + @Override + protected ProgressBar getPodcastDownloadProgress() { + return binding.podcastWrapper.podcastDownloadProgress; + } + + @CallSuper + public void bind(@NonNull RssItem rssItem) { + super.bind(rssItem); + } +} \ No newline at end of file diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemTextViewHolder.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemTextViewHolder.java new file mode 100644 index 00000000..6623c332 --- /dev/null +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemTextViewHolder.java @@ -0,0 +1,78 @@ +package de.luhmer.owncloudnewsreader.adapter; + +import android.content.SharedPreferences; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; + +import de.luhmer.owncloudnewsreader.database.model.RssItem; +import de.luhmer.owncloudnewsreader.databinding.SubscriptionDetailListItemTextBinding; + +public class RssItemTextViewHolder extends RssItemViewHolder { + SubscriptionDetailListItemTextBinding binding; + + RssItemTextViewHolder(@NonNull SubscriptionDetailListItemTextBinding binding, SharedPreferences sharedPreferences) { + super(binding.getRoot(), sharedPreferences); + this.binding = binding; + } + + @Override + protected ImageView getImageViewFavIcon() { + return binding.imgViewFavIcon; + } + + @Override + protected ImageView getStar() { + return binding.starImageview; + } + + @Override + protected ImageView getPlayPausePodcastButton() { + return binding.podcastWrapper.btnPlayPausePodcast; + } + + @Override + protected View getColorFeed() { + return binding.colorLineFeed; + } + + @Override + protected TextView getTextViewTitle() { + return binding.tvSubscription; + } + + @Override + protected TextView getTextViewSummary() { + return binding.summary; + } + + @Override + protected TextView getTextViewBody() { + return binding.body; + } + + @Override + protected TextView getTextViewItemDate() { + return binding.tvItemDate; + } + + @Override + protected FrameLayout getPlayPausePodcastWrapper() { + return binding.podcastWrapper.flPlayPausePodcastWrapper; + } + + @Override + protected ProgressBar getPodcastDownloadProgress() { + return binding.podcastWrapper.podcastDownloadProgress; + } + + @CallSuper + public void bind(@NonNull RssItem rssItem) { + super.bind(rssItem); + } +} \ No newline at end of file diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemThumbnailViewHolder.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemThumbnailViewHolder.java new file mode 100644 index 00000000..3be61ffc --- /dev/null +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemThumbnailViewHolder.java @@ -0,0 +1,128 @@ +package de.luhmer.owncloudnewsreader.adapter; + +import android.content.SharedPreferences; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; +import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; + +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.ImageLoader; + +import java.util.Collections; +import java.util.List; + +import de.luhmer.owncloudnewsreader.R; +import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; +import de.luhmer.owncloudnewsreader.database.model.RssItem; +import de.luhmer.owncloudnewsreader.databinding.SubscriptionDetailListItemThumbnailBinding; +import de.luhmer.owncloudnewsreader.helper.ImageHandler; +import de.luhmer.owncloudnewsreader.helper.SquareRoundedBitmapDisplayer; + +import static android.view.View.GONE; + +public class RssItemThumbnailViewHolder extends RssItemViewHolder { + private final DisplayImageOptions displayImageOptionsThumbnail; + SubscriptionDetailListItemThumbnailBinding binding; + + RssItemThumbnailViewHolder(@NonNull SubscriptionDetailListItemThumbnailBinding binding, SharedPreferences sharedPreferences) { + super(binding.getRoot(), sharedPreferences); + this.binding = binding; + + + Drawable feedIcon = VectorDrawableCompat.create(itemView.getResources(), R.drawable.feed_icon, null); + displayImageOptionsThumbnail = new DisplayImageOptions.Builder() + .displayer(new SquareRoundedBitmapDisplayer(30)) + .showImageOnLoading(feedIcon) + .showImageForEmptyUri(feedIcon) + .showImageOnFail(feedIcon) + .cacheOnDisk(true) + .cacheInMemory(true) + .build(); + } + + @Override + protected ImageView getImageViewFavIcon() { + return binding.imgViewFavIcon; + } + + @Override + protected ImageView getStar() { + return binding.starImageview; + } + + @Override + protected ImageView getPlayPausePodcastButton() { + return binding.podcastWrapper.btnPlayPausePodcast; + } + + @Override + protected View getColorFeed() { + return null; + } + + @Override + protected TextView getTextViewTitle() { + return binding.tvSubscription; + } + + @Override + protected TextView getTextViewSummary() { + return binding.summary; + } + + @Override + protected TextView getTextViewBody() { + return binding.body; + } + + @Override + protected TextView getTextViewItemDate() { + return binding.tvItemDate; + } + + @Override + protected FrameLayout getPlayPausePodcastWrapper() { + return binding.podcastWrapper.flPlayPausePodcastWrapper; + } + + @Override + protected ProgressBar getPodcastDownloadProgress() { + return binding.podcastWrapper.podcastDownloadProgress; + } + + @CallSuper + public void bind(@NonNull RssItem rssItem) { + super.bind(rssItem); + + binding.imgViewThumbnail.setColorFilter(null); + String body = rssItem.getBody(); + List images; + if (rssItem.getMediaThumbnail() != null && !rssItem.getMediaThumbnail().isEmpty()) { + images = Collections.singletonList(rssItem.getMediaThumbnail()); + } else { + images = ImageHandler.getImageLinksFromText(body); + } + + if (images.size() > 0) { + binding.imgViewThumbnail.setVisibility(View.VISIBLE); + ImageLoader.getInstance().displayImage(images.get(0), binding.imgViewThumbnail, displayImageOptionsThumbnail); + } else { + // Show Podcast Icon if no thumbnail is available but it is a podcast (otherwise the podcast button will go missing) + if (DatabaseConnectionOrm.ALLOWED_PODCASTS_TYPES.contains(rssItem.getEnclosureMime())) { + binding.imgViewThumbnail.setVisibility(View.VISIBLE); + //imgViewThumbnail.setColorFilter(Color.parseColor("#d8d8d8")); + Drawable feedIcon = VectorDrawableCompat.create(itemView.getResources(), R.drawable.feed_icon, null); + binding.imgViewThumbnail.setImageDrawable(feedIcon); + } else { + binding.imgViewThumbnail.setVisibility(GONE); + } + } + } +} \ No newline at end of file diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemViewHolder.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemViewHolder.java new file mode 100644 index 00000000..4597e468 --- /dev/null +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemViewHolder.java @@ -0,0 +1,323 @@ +package de.luhmer.owncloudnewsreader.adapter; + +import android.content.SharedPreferences; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.Typeface; +import android.text.Html; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.format.DateUtils; +import android.text.style.ForegroundColorSpan; +import android.util.Log; +import android.util.SparseIntArray; +import android.util.TypedValue; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; + +import org.greenrobot.eventbus.Subscribe; + +import java.util.regex.Pattern; + +import de.luhmer.owncloudnewsreader.R; +import de.luhmer.owncloudnewsreader.SettingsActivity; +import de.luhmer.owncloudnewsreader.database.model.RssItem; +import de.luhmer.owncloudnewsreader.helper.ColorHelper; +import de.luhmer.owncloudnewsreader.helper.FavIconHandler; +import de.luhmer.owncloudnewsreader.services.PodcastDownloadService; + +public abstract class RssItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { + private final static String TAG = RssItemViewHolder.class.getCanonicalName(); + + private static final SparseIntArray downloadProgressList = new SparseIntArray(); + private static FavIconHandler favIconHandler = null; + protected final SharedPreferences mPrefs; + private final int LengthBody = 400; + private final ForegroundColorSpan bodyForegroundColor; + private RecyclerItemClickListener clickListener; + private RssItem rssItem; + private boolean stayUnread = false; + private boolean playing; + private int starColor; + private int inactiveStarColor; + + + RssItemViewHolder(@NonNull View itemView, SharedPreferences sharedPreferences) { + super(itemView); + this.mPrefs = sharedPreferences; + + bodyForegroundColor = new ForegroundColorSpan(ContextCompat.getColor(itemView.getContext(), android.R.color.secondary_text_dark)); + + if (favIconHandler == null) { + favIconHandler = new FavIconHandler(itemView.getContext()); + } + + itemView.setOnClickListener(this); + itemView.setOnLongClickListener(this); + } + + /** + * Apply scaling factor to TextView font size, based on app font-size preference. + * + * @param tv TextView object to be scaled + * @param initialTvSize app layout definition default size of TextView element + * @param halfScale if set to true, will only apply half of the scaling factor + */ + private static void scaleTextSize(TextView tv, int initialTvSize, boolean halfScale, SharedPreferences mPrefs) { + float scalingFactor = Float.parseFloat(mPrefs.getString(SettingsActivity.SP_FONT_SIZE, "1.0")); + if (halfScale) { + scalingFactor = scalingFactor + (1 - scalingFactor) / 2; + } + + int initialSize = initialTvSize; + if (initialSize < 0) { + initialSize = Math.round(tv.getTextSize()); + } + // float sp = initialSize / tv.getContext().getResources().getDisplayMetrics().scaledDensity; // transform scaled pixels, device pixels + tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, Math.round(initialSize * scalingFactor)); + } + + /** + * Return the number of rss item body text lines, depending on the currently selected font size/scale; + * only meant to be used with thumbnail feed view. + * + * @return number of lines of rss item body text lines to be used in thumbnail feed view + */ + private static int scaleTextLines(SharedPreferences prefs) { + float scalingFactor = Float.parseFloat(prefs.getString(SettingsActivity.SP_FONT_SIZE, "1.0")); + /* The following formula computes the number of text lines for Simple item view; it simply boils + * down to a linear conversion from the font scaling factor from 0.8 -> 6 lines to 1.6 -> 3 lines + */ + return Math.round((scalingFactor * -5) + 10); + } + + abstract protected ImageView getImageViewFavIcon(); + + abstract protected ImageView getStar(); + + abstract protected ImageView getPlayPausePodcastButton(); + + abstract protected View getColorFeed(); + + abstract protected TextView getTextViewTitle(); + + abstract protected TextView getTextViewSummary(); + + abstract protected TextView getTextViewBody(); + + abstract protected TextView getTextViewItemDate(); + + abstract protected FrameLayout getPlayPausePodcastWrapper(); + + abstract protected ProgressBar getPodcastDownloadProgress(); + + @CallSuper + public void bind(@NonNull RssItem rssItem) { + this.rssItem = rssItem; + + int[] attribute = new int[]{R.attr.starredColor, R.attr.unstarredColor}; + TypedArray array = getStar().getContext().getTheme().obtainStyledAttributes(attribute); + starColor = array.getColor(0, Color.TRANSPARENT); + inactiveStarColor = array.getColor(1, Color.LTGRAY); + array.recycle(); + + TextView textViewBody = getTextViewBody(); + + // get and store initial item text sizes (can't figure out how to directly get this info from layout definition) + int textSizeSummary = Math.round(getTextViewSummary().getTextSize()); + int textSizeTitle = Math.round(getTextViewTitle().getTextSize()); + int textSizeItemDate = Math.round(getTextViewItemDate().getTextSize()); + + + String title = null; + String favIconUrl = null; + if (rssItem.getFeed() != null) { + title = rssItem.getFeed().getFeedTitle(); + favIconUrl = rssItem.getFeed().getFaviconUrl(); + } else { + Log.v(TAG, "Feed not found!!!"); + } + + setReadState(rssItem.getRead_temp()); + setStarred(rssItem.getStarred_temp()); + + setFeedColor(ColorHelper.getFeedColor(itemView.getContext(), rssItem.getFeed())); + + TextView textViewSummary = getTextViewSummary(); + if (textViewSummary != null) { + try { + textViewSummary.setText(Html.fromHtml(rssItem.getTitle())); + scaleTextSize(textViewSummary, textSizeSummary, false, mPrefs); + } catch (Exception e) { + e.printStackTrace(); + } + } + + TextView textViewTitle = getTextViewTitle(); + if (textViewTitle != null && title != null) { + textViewTitle.setText(Html.fromHtml(title)); + scaleTextSize(textViewTitle, textSizeTitle, true, mPrefs); + } + + int height = 0; // used for feed icon vertical offset calculation + + TextView textViewItemDate = getTextViewItemDate(); + if (textViewItemDate != null) { + textViewItemDate.setText(DateUtils.getRelativeTimeSpanString(rssItem.getPubDate().getTime())); + scaleTextSize(textViewItemDate, textSizeItemDate, true, mPrefs); + height = Math.round(textViewItemDate.getTextSize()); + } + + ImageView imgViewFavIcon = getImageViewFavIcon(); + if (imgViewFavIcon != null) { + favIconHandler.loadFavIconForFeed(favIconUrl, imgViewFavIcon, Math.round((height - textSizeItemDate) / 2)); + } + + + if (textViewBody != null) { + int textSizeBody = Math.round(textViewBody.getTextSize()); + + String body = rssItem.getMediaDescription(); + if (body == null || body.isEmpty()) { + body = rssItem.getBody(); + } + + boolean limitLength = true; + // Strip html from String + if (this instanceof RssItemFullTextViewHolder) { + textViewBody.setMaxLines(200); + limitLength = false; + } else if (this instanceof RssItemTextViewHolder) { + textViewBody.setMaxLines(scaleTextLines(mPrefs)); + limitLength = false; + } + body = getBodyText(body, limitLength); + textViewBody.setText(Html.fromHtml(body)); + scaleTextSize(textViewBody, textSizeBody, false, mPrefs); + } + } + + @Override + public void onClick(View v) { + clickListener.onClick(this, getLayoutPosition()); + } + + public void setClickListener(RecyclerItemClickListener clickListener) { + this.clickListener = clickListener; + } + + @Override + public boolean onLongClick(View v) { + return clickListener.onLongClick(this, getLayoutPosition()); + } + + public void setStarred(boolean isStarred) { + int color = isStarred ? starColor : inactiveStarColor; + int contentDescriptionId = isStarred ? + R.string.content_desc_remove_from_favorites : + R.string.content_desc_add_to_favorites; + ImageView star = getStar(); + star.setColorFilter(color); + star.setContentDescription(star.getContext().getString(contentDescriptionId)); + } + + public RssItem getRssItem() { + return rssItem; + } + + public boolean shouldStayUnread() { + return stayUnread; + } + + public void setStayUnread(boolean shouldStayUnread) { + this.stayUnread = shouldStayUnread; + } + + private String getBodyText(String body, boolean limitLength) { + if (body.startsWith("", ""); + } + + body = body.replaceAll("]*>", ""); + body = body.replaceAll("]*>", ""); + + SpannableString bodyStringSpannable = new SpannableString(Html.fromHtml(body)); + bodyStringSpannable.setSpan(bodyForegroundColor, 0, bodyStringSpannable.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); + + String bodyString = bodyStringSpannable.toString().trim(); + + + if (limitLength && bodyString.length() > LengthBody) { + bodyString = bodyString.substring(0, LengthBody) + "..."; + } + + return bodyString; + } + + private void setFeedColor(int color) { + if (getColorFeed() != null) { + getColorFeed().setBackgroundColor(color); + } + } + + public void setReadState(boolean isRead) { + TextView textViewSummary = getTextViewSummary(); + if (textViewSummary != null) { + float alpha = 1f; + if (isRead) { + textViewSummary.setTypeface(Typeface.DEFAULT); + alpha = 0.7f; + } else { + textViewSummary.setTypeface(Typeface.DEFAULT_BOLD); + } + + ((View) textViewSummary.getParent()).setAlpha(alpha); + } + } + + public boolean isPlaying() { + return playing; + } + + public void setPlaying(boolean playing) { + this.playing = playing; + + int imageId = playing ? R.drawable.ic_action_pause : R.drawable.ic_action_play; + int contentDescriptionId = playing ? R.string.content_desc_pause : R.string.content_desc_play; + + ImageView playPause = getPlayPausePodcastButton(); + String contentDescription = playPause.getContext().getString(contentDescriptionId); + playPause.setContentDescription(contentDescription); + playPause.setImageResource(imageId); + } + + public void setDownloadPodcastProgressbar() { + float progress; + if (PodcastDownloadService.PodcastAlreadyCached(itemView.getContext(), rssItem.getEnclosureLink())) { + progress = 100; + } else { + progress = downloadProgressList.get(rssItem.getId().intValue(), 0); + } + getPodcastDownloadProgress().setProgress((int) progress); + Log.v(TAG, "Progress of download2: " + progress); + } + + @Subscribe + public void onEvent(PodcastDownloadService.DownloadProgressUpdate downloadProgress) { + downloadProgressList.put((int) downloadProgress.podcast.itemId, downloadProgress.podcast.downloadProgress); + if (rssItem.getId().equals(downloadProgress.podcast.itemId)) { + getPodcastDownloadProgress().setProgress(downloadProgress.podcast.downloadProgress); + + Log.v(TAG, "Progress of download1: " + downloadProgress.podcast.downloadProgress); + } + } +} \ No newline at end of file diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemWebViewHolder.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemWebViewHolder.java new file mode 100644 index 00000000..b187face --- /dev/null +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemWebViewHolder.java @@ -0,0 +1,82 @@ +package de.luhmer.owncloudnewsreader.adapter; + +import android.content.SharedPreferences; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; + +import de.luhmer.owncloudnewsreader.async_tasks.RssItemToHtmlTask; +import de.luhmer.owncloudnewsreader.database.model.RssItem; +import de.luhmer.owncloudnewsreader.databinding.SubscriptionDetailListItemWebLayoutBinding; + +public class RssItemWebViewHolder extends RssItemViewHolder { + SubscriptionDetailListItemWebLayoutBinding binding; + + RssItemWebViewHolder(@NonNull SubscriptionDetailListItemWebLayoutBinding binding, SharedPreferences sharedPreferences) { + super(binding.getRoot(), sharedPreferences); + this.binding = binding; + } + + @Override + protected ImageView getImageViewFavIcon() { + return binding.layoutThumbnail.imgViewFavIcon; + } + + @Override + protected ImageView getStar() { + return binding.layoutThumbnail.starImageview; + } + + @Override + protected ImageView getPlayPausePodcastButton() { + return binding.layoutThumbnail.podcastWrapper.btnPlayPausePodcast; + } + + @Override + protected ImageView getColorFeed() { + return null; + } + + @Override + protected TextView getTextViewTitle() { + return binding.layoutThumbnail.tvSubscription; + } + + @Override + protected TextView getTextViewSummary() { + return binding.layoutThumbnail.summary; + } + + @Override + protected TextView getTextViewBody() { + return binding.layoutThumbnail.body; + } + + @Override + protected TextView getTextViewItemDate() { + return binding.layoutThumbnail.tvItemDate; + } + + @Override + protected FrameLayout getPlayPausePodcastWrapper() { + return binding.layoutThumbnail.podcastWrapper.flPlayPausePodcastWrapper; + } + + @Override + protected ProgressBar getPodcastDownloadProgress() { + return binding.layoutThumbnail.podcastWrapper.podcastDownloadProgress; + } + + @CallSuper + public void bind(@NonNull RssItem rssItem) { + super.bind(rssItem); + + String htmlPage = RssItemToHtmlTask.getHtmlPage(rssItem, false, mPrefs, itemView.getContext()); + binding.webViewBody.loadDataWithBaseURL("file:///android_asset/", htmlPage, "text/html", "UTF-8", ""); + + } +} \ No newline at end of file diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/ViewHolder.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/ViewHolder.java deleted file mode 100644 index 7af3614f..00000000 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/ViewHolder.java +++ /dev/null @@ -1,413 +0,0 @@ -package de.luhmer.owncloudnewsreader.adapter; - -import android.content.SharedPreferences; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.text.Html; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.format.DateUtils; -import android.text.style.ForegroundColorSpan; -import android.util.Log; -import android.util.SparseArray; -import android.util.TypedValue; -import android.view.View; -import android.webkit.WebView; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; - -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.RecyclerView; -import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; - -import com.nostra13.universalimageloader.core.DisplayImageOptions; -import com.nostra13.universalimageloader.core.ImageLoader; - -import org.greenrobot.eventbus.Subscribe; - -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -import butterknife.BindView; -import butterknife.ButterKnife; -import de.luhmer.owncloudnewsreader.R; -import de.luhmer.owncloudnewsreader.SettingsActivity; -import de.luhmer.owncloudnewsreader.async_tasks.RssItemToHtmlTask; -import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; -import de.luhmer.owncloudnewsreader.database.model.RssItem; -import de.luhmer.owncloudnewsreader.helper.ColorHelper; -import de.luhmer.owncloudnewsreader.helper.FavIconHandler; -import de.luhmer.owncloudnewsreader.helper.ImageHandler; -import de.luhmer.owncloudnewsreader.helper.SquareRoundedBitmapDisplayer; -import de.luhmer.owncloudnewsreader.services.PodcastDownloadService; - -import static android.view.View.GONE; - -public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { - private final static String TAG = "RecyclerView.ViewHolder"; - - private static SparseArray downloadProgressList = new SparseArray<>(); - - @Nullable - @BindView(R.id.star_imageview) - protected ImageView starImageView; - - @BindView(R.id.summary) - protected TextView textViewSummary; - - @BindView(R.id.tv_item_date) - protected TextView textViewItemDate; - - @BindView(R.id.tv_subscription) - protected TextView textViewTitle; - - @Nullable - @BindView(R.id.imgViewFavIcon) - protected ImageView imgViewFavIcon; - - @Nullable - @BindView(R.id.imgViewThumbnail) - protected ImageView imgViewThumbnail; - - - @Nullable - @BindView(R.id.color_line_feed) - protected View colorLineFeed; - - @BindView(R.id.btn_playPausePodcast) - protected ImageView btnPlayPausePodcast; - - @BindView(R.id.podcastDownloadProgress) - //protected HoloCircularProgressBar pbPodcastDownloadProgress; // TODO reminder: remove this dependency (and fix podcast progressbar issues) - protected ProgressBar pbPodcastDownloadProgress; - - @BindView(R.id.podcast_wrapper) - View flPlayPausePodcastWrapper; - - // only in extended layout - @Nullable @BindView(R.id.body) - protected TextView textViewBody; - - // Only in extended with webview layout - @Nullable @BindView(R.id.webView_body) - protected WebView webView_body; - - private RecyclerItemClickListener clickListener; - private RssItem rssItem; - private boolean stayUnread = false; - private static FavIconHandler favIconHandler = null; - private final int LengthBody = 400; - private ForegroundColorSpan bodyForegroundColor; - private boolean playing; - private int selectedListLayout; - private int starColor; - private int inactiveStarColor; - private DisplayImageOptions displayImageOptionsThumbnail; - - private int textSizeSummary; - private int textSizeTitle; - private int textSizeItemDate; - private int textSizeBody = -1; - - private SharedPreferences mPrefs; - - public ViewHolder(View itemView, SharedPreferences prefs) { - super(itemView); - - this.mPrefs = prefs; - - selectedListLayout = Integer.parseInt(mPrefs.getString(SettingsActivity.SP_FEED_LIST_LAYOUT, "0")); - - bodyForegroundColor = new ForegroundColorSpan(ContextCompat.getColor(itemView.getContext(), android.R.color.secondary_text_dark)); - - if(favIconHandler == null) { - favIconHandler = new FavIconHandler(itemView.getContext()); - } - - ButterKnife.bind(this, itemView); - - int[] attribute = new int[]{ R.attr.starredColor, R.attr.unstarredColor }; - TypedArray array = starImageView.getContext().getTheme().obtainStyledAttributes(attribute); - starColor = array.getColor(0, Color.TRANSPARENT); - inactiveStarColor = array.getColor(1, Color.LTGRAY); - array.recycle(); - - // get and store initial item text sizes (can't figure out how to directly get this info from layout definition) - textSizeSummary = Math.round(textViewSummary.getTextSize()); - textSizeTitle = Math.round(textViewTitle.getTextSize()); - if(textViewBody != null) { - textSizeBody = Math.round(textViewBody.getTextSize()); - } - textSizeItemDate = Math.round(textViewItemDate.getTextSize()); - - itemView.setOnClickListener(this); - itemView.setOnLongClickListener(this); - - Drawable feedIcon = VectorDrawableCompat.create(itemView.getResources(), R.drawable.feed_icon, null) ; - displayImageOptionsThumbnail = new DisplayImageOptions.Builder() - .displayer(new SquareRoundedBitmapDisplayer(30)) - .showImageOnLoading(feedIcon) - .showImageForEmptyUri(feedIcon) - .showImageOnFail(feedIcon) - .cacheOnDisk(true) - .cacheInMemory(true) - .build(); - } - - @Subscribe - public void onEvent(PodcastDownloadService.DownloadProgressUpdate downloadProgress) { - downloadProgressList.put((int) downloadProgress.podcast.itemId, downloadProgress.podcast.downloadProgress); - if (rssItem.getId().equals(downloadProgress.podcast.itemId)) { - pbPodcastDownloadProgress.setProgress(downloadProgress.podcast.downloadProgress); - - Log.v(TAG, "Progress of download1: " + downloadProgress.podcast.downloadProgress); - } - } - - public void setDownloadPodcastProgressbar() { - float progress; - if(PodcastDownloadService.PodcastAlreadyCached(itemView.getContext(), rssItem.getEnclosureLink())) { - progress = 100; - } else { - if(downloadProgressList.get(rssItem.getId().intValue()) != null) { - progress = downloadProgressList.get(rssItem.getId().intValue()); - } else { - progress = 0; - } - } - pbPodcastDownloadProgress.setProgress((int) progress); - Log.v(TAG, "Progress of download2: " + progress); - } - - @Override - public void onClick(View v) { - clickListener.onClick(this, getLayoutPosition()); - } - - public void setClickListener(RecyclerItemClickListener clickListener) { - this.clickListener = clickListener; - } - - @Override - public boolean onLongClick(View v) { - return clickListener.onLongClick(this, getLayoutPosition()); - } - - private void setFeedColor(int color) { - if(colorLineFeed != null) { - colorLineFeed.setBackgroundColor(color); - } - } - - public void setReadState(boolean isRead) { - if(textViewSummary != null) { - float alpha = 1f; - if (isRead) { - textViewSummary.setTypeface(Typeface.DEFAULT); - alpha = 0.7f; - } else { - textViewSummary.setTypeface(Typeface.DEFAULT_BOLD); - } - - ((View) textViewSummary.getParent()).setAlpha(alpha); - } - } - - public void setStarred(boolean isStarred) { - int color = isStarred ? starColor : inactiveStarColor; - int contentDescriptionId = isStarred ? - R.string.content_desc_remove_from_favorites : - R.string.content_desc_add_to_favorites; - starImageView.setColorFilter(color); - starImageView.setContentDescription(starImageView.getContext().getString(contentDescriptionId)); - } - - public void setPlaying(boolean playing) { - this.playing = playing; - - int imageId = playing ? R.drawable.ic_action_pause : R.drawable.ic_action_play; - int contentDescriptionId = playing ? R.string.content_desc_pause : R.string.content_desc_play; - - String contentDescription = btnPlayPausePodcast.getContext().getString(contentDescriptionId); - btnPlayPausePodcast.setContentDescription(contentDescription); - btnPlayPausePodcast.setImageResource(imageId); - } - - public boolean isPlaying() { - return playing; - } - - public RssItem getRssItem() { - return rssItem; - } - - public void setRssItem(RssItem rssItem) { - this.rssItem = rssItem; - String title = null; - String favIconUrl = null; - if(rssItem.getFeed() != null) { - title = rssItem.getFeed().getFeedTitle(); - favIconUrl = rssItem.getFeed().getFaviconUrl(); - } else { - Log.v(TAG, "Feed not found!!!"); - } - - setReadState(rssItem.getRead_temp()); - setStarred(rssItem.getStarred_temp()); - - setFeedColor(ColorHelper.getFeedColor(itemView.getContext(), rssItem.getFeed())); - - if(textViewSummary != null) { - try { - //byte[] arrByteForSpanish = rssItem.getTitle().getBytes("ISO-8859-1"); - //String spanish = new String(arrByteForSpanish);//.getBytes("UTF-8"); - //textViewSummary.setText(Html.fromHtml(spanish)); - - textViewSummary.setText(Html.fromHtml(rssItem.getTitle())); - scaleTextSize(textViewSummary, textSizeSummary, false, mPrefs); - } catch (Exception e) { - e.printStackTrace(); - } - } - - if(textViewTitle != null && title != null) { - textViewTitle.setText(Html.fromHtml(title)); - scaleTextSize(textViewTitle, textSizeTitle, true, mPrefs); - } - - if(textViewBody != null) { - String body = rssItem.getMediaDescription(); - if(body == null || body.isEmpty()) { - body = rssItem.getBody(); - } - - boolean limitLength = true; - // Strip html from String - if(selectedListLayout == 0) { - textViewBody.setMaxLines(scaleTextLines(mPrefs)); - limitLength = false; - } else if(selectedListLayout == 3) { - textViewBody.setMaxLines(200); - limitLength = false; - } - body = getBodyText(body, limitLength); - textViewBody.setText(Html.fromHtml(body)); - scaleTextSize(textViewBody, textSizeBody, false, mPrefs); - } - - int height = 0; // used for feed icon vertical offset calculation - if(textViewItemDate != null) { - textViewItemDate.setText(DateUtils.getRelativeTimeSpanString(rssItem.getPubDate().getTime())); - scaleTextSize(textViewItemDate, textSizeItemDate, true, mPrefs); - height = Math.round(textViewItemDate.getTextSize()); - } - - if (imgViewFavIcon != null) { - favIconHandler.loadFavIconForFeed(favIconUrl, imgViewFavIcon, Math.round((height-textSizeItemDate)/2)); - } - - if(imgViewThumbnail != null) { - imgViewThumbnail.setColorFilter(null); - String body = rssItem.getBody(); - List images; - if(rssItem.getMediaThumbnail() != null && !rssItem.getMediaThumbnail().isEmpty()) { - images = new ArrayList(); - images.add(rssItem.getMediaThumbnail()); - } else { - images = ImageHandler.getImageLinksFromText(body); - } - - if(images.size() > 0) { - imgViewThumbnail.setVisibility(View.VISIBLE); - ImageLoader.getInstance().displayImage(images.get(0), imgViewThumbnail, displayImageOptionsThumbnail); - } else { - // Show Podcast Icon if no thumbnail is available but it is a podcast (otherwise the podcast button will go missing) - if (DatabaseConnectionOrm.ALLOWED_PODCASTS_TYPES.contains(rssItem.getEnclosureMime())) { - imgViewThumbnail.setVisibility(View.VISIBLE); - //imgViewThumbnail.setColorFilter(Color.parseColor("#d8d8d8")); - Drawable feedIcon = VectorDrawableCompat.create(itemView.getResources(), R.drawable.feed_icon, null) ; - imgViewThumbnail.setImageDrawable(feedIcon); - } else { - imgViewThumbnail.setVisibility(GONE); - } - } - } - - if(webView_body != null) { - String htmlPage = RssItemToHtmlTask.getHtmlPage(rssItem, false, mPrefs, itemView.getContext()); - webView_body.loadDataWithBaseURL("file:///android_asset/", htmlPage, "text/html", "UTF-8", ""); - } - } - - /** - * Apply scaling factor to TextView font size, based on app font-size preference. - * - * @param tv TextView object to be scaled - * @param initialTvSize app layout definition default size of TextView element - * @param halfScale if set to true, will only apply half of the scaling factor - */ - private static void scaleTextSize(TextView tv, int initialTvSize, boolean halfScale, SharedPreferences mPrefs) { - float scalingFactor = Float.parseFloat(mPrefs.getString(SettingsActivity.SP_FONT_SIZE, "1.0")); - if(halfScale) { - scalingFactor = scalingFactor + (1-scalingFactor)/2; - } - - int initialSize = initialTvSize; - if(initialSize < 0) { - initialSize = Math.round(tv.getTextSize()); - } - // float sp = initialSize / tv.getContext().getResources().getDisplayMetrics().scaledDensity; // transform scaled pixels, device pixels - tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, Math.round(initialSize*scalingFactor)); - } - - /** - * Return the number of rss item body text lines, depending on the currently selected font size/scale; - * only meant to be used with thumbnail feed view. - * - * @return number of lines of rss item body text lines to be used in thumbnail feed view - */ - private static int scaleTextLines(SharedPreferences prefs) { - float scalingFactor = Float.parseFloat(prefs.getString(SettingsActivity.SP_FONT_SIZE, "1.0")); - /* The following formula computes the number of text lines for Simple item view; it simply boils - * down to a linear conversion from the font scaling factor from 0.8 -> 6 lines to 1.6 -> 3 lines - */ - return Math.round((scalingFactor*-5)+10); - } - - - public boolean shouldStayUnread() { - return stayUnread; - } - - public void setStayUnread(boolean shouldStayUnread) { - this.stayUnread = shouldStayUnread; - } - - private String getBodyText(String body, boolean limitLength) - { - if (body.startsWith("", ""); - } - - body = body.replaceAll("]*>", ""); - body = body.replaceAll("]*>", ""); - - SpannableString bodyStringSpannable = new SpannableString(Html.fromHtml(body)); - bodyStringSpannable.setSpan(bodyForegroundColor, 0, bodyStringSpannable.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); - - String bodyString = bodyStringSpannable.toString().trim(); - - - if(limitLength && bodyString.length() > LengthBody) { - bodyString = bodyString.substring(0, LengthBody) + "..."; - } - - return bodyString; - } -} diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/helper/FavIconHandler.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/helper/FavIconHandler.java index 55d99152..f877a866 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/helper/FavIconHandler.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/helper/FavIconHandler.java @@ -27,13 +27,14 @@ import android.util.Log; import android.view.View; import android.widget.ImageView; +import androidx.core.content.ContextCompat; +import androidx.palette.graphics.Palette; + import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; -import androidx.core.content.ContextCompat; -import androidx.palette.graphics.Palette; import de.luhmer.owncloudnewsreader.R; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; import de.luhmer.owncloudnewsreader.database.model.Feed; @@ -42,10 +43,7 @@ public class FavIconHandler { private static final String TAG = FavIconHandler.class.getCanonicalName(); private final DisplayImageOptions displayImageOptions; - private Context context; - public FavIconHandler(Context context) { - this.context = context; int placeHolder = FavIconHandler.getResourceIdForRightDefaultFeedIcon(); displayImageOptions = new DisplayImageOptions.Builder() .showImageOnLoading(placeHolder) @@ -73,19 +71,18 @@ public class FavIconHandler { imgView.setTranslationY(offset); } - private static int getResourceIdForRightDefaultFeedIcon() - { - if(ThemeChooser.getSelectedTheme().equals(ThemeChooser.THEME.LIGHT)) { + private static int getResourceIdForRightDefaultFeedIcon() { + if (ThemeChooser.getSelectedTheme().equals(ThemeChooser.THEME.LIGHT)) { return R.drawable.default_feed_icon_dark; } else { return R.drawable.default_feed_icon_light; } - } + } - public void preCacheFavIcon(final Feed feed) throws IllegalStateException { - if(feed.getFaviconUrl() == null) { - Log.v(TAG, "No favicon for "+feed.getFeedTitle()); + public void preCacheFavIcon(final Feed feed, Context context) throws IllegalStateException { + if (feed.getFaviconUrl() == null) { + Log.v(TAG, "No favicon for " + feed.getFeedTitle()); return; } @@ -103,7 +100,7 @@ public class FavIconHandler { @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { - DownloadFinished(feed.getId(), loadedImage); + DownloadFinished(feed.getId(), loadedImage, context); } @Override @@ -113,8 +110,8 @@ public class FavIconHandler { }); } - private void DownloadFinished(long feedId, Bitmap bitmap) { - if(bitmap != null) { + private void DownloadFinished(long feedId, Bitmap bitmap, Context context) { + if (bitmap != null) { DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(context); Feed feed = dbConn.getFeedById(feedId); Palette palette = Palette.from(bitmap).generate(); -- cgit v1.2.3