diff options
Diffstat (limited to 'News-Android-App/src/main/java')
26 files changed, 1315 insertions, 1118 deletions
diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/ListView/PodcastArrayAdapter.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/ListView/PodcastArrayAdapter.java index 09efbe57..5e9b45b7 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/ListView/PodcastArrayAdapter.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/ListView/PodcastArrayAdapter.java @@ -5,16 +5,14 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; -import android.widget.FrameLayout; -import android.widget.ProgressBar; -import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; + import org.greenrobot.eventbus.EventBus; -import butterknife.BindView; -import butterknife.ButterKnife; import de.luhmer.owncloudnewsreader.R; +import de.luhmer.owncloudnewsreader.databinding.PodcastRowBinding; import de.luhmer.owncloudnewsreader.events.podcast.AudioPodcastClicked; import de.luhmer.owncloudnewsreader.events.podcast.StartDownloadPodcast; import de.luhmer.owncloudnewsreader.helper.NewsFileUtils; @@ -38,15 +36,16 @@ public class PodcastArrayAdapter extends ArrayAdapter<PodcastItem> { if (view != null) { holder = (ViewHolder) view.getTag(); } else { - view = inflater.inflate(R.layout.podcast_row, parent, false); - holder = new ViewHolder(view); + PodcastRowBinding binding = PodcastRowBinding.inflate(inflater, parent, false); + view = binding.getRoot(); + holder = new ViewHolder(binding); view.setTag(holder); } final PodcastItem podcastItem = getItem(position); - holder.tvTitle.setText(podcastItem.title); - holder.tvBody.setText(podcastItem.mimeType); + holder.binding.tvTitle.setText(podcastItem.title); + holder.binding.tvBody.setText(podcastItem.mimeType); view.setOnClickListener(new View.OnClickListener() { @Override @@ -56,10 +55,10 @@ public class PodcastArrayAdapter extends ArrayAdapter<PodcastItem> { }); - holder.flDownloadPodcast.setOnClickListener(new View.OnClickListener() { + holder.binding.flDownloadPodcastWrapper.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - holder.flDownloadPodcast.setVisibility(View.GONE); + holder.binding.flDownloadPodcastWrapper.setVisibility(View.GONE); Toast.makeText(getContext(), "Starting download.. Please wait", Toast.LENGTH_SHORT).show(); @@ -67,14 +66,14 @@ public class PodcastArrayAdapter extends ArrayAdapter<PodcastItem> { } }); - holder.flPlayPodcast.setOnClickListener(new View.OnClickListener() { + holder.binding.flPlayPodcastWrapper.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { playPodcast(position); } }); - holder.flDeletePodcast.setOnClickListener(new View.OnClickListener() { + holder.binding.flDeletePodcastWrapper.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(NewsFileUtils.deletePodcastFile(getContext(), podcastItem.link)) { @@ -86,25 +85,25 @@ public class PodcastArrayAdapter extends ArrayAdapter<PodcastItem> { }); - holder.pbDownloadPodcast.setProgress(podcastItem.downloadProgress); + holder.binding.pbDownloadPodcast.setProgress(podcastItem.downloadProgress); if(podcastItem.downloadProgress >= 0) { - holder.tvDownloadPodcastProgress.setVisibility(View.VISIBLE); - holder.pbDownloadPodcast.setVisibility(View.VISIBLE); - holder.tvDownloadPodcastProgress.setText(podcastItem.downloadProgress + "%"); + holder.binding.tvDownloadPodcastProgress.setVisibility(View.VISIBLE); + holder.binding.pbDownloadPodcast.setVisibility(View.VISIBLE); + holder.binding.tvDownloadPodcastProgress.setText(podcastItem.downloadProgress + "%"); } else { - holder.tvDownloadPodcastProgress.setVisibility(View.GONE); - holder.pbDownloadPodcast.setVisibility(View.GONE); + holder.binding.tvDownloadPodcastProgress.setVisibility(View.GONE); + holder.binding.pbDownloadPodcast.setVisibility(View.GONE); } if(podcastItem.downloadProgress.equals(PodcastItem.DOWNLOAD_NOT_STARTED)) { - holder.flDownloadPodcast.setVisibility(View.VISIBLE); + holder.binding.flDownloadPodcastWrapper.setVisibility(View.VISIBLE); } else { - holder.flDownloadPodcast.setVisibility(View.GONE); + holder.binding.flDownloadPodcastWrapper.setVisibility(View.GONE); } - holder.flDeletePodcast.setVisibility((podcastItem.downloadProgress.equals(PodcastItem.DOWNLOAD_COMPLETED)) ? View.VISIBLE : View.GONE ); + holder.binding.flDeletePodcastWrapper.setVisibility((podcastItem.downloadProgress.equals(PodcastItem.DOWNLOAD_COMPLETED)) ? View.VISIBLE : View.GONE ); /* File podcastFile = new File(PodcastDownloadService.getUrlToPodcastFile(getContext(), podcastItem.link, true)); @@ -132,18 +131,10 @@ public class PodcastArrayAdapter extends ArrayAdapter<PodcastItem> { static class ViewHolder { - @BindView(R.id.tv_title) TextView tvTitle; - @BindView(R.id.tv_body) TextView tvBody; - @BindView(R.id.fl_downloadPodcastWrapper) FrameLayout flDownloadPodcast; - @BindView(R.id.fl_PlayPodcastWrapper) FrameLayout flPlayPodcast; - @BindView(R.id.fl_deletePodcastWrapper) FrameLayout flDeletePodcast; - @BindView(R.id.pbDownloadPodcast) ProgressBar pbDownloadPodcast; - @BindView(R.id.tvDownloadPodcastProgress) TextView tvDownloadPodcastProgress; - - + @NonNull final PodcastRowBinding binding; - public ViewHolder(View view) { - ButterKnife.bind(this, view); + public ViewHolder(@NonNull PodcastRowBinding binding) { + this.binding = binding; } } } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/ListView/PodcastFeedArrayAdapter.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/ListView/PodcastFeedArrayAdapter.java index ff993dde..f30dd4e9 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/ListView/PodcastFeedArrayAdapter.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/ListView/PodcastFeedArrayAdapter.java @@ -7,11 +7,12 @@ import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; +import androidx.annotation.NonNull; + import org.greenrobot.eventbus.EventBus; -import butterknife.BindView; -import butterknife.ButterKnife; import de.luhmer.owncloudnewsreader.R; +import de.luhmer.owncloudnewsreader.databinding.PodcastFeedRowBinding; import de.luhmer.owncloudnewsreader.events.podcast.PodcastFeedClicked; import de.luhmer.owncloudnewsreader.model.PodcastFeedItem; @@ -32,15 +33,16 @@ public class PodcastFeedArrayAdapter extends ArrayAdapter<PodcastFeedItem> { if (view != null) { holder = (ViewHolder) view.getTag(); } else { - view = inflater.inflate(R.layout.podcast_feed_row, parent, false); - holder = new ViewHolder(view); - view.setTag(holder); + PodcastFeedRowBinding binding = PodcastFeedRowBinding.inflate(inflater, parent, false); + view = binding.getRoot(); + holder = new ViewHolder(binding); + binding.getRoot().setTag(holder); } final PodcastFeedItem feedItem = getItem(position); - holder.tvTitle.setText(feedItem.mFeed.getFeedTitle()); - holder.tvBody.setText(feedItem.mPodcastCount + " Podcasts available"); + holder.binding.tvTitle.setText(feedItem.mFeed.getFeedTitle()); + holder.binding.tvBody.setText(feedItem.mPodcastCount + " Podcasts available"); view.setOnClickListener(new View.OnClickListener() { @Override @@ -56,11 +58,10 @@ public class PodcastFeedArrayAdapter extends ArrayAdapter<PodcastFeedItem> { static class ViewHolder { - @BindView(R.id.tv_title) TextView tvTitle; - @BindView(R.id.tv_body) TextView tvBody; + @NonNull final PodcastFeedRowBinding binding; - public ViewHolder(View view) { - ButterKnife.bind(this, view); + public ViewHolder(@NonNull PodcastFeedRowBinding binding) { + this.binding = binding; } } } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/ListView/SubscriptionExpandableListAdapter.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/ListView/SubscriptionExpandableListAdapter.java index 7495f74e..de94ffb9 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/ListView/SubscriptionExpandableListAdapter.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/ListView/SubscriptionExpandableListAdapter.java @@ -25,7 +25,6 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; -import android.preference.PreferenceManager; import android.util.Log; import android.util.SparseArray; import android.view.LayoutInflater; @@ -34,23 +33,21 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.ExpandableListView; -import android.widget.ImageButton; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; -import android.widget.TextView; import java.util.ArrayList; import java.util.List; +import androidx.annotation.NonNull; import androidx.core.view.ViewCompat; -import butterknife.BindView; -import butterknife.ButterKnife; import de.luhmer.owncloudnewsreader.R; import de.luhmer.owncloudnewsreader.SettingsActivity; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; import de.luhmer.owncloudnewsreader.database.model.Feed; import de.luhmer.owncloudnewsreader.database.model.Folder; +import de.luhmer.owncloudnewsreader.databinding.SubscriptionListItemBinding; +import de.luhmer.owncloudnewsreader.databinding.SubscriptionListSubItemBinding; import de.luhmer.owncloudnewsreader.helper.FavIconHandler; import de.luhmer.owncloudnewsreader.helper.StopWatch; import de.luhmer.owncloudnewsreader.helper.ThemeChooser; @@ -150,8 +147,9 @@ public class SubscriptionExpandableListAdapter extends BaseExpandableListAdapter viewHolder = (ChildHolder) convertView.getTag(); } else { LinearLayout view = new LinearLayout(mContext); - convertView = inflater.inflate(R.layout.subscription_list_sub_item, view, true); - viewHolder = new ChildHolder(convertView); + SubscriptionListSubItemBinding binding = SubscriptionListSubItemBinding.inflate(LayoutInflater.from(mContext), view, true); + convertView = binding.getRoot(); + viewHolder = new ChildHolder(binding); convertView.setTag(viewHolder); } @@ -159,7 +157,7 @@ public class SubscriptionExpandableListAdapter extends BaseExpandableListAdapter if(item != null) { String headerText = (item.header != null) ? item.header : ""; - viewHolder.tV_HeaderText.setText(headerText); + viewHolder.binding.summary.setText(headerText); String unreadCount; @@ -170,30 +168,27 @@ public class SubscriptionExpandableListAdapter extends BaseExpandableListAdapter } if(unreadCount != null) - viewHolder.tV_UnreadCount.setText(unreadCount); + viewHolder.binding.tvUnreadCount.setText(unreadCount); else - viewHolder.tV_UnreadCount.setText(""); + viewHolder.binding.tvUnreadCount.setText(""); - favIconHandler.loadFavIconForFeed(item.favIcon, viewHolder.imgView_FavIcon); + favIconHandler.loadFavIconForFeed(item.favIcon, viewHolder.binding.iVFavicon); } else { - viewHolder.tV_HeaderText.setText(mContext.getString(R.string.login_dialog_text_something_went_wrong)); - viewHolder.tV_UnreadCount.setText(""); - viewHolder.imgView_FavIcon.setImageDrawable(null); + viewHolder.binding.summary.setText(mContext.getString(R.string.login_dialog_text_something_went_wrong)); + viewHolder.binding.tvUnreadCount.setText(""); + viewHolder.binding.iVFavicon.setImageDrawable(null); } return convertView; } static class ChildHolder { - @BindView(R.id.list_item_layout) View listItemLayout; - @BindView(R.id.summary) TextView tV_HeaderText; - @BindView(R.id.tv_unreadCount) TextView tV_UnreadCount; - @BindView(R.id.iVFavicon) ImageView imgView_FavIcon; + @NonNull final SubscriptionListSubItemBinding binding; - public ChildHolder(View view) { - ButterKnife.bind(this, view); + public ChildHolder(@NonNull SubscriptionListSubItemBinding binding) { + this.binding = binding; } } @@ -242,16 +237,16 @@ public class SubscriptionExpandableListAdapter extends BaseExpandableListAdapter final AbstractItem group = (AbstractItem) getGroup(groupPosition); if (convertView == null) { - LinearLayout view = new LinearLayout(mContext); - convertView = inflater.inflate(R.layout.subscription_list_item, view, true); - viewHolder = new GroupHolder(convertView); - view.setTag(viewHolder); + SubscriptionListItemBinding binding = SubscriptionListItemBinding.inflate(LayoutInflater.from(mContext), new LinearLayout(mContext), true); + viewHolder = new GroupHolder(binding); + convertView = binding.getRoot(); + binding.getRoot().setTag(viewHolder); } else { viewHolder = (GroupHolder) convertView.getTag(); } - viewHolder.txt_Summary.setText(group.header); - viewHolder.listItemLayout.setOnClickListener(new OnClickListener() { + viewHolder.binding.summary.setText(group.header); + viewHolder.binding.listItemLayout.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -269,7 +264,7 @@ public class SubscriptionExpandableListAdapter extends BaseExpandableListAdapter } }); - viewHolder.listItemLayout.setOnLongClickListener(new View.OnLongClickListener() { + viewHolder.binding.listItemLayout.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { @@ -286,12 +281,12 @@ public class SubscriptionExpandableListAdapter extends BaseExpandableListAdapter }); - viewHolder.txt_UnreadCount.setText(""); + viewHolder.binding.tVFeedsCount.setText(""); boolean skipGetUnread = false; if(group.idFolder != null && group.idFolder == ITEMS_WITHOUT_FOLDER.getValue()) { String unreadCount = unreadCountFeeds.get((int) group.id_database); if(unreadCount != null) { - viewHolder.txt_UnreadCount.setText(unreadCount); + viewHolder.binding.tVFeedsCount.setText(unreadCount); } skipGetUnread = true; @@ -300,7 +295,7 @@ public class SubscriptionExpandableListAdapter extends BaseExpandableListAdapter if(!skipGetUnread) { String unreadCount = unreadCountFolders.get((int) group.id_database); if(unreadCount != null) - viewHolder.txt_UnreadCount.setText(unreadCount); + viewHolder.binding.tVFeedsCount.setText(unreadCount); } @@ -310,25 +305,25 @@ public class SubscriptionExpandableListAdapter extends BaseExpandableListAdapter if(group.idFolder != null) { - viewHolder.imgView.setVisibility(View.GONE); + viewHolder.binding.imgViewExpandableIndicator.setVisibility(View.GONE); if(group.idFolder == ITEMS_WITHOUT_FOLDER.getValue()) { ConcreteFeedItem concreteFeedItem = ((ConcreteFeedItem) group); - favIconHandler.loadFavIconForFeed(concreteFeedItem.favIcon, viewHolder.faviconView); + favIconHandler.loadFavIconForFeed(concreteFeedItem.favIcon, viewHolder.binding.imgViewFavicon); } } else { if(group.id_database == ALL_STARRED_ITEMS.getValue()) { - viewHolder.imgView.setVisibility(View.GONE); - viewHolder.faviconView.setVisibility(View.VISIBLE); + viewHolder.binding.imgViewExpandableIndicator.setVisibility(View.GONE); + viewHolder.binding.imgViewFavicon.setVisibility(View.VISIBLE); rotation = 0; - viewHolder.faviconView.setImageResource(getBtn_rating_star_off_normal_holo_light()); + viewHolder.binding.imgViewFavicon.setImageResource(getBtn_rating_star_off_normal_holo_light()); } else if (getChildrenCount( groupPosition ) == 0 ) { - viewHolder.imgView.setVisibility(View.GONE); - viewHolder.faviconView.setVisibility(View.INVISIBLE); + viewHolder.binding.imgViewExpandableIndicator.setVisibility(View.GONE); + viewHolder.binding.imgViewFavicon.setVisibility(View.INVISIBLE); } else { - viewHolder.imgView.setVisibility(View.VISIBLE); - viewHolder.faviconView.setVisibility(View.INVISIBLE); - viewHolder.imgView.setImageResource(R.drawable.ic_action_expand_less); + viewHolder.binding.imgViewExpandableIndicator.setVisibility(View.VISIBLE); + viewHolder.binding.imgViewFavicon.setVisibility(View.INVISIBLE); + viewHolder.binding.imgViewExpandableIndicator.setImageResource(R.drawable.ic_action_expand_less); if(isExpanded) { rotation = 180; @@ -342,7 +337,7 @@ public class SubscriptionExpandableListAdapter extends BaseExpandableListAdapter contentDescriptionId = R.string.content_desc_expand; } - viewHolder.imgView.setOnClickListener(new OnClickListener() { + viewHolder.binding.imgViewExpandableIndicator.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(isExpanded) @@ -354,8 +349,8 @@ public class SubscriptionExpandableListAdapter extends BaseExpandableListAdapter } } - viewHolder.imgView.setRotation(rotation); - viewHolder.imgView.setContentDescription(viewHolder.imgView.getContext().getString(contentDescriptionId)); + viewHolder.binding.imgViewExpandableIndicator.setRotation(rotation); + viewHolder.binding.imgViewExpandableIndicator.setContentDescription(viewHolder.binding.imgViewExpandableIndicator.getContext().getString(contentDescriptionId)); return convertView; } @@ -373,14 +368,10 @@ public class SubscriptionExpandableListAdapter extends BaseExpandableListAdapter } static class GroupHolder { - @BindView(R.id.list_item_layout) View listItemLayout; - @BindView(R.id.summary) TextView txt_Summary; - @BindView(R.id.tV_feedsCount) TextView txt_UnreadCount; - @BindView(R.id.img_View_expandable_indicator) ImageButton imgView; - @BindView(R.id.img_view_favicon) ImageView faviconView; - - public GroupHolder(View view) { - ButterKnife.bind(this, view); + @NonNull final SubscriptionListItemBinding binding; + + public GroupHolder(@NonNull SubscriptionListItemBinding binding) { + this.binding = binding; } } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/LoginDialogActivity.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/LoginDialogActivity.java index 29b6ce7a..da8feb32 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/LoginDialogActivity.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/LoginDialogActivity.java @@ -66,10 +66,8 @@ import java.net.URL; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; +import de.luhmer.owncloudnewsreader.databinding.ActivityLoginDialogBinding; import de.luhmer.owncloudnewsreader.di.ApiProvider; import de.luhmer.owncloudnewsreader.model.NextcloudNewsVersion; import de.luhmer.owncloudnewsreader.ssl.MemorizingTrustManager; @@ -106,15 +104,7 @@ public class LoginDialogActivity extends AppCompatActivity { private String mOc_root_path; // UI references. - protected @BindView(R.id.username) EditText mUsernameView; - protected @BindView(R.id.password) EditText mPasswordView; - protected @BindView(R.id.password_container) TextInputLayout mPasswordContainerView; - protected @BindView(R.id.edt_owncloudRootPath) EditText mOc_root_path_View; - protected @BindView(R.id.cb_AllowAllSSLCertificates) CheckBox mCbDisableHostnameVerificationView; - protected @BindView(R.id.imgView_ShowPassword) ImageView mImageViewShowPwd; - protected @BindView(R.id.tv_manual_login) TextView mTvManualLogin; - protected @BindView(R.id.old_login_wrapper) RelativeLayout mOldLoginWrapper; - + protected ActivityLoginDialogBinding binding; private SingleSignOnAccount importedAccount = null; private boolean mPasswordVisible = false; @@ -124,13 +114,17 @@ public class LoginDialogActivity extends AppCompatActivity { public void onCreate(Bundle savedInstance) { super.onCreate(savedInstance); ((NewsReaderApplication) getApplication()).getAppComponent().injectActivity(this); - setContentView(R.layout.activity_login_dialog); - ButterKnife.bind(this); + + binding = ActivityLoginDialogBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + binding.btnSingleSignOn.setOnClickListener((v) -> startSingleSignOn()); + binding.btnLogin.setOnClickListener((v) -> startManualLogin()); + binding.tvManualLogin.setOnClickListener((v) -> manualLogin()); // Manual Login - mImageViewShowPwd.setOnClickListener(ImgViewShowPasswordListener); - mPasswordView.addTextChangedListener(PasswordTextChangedListener); + binding.imgViewShowPassword.setOnClickListener(ImgViewShowPasswordListener); + binding.password.addTextChangedListener(PasswordTextChangedListener); mUsername = mPrefs.getString(SettingsActivity.EDT_USERNAME_STRING, ""); mPassword = mPrefs.getString(SettingsActivity.EDT_PASSWORD_STRING, ""); @@ -138,16 +132,16 @@ public class LoginDialogActivity extends AppCompatActivity { boolean mCbDisableHostnameVerification = mPrefs.getBoolean(SettingsActivity.CB_DISABLE_HOSTNAME_VERIFICATION_STRING, false); if(!mPassword.isEmpty()) { - mImageViewShowPwd.setVisibility(View.GONE); + binding.imgViewShowPassword.setVisibility(View.GONE); } // Set up the login form. - mUsernameView.setText(mUsername); - mPasswordView.setText(mPassword); - mOc_root_path_View.setText(mOc_root_path); + binding.username.setText(mUsername); + binding.password.setText(mPassword); + binding.edtOwncloudRootPath.setText(mOc_root_path); - mCbDisableHostnameVerificationView.setChecked(mCbDisableHostnameVerification); - mCbDisableHostnameVerificationView.setOnCheckedChangeListener(new OnCheckedChangeListener() { + binding.cbAllowAllSSLCertificates.setChecked(mCbDisableHostnameVerification); + binding.cbAllowAllSSLCertificates.setOnCheckedChangeListener(new OnCheckedChangeListener() { @SuppressLint("ApplySharedPref") @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { @@ -181,14 +175,13 @@ public class LoginDialogActivity extends AppCompatActivity { super.onStop(); } - @OnClick(R.id.btnSingleSignOn) public void startSingleSignOn() { if (!VersionCheckHelper.verifyMinVersion(LoginDialogActivity.this, MIN_NEXTCLOUD_FILES_APP_VERSION_CODE)) { // Dialog will be shown automatically return; } - mOldLoginWrapper.setVisibility(View.GONE); + binding.oldLoginWrapper.setVisibility(View.GONE); try { AccountImporter.pickNewAccount(LoginDialogActivity.this); @@ -199,14 +192,12 @@ public class LoginDialogActivity extends AppCompatActivity { } } - @OnClick(R.id.btnLogin) public void startManualLogin() { attemptLogin(); } - @OnClick(R.id.tv_manual_login) public void manualLogin() { - mOldLoginWrapper.setVisibility(View.VISIBLE); + binding.oldLoginWrapper.setVisibility(View.VISIBLE); } private TextWatcher PasswordTextChangedListener = new TextWatcher() { @@ -223,7 +214,7 @@ public class LoginDialogActivity extends AppCompatActivity { @Override public void afterTextChanged(Editable s) { if(s.toString().isEmpty()) { - mImageViewShowPwd.setVisibility(View.VISIBLE); + binding.imgViewShowPassword.setVisibility(View.VISIBLE); } } }; @@ -234,9 +225,9 @@ public class LoginDialogActivity extends AppCompatActivity { mPasswordVisible = !mPasswordVisible; if(mPasswordVisible) { - mPasswordView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); + binding.password.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); } else { - mPasswordView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); + binding.password.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); } } }; @@ -285,40 +276,40 @@ public class LoginDialogActivity extends AppCompatActivity { */ public void attemptLogin() { // Reset errors. - mUsernameView.setError(null); - mPasswordView.setError(null); - mOc_root_path_View.setError(null); + binding.username.setError(null); + binding.password.setError(null); + binding.edtOwncloudRootPath.setError(null); // Append "https://" is url doesn't contain it already - mOc_root_path = mOc_root_path_View.getText().toString().trim(); + mOc_root_path = binding.edtOwncloudRootPath.getText().toString().trim(); if(!mOc_root_path.startsWith("http")) { - mOc_root_path_View.setText("https://" + mOc_root_path); + binding.edtOwncloudRootPath.setText("https://" + mOc_root_path); } // Store values at the time of the login attempt. - mUsername = mUsernameView.getText().toString().trim(); - mPassword = mPasswordView.getText().toString(); - mOc_root_path = mOc_root_path_View.getText().toString().trim(); + mUsername = binding.username.getText().toString().trim(); + mPassword = binding.password.getText().toString(); + mOc_root_path = binding.edtOwncloudRootPath.getText().toString().trim(); boolean cancel = false; View focusView = null; // Check for a valid password. if (TextUtils.isEmpty(mPassword)) { - mPasswordView.setError(getString(R.string.error_field_required)); - focusView = mPasswordView; + binding.password.setError(getString(R.string.error_field_required)); + focusView = binding.password; cancel = true; } // Check for a valid email address. if (TextUtils.isEmpty(mUsername)) { - mUsernameView.setError(getString(R.string.error_field_required)); - focusView = mUsernameView; + binding.username.setError(getString(R.string.error_field_required)); + focusView = binding.username; cancel = true; } if (TextUtils.isEmpty(mOc_root_path)) { - mOc_root_path_View.setError(getString(R.string.error_field_required)); - focusView = mOc_root_path_View; + binding.edtOwncloudRootPath.setError(getString(R.string.error_field_required)); + focusView = binding.edtOwncloudRootPath; cancel = true; } else { try { @@ -331,8 +322,8 @@ public class LoginDialogActivity extends AppCompatActivity { getString(R.string.login_dialog_text_security_warning), this); } } catch (MalformedURLException e) { - mOc_root_path_View.setError(getString(R.string.error_invalid_url)); - focusView = mOc_root_path_View; + binding.edtOwncloudRootPath.setError(getString(R.string.error_invalid_url)); + focusView = binding.edtOwncloudRootPath; cancel = true; } } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewFeedActivity.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewFeedActivity.java index 29e2adc9..d114fc8c 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewFeedActivity.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewFeedActivity.java @@ -17,15 +17,11 @@ import android.view.MenuItem; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.EditText; -import android.widget.Spinner; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; @@ -54,12 +50,10 @@ import java.util.Map; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; import de.luhmer.owncloudnewsreader.database.model.Feed; import de.luhmer.owncloudnewsreader.database.model.Folder; +import de.luhmer.owncloudnewsreader.databinding.ActivityNewFeedBinding; import de.luhmer.owncloudnewsreader.di.ApiProvider; import de.luhmer.owncloudnewsreader.helper.AsyncTaskHelper; import de.luhmer.owncloudnewsreader.helper.OpmlXmlParser; @@ -79,12 +73,7 @@ public class NewFeedActivity extends AppCompatActivity { private final static int REQUEST_CODE_OPML_IMPORT = 2; // UI references. - protected @BindView(R.id.et_feed_url) EditText mFeedUrlView; - protected @BindView(R.id.sp_folder) Spinner mFolderView; - protected @BindView(R.id.new_feed_progress) View mProgressView; - protected @BindView(R.id.new_feed_form) View mLoginFormView; - protected @BindView(R.id.btn_addFeed) Button mAddFeedButton; - protected @BindView(R.id.toolbar) Toolbar toolbar; + protected ActivityNewFeedBinding binding; private List<Folder> folders; protected @Inject ApiProvider mApi; @@ -96,13 +85,16 @@ public class NewFeedActivity extends AppCompatActivity { ThemeChooser.chooseTheme(this); super.onCreate(savedInstanceState); ThemeChooser.afterOnCreate(this); - setContentView(R.layout.activity_new_feed); - ButterKnife.bind(this); + binding = ActivityNewFeedBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + binding.btnAddFeed.setOnClickListener((v) -> btnAddFeedClick()); + binding.btnImportOpml.setOnClickListener((v) -> importOpml()); + binding.btnExportOpml.setOnClickListener((v) -> exportOpml()); - if (toolbar != null) { - setSupportActionBar(toolbar); + if (binding.toolbarLayout.toolbar != null) { + setSupportActionBar(binding.toolbarLayout.toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } @@ -118,7 +110,7 @@ public class NewFeedActivity extends AppCompatActivity { } ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, folderNames); - mFolderView.setAdapter(spinnerArrayAdapter); + binding.spFolder.setAdapter(spinnerArrayAdapter); Intent intent = getIntent(); String action = intent.getAction(); @@ -140,22 +132,20 @@ public class NewFeedActivity extends AppCompatActivity { //Uri uri = intent.getData(); Log.v("tag" , "Content intent detected: " + action + " : " + url); - mFeedUrlView.setText(url); + binding.etFeedUrl.setText(url); } } - @OnClick(R.id.btn_addFeed) public void btnAddFeedClick() { //Hide keyboard InputMethodManager imm = (InputMethodManager)getSystemService( Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(mFeedUrlView.getWindowToken(), 0); + imm.hideSoftInputFromWindow(binding.etFeedUrl.getWindowToken(), 0); attemptAddNewFeed(); } - @OnClick(R.id.btn_import_opml) public void importOpml() { String permission = Manifest.permission.READ_EXTERNAL_STORAGE; @@ -181,9 +171,6 @@ public class NewFeedActivity extends AppCompatActivity { .start(); } - - - @OnClick(R.id.btn_export_opml) public void exportOpml() { String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE; @@ -348,13 +335,13 @@ public class NewFeedActivity extends AppCompatActivity { * errors are presented and no actual login attempt is made. */ public void attemptAddNewFeed() { - Folder folder = folders.get(mFolderView.getSelectedItemPosition()); + Folder folder = folders.get(binding.spFolder.getSelectedItemPosition()); // Reset errors. - mFeedUrlView.setError(null); + binding.etFeedUrl.setError(null); // Store values at the time of the login attempt. - String urlToFeed = mFeedUrlView.getText().toString(); + String urlToFeed = binding.etFeedUrl.getText().toString(); boolean cancel = false; View focusView = null; @@ -362,12 +349,12 @@ public class NewFeedActivity extends AppCompatActivity { // Check for a valid email address. if (TextUtils.isEmpty(urlToFeed)) { - mFeedUrlView.setError(getString(R.string.error_field_required)); - focusView = mFeedUrlView; + binding.etFeedUrl.setError(getString(R.string.error_field_required)); + focusView = binding.etFeedUrl; cancel = true; } else if (!isUrlValid(urlToFeed)) { - mFeedUrlView.setError(getString(R.string.error_invalid_url)); - focusView = mFeedUrlView; + binding.etFeedUrl.setError(getString(R.string.error_invalid_url)); + focusView = binding.etFeedUrl; cancel = true; } @@ -403,13 +390,13 @@ public class NewFeedActivity extends AppCompatActivity { } catch (JSONException e) { Log.e(TAG, "Extracting error message failed: " + errorMessage, e); } - mFeedUrlView.setError(errorMessage); + binding.etFeedUrl.setError(errorMessage); Log.e(TAG, errorMessage); } catch (IOException e) { Log.e(TAG, "IOException", e); - mFeedUrlView.setError(getString(R.string.login_dialog_text_something_went_wrong)); + binding.etFeedUrl.setError(getString(R.string.login_dialog_text_something_went_wrong)); } - mFeedUrlView.requestFocus(); + binding.etFeedUrl.requestFocus(); } }); } @@ -419,8 +406,8 @@ public class NewFeedActivity extends AppCompatActivity { runOnUiThread(() -> { showProgress(false); - mFeedUrlView.setError(getString(R.string.login_dialog_text_something_went_wrong) + " - " + OkHttpSSLClient.HandleExceptions((Exception) t).getMessage()); - mFeedUrlView.requestFocus(); + binding.etFeedUrl.setError(getString(R.string.login_dialog_text_something_went_wrong) + " - " + OkHttpSSLClient.HandleExceptions((Exception) t).getMessage()); + binding.etFeedUrl.requestFocus(); }); } }); @@ -451,21 +438,21 @@ public class NewFeedActivity extends AppCompatActivity { public void showProgress(final boolean show) { int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime); - mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); - mLoginFormView.animate().setDuration(shortAnimTime).alpha( + binding.newFeedForm.setVisibility(show ? View.GONE : View.VISIBLE); + binding.newFeedForm.animate().setDuration(shortAnimTime).alpha( show ? 0 : 1).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); + binding.newFeedForm.setVisibility(show ? View.GONE : View.VISIBLE); } }); - mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); - mProgressView.animate().setDuration(shortAnimTime).alpha( + binding.newFeedProgress.setVisibility(show ? View.VISIBLE : View.GONE); + binding.newFeedProgress.animate().setDuration(shortAnimTime).alpha( show ? 1 : 0).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); + binding.newFeedProgress.setVisibility(show ? View.VISIBLE : View.GONE); } }); } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsDetailActivity.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsDetailActivity.java index 86878af3..16859f1c 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsDetailActivity.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsDetailActivity.java @@ -36,10 +36,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.ProgressBar; -import androidx.appcompat.widget.AppCompatImageButton; -import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentPagerAdapter; @@ -54,14 +51,14 @@ import java.util.Set; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm.SORT_DIRECTION; import de.luhmer.owncloudnewsreader.database.model.RssItem; +import de.luhmer.owncloudnewsreader.databinding.ActivityNewsDetailBinding; import de.luhmer.owncloudnewsreader.helper.ThemeUtils; import de.luhmer.owncloudnewsreader.model.PodcastItem; import de.luhmer.owncloudnewsreader.model.TTSItem; +import de.luhmer.owncloudnewsreader.view.PodcastSlidingUpPanelLayout; import de.luhmer.owncloudnewsreader.widget.WidgetProvider; @@ -79,18 +76,7 @@ public class NewsDetailActivity extends PodcastFragmentActivity { * {@link FragmentStatePagerAdapter}. */ private SectionsPagerAdapter mSectionsPagerAdapter; - protected @BindView(R.id.toolbar) Toolbar toolbar; - // protected @BindView(R.id.bottomAppBar) BottomAppBar bottomAppBar; - protected @BindView(R.id.progressIndicator) ProgressBar progressIndicator; - //protected @BindView(R.id.btn_disable_incognito) ImageButton mBtnDisableIncognito; - protected @BindView(R.id.fa_detail_bar) View fastActionDetailBar; - protected @BindView(R.id.fa_collapse_layout) View fastActionCollapseLayout; - protected @BindView(R.id.fa_star) AppCompatImageButton fastActionStar; - protected @BindView(R.id.fa_mark_as_read) AppCompatImageButton fastActionRead; - protected @BindView(R.id.fa_toggle) AppCompatImageButton fastActionToggle; - protected @BindView(R.id.fa_open_in_browser) AppCompatImageButton fastActionOpenInBrowser; - protected @BindView(R.id.fa_share) AppCompatImageButton fastActionShare; - + protected ActivityNewsDetailBinding binding; /** * The {@link ViewPager} that will host the section contents. @@ -116,6 +102,9 @@ public class NewsDetailActivity extends PodcastFragmentActivity { super.onCreate(savedInstanceState); + binding = ActivityNewsDetailBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + /* //make full transparent statusBar if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) { @@ -144,10 +133,6 @@ public class NewsDetailActivity extends PodcastFragmentActivity { } */ - - - setContentView(R.layout.activity_news_detail); - /* // For Debugging the WebView using Chrome Remote Debugging if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { @@ -155,10 +140,8 @@ public class NewsDetailActivity extends PodcastFragmentActivity { } */ - ButterKnife.bind(this); - - if (toolbar != null) { - setSupportActionBar(toolbar); + if (binding.toolbarLayout.toolbar != null) { + setSupportActionBar(binding.toolbarLayout.toolbar); } /* if (bottomAppBar != null) { @@ -200,7 +183,7 @@ public class NewsDetailActivity extends PodcastFragmentActivity { // primary sections of the app. mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); - progressIndicator.setMax(mSectionsPagerAdapter.getCount()); + binding.progressIndicator.setMax(mSectionsPagerAdapter.getCount()); // Set up the ViewPager with the sections adapter. mViewPager = findViewById(R.id.pager); @@ -232,7 +215,12 @@ public class NewsDetailActivity extends PodcastFragmentActivity { updateActionBarIcons(); } - /** + @Override + protected PodcastSlidingUpPanelLayout getPodcastSlidingUpPanelLayout() { + return binding.slidingLayout; + } + + /** * Init fast action bar based on user settings. * Only show if user selected setting CB_SHOW_FAST_ACTIONS. Otherwise hide. * @@ -243,18 +231,18 @@ public class NewsDetailActivity extends PodcastFragmentActivity { if (mShowFastActions) { // Set click listener for buttons on action bar - fastActionOpenInBrowser.setOnClickListener(v -> this.openInBrowser(currentPosition)); - fastActionToggle.setOnClickListener(v -> this.toggleFastActionBar()); // toggle expand / collapse - fastActionStar.setOnClickListener(v -> NewsDetailActivity.this.toggleRssItemStarredState()); - fastActionRead.setOnClickListener(v -> NewsDetailActivity.this.markRead(currentPosition)); - fastActionShare.setOnClickListener(v -> this.share(currentPosition)); + binding.faDetailBar.faOpenInBrowser.setOnClickListener(v -> this.openInBrowser(currentPosition)); + binding.faDetailBar.faToggle.setOnClickListener(v -> this.toggleFastActionBar()); // toggle expand / collapse + binding.faDetailBar.faStar.setOnClickListener(v -> NewsDetailActivity.this.toggleRssItemStarredState()); + binding.faDetailBar.faMarkAsRead.setOnClickListener(v -> NewsDetailActivity.this.markRead(currentPosition)); + binding.faDetailBar.faShare.setOnClickListener(v -> this.share(currentPosition)); - fastActionDetailBar.setVisibility(View.VISIBLE); + binding.faDetailBar.getRoot().setVisibility(View.VISIBLE); // initially the bar should be opened in the expanded state this.toggleFastActionBar(); } else { - fastActionDetailBar.setVisibility(View.INVISIBLE); + binding.faDetailBar.getRoot().setVisibility(View.INVISIBLE); } } @@ -262,21 +250,21 @@ public class NewsDetailActivity extends PodcastFragmentActivity { * Expands or shrinks the fast action bar to show/hide secondary functions */ private void toggleFastActionBar() { - int currentState = fastActionCollapseLayout.getVisibility(); + int currentState = binding.faDetailBar.faCollapseLayout.getVisibility(); switch (currentState) { case View.GONE: - fastActionToggle.setImageResource(R.drawable.ic_fa_expand); - fastActionCollapseLayout.setVisibility(View.VISIBLE); + binding.faDetailBar.faToggle.setImageResource(R.drawable.ic_fa_expand); + binding.faDetailBar.faCollapseLayout.setVisibility(View.VISIBLE); break; case View.VISIBLE: - fastActionToggle.setImageResource(R.drawable.ic_fa_shrink); - fastActionCollapseLayout.setVisibility(View.GONE); + binding.faDetailBar.faToggle.setImageResource(R.drawable.ic_fa_shrink); + binding.faDetailBar.faCollapseLayout.setVisibility(View.GONE); break; default: break; } //((Animatable)fastActionToggle.getDrawable()).start(); - fastActionToggle.setScaleX(-1); + binding.faDetailBar.faToggle.setScaleX(-1); } private void toggleIncognitoMode() { @@ -369,7 +357,7 @@ public class NewsDetailActivity extends PodcastFragmentActivity { stopVideoOnCurrentPage(); currentPosition = position; resumeVideoPlayersOnCurrentPage(); - progressIndicator.setProgress(position + 1); + binding.progressIndicator.setProgress(position + 1); if(rssItems.get(position).getFeed() != null) { // Try getting the feed title and use it for the action bar title @@ -429,10 +417,10 @@ public class NewsDetailActivity extends PodcastFragmentActivity { if(menuItem_Starred != null) { if (isStarred) { menuItem_Starred.setIcon(R.drawable.ic_action_star_dark); - fastActionStar.setImageResource(R.drawable.ic_action_star_dark); + binding.faDetailBar.faStar.setImageResource(R.drawable.ic_action_star_dark); } else { menuItem_Starred.setIcon(R.drawable.ic_action_star_border_dark); - fastActionStar.setImageResource(R.drawable.ic_action_star_border_dark); + binding.faDetailBar.faStar.setImageResource(R.drawable.ic_action_star_border_dark); } } @@ -440,11 +428,11 @@ public class NewsDetailActivity extends PodcastFragmentActivity { if (isRead) { menuItem_Read.setIcon(R.drawable.ic_check_box_white); menuItem_Read.setChecked(true); - fastActionRead.setImageResource(R.drawable.ic_check_box_white); + binding.faDetailBar.faMarkAsRead.setImageResource(R.drawable.ic_check_box_white); } else { menuItem_Read.setIcon(R.drawable.ic_check_box_outline_blank_white); menuItem_Read.setChecked(false); - fastActionRead.setImageResource(R.drawable.ic_check_box_outline_blank_white); + binding.faDetailBar.faMarkAsRead.setImageResource(R.drawable.ic_check_box_outline_blank_white); } } } @@ -552,8 +540,8 @@ public class NewsDetailActivity extends PodcastFragmentActivity { NewsDetailFragment newsDetailFragment = getNewsDetailFragmentAtPosition(currentPosition); String link = "about:blank"; - if(newsDetailFragment != null && newsDetailFragment.mWebView != null) { - link = newsDetailFragment.mWebView.getUrl(); + if(newsDetailFragment != null && newsDetailFragment.binding.webview != null) { + link = newsDetailFragment.binding.webview.getUrl(); } if("about:blank".equals(link)) { @@ -578,9 +566,9 @@ public class NewsDetailActivity extends PodcastFragmentActivity { NewsDetailFragment fragment = getNewsDetailFragmentAtPosition(currentPosition); if(fragment != null) { // could be null if not instantiated yet - if(!fragment.mWebView.getUrl().equals("about:blank") && !fragment.mWebView.getUrl().trim().equals("")) { - content = fragment.mWebView.getUrl(); - title = fragment.mWebView.getTitle(); + if(!fragment.binding.webview.getUrl().equals("about:blank") && !fragment.binding.webview.getUrl().trim().equals("")) { + content = fragment.binding.webview.getUrl(); + title = fragment.binding.webview.getTitle(); } } @@ -667,7 +655,7 @@ public class NewsDetailActivity extends PodcastFragmentActivity { public void initIncognitoMode() { int color = getResources().getColor(isIncognitoEnabled() ? R.color.material_grey_900 : R.color.colorPrimary); - ThemeUtils.colorizeToolbar(toolbar, color); + ThemeUtils.colorizeToolbar(binding.toolbarLayout.toolbar, color); //ThemeUtils.colorizeToolbar(bottomAppBar, color); //ThemeUtils.changeStatusBarColor(this, color); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsDetailFragment.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsDetailFragment.java index 8b8090fb..2c2e1920 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsDetailFragment.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsDetailFragment.java @@ -38,8 +38,6 @@ import android.webkit.WebResourceResponse; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; -import android.widget.ProgressBar; -import android.widget.TextView; import androidx.annotation.Nullable; import androidx.browser.customtabs.CustomTabsIntent; @@ -60,11 +58,10 @@ import java.util.Map; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; import de.luhmer.owncloudnewsreader.adapter.ProgressBarWebChromeClient; import de.luhmer.owncloudnewsreader.async_tasks.RssItemToHtmlTask; import de.luhmer.owncloudnewsreader.database.model.RssItem; +import de.luhmer.owncloudnewsreader.databinding.FragmentNewsDetailBinding; import de.luhmer.owncloudnewsreader.helper.AdBlocker; import de.luhmer.owncloudnewsreader.helper.AsyncTaskHelper; import de.luhmer.owncloudnewsreader.helper.ColorHelper; @@ -77,10 +74,7 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li public final String TAG = getClass().getCanonicalName(); - protected @BindView(R.id.webview) WebView mWebView; - protected @BindView(R.id.progressBarLoading) ProgressBar mProgressBarLoading; - protected @BindView(R.id.progressbar_webview) ProgressBar mProgressbarWebView; - protected @BindView(R.id.tv_offline_version) TextView mTvOfflineVersion; + protected FragmentNewsDetailBinding binding; protected @Inject SharedPreferences mPrefs; @@ -109,7 +103,7 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li super.onResume(); resumeCurrentPage(); - registerForContextMenu(mWebView); + registerForContextMenu(binding.webview); } @Override @@ -121,23 +115,23 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li @Override public void onDestroy() { super.onDestroy(); - if(mWebView != null) { - mWebView.destroy(); + if(binding.webview != null) { + binding.webview.destroy(); } } public void pauseCurrentPage() { - if(mWebView != null) { - mWebView.onPause(); - mWebView.pauseTimers(); + if(binding.webview != null) { + binding.webview.onPause(); + binding.webview.pauseTimers(); } } public void resumeCurrentPage() { - if(mWebView != null) { - mWebView.onResume(); - mWebView.resumeTimers(); + if(binding.webview != null) { + binding.webview.onResume(); + binding.webview.resumeTimers(); } } @@ -157,47 +151,45 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li */ public void navigateBack() { if (isLastPageRssItem()) { - mWebView.clearHistory(); + binding.webview.clearHistory(); startLoadRssItemToWebViewTask(); } else if (!isCurrentPageRssItem()){ - mWebView.goBack(); + binding.webview.goBack(); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_news_detail, container, false); + binding = FragmentNewsDetailBinding.inflate(inflater, container, false); section_number = (Integer) getArguments().get(ARG_SECTION_NUMBER); - ButterKnife.bind(this, rootView); - // Do not reload webview if retained if(savedInstanceState == null) { startLoadRssItemToWebViewTask(); } else { - mWebView.restoreState(savedInstanceState); - mProgressBarLoading.setVisibility(View.GONE); + binding.webview.restoreState(savedInstanceState); + binding.progressBarLoading.setVisibility(View.GONE); // Make sure to sync the incognitio on retained views syncIncognitoState(); - this.addBottomPaddingForFastActions(mWebView); + this.addBottomPaddingForFastActions(binding.webview); } // setUpGestureDetector(); - return rootView; + return binding.getRoot(); } protected void syncIncognitoState() { NewsDetailActivity ndActivity = ((NewsDetailActivity)getActivity()); boolean isIncognito = ndActivity.isIncognitoEnabled(); - mWebView.getSettings().setBlockNetworkLoads(isIncognito); - mWebView.getSettings().setBlockNetworkImage(isIncognito); + binding.webview.getSettings().setBlockNetworkLoads(isIncognito); + binding.webview.getSettings().setBlockNetworkImage(isIncognito); } @Override public void onSaveInstanceState(Bundle outState) { - mWebView.saveState(outState); + binding.webview.saveState(outState); } /** @@ -240,14 +232,14 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li protected void startLoadRssItemToWebViewTask() { Log.d(TAG, "startLoadRssItemToWebViewTask() called"); - mWebView.setVisibility(View.GONE); - mProgressBarLoading.setVisibility(View.VISIBLE); + binding.webview.setVisibility(View.GONE); + binding.progressBarLoading.setVisibility(View.VISIBLE); NewsDetailActivity ndActivity = ((NewsDetailActivity)getActivity()); assert ndActivity != null; int backgroundColor = ContextCompat.getColor(ndActivity, R.color.news_detail_background_color); - mWebView.setBackgroundColor(backgroundColor); + binding.webview.setBackgroundColor(backgroundColor); ndActivity.setBackgroundColorOfViewPager(backgroundColor); init_webView(); @@ -258,13 +250,13 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li @Override public void onRssItemParsed(String htmlPage) { - mWebView.setVisibility(View.VISIBLE); - mProgressBarLoading.setVisibility(View.GONE); + binding.webview.setVisibility(View.VISIBLE); + binding.progressBarLoading.setVisibility(View.GONE); - setSoftwareRenderModeForWebView(htmlPage, mWebView); + setSoftwareRenderModeForWebView(htmlPage, binding.webview); html = htmlPage; - mWebView.loadDataWithBaseURL("file:///android_asset/", htmlPage, "text/html", "UTF-8", RSS_ITEM_PAGE_URL); + binding.webview.loadDataWithBaseURL("file:///android_asset/", htmlPage, "text/html", "UTF-8", RSS_ITEM_PAGE_URL); } /** @@ -295,9 +287,9 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li private void init_webView() { int backgroundColor = ColorHelper.getColorFromAttribute(getContext(), R.attr.news_detail_background_color); - mWebView.setBackgroundColor(backgroundColor); + binding.webview.setBackgroundColor(backgroundColor); - WebSettings webSettings = mWebView.getSettings(); + WebSettings webSettings = binding.webview.getSettings(); //webSettings.setPluginState(WebSettings.PluginState.ON); webSettings.setJavaScriptEnabled(true); webSettings.setAllowContentAccess(true); @@ -311,9 +303,9 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li syncIncognitoState(); - mWebView.setWebChromeClient(new ProgressBarWebChromeClient(mProgressbarWebView)); + binding.webview.setWebChromeClient(new ProgressBarWebChromeClient(binding.progressbarWebview)); - mWebView.setWebViewClient(new WebViewClient() { + binding.webview.setWebViewClient(new WebViewClient() { private Map<String, Boolean> loadedUrls = new HashMap<>(); @@ -345,7 +337,7 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li }); /* - mWebView.setOnTouchListener((v, event) -> { + binding.webview.setOnTouchListener((v, event) -> { mGestureDetector.onTouchEvent(event); return false; }); @@ -387,10 +379,10 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li File webArchiveFile = DownloadWebPageService.getWebPageArchiveFileForUrl(getActivity(), url); if(webArchiveFile.exists()) { // Test if WebArchive exists for url - mTvOfflineVersion.setVisibility(View.VISIBLE); - mWebView.loadUrl("file://" + webArchiveFile.getAbsolutePath()); + binding.tvOfflineVersion.setVisibility(View.VISIBLE); + binding.webview.loadUrl("file://" + webArchiveFile.getAbsolutePath()); } else { - mTvOfflineVersion.setVisibility(View.GONE); + binding.tvOfflineVersion.setVisibility(View.GONE); switch (selectedBrowser) { case 0: // Custom Tabs CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder() @@ -406,7 +398,7 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li startActivity(browserIntent); break; case 2: // Built in - mWebView.loadUrl(url); + binding.webview.loadUrl(url); break; default: throw new IllegalStateException("Unknown selection!"); @@ -504,7 +496,7 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li * the original rss item page */ private boolean isLastPageRssItem() { - WebBackForwardList list = mWebView.copyBackForwardList(); + WebBackForwardList list = binding.webview.copyBackForwardList(); WebHistoryItem lastItem = list.getItemAtIndex(list.getCurrentIndex() - 1); return lastItem != null && lastItem.getUrl().equals(RSS_ITEM_PAGE_URL); } @@ -514,8 +506,8 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li * the original rss item page */ private boolean isCurrentPageRssItem() { - if(mWebView.copyBackForwardList().getCurrentItem() != null) { - String currentPageUrl = mWebView.copyBackForwardList().getCurrentItem().getOriginalUrl(); + if(binding.webview.copyBackForwardList().getCurrentItem() != null) { + String currentPageUrl = binding.webview.copyBackForwardList().getCurrentItem().getOriginalUrl(); return currentPageUrl.equals("data:text/html;charset=utf-8;base64,"); } return true; 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 4d31498b..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 @@ -44,7 +44,6 @@ import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.ImageView; -import android.widget.ProgressBar; import android.widget.Toast; import androidx.core.content.ContextCompat; @@ -62,14 +61,13 @@ import java.util.List; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; 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; import de.luhmer.owncloudnewsreader.database.model.RssItemDao; +import de.luhmer.owncloudnewsreader.databinding.FragmentNewsreaderDetailBinding; import de.luhmer.owncloudnewsreader.helper.AsyncTaskHelper; import de.luhmer.owncloudnewsreader.helper.PostDelayHandler; import de.luhmer.owncloudnewsreader.helper.Search; @@ -94,14 +92,7 @@ public class NewsReaderDetailFragment extends Fragment { protected final String TAG = getClass().getCanonicalName(); - @BindView(R.id.pb_loading) - ProgressBar pbLoading; - @BindView(R.id.tv_no_items_available) - View tvNoItemsAvailable; - @BindView(R.id.list) - RecyclerView recyclerView; - @BindView(R.id.swipeRefresh) - SwipeRefreshLayout swipeRefresh; + FragmentNewsreaderDetailBinding binding; private Long idFeed; private Drawable leftSwipeDrawable; @@ -152,7 +143,7 @@ public class NewsReaderDetailFragment extends Fragment { @Override public void onError(Throwable e) { - pbLoading.setVisibility(View.GONE); + binding.pbLoading.setVisibility(View.GONE); Toast.makeText(mActivity, e.getLocalizedMessage(), Toast.LENGTH_LONG).show(); } @@ -233,7 +224,7 @@ public class NewsReaderDetailFragment extends Fragment { } protected void notifyDataSetChangedOnAdapter() { - NewsListRecyclerAdapter nca = (NewsListRecyclerAdapter) recyclerView.getAdapter(); + NewsListRecyclerAdapter nca = (NewsListRecyclerAdapter) binding.list.getAdapter(); if (nca != null) { nca.notifyDataSetChanged(); } @@ -244,14 +235,14 @@ public class NewsReaderDetailFragment extends Fragment { */ protected void refreshCurrentRssView() { Log.v(TAG, "refreshCurrentRssView"); - NewsListRecyclerAdapter nra = ((NewsListRecyclerAdapter) recyclerView.getAdapter()); + NewsListRecyclerAdapter nra = ((NewsListRecyclerAdapter) binding.list.getAdapter()); if (nra != null) { nra.refreshAdapterDataAsync(() -> { - pbLoading.setVisibility(View.GONE); + binding.pbLoading.setVisibility(View.GONE); if (layoutManagerSavedState != null) { - recyclerView.getLayoutManager().onRestoreInstanceState(layoutManagerSavedState); + binding.list.getLayoutManager().onRestoreInstanceState(layoutManagerSavedState); layoutManagerSavedState = null; } }); @@ -282,20 +273,20 @@ public class NewsReaderDetailFragment extends Fragment { } public RecyclerView getRecyclerView() { - return recyclerView; + return binding.list; } public LinearLayoutManager getLayoutManager() { - if (recyclerView == null) return null; - return (LinearLayoutManager) recyclerView.getLayoutManager(); + if (binding.list == null) return null; + return (LinearLayoutManager) binding.list.getLayoutManager(); } protected List<RssItem> performSearch(String searchString) { Handler mainHandler = new Handler(mActivity.getMainLooper()); Runnable myRunnable = () -> { - pbLoading.setVisibility(View.VISIBLE); - tvNoItemsAvailable.setVisibility(View.GONE); + binding.pbLoading.setVisibility(View.VISIBLE); + binding.tvNoItemsAvailable.setVisibility(View.GONE); }; mainHandler.post(myRunnable); @@ -305,21 +296,21 @@ public class NewsReaderDetailFragment extends Fragment { void loadRssItemsIntoView(List<RssItem> rssItems) { previousFirstVisibleItem = -1; try { - NewsListRecyclerAdapter nra = ((NewsListRecyclerAdapter) recyclerView.getAdapter()); + NewsListRecyclerAdapter nra = ((NewsListRecyclerAdapter) binding.list.getAdapter()); if (nra == null) { - nra = new NewsListRecyclerAdapter(mActivity, recyclerView, mActivity, mPostDelayHandler, mPrefs); - recyclerView.setAdapter(nra); + nra = new NewsListRecyclerAdapter(mActivity, binding.list, mActivity, mPostDelayHandler, mPrefs); + binding.list.setAdapter(nra); } nra.updateAdapterData(rssItems); - pbLoading.setVisibility(View.GONE); + binding.pbLoading.setVisibility(View.GONE); if (nra.getItemCount() <= 0) { - tvNoItemsAvailable.setVisibility(View.VISIBLE); + binding.tvNoItemsAvailable.setVisibility(View.VISIBLE); } else { - tvNoItemsAvailable.setVisibility(View.GONE); + binding.tvNoItemsAvailable.setVisibility(View.GONE); } - recyclerView.scrollToPosition(0); + binding.list.scrollToPosition(0); } catch (Exception ex) { ex.printStackTrace(); @@ -329,16 +320,14 @@ public class NewsReaderDetailFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_newsreader_detail, container, false); + binding = FragmentNewsreaderDetailBinding.inflate(inflater, container, false); - ButterKnife.bind(this, rootView); - - recyclerView.setHasFixedSize(true); - recyclerView.setLayoutManager(new LinearLayoutManager(mActivity, RecyclerView.VERTICAL, false)); - recyclerView.setItemAnimator(new DefaultItemAnimator()); + binding.list.setHasFixedSize(true); + binding.list.setLayoutManager(new LinearLayoutManager(mActivity, RecyclerView.VERTICAL, false)); + binding.list.setItemAnimator(new DefaultItemAnimator()); ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new NewsReaderItemTouchHelperCallback()); - itemTouchHelper.attachToRecyclerView(recyclerView); + itemTouchHelper.attachToRecyclerView(binding.list); //recyclerView.addItemDecoration(new DividerItemDecoration(mActivity)); // Enable divider line /* @@ -351,10 +340,10 @@ public class NewsReaderDetailFragment extends Fragment { }); */ - swipeRefresh.setColorSchemeColors(accentColor); - swipeRefresh.setOnRefreshListener((SwipeRefreshLayout.OnRefreshListener) mActivity); + binding.swipeRefresh.setColorSchemeColors(accentColor); + binding.swipeRefresh.setOnRefreshListener((SwipeRefreshLayout.OnRefreshListener) mActivity); - recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + binding.list.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (dy > 0) { //check for scroll down @@ -384,12 +373,12 @@ public class NewsReaderDetailFragment extends Fragment { } }; - return rootView; + return binding.getRoot(); } private void handleMarkAsReadScrollEvent() { - LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); - NewsListRecyclerAdapter adapter = (NewsListRecyclerAdapter) recyclerView.getAdapter(); + LinearLayoutManager linearLayoutManager = (LinearLayoutManager) binding.list.getLayoutManager(); + NewsListRecyclerAdapter adapter = (NewsListRecyclerAdapter) binding.list.getAdapter(); int firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition(); int lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition(); @@ -414,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) recyclerView.findViewHolderForLayoutPosition(i); + RssItemViewHolder vh = (RssItemViewHolder) binding.list.findViewHolderForLayoutPosition(i); if (vh != null && !vh.shouldStayUnread()) { adapter.changeReadStateOfItem(vh, true); } @@ -422,13 +411,13 @@ public class NewsReaderDetailFragment extends Fragment { //Check if Listview is scrolled to bottom if (reachedBottom && visibleItemCount != 0 && //Check if list is empty - recyclerView.getChildAt(visibleItemCount).getBottom() <= recyclerView.getHeight()) { + binding.list.getChildAt(visibleItemCount).getBottom() <= binding.list.getHeight()) { for (int i = firstVisibleItem; i <= lastVisibleItem; i++) { - RecyclerView.ViewHolder vhTemp = recyclerView.findViewHolderForLayoutPosition(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); @@ -502,7 +491,7 @@ public class NewsReaderDetailFragment extends Fragment { } public int getFirstVisibleScrollPosition() { - LinearLayoutManager layoutManager = ((LinearLayoutManager) recyclerView.getLayoutManager()); + LinearLayoutManager layoutManager = ((LinearLayoutManager) binding.list.getLayoutManager()); return layoutManager.findFirstVisibleItemPosition(); } @@ -510,8 +499,8 @@ public class NewsReaderDetailFragment extends Fragment { @Override protected void onPreExecute() { - pbLoading.setVisibility(View.VISIBLE); - tvNoItemsAvailable.setVisibility(View.GONE); + binding.pbLoading.setVisibility(View.VISIBLE); + binding.tvNoItemsAvailable.setVisibility(View.GONE); super.onPreExecute(); } @@ -562,10 +551,10 @@ public class NewsReaderDetailFragment extends Fragment { if (rssItem.size() < 10) { // Less than 10 items in the list (usually 3-5 items fit on one screen) // There is no API to check, if this listener has already been added. We don't want to // add it multiple times, so we take the safe route here by removing it before adding it. - recyclerView.removeOnItemTouchListener(itemTouchListener); - recyclerView.addOnItemTouchListener(itemTouchListener); + binding.list.removeOnItemTouchListener(itemTouchListener); + binding.list.addOnItemTouchListener(itemTouchListener); } else { - recyclerView.removeOnItemTouchListener(itemTouchListener); + binding.list.removeOnItemTouchListener(itemTouchListener); } } } @@ -618,7 +607,7 @@ public class NewsReaderDetailFragment extends Fragment { @Override public void onSwiped(final RecyclerView.ViewHolder viewHolder, final int direction) { - final NewsListRecyclerAdapter adapter = (NewsListRecyclerAdapter) recyclerView.getAdapter(); + final NewsListRecyclerAdapter adapter = (NewsListRecyclerAdapter) binding.list.getAdapter(); String swipeAction; if (direction == ItemTouchHelper.LEFT) @@ -627,30 +616,30 @@ 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"); break; } // Hack to reset view, see https://code.google.com/p/android/issues/detail?id=175798 - recyclerView.removeView(viewHolder.itemView); + binding.list.removeView(viewHolder.itemView); } @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); - // swipeRefresh cancels swiping left/right when accidentally moving in the y direction; - swipeRefresh.setEnabled(!isCurrentlyActive); + // binding.swipeRefresh cancels swiping left/right when accidentally moving in the y direction; + binding.swipeRefresh.setEnabled(!isCurrentlyActive); if (isCurrentlyActive) { Rect viewRect = new Rect(); viewHolder.itemView.getDrawingRect(viewRect); 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 3f7a2b19..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 @@ -44,17 +44,14 @@ import android.widget.SearchView; import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.widget.Toolbar; import androidx.browser.customtabs.CustomTabsIntent; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.core.view.GravityCompat; import androidx.customview.widget.ViewDragHelper; -import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; @@ -84,21 +81,21 @@ 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; import javax.inject.Named; -import butterknife.BindView; -import butterknife.ButterKnife; 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; import de.luhmer.owncloudnewsreader.database.model.RssItem; +import de.luhmer.owncloudnewsreader.databinding.ActivityNewsreaderBinding; import de.luhmer.owncloudnewsreader.events.podcast.FeedPanelSlideEvent; import de.luhmer.owncloudnewsreader.helper.DatabaseUtils; import de.luhmer.owncloudnewsreader.helper.ThemeChooser; @@ -111,6 +108,7 @@ import de.luhmer.owncloudnewsreader.services.events.SyncFailedEvent; import de.luhmer.owncloudnewsreader.services.events.SyncFinishedEvent; import de.luhmer.owncloudnewsreader.services.events.SyncStartedEvent; import de.luhmer.owncloudnewsreader.ssl.OkHttpSSLClient; +import de.luhmer.owncloudnewsreader.view.PodcastSlidingUpPanelLayout; import io.reactivex.Completable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.functions.Action; @@ -147,51 +145,91 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements private static MenuItem menuItemDownloadMoreItems; - protected @BindView(R.id.toolbar) Toolbar toolbar; + protected ActivityNewsreaderBinding binding; //private ServiceConnection mConnection = null; - @VisibleForTesting @Nullable @BindView(R.id.drawer_layout) public DrawerLayout drawerLayout; - 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<String> searchPublishSubject; - private static final int REQUEST_CODE_PERMISSION_DOWNLOAD_WEB_ARCHIVE = 1; + private PublishSubject<String> 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(); + } - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_newsreader); + // Fragments are not ready when calling the method below in onCreate() + updateButtonLayout(); - ButterKnife.bind(this); + //Start auto sync if enabled + if (mPrefs.getBoolean(SettingsActivity.CB_SYNCONSTARTUP_STRING, false)) { + startSync(); + } - if (toolbar != null) { - setSupportActionBar(toolbar); + 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()); + + setSupportActionBar(binding.toolbarLayout.toolbar); + initAccountManager(); // Init config --> if nothing is configured start the login dialog. @@ -212,8 +250,8 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements .replace(R.id.left_drawer, newsReaderListFragment) .commit(); - if (drawerLayout != null) { - drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.news_list_drawer_text, R.string.news_list_drawer_text) { + if (binding.drawerLayout != null) { + drawerToggle = new ActionBarDrawerToggle(this, binding.drawerLayout, binding.toolbarLayout.toolbar, R.string.news_list_drawer_text, R.string.news_list_drawer_text) { @Override public void onDrawerClosed(View drawerView) { super.onDrawerClosed(drawerView); @@ -233,12 +271,12 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements } }; - drawerLayout.addDrawerListener(drawerToggle); + binding.drawerLayout.addDrawerListener(drawerToggle); - adjustEdgeSizeOfDrawer(); + adjustEdgeSizeOfDrawer(); } - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayShowHomeEnabled(true); + setSupportActionBar(binding.toolbarLayout.toolbar); + Objects.requireNonNull(getSupportActionBar()).setDisplayShowHomeEnabled(true); if (drawerToggle != null) { drawerToggle.syncState(); } @@ -246,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); } } @@ -332,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().recyclerView, 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 = drawerLayout.getClass().getDeclaredField("mLeftDragger"); - mDragger.setAccessible(true); - ViewDragHelper draggerObj = (ViewDragHelper) mDragger.get(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 = drawerLayout.getClass().getDeclaredField("mLeftDragger"); - mDragger.setAccessible(true); - ViewDragHelper draggerObj = (ViewDragHelper) mDragger.get(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; + } /** @@ -501,9 +493,9 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements config.setDelay(300); // half second between each showcase view MaterialShowcaseSequence sequence = new MaterialShowcaseSequence(this, "SWIPE_LEFT_RIGHT_AND_PTR"); sequence.setConfig(config); - sequence.addSequenceItem(getNewsReaderDetailFragment().pbLoading, + sequence.addSequenceItem(getNewsReaderDetailFragment().binding.pbLoading, "Pull-to-Refresh to sync with server", "GOT IT", true); - sequence.addSequenceItem(getNewsReaderDetailFragment().pbLoading, + sequence.addSequenceItem(getNewsReaderDetailFragment().binding.pbLoading, "Swipe Left/Right to mark article as read", "GOT IT", true); sequence.start(); @@ -551,6 +543,11 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements } @Override + protected PodcastSlidingUpPanelLayout getPodcastSlidingUpPanelLayout() { + return binding.slidingLayout; + } + + @Override public void onRefresh() { startSync(); } @@ -574,16 +571,16 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements */ @Override public void onTopItemClicked(long idFeed, boolean isFolder, Long optional_folder_id) { - if (drawerLayout != null) - drawerLayout.closeDrawer(GravityCompat.START); + if (binding.drawerLayout != null) + binding.drawerLayout.closeDrawer(GravityCompat.START); updateDetailFragment(idFeed, isFolder, optional_folder_id, true); } @Override public void onChildItemClicked(long idFeed, Long optional_folder_id) { - if (drawerLayout != null) - drawerLayout.closeDrawer(GravityCompat.START); + if (binding.drawerLayout != null) + binding.drawerLayout.closeDrawer(GravityCompat.START); updateDetailFragment(idFeed, false, optional_folder_id, true); } @@ -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(); } } @@ -704,7 +694,7 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements if(newsReaderListFragment != null && newsReaderDetailFragment != null) { boolean isSyncRunning = OwnCloudSyncService.isSyncRunning(); newsReaderListFragment.setRefreshing(isSyncRunning); - newsReaderDetailFragment.swipeRefresh.setRefreshing(isSyncRunning); + newsReaderDetailFragment.binding.swipeRefresh.setRefreshing(isSyncRunning); } } @@ -771,11 +761,11 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements @Override public void onBackPressed() { if(!handlePodcastBackPressed()) { - if (drawerLayout != null) { - if (drawerLayout.isDrawerOpen(GravityCompat.START)) + if (binding.drawerLayout != null) { + if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) super.onBackPressed(); else - drawerLayout.openDrawer(GravityCompat.START); + binding.drawerLayout.openDrawer(GravityCompat.START); } else { super.onBackPressed(); } @@ -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/NewsReaderListDialogFragment.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderListDialogFragment.java index 7d384616..62c71275 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderListDialogFragment.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderListDialogFragment.java @@ -12,12 +12,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.RelativeLayout; -import android.widget.TextView; import android.widget.Toast; import androidx.fragment.app.DialogFragment; @@ -29,11 +23,10 @@ import java.util.Map; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; import de.luhmer.owncloudnewsreader.database.model.Feed; import de.luhmer.owncloudnewsreader.database.model.Folder; +import de.luhmer.owncloudnewsreader.databinding.FragmentDialogFeedoptionsBinding; import de.luhmer.owncloudnewsreader.di.ApiProvider; import de.luhmer.owncloudnewsreader.helper.FavIconHandler; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -55,26 +48,7 @@ public class NewsReaderListDialogFragment extends DialogFragment { private LinkedHashMap<String, MenuAction> mMenuItems; private NewsReaderListActivity parentActivity; - protected @BindView(R.id.lv_menu_list) ListView mListView; - protected @BindView(R.id.folder_list) ListView mFolderList; - - protected @BindView(R.id.tv_menu_title) TextView tvTitle; - protected @BindView(R.id.tv_menu_text) TextView tvText; - - protected @BindView(R.id.ic_menu_feedicon) ImageView imgTitle; - - protected @BindView(R.id.remove_feed_dialog) RelativeLayout mRemoveFeedDialogView; - protected @BindView(R.id.rename_feed_dialog) RelativeLayout mRenameFeedDialogView; - protected @BindView(R.id.move_feed_dialog) RelativeLayout mMoveFeedDialogView; - - protected @BindView(R.id.progressView) RelativeLayout mProgressView; - - protected @BindView(R.id.button_remove_confirm) Button mButtonRemoveConfirm; - protected @BindView(R.id.button_remove_cancel) Button mButtonRemoveCancel; - protected @BindView(R.id.button_rename_confirm) Button mButtonRenameConfirm; - protected @BindView(R.id.button_rename_cancel) Button mButtonRenameCancel; - - protected @BindView(R.id.renamefeed_feedname) EditText mFeedName; + protected FragmentDialogFeedoptionsBinding binding; static NewsReaderListDialogFragment newInstance(long feedId, String dialogTitle, String iconurl, String feedurl) { @@ -131,17 +105,15 @@ public class NewsReaderListDialogFragment extends DialogFragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_dialog_feedoptions, container, false); - - ButterKnife.bind(this, v); + binding = FragmentDialogFeedoptionsBinding.inflate(inflater, container, false); FavIconHandler favIconHandler = new FavIconHandler(getContext()); - favIconHandler.loadFavIconForFeed(mDialogIconUrl, imgTitle); + favIconHandler.loadFavIconForFeed(mDialogIconUrl, binding.icMenuFeedicon); - tvTitle.setText(mDialogTitle); - tvText.setText(mDialogText); + binding.tvMenuTitle.setText(mDialogTitle); + binding.tvMenuText.setText(mDialogText); - tvText.setOnClickListener(new View.OnClickListener() { + binding.tvMenuText.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mDialogText != null) { @@ -159,9 +131,9 @@ public class NewsReaderListDialogFragment extends DialogFragment { R.layout.fragment_dialog_listviewitem, menuItemsList); - mListView.setAdapter(arrayAdapter); + binding.lvMenuList.setAdapter(arrayAdapter); - mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + binding.lvMenuList.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { String key = arrayAdapter.getItem(i); @@ -169,7 +141,7 @@ public class NewsReaderListDialogFragment extends DialogFragment { mAction.execute(); } }); - return v; + return binding.getRoot(); } @@ -182,24 +154,24 @@ public class NewsReaderListDialogFragment extends DialogFragment { public void showProgress(final boolean show) { int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime); - mRenameFeedDialogView.setVisibility(show ? View.GONE : View.VISIBLE); - mRemoveFeedDialogView.setVisibility(show ? View.GONE : View.VISIBLE); + binding.renameFeedDialog.setVisibility(show ? View.GONE : View.VISIBLE); + binding.removeFeedDialog.setVisibility(show ? View.GONE : View.VISIBLE); - mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); - mProgressView.animate().setDuration(shortAnimTime).alpha( + binding.progressView.setVisibility(show ? View.VISIBLE : View.GONE); + binding.progressView.animate().setDuration(shortAnimTime).alpha( show ? 1 : 0).setListener(new AnimatorListenerAdapter() { }); } private void showRenameFeedView(final long feedId, final String feedName) { - mFeedName.setText(feedName); - mButtonRenameConfirm.setEnabled(false); + binding.renamefeedFeedname.setText(feedName); + binding.buttonRenameConfirm.setEnabled(false); - mListView.setVisibility(View.GONE); - mRenameFeedDialogView.setVisibility(View.VISIBLE); + binding.lvMenuList.setVisibility(View.GONE); + binding.renameFeedDialog.setVisibility(View.VISIBLE); - mFeedName.addTextChangedListener(new TextWatcher() { + binding.renamefeedFeedname.addTextChangedListener(new TextWatcher() { @Override public void afterTextChanged(Editable s) {} @@ -211,20 +183,20 @@ public class NewsReaderListDialogFragment extends DialogFragment { public void onTextChanged(CharSequence s, int start, int before, int count) { if (s.toString().equals(feedName) || s.length() == 0) { - mButtonRenameConfirm.setEnabled(false); + binding.buttonRenameConfirm.setEnabled(false); } else { - mButtonRenameConfirm.setEnabled(true); + binding.buttonRenameConfirm.setEnabled(true); } } }); - mButtonRenameCancel.setOnClickListener(new View.OnClickListener() { + binding.buttonRenameCancel.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { dismiss(); } }); - mButtonRenameConfirm.setOnClickListener(new View.OnClickListener() { + binding.buttonRenameConfirm.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { showProgress(true); setCancelable(false); @@ -232,7 +204,7 @@ public class NewsReaderListDialogFragment extends DialogFragment { Map<String, String> paramMap = new LinkedHashMap<>(); - paramMap.put("feedTitle", mFeedName.getText().toString()); + paramMap.put("feedTitle", binding.renamefeedFeedname.getText().toString()); mApi.getNewsAPI().renameFeed(feedId, paramMap) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) @@ -240,7 +212,7 @@ public class NewsReaderListDialogFragment extends DialogFragment { @Override public void run() throws Exception { DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(getContext()); - dbConn.renameFeedById(mFeedId, mFeedName.getText().toString()); + dbConn.renameFeedById(mFeedId, binding.renamefeedFeedname.getText().toString()); parentActivity.getSlidingListFragment().reloadAdapter(); parentActivity.startSync(); @@ -260,16 +232,16 @@ public class NewsReaderListDialogFragment extends DialogFragment { private void showRemoveFeedView(final long feedId) { - mListView.setVisibility(View.GONE); - mRemoveFeedDialogView.setVisibility(View.VISIBLE); + binding.lvMenuList.setVisibility(View.GONE); + binding.removeFeedDialog.setVisibility(View.VISIBLE); - mButtonRemoveCancel.setOnClickListener(new View.OnClickListener() { + binding.buttonRemoveCancel.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { dismiss(); } }); - mButtonRemoveConfirm.setOnClickListener(new View.OnClickListener() { + binding.buttonRemoveConfirm.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { showProgress(true); setCancelable(false); @@ -311,10 +283,10 @@ public class NewsReaderListDialogFragment extends DialogFragment { * @param mFeedId Feed to move */ private void showMoveFeedView(final long mFeedId) { - mListView.setVisibility(View.GONE); - mMoveFeedDialogView.setVisibility(View.VISIBLE); + binding.lvMenuList.setVisibility(View.GONE); + binding.moveFeedDialog.setVisibility(View.VISIBLE); - tvText.setText(getString(R.string.feed_move_list_description)); + binding.tvMenuText.setText(getString(R.string.feed_move_list_description)); DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(getContext()); final List<Folder> folders = dbConn.getListOfFolders(); @@ -326,8 +298,8 @@ public class NewsReaderListDialogFragment extends DialogFragment { } ArrayAdapter<String> folderAdapter = new ArrayAdapter<> (getActivity(), R.layout.dialog_list_folder, android.R.id.text1, folderNames); - mFolderList.setAdapter(folderAdapter); - mFolderList.setOnItemClickListener(new AdapterView.OnItemClickListener() { + binding.folderList.setAdapter(folderAdapter); + binding.folderList.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { final Folder folder = folders.get(position); diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderListFragment.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderListFragment.java index dd11c4bf..b05d63e3 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderListFragment.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsReaderListFragment.java @@ -55,10 +55,9 @@ import java.io.Serializable; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; import de.luhmer.owncloudnewsreader.ListView.SubscriptionExpandableListAdapter; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; +import de.luhmer.owncloudnewsreader.databinding.FragmentNewsreaderListBinding; import de.luhmer.owncloudnewsreader.di.ApiProvider; import de.luhmer.owncloudnewsreader.interfaces.ExpListTextClicked; import de.luhmer.owncloudnewsreader.model.AbstractItem; @@ -90,12 +89,7 @@ public class NewsReaderListFragment extends Fragment implements OnCreateContextM private SubscriptionExpandableListAdapter lvAdapter; - @BindView(R.id.expandableListView) protected ExpandableListView eListView; - @BindView(R.id.urlTextView) protected TextView urlTextView; - @BindView(R.id.userTextView) protected TextView userTextView; - @BindView(R.id.header_view) protected ViewGroup headerView; - @BindView(R.id.header_logo) protected ImageView headerLogo; - @BindView(R.id.header_logo_progress) protected View headerLogoProgress; + protected FragmentNewsreaderListBinding binding; /** * The fragment's current callback object, which is notified of list item @@ -118,12 +112,12 @@ public class NewsReaderListFragment extends Fragment implements OnCreateContextM public void setRefreshing(boolean isRefreshing) { if(isRefreshing) { //headerLogo.setImageResource(R.drawable.ic_launcher_background); - headerLogo.setVisibility(View.INVISIBLE); - headerLogoProgress.setVisibility(View.VISIBLE); + binding.headerLogo.setVisibility(View.INVISIBLE); + binding.headerLogoProgress.setVisibility(View.VISIBLE); } else { //headerLogo.setImageResource(R.drawable.ic_launcher); - headerLogo.setVisibility(View.VISIBLE); - headerLogoProgress.setVisibility(View.INVISIBLE); + binding.headerLogo.setVisibility(View.VISIBLE); + binding.headerLogoProgress.setVisibility(View.INVISIBLE); } } @@ -158,25 +152,23 @@ public class NewsReaderListFragment extends Fragment implements OnCreateContextM @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_newsreader_list, container, false); - - ButterKnife.bind(this, view); + binding = FragmentNewsreaderListBinding.inflate(requireActivity().getLayoutInflater(), container, false); loadOwncloudOrNextcloudBanner(); - lvAdapter = new SubscriptionExpandableListAdapter(getActivity(), new DatabaseConnectionOrm(getActivity()), eListView, mPrefs); + lvAdapter = new SubscriptionExpandableListAdapter(getActivity(), new DatabaseConnectionOrm(getActivity()), binding.expandableListView, mPrefs); lvAdapter.setHandlerListener(expListTextClickedListener); - eListView.setGroupIndicator(null); + binding.expandableListView.setGroupIndicator(null); - eListView.setOnChildClickListener(onChildClickListener); - eListView.setOnItemLongClickListener(onItemLongClickListener); + binding.expandableListView.setOnChildClickListener(onChildClickListener); + binding.expandableListView.setOnItemLongClickListener(onItemLongClickListener); - eListView.setClickable(true); - eListView.setLongClickable(true); - eListView.setAdapter(lvAdapter); + binding.expandableListView.setClickable(true); + binding.expandableListView.setLongClickable(true); + binding.expandableListView.setAdapter(lvAdapter); - headerView.setOnClickListener(new View.OnClickListener() { + binding.headerView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ((NewsReaderListActivity) getActivity()).startSync(); @@ -186,9 +178,9 @@ public class NewsReaderListFragment extends Fragment implements OnCreateContextM lvAdapter.notifyDataSetChanged(); reloadAdapter(); - bindNavigationMenu(view, inflater); + bindNavigationMenu(binding.getRoot(), inflater); - return view; + return binding.getRoot(); } @Override @@ -214,7 +206,7 @@ public class NewsReaderListFragment extends Fragment implements OnCreateContextM protected void loadOwncloudOrNextcloudBanner() { if(!Constants.isNextCloud(mPrefs)) { // Set ownCloud view - headerView.setBackgroundResource(R.drawable.left_drawer_header_background); + binding.headerView.setBackgroundResource(R.drawable.left_drawer_header_background); } } @@ -321,13 +313,13 @@ public class NewsReaderListFragment extends Fragment implements OnCreateContextM public ExpandableListView getListView() { - return eListView; + return binding.expandableListView; } protected void showTapLogoToSyncShowcaseView() { new MaterialShowcaseView.Builder(getActivity()) - .setTarget(headerLogo) + .setTarget(binding.headerLogo) .setDismissText("GOT IT") .setContentText("Tap this logo to sync with server") .setDelay(300) // optional but starting animations immediately in onCreate can make them choppy @@ -392,8 +384,8 @@ public class NewsReaderListFragment extends Fragment implements OnCreateContextM String mOc_root_path = mPrefs.getString(SettingsActivity.EDT_OWNCLOUDROOTPATH_STRING, null); String mOc_root_path_without_protocol = mOc_root_path.replace("http://", "").replace("https://", ""); //Remove http:// or https:// - userTextView.setText(mUsername); - urlTextView.setText(mOc_root_path_without_protocol); + binding.userTextView.setText(mUsername); + binding.urlTextView.setText(mOc_root_path_without_protocol); String uInfo = mPrefs.getString(USER_INFO_STRING, null); if(uInfo == null) { @@ -403,7 +395,7 @@ public class NewsReaderListFragment extends Fragment implements OnCreateContextM try { OcsUser userInfo = (OcsUser) fromString(uInfo); if (userInfo.getDisplayName() != null) - userTextView.setText(userInfo.getDisplayName()); + binding.userTextView.setText(userInfo.getDisplayName()); final int placeHolder = R.mipmap.ic_launcher; DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder() .displayer(new CircleBitmapDisplayer()) @@ -416,7 +408,7 @@ public class NewsReaderListFragment extends Fragment implements OnCreateContextM if(userInfo.getId() != null) { String avatarUrl = mOc_root_path + "/index.php/avatar/" + Uri.encode(userInfo.getId()) + "/64"; - ImageLoader.getInstance().displayImage(avatarUrl, this.headerLogo, displayImageOptions); + ImageLoader.getInstance().displayImage(avatarUrl, binding.headerLogo, displayImageOptions); } } catch (Exception ex) { ex.printStackTrace(); diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragment.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragment.java index b91185d6..037d1882 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragment.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragment.java @@ -24,17 +24,8 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.ListView; import android.widget.NumberPicker; -import android.widget.ProgressBar; -import android.widget.RelativeLayout; import android.widget.SeekBar; -import android.widget.TextView; -import android.widget.ViewSwitcher; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; @@ -49,11 +40,9 @@ import java.util.Arrays; import java.util.Locale; import androidx.fragment.app.Fragment; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; import de.luhmer.owncloudnewsreader.ListView.PodcastArrayAdapter; import de.luhmer.owncloudnewsreader.ListView.PodcastFeedArrayAdapter; +import de.luhmer.owncloudnewsreader.databinding.FragmentPodcastBinding; import de.luhmer.owncloudnewsreader.events.podcast.CollapsePodcastView; import de.luhmer.owncloudnewsreader.events.podcast.ExpandPodcastView; import de.luhmer.owncloudnewsreader.events.podcast.SpeedPodcast; @@ -90,33 +79,7 @@ public class PodcastFragment extends Fragment { private long currentPositionInMillis = 0; private long maxPositionInMillis = 100000; - protected @BindView(R.id.btn_playPausePodcast) ImageButton btnPlayPausePodcast; - protected @BindView(R.id.btn_playPausePodcastSlider) ImageButton btnPlayPausePodcastSlider; - protected @BindView(R.id.btn_nextPodcastSlider) ImageButton btnNextPodcastSlider; - protected @BindView(R.id.btn_previousPodcastSlider) ImageButton btnPreviousPodcastSlider; - protected @BindView(R.id.btn_podcastSpeed) ImageButton btnPlaybackSpeed; - - protected @BindView(R.id.img_feed_favicon) ImageView imgFavIcon; - - protected @BindView(R.id.tv_title) TextView tvTitle; - protected @BindView(R.id.tv_titleSlider) TextView tvTitleSlider; - - protected @BindView(R.id.tv_from) TextView tvFrom; - protected @BindView(R.id.tv_to) TextView tvTo; - protected @BindView(R.id.tv_fromSlider) TextView tvFromSlider; - protected @BindView(R.id.tv_ToSlider) TextView tvToSlider; - - protected @BindView(R.id.sb_progress) SeekBar sb_progress; - protected @BindView(R.id.pb_progress) ProgressBar pb_progress; - protected @BindView(R.id.pb_progress2) ProgressBar pb_progress2; - - protected @BindView(R.id.podcastFeedList) ListView /* CardGridView CardListView*/ podcastFeedList; - protected @BindView(R.id.rlPodcast) RelativeLayout rlPodcast; - protected @BindView(R.id.ll_podcast_header) LinearLayout rlPodcastHeader; - protected @BindView(R.id.fl_playPausePodcastWrapper) FrameLayout playPausePodcastWrapper; - protected @BindView(R.id.podcastTitleGrid) ListView /*CardGridView*/ podcastTitleGrid; - - protected @BindView(R.id.viewSwitcherProgress) ViewSwitcher /*CardGridView*/ viewSwitcherProgress; + protected FragmentPodcastBinding binding; /** * Use this factory method to create a new instance of @@ -206,9 +169,9 @@ public class PodcastFragment extends Fragment { @Subscribe public void onEvent(PodcastDownloadService.DownloadProgressUpdate downloadProgress) { - PodcastArrayAdapter podcastArrayAdapter = (PodcastArrayAdapter) podcastTitleGrid.getAdapter(); + PodcastArrayAdapter podcastArrayAdapter = (PodcastArrayAdapter) binding.podcastTitleGrid.getAdapter(); - for(int i = 0; i < podcastTitleGrid.getCount(); i++) { + for(int i = 0; i < binding.podcastTitleGrid.getCount(); i++) { if(podcastArrayAdapter.getItem(i).link.equals(downloadProgress.podcast.link)) { if(!podcastArrayAdapter.getItem(i).downloadProgress.equals(downloadProgress.podcast.downloadProgress)) { //If Progress changed @@ -220,7 +183,7 @@ public class PodcastFragment extends Fragment { pItem.offlineCached = file.exists(); } else pItem.downloadProgress = downloadProgress.podcast.downloadProgress; - podcastTitleGrid.invalidateViews(); + binding.podcastTitleGrid.invalidateViews(); } return; @@ -228,29 +191,24 @@ public class PodcastFragment extends Fragment { } } - @OnClick(R.id.fl_playPausePodcastWrapper) protected void playPause() { eventBus.post(new TogglePlayerStateEvent()); } - @OnClick(R.id.btn_playPausePodcastSlider) protected void playPauseSlider() { playPause(); } - @OnClick(R.id.btn_nextPodcastSlider) protected void windForward() { eventBus.post(new WindPodcast(30000)); //Toast.makeText(getActivity(), "This feature is not supported yet :(", Toast.LENGTH_SHORT).show(); } - @OnClick(R.id.btn_previousPodcastSlider) protected void windBack() { eventBus.post(new WindPodcast(-10000)); } - @OnClick(R.id.btn_podcastSpeed) protected void openSpeedMenu() { showPlaybackSpeedPicker(); } @@ -263,18 +221,23 @@ public class PodcastFragment extends Fragment { //LayoutInflater localInflater = inflater.cloneInContext(context); // inflate using the cloned inflater, not the passed in default //View view = localInflater.inflate(R.layout.fragment_podcast, container, false); - View view = inflater.inflate(R.layout.fragment_podcast, container, false); + binding = FragmentPodcastBinding.inflate(inflater, container, false); + + binding.flPlayPausePodcastWrapper.setOnClickListener((v) -> playPause()); + binding.btnPlayPausePodcastSlider.setOnClickListener((v) -> playPauseSlider()); + binding.btnNextPodcastSlider.setOnClickListener((v) -> windForward()); + binding.btnPreviousPodcastSlider.setOnClickListener((v) -> windBack()); + binding.btnPodcastSpeed.setOnClickListener((v) -> openSpeedMenu()); //View view = inflater.inflate(R.layout.fragment_podcast, container, false); - ButterKnife.bind(this, view); if(getActivity() instanceof PodcastFragmentActivity) { sliding_layout = ((PodcastFragmentActivity) getActivity()).getSlidingLayout(); } if(sliding_layout != null) { - sliding_layout.setSlideableView(rlPodcast); - sliding_layout.setDragView(rlPodcastHeader); + sliding_layout.setSlideableView(binding.rlPodcast); + sliding_layout.setDragView(binding.llPodcastHeader); //sliding_layout.setEnableDragViewTouchEvents(true); sliding_layout.setPanelSlideListener(onPanelSlideListener); @@ -283,15 +246,15 @@ public class PodcastFragment extends Fragment { PodcastFeedArrayAdapter mArrayAdapter = new PodcastFeedArrayAdapter(getActivity(), new PodcastFeedItem[0]); if(mArrayAdapter.getCount() > 0) { - view.findViewById(R.id.tv_no_podcasts_available).setVisibility(View.GONE); + binding.tvNoPodcastsAvailable.setVisibility(View.GONE); } - podcastTitleGrid.setVisibility(View.GONE); - podcastFeedList.setVisibility(View.VISIBLE); + binding.podcastTitleGrid.setVisibility(View.GONE); + binding.podcastFeedList.setVisibility(View.VISIBLE); - sb_progress.setOnSeekBarChangeListener(onSeekBarChangeListener); + binding.sbProgress.setOnSeekBarChangeListener(onSeekBarChangeListener); - return view; + return binding.getRoot(); } @@ -303,15 +266,15 @@ public class PodcastFragment extends Fragment { @Override public void onPanelCollapsed(View view) { if(sliding_layout != null) - sliding_layout.setDragView(rlPodcastHeader); - viewSwitcherProgress.setDisplayedChild(0); + sliding_layout.setDragView(binding.llPodcastHeader); + binding.viewSwitcherProgress.setDisplayedChild(0); } @Override public void onPanelExpanded(View view) { if(sliding_layout != null) - sliding_layout.setDragView(viewSwitcherProgress); - viewSwitcherProgress.setDisplayedChild(1); + sliding_layout.setDragView(binding.viewSwitcherProgress); + binding.viewSwitcherProgress.setDisplayedChild(1); } @Override public void onPanelAnchored(View view) { } @@ -409,19 +372,19 @@ public class PodcastFragment extends Fragment { } private MediaControllerCompat.Callback controllerCallback = - new MediaControllerCompat.Callback() { - @Override - public void onMetadataChanged(MediaMetadataCompat metadata) { - Log.v(TAG, "onMetadataChanged() called with: metadata = [" + metadata + "]"); - displayMetadata(metadata); - } + new MediaControllerCompat.Callback() { + @Override + public void onMetadataChanged(MediaMetadataCompat metadata) { + Log.v(TAG, "onMetadataChanged() called with: metadata = [" + metadata + "]"); + displayMetadata(metadata); + } - @Override - public void onPlaybackStateChanged(PlaybackStateCompat stateCompat) { - Log.v(TAG, "onPlaybackStateChanged() called with: state = [" + stateCompat + "]"); - displayPlaybackState(stateCompat); - } - }; + @Override + public void onPlaybackStateChanged(PlaybackStateCompat stateCompat) { + Log.v(TAG, "onPlaybackStateChanged() called with: state = [" + stateCompat + "]"); + displayPlaybackState(stateCompat); + } + }; private void displayMetadata(MediaMetadataCompat metadata) { @@ -430,8 +393,8 @@ public class PodcastFragment extends Fragment { if(author != null) { title += " - " + author; } - tvTitle.setText(title); - tvTitleSlider.setText(title); + binding.tvTitle.setText(title); + binding.tvTitleSlider.setText(title); String favIconUrl = metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI); if(favIconUrl != null) { @@ -441,7 +404,7 @@ public class PodcastFragment extends Fragment { showImageForEmptyUri(R.drawable.default_feed_icon_light). showImageOnFail(R.drawable.default_feed_icon_light). build(); - ImageLoader.getInstance().displayImage(favIconUrl, imgFavIcon, displayImageOptions); + ImageLoader.getInstance().displayImage(favIconUrl, binding.imgFeedFavicon, displayImageOptions); } PlaybackService.VideoType mediaType = PlaybackService.VideoType.valueOf(metadata.getString(CURRENT_PODCAST_MEDIA_TYPE)); @@ -482,9 +445,9 @@ public class PodcastFragment extends Fragment { // If attached to context.. if(mActivity != null) { - btnPlayPausePodcast.setImageResource(drawableId); - btnPlayPausePodcast.setContentDescription(getString(contentDescriptionId)); - btnPlayPausePodcastSlider.setImageResource(drawableId); + binding.btnPlayPausePodcast.setImageResource(drawableId); + binding.btnPlayPausePodcast.setContentDescription(getString(contentDescriptionId)); + binding.btnPlayPausePodcastSlider.setImageResource(drawableId); } currentPositionInMillis = stateCompat.getPosition(); @@ -497,32 +460,32 @@ public class PodcastFragment extends Fragment { int minutes = (int)(currentPositionInMillis % (1000*60*60)) / (1000*60); int seconds = (int) ((currentPositionInMillis % (1000*60*60)) % (1000*60) / 1000); minutes += hours * 60; - tvFrom.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds)); - tvFromSlider.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds)); + binding.tvFrom.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds)); + binding.tvFromSlider.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds)); hours = (int)(maxPositionInMillis / (1000*60*60)); minutes = (int)(maxPositionInMillis % (1000*60*60)) / (1000*60); seconds = (int) ((maxPositionInMillis % (1000*60*60)) % (1000*60) / 1000); minutes += hours * 60; - tvTo.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds)); - tvToSlider.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds)); + binding.tvTo.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds)); + binding.tvToSlider.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds)); if(state == PlaybackStateCompat.STATE_CONNECTING) { - sb_progress.setVisibility(View.INVISIBLE); - pb_progress2.setVisibility(View.VISIBLE); + binding.sbProgress.setVisibility(View.INVISIBLE); + binding.pbProgress2.setVisibility(View.VISIBLE); - pb_progress.setIndeterminate(true); + binding.pbProgress.setIndeterminate(true); } else { double progress = ((double) currentPositionInMillis / (double) maxPositionInMillis) * 100d; if(!blockSeekbarUpdate) { - sb_progress.setVisibility(View.VISIBLE); - pb_progress2.setVisibility(View.INVISIBLE); - sb_progress.setProgress((int) progress); + binding.sbProgress.setVisibility(View.VISIBLE); + binding.pbProgress2.setVisibility(View.INVISIBLE); + binding.sbProgress.setProgress((int) progress); } - pb_progress.setIndeterminate(false); - pb_progress.setProgress((int) progress); + binding.pbProgress.setIndeterminate(false); + binding.pbProgress.setProgress((int) progress); } } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragmentActivity.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragmentActivity.java index d189ea7c..4c264e0c 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragmentActivity.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragmentActivity.java @@ -23,14 +23,11 @@ import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import java.io.File; -import java.lang.reflect.Proxy; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; import de.luhmer.owncloudnewsreader.ListView.SubscriptionExpandableListAdapter; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; import de.luhmer.owncloudnewsreader.database.model.RssItem; @@ -52,7 +49,7 @@ import de.luhmer.owncloudnewsreader.widget.WidgetProvider; import static de.luhmer.owncloudnewsreader.Constants.MIN_NEXTCLOUD_FILES_APP_VERSION_CODE; -public class PodcastFragmentActivity extends AppCompatActivity implements IPlayPausePodcastClicked { +public abstract class PodcastFragmentActivity extends AppCompatActivity implements IPlayPausePodcastClicked { private static final String TAG = PodcastFragmentActivity.class.getCanonicalName(); @@ -64,11 +61,6 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP private EventBus eventBus; private PodcastFragment mPodcastFragment; - @BindView(R.id.sliding_layout) - protected PodcastSlidingUpPanelLayout sliding_layout; - - - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { //Log.v(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]"); @@ -94,8 +86,6 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP eventBus = EventBus.getDefault(); - ButterKnife.bind(this); - updatePodcastView(); } @@ -125,7 +115,7 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP if (hasWindowFocus) { int currentOrientation = getResources().getConfiguration().orientation; if (currentOrientation != lastOrientation) { - sliding_layout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); + getPodcastSlidingUpPanelLayout().setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); lastOrientation = currentOrientation; } } @@ -210,12 +200,12 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP */ public PodcastSlidingUpPanelLayout getSlidingLayout() { - return sliding_layout; + return getPodcastSlidingUpPanelLayout(); } public boolean handlePodcastBackPressed() { - if(mPodcastFragment != null && sliding_layout.getPanelState().equals(SlidingUpPanelLayout.PanelState.EXPANDED)) { - sliding_layout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); + if(mPodcastFragment != null && getPodcastSlidingUpPanelLayout().getPanelState().equals(SlidingUpPanelLayout.PanelState.EXPANDED)) { + getPodcastSlidingUpPanelLayout().setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); return true; } return false; @@ -253,17 +243,17 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP private void collapsePodcastView() { - sliding_layout.setPanelHeight(0); + getPodcastSlidingUpPanelLayout().setPanelHeight(0); } private void expandPodcastView() { - sliding_layout.setPanelHeight((int) dipToPx(68)); + getPodcastSlidingUpPanelLayout().setPanelHeight((int) dipToPx(68)); } @Subscribe public void onEvent(PodcastCompletedEvent podcastCompletedEvent) { collapsePodcastView(); - sliding_layout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); + getPodcastSlidingUpPanelLayout().setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); //currentlyPlaying = false; } @@ -353,4 +343,6 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP } return videoId; } + + protected abstract PodcastSlidingUpPanelLayout getPodcastSlidingUpPanelLayout(); } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/SyncIntervalSelectorActivity.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/SyncIntervalSelectorActivity.java index 6b55e3ec..3a363d7b 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/SyncIntervalSelectorActivity.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/SyncIntervalSelectorActivity.java @@ -16,14 +16,12 @@ import android.widget.ListView; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.Fragment; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; import de.luhmer.owncloudnewsreader.authentication.AccountGeneral; +import de.luhmer.owncloudnewsreader.databinding.ActivitySyncIntervalSelectorBinding; import de.luhmer.owncloudnewsreader.helper.ThemeChooser; @@ -31,7 +29,7 @@ public class SyncIntervalSelectorActivity extends AppCompatActivity { private PlaceholderFragment mFragment; private String[] items_values; - protected @BindView(R.id.toolbar) Toolbar toolbar; + protected ActivitySyncIntervalSelectorBinding binding; protected @Inject SharedPreferences mPrefs; @Override @@ -42,12 +40,11 @@ public class SyncIntervalSelectorActivity extends AppCompatActivity { super.onCreate(savedInstanceState); ThemeChooser.afterOnCreate(this); - setContentView(R.layout.activity_sync_interval_selector); + binding = ActivitySyncIntervalSelectorBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); - ButterKnife.bind(this); - - if (toolbar != null) { - setSupportActionBar(toolbar); + if (binding.toolbarLayout.toolbar != null) { + setSupportActionBar(binding.toolbarLayout.toolbar); } items_values = getResources().getStringArray(R.array.array_sync_interval_values); 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<RssItem> 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<String> 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/ViewHolder.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemViewHolder.java index 7af3614f..4597e468 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/ViewHolder.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemViewHolder.java @@ -4,253 +4,142 @@ 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.SparseIntArray; import android.util.TypedValue; import android.view.View; -import android.webkit.WebView; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; -import androidx.annotation.Nullable; +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; 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<Integer> 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; +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 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) { + RssItemViewHolder(@NonNull View itemView, SharedPreferences sharedPreferences) { super(itemView); - - this.mPrefs = prefs; - - selectedListLayout = Integer.parseInt(mPrefs.getString(SettingsActivity.SP_FEED_LIST_LAYOUT, "0")); + this.mPrefs = sharedPreferences; bodyForegroundColor = new ForegroundColorSpan(ContextCompat.getColor(itemView.getContext(), android.R.color.secondary_text_dark)); - if(favIconHandler == null) { + 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); + /** + * 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; } - } - 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; - } + int initialSize = initialTvSize; + if (initialSize < 0) { + initialSize = Math.round(tv.getTextSize()); } - pbPodcastDownloadProgress.setProgress((int) progress); - Log.v(TAG, "Progress of download2: " + progress); + // float sp = initialSize / tv.getContext().getResources().getDisplayMetrics().scaledDensity; // transform scaled pixels, device pixels + tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, Math.round(initialSize * scalingFactor)); } - @Override - public void onClick(View v) { - clickListener.onClick(this, getLayoutPosition()); + /** + * 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 void setClickListener(RecyclerItemClickListener clickListener) { - this.clickListener = clickListener; - } + abstract protected ImageView getImageViewFavIcon(); - @Override - public boolean onLongClick(View v) { - return clickListener.onLongClick(this, getLayoutPosition()); - } + abstract protected ImageView getStar(); - private void setFeedColor(int color) { - if(colorLineFeed != null) { - colorLineFeed.setBackgroundColor(color); - } - } + abstract protected ImageView getPlayPausePodcastButton(); - 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); - } + abstract protected View getColorFeed(); - ((View) textViewSummary.getParent()).setAlpha(alpha); - } - } + abstract protected TextView getTextViewTitle(); - 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)); - } + abstract protected TextView getTextViewSummary(); - 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; + abstract protected TextView getTextViewBody(); - String contentDescription = btnPlayPausePodcast.getContext().getString(contentDescriptionId); - btnPlayPausePodcast.setContentDescription(contentDescription); - btnPlayPausePodcast.setImageResource(imageId); - } + abstract protected TextView getTextViewItemDate(); - public boolean isPlaying() { - return playing; - } + abstract protected FrameLayout getPlayPausePodcastWrapper(); - public RssItem getRssItem() { - return rssItem; - } + abstract protected ProgressBar getPodcastDownloadProgress(); - public void setRssItem(RssItem rssItem) { + @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) { + if (rssItem.getFeed() != null) { title = rssItem.getFeed().getFeedTitle(); favIconUrl = rssItem.getFeed().getFaviconUrl(); } else { @@ -262,12 +151,9 @@ public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickL setFeedColor(ColorHelper.getFeedColor(itemView.getContext(), rssItem.getFeed())); - if(textViewSummary != null) { + TextView textViewSummary = getTextViewSummary(); + 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) { @@ -275,110 +161,77 @@ public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickL } } - if(textViewTitle != null && title != null) { + TextView textViewTitle = getTextViewTitle(); + 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) { + + 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)); + favIconHandler.loadFavIconForFeed(favIconUrl, imgViewFavIcon, Math.round((height - textSizeItemDate) / 2)); } - if(imgViewThumbnail != null) { - imgViewThumbnail.setColorFilter(null); - String body = rssItem.getBody(); - List<String> images; - if(rssItem.getMediaThumbnail() != null && !rssItem.getMediaThumbnail().isEmpty()) { - images = new ArrayList(); - images.add(rssItem.getMediaThumbnail()); - } else { - images = ImageHandler.getImageLinksFromText(body); + + if (textViewBody != null) { + int textSizeBody = Math.round(textViewBody.getTextSize()); + + String body = rssItem.getMediaDescription(); + if (body == null || body.isEmpty()) { + body = rssItem.getBody(); } - 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); - } + 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); } + } - if(webView_body != null) { - String htmlPage = RssItemToHtmlTask.getHtmlPage(rssItem, false, mPrefs, itemView.getContext()); - webView_body.loadDataWithBaseURL("file:///android_asset/", htmlPage, "text/html", "UTF-8", ""); - } + @Override + public void onClick(View v) { + clickListener.onClick(this, getLayoutPosition()); } - /** - * 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; - } + public void setClickListener(RecyclerItemClickListener clickListener) { + this.clickListener = clickListener; + } - 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)); + @Override + public boolean onLongClick(View v) { + return clickListener.onLongClick(this, getLayoutPosition()); } - /** - * 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 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; @@ -388,10 +241,9 @@ public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickL this.stayUnread = shouldStayUnread; } - private String getBodyText(String body, boolean limitLength) - { + private String getBodyText(String body, boolean limitLength) { if (body.startsWith("<![CDATA[")) { - body = body.replaceFirst( Pattern.quote("<![CDATA["), ""); + body = body.replaceFirst(Pattern.quote("<![CDATA["), ""); body = body.replaceFirst("]]>", ""); } @@ -404,10 +256,68 @@ public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickL String bodyString = bodyStringSpannable.toString().trim(); - if(limitLength && bodyString.length() > LengthBody) { + 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/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(); diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/DownloadImagesService.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/DownloadImagesService.java index 9e60269c..fdc51be1 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/DownloadImagesService.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/DownloadImagesService.java @@ -24,10 +24,11 @@ package de.luhmer.owncloudnewsreader.services; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; +import android.util.Log; + import androidx.annotation.NonNull; import androidx.core.app.JobIntentService; import androidx.core.app.NotificationCompat; -import android.util.Log; import com.nostra13.universalimageloader.core.ImageLoader; @@ -116,7 +117,7 @@ public class DownloadImagesService extends JobIntentService { FavIconHandler favIconHandler = new FavIconHandler(this); for(Feed feed : feedList) { try { - favIconHandler.preCacheFavIcon(feed); + favIconHandler.preCacheFavIcon(feed, this); } catch(IllegalStateException ex) { Log.e(TAG, ex.getMessage()); } |