diff --git a/app/build.gradle b/app/build.gradle index e6f4102dd..305a46b46 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,18 +2,18 @@ apply plugin: 'com.android.application' apply plugin: 'org.greenrobot.greendao' android { - compileSdkVersion 28 + compileSdkVersion 29 defaultConfig { applicationId "fr.gaulupeau.apps.InThePoche" - minSdkVersion 21 - targetSdkVersion 28 + minSdkVersion 24 + targetSdkVersion 29 versionCode 215 versionName "2.3.0-beta.1" javaCompileOptions { annotationProcessorOptions { - arguments = [ eventBusIndex : 'fr.gaulupeau.apps.Poche.EventBusIndex' ] + arguments = [eventBusIndex: 'fr.gaulupeau.apps.Poche.EventBusIndex'] } } } @@ -33,8 +33,9 @@ android { buildTypes { release { - minifyEnabled false + minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + multiDexEnabled = true } debug { applicationIdSuffix '.debug' @@ -50,6 +51,7 @@ android { } } } + buildToolsVersion = '29.0.2' } greendao { @@ -58,10 +60,11 @@ greendao { } dependencies { - implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.appcompat:appcompat:1.1.0-rc01' implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.recyclerview:recyclerview:1.0.0' - implementation 'com.google.android.material:material:1.0.0' + implementation 'androidx.recyclerview:recyclerview:1.1.0-beta03' + implementation 'androidx.preference:preference:1.1.0-rc01' + implementation 'com.google.android.material:material:1.1.0-alpha09' implementation 'org.greenrobot:eventbus:3.1.1' implementation 'org.greenrobot:greendao:3.2.2' annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ed2c3ddaf..57b5f99a2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,43 +1,47 @@ - - - - - - + xmlns:tools="http://schemas.android.com/tools" + package="fr.gaulupeau.apps.InThePoche" + android:installLocation="auto"> + android:theme="@style/MyTheme.DayNight"> + android:name="fr.gaulupeau.apps.Poche.ui.preferences.SettingsActivity" + android:label="@string/title_activity_settings" + android:parentActivityName="fr.gaulupeau.apps.Poche.ui.MainActivity" + android:theme="@style/MyTheme.DayNight"> + + + - - + + - + - + + - + android:hardwareAccelerated="true" + android:theme="@style/MyTheme.DayNight"/> + + android:theme="@style/MyTheme.DayNight"> @@ -52,7 +56,7 @@ android:enabled="false" android:excludeFromRecents="true" android:noHistory="true" - android:theme="@style/ProxyTheme"> + android:theme="@style/MyTheme.DayNight"> @@ -76,37 +80,40 @@ - - + + - - + - - - - + + + + + + + + + + - - - - - - - @@ -120,8 +127,9 @@ android:name="fr.gaulupeau.apps.Poche.network.ConnectivityChangeReceiver" android:enabled="false"> - + + + + + + - + android:exported="true" + android:permission="android.permission.BIND_JOB_SERVICE" /> - - - - - + + + + + + - + \ No newline at end of file diff --git a/app/src/main/assets/fonts/librefranklin_400.ttf b/app/src/main/assets/fonts/librefranklin_400.ttf new file mode 100644 index 000000000..0bc602450 Binary files /dev/null and b/app/src/main/assets/fonts/librefranklin_400.ttf differ diff --git a/app/src/main/assets/fonts/merriweather_400.ttf b/app/src/main/assets/fonts/merriweather_400.ttf new file mode 100644 index 000000000..18da9e5b0 Binary files /dev/null and b/app/src/main/assets/fonts/merriweather_400.ttf differ diff --git a/app/src/main/assets/ic_web.svg b/app/src/main/assets/ic_web.svg new file mode 100644 index 000000000..16b04e8fe --- /dev/null +++ b/app/src/main/assets/ic_web.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/src/main/assets/main.css b/app/src/main/assets/main.css index 7d9a0b873..0da81f282 100755 --- a/app/src/main/assets/main.css +++ b/app/src/main/assets/main.css @@ -15,7 +15,7 @@ html { } body { - background: #EEE; + background: #FFF; } .high-contrast { @@ -43,24 +43,19 @@ body { background: #000; } -h2, h3, h4 { - font-family: 'PT Sans', sans-serif; - text-transform: uppercase; -} - p, li { color: #666; } table { - border-collapse: collapse; + border-collapse: collapse;align width: 100%; } table, th, td { border:1px solid #999; padding: 0.25em; - text-align: left; + text-align: start; } .high-contrast p, @@ -102,7 +97,7 @@ h2:after { top: 0; width: 10em; left: 0; - text-align: right; + text-align: end; background: #333; padding-top: 9.5em; height: 100%; @@ -176,7 +171,7 @@ h2:after { } footer { - text-align: right; + text-align: end; position: relative; bottom: 0; right: 5em; @@ -195,14 +190,16 @@ footer a { 5 = Article ========================================================================== */ + header.mbm { - text-align: left; + text-align: start; } #article { width: 70%; /* margin-bottom: 3em; */ word-wrap: break-word; + font: normal regular 1em/1.5 'Merriweather', serif; } #article .tags { @@ -223,7 +220,7 @@ header.mbm { #article pre { font-family: monospace; white-space: pre; - text-justify: none; + text-justify: start; } .pre-overflow #article pre { @@ -246,6 +243,55 @@ header.mbm { content: none; } +.no-bottom-margin { + margin-bottom:0px; +} + +@font-face { + font-family: 'Libre Franklin'; + src: url('file:///android_asset/fonts/librefranklin_400.ttf'); +} +@font-face { + font-family: 'Merriweather'; + src: url('file:///android_asset/fonts/merriweather_400.ttf'); +} + + +h1{ + font-size: 3rem; + line-height: 3.125rem; + font-family: 'Merriweather', serif; + font-style: italic; + font-weight: 900; +} +h2 { + font-size: 2.125rem; + line-height: 2.5rem; + font-family: 'Libre Franklin', sans-serif; +} +h3 { + font-size: 1.5rem; + line-height: 2rem; + font-family: 'Libre Franklin', sans-serif; +} +h4 { + font-size: 1.25rem; + line-height: 2rem; + font-family: 'Merriweather', serif; + font-style: italic; +} +p { + font-size: 1rem; + line-height: 1.5rem; + font-family: 'Merriweather', serif; +} +.caption { + font-size: .75rem; + line-height: 1.25rem; + font-family: 'Libre Franklin', sans-serif; + margin-bottom:0px; +} + /* ========================================================================== 6 = Media Queries ========================================================================== */ @@ -287,8 +333,7 @@ header.mbm { width: 100%; } - #article h1 { - font-size: 1.2em; + #article h2 { margin-bottom:0px; } diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/data/Settings.java b/app/src/main/java/fr/gaulupeau/apps/Poche/data/Settings.java index 56b7241d3..b21bee483 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/data/Settings.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/data/Settings.java @@ -6,7 +6,7 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Build; -import android.preference.PreferenceManager; +import androidx.preference.PreferenceManager; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/data/TagListAdapter.java b/app/src/main/java/fr/gaulupeau/apps/Poche/data/TagListAdapter.java index a9551f49d..f90df57a9 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/data/TagListAdapter.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/data/TagListAdapter.java @@ -8,6 +8,8 @@ import android.widget.ImageButton; import android.widget.TextView; +import com.google.android.material.button.MaterialButton; + import java.util.List; import fr.gaulupeau.apps.InThePoche.R; @@ -56,7 +58,7 @@ public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickL OnItemButtonClickListener buttonClickListener; TextView label; - ImageButton button; + MaterialButton button; public ViewHolder(View itemView, OnItemClickListener listener, OnItemButtonClickListener buttonClickListener) { @@ -69,7 +71,7 @@ public ViewHolder(View itemView, OnItemClickListener listener, itemView.setOnClickListener(this); - button = (ImageButton)itemView.findViewById(R.id.tag_remove_button); + button = (MaterialButton)itemView.findViewById(R.id.tag_remove_button); if(button != null) { button.setOnClickListener(this); } diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/events/EventProcessor.java b/app/src/main/java/fr/gaulupeau/apps/Poche/events/EventProcessor.java index 0bf13d296..8ba91bc19 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/events/EventProcessor.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/events/EventProcessor.java @@ -175,7 +175,7 @@ public void onUpdateArticlesStartedEvent(UpdateArticlesStartedEvent event) { detailedMessage = prependAppName(detailedMessage); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID_SYNC) - .setSmallIcon(R.drawable.ic_action_refresh) + .setSmallIcon(R.drawable.ic_refresh_24dp) .setContentTitle(context.getString(R.string.notification_updatingArticles)) .setContentText(detailedMessage) .setOngoing(true); @@ -215,7 +215,7 @@ public void onSweepDeletedArticlesStartedEvent(SweepDeletedArticlesStartedEvent Context context = getContext(); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID_SYNC) - .setSmallIcon(R.drawable.ic_action_refresh) + .setSmallIcon(R.drawable.ic_refresh_24dp) .setContentTitle(context.getString(R.string.notification_sweepingDeletedArticles)) .setOngoing(true); @@ -259,7 +259,7 @@ public void onFetchImagesProgressEvent(FetchImagesProgressEvent event) { Context context = getContext(); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID_SYNC) - .setSmallIcon(R.drawable.ic_action_refresh) + .setSmallIcon(R.drawable.ic_refresh_24dp) .setContentTitle(context.getString(R.string.notification_downloadingImages)) .setOngoing(true); @@ -313,7 +313,7 @@ public void onSyncQueueProgressEvent(SyncQueueProgressEvent event) { Context context = getContext(); notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID_SYNC) - .setSmallIcon(R.drawable.ic_action_refresh) + .setSmallIcon(R.drawable.ic_refresh_24dp) .setContentTitle(getContext().getString(R.string.notification_syncingQueue)) .setOngoing(true); diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/tts/TtsFragment.java b/app/src/main/java/fr/gaulupeau/apps/Poche/tts/TtsFragment.java index 1230fd64e..ffd308500 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/tts/TtsFragment.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/tts/TtsFragment.java @@ -19,6 +19,7 @@ import android.speech.tts.TextToSpeech; import androidx.annotation.NonNull; import androidx.annotation.StringRes; +import androidx.core.widget.NestedScrollView; import androidx.fragment.app.Fragment; import android.support.v4.media.session.MediaControllerCompat; import android.support.v4.media.session.PlaybackStateCompat; @@ -30,9 +31,9 @@ import android.webkit.WebView; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; import android.widget.CheckBox; import android.widget.CompoundButton; -import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ScrollView; import android.widget.SeekBar; @@ -40,6 +41,8 @@ import android.widget.TextView; import android.widget.Toast; +import com.google.android.material.button.MaterialButton; + import fr.gaulupeau.apps.InThePoche.R; import fr.gaulupeau.apps.Poche.App; import fr.gaulupeau.apps.Poche.data.Settings; @@ -62,7 +65,7 @@ public class TtsFragment private WebViewText webViewText; private Settings settings; private View viewTTSOption; - private ImageButton btnTTSPlayStop; + private MaterialButton btnTTSPlayStop; private SeekBar seekBarTTSSpeed; private SeekBar seekBarTTSPitch; private SeekBar seekBarTTSVolume; @@ -71,8 +74,8 @@ public class TtsFragment private TextView textViewTTSPitch; private TextView textViewTTSVolume; private TextView textViewTTSSleep; - private Spinner spinnerLanguage; - private Spinner spinnerVoice; + private AutoCompleteTextView spinnerLanguage; + private AutoCompleteTextView spinnerVoice; private ArrayAdapter spinnerLanguageAdapter; private ArrayAdapter spinnerVoiceAdapter; @@ -178,7 +181,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa if(!this.settings.isTtsOptionsVisible()) { this.viewTTSOption.setVisibility(View.GONE); } - this.btnTTSPlayStop = ((ImageButton) view.findViewById(R.id.btnTTSPlayPause)); + this.btnTTSPlayStop = ((MaterialButton) view.findViewById(R.id.btnTTSPlayPause)); this.btnTTSPlayStop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -188,7 +191,7 @@ public void onClick(View v) { } }); - ImageButton btnTTSFastRewind = (ImageButton) view.findViewById(R.id.btnTTSFastRewind); + MaterialButton btnTTSFastRewind = (MaterialButton) view.findViewById(R.id.btnTTSFastRewind); btnTTSFastRewind.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -198,7 +201,7 @@ public void onClick(View v) { } }); - ImageButton btnTTSFastForward = (ImageButton) view.findViewById(R.id.btnTTSFastForward); + MaterialButton btnTTSFastForward = (MaterialButton) view.findViewById(R.id.btnTTSFastForward); btnTTSFastForward.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -209,11 +212,11 @@ public void onClick(View v) { }); - ImageButton btnTTSOptions = (ImageButton) view.findViewById(R.id.btnTTSOptions); + MaterialButton btnTTSOptions = (MaterialButton) view.findViewById(R.id.btnTTSOptions); btnTTSOptions.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - onTTSOptionsClicked((ImageButton) v); + onTTSOptionsClicked((MaterialButton) v); } }); @@ -353,13 +356,13 @@ public void onStopTrackingTouch(SeekBar seekBar) { } }); - spinnerLanguage = (Spinner) view.findViewById(R.id.spinnerLanguage); + spinnerLanguage = (AutoCompleteTextView) view.findViewById(R.id.spinnerLanguage); spinnerLanguageAdapter = new ArrayAdapter(this.getContext(), android.R.layout.simple_spinner_item, new ArrayList()); spinnerLanguageAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerLanguage.setAdapter(spinnerLanguageAdapter); - spinnerVoice = (Spinner) view.findViewById(R.id.spinnerVoice); + spinnerVoice = (AutoCompleteTextView) view.findViewById(R.id.spinnerVoice); spinnerVoiceAdapter = new ArrayAdapter(this.getContext(), android.R.layout.simple_spinner_item, new ArrayList()); spinnerVoiceAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); @@ -388,13 +391,13 @@ public void onNothingSelected(AdapterView parentView) {} public void onPlaybackStateChanged(PlaybackStateCompat state) { switch (state.getState()) { case PlaybackStateCompat.STATE_BUFFERING: - btnTTSPlayStop.setImageResource(R.drawable.ic_more_horiz_24dp); + btnTTSPlayStop.setIconResource(R.drawable.ic_more_horiz_24dp); break; case PlaybackStateCompat.STATE_PLAYING: - btnTTSPlayStop.setImageResource(R.drawable.ic_stop_24dp); + btnTTSPlayStop.setIconResource(R.drawable.ic_stop_24dp); break; case PlaybackStateCompat.STATE_PAUSED: - btnTTSPlayStop.setImageResource(R.drawable.ic_play_arrow_24dp); + btnTTSPlayStop.setIconResource(R.drawable.ic_play_arrow_24dp); break; case PlaybackStateCompat.STATE_STOPPED: //Log.d(LOG_TAG, "onPlaybackStateChanged: STATE_STOPPED"); @@ -507,7 +510,7 @@ private float getPitchBarValue() { } - private void onTTSOptionsClicked(ImageButton btn) { + private void onTTSOptionsClicked(MaterialButton btn) { if (viewTTSOption.getVisibility() == View.VISIBLE) { viewTTSOption.setVisibility(View.GONE); } else { @@ -538,7 +541,7 @@ public void onDocumentLoadStart(String domain, String title, String language) { this.selectLanguage(language); } - public void onDocumentLoadFinished(WebView webView, ScrollView scrollView) { + public void onDocumentLoadFinished(WebView webView, NestedScrollView scrollView) { //Log.d(LOG_TAG, "onDocumentLoadFinished"); if (webViewText == null) { if (readArticleActivity == null) { @@ -788,14 +791,13 @@ private void onLanguageSelectionChanged() { //Log.d(LOG_TAG, "onLanguageSelectionChanged"); spinnerVoiceAdapter.setNotifyOnChange(false); spinnerVoiceAdapter.clear(); - int languagePosition = spinnerLanguage.getSelectedItemPosition(); - String language = ttsLanguages.get(languagePosition).name; + String language = spinnerLanguage.getText().toString(); String languageVoicePreference = settings.getTtsLanguageVoice(language); int voicePositionToSelect = 0; for (VoiceInfo voiceInfo : ttsVoiceByLanguage.get(language)) { spinnerVoiceAdapter.add(voiceInfo.displayName); if (voiceInfo.displayName.equals(languageVoicePreference)) { - voicePositionToSelect = spinnerVoiceAdapter.getCount() - 1; + voicePositionToSelect = spinnerVoiceAdapter.getCount() - 1; } } spinnerVoice.setSelection(voicePositionToSelect); @@ -806,10 +808,19 @@ private void onLanguageSelectionChanged() { private void onVoiceSelectionChanged() { //Log.d(LOG_TAG, "onVoiceSelectionChanged"); - int voicePosition = spinnerVoice.getSelectedItemPosition(); - int languagePosition = spinnerLanguage.getSelectedItemPosition(); - if ((voicePosition >=0) && (languagePosition >=0)) { - String language = ttsLanguages.get(languagePosition).name; + String languageVoicePreference = spinnerVoice.getText().toString(); + String language = spinnerLanguage.getText().toString(); + int voicePosition = 0; + + for (VoiceInfo voiceInfo : ttsVoiceByLanguage.get(language)) { + spinnerVoiceAdapter.add(voiceInfo.displayName); + if (voiceInfo.displayName.equals(languageVoicePreference)) { + break; + } else { + voicePosition += 1; + } + } + if ((voicePosition >=0) && (!language.isEmpty())) { VoiceInfo voiceInfo = ttsVoiceByLanguage.get(language).get(voicePosition); if (voiceInfo != null) { if (ttsService != null) { diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/tts/WebViewText.java b/app/src/main/java/fr/gaulupeau/apps/Poche/tts/WebViewText.java index 6b9e9789d..b7f252c39 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/tts/WebViewText.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/tts/WebViewText.java @@ -4,7 +4,7 @@ import android.util.Log; import android.webkit.ConsoleMessage; import android.webkit.WebView; -import android.widget.ScrollView; +import androidx.core.widget.NestedScrollView; import java.util.Vector; @@ -17,7 +17,7 @@ public class WebViewText implements TextInterface { ReadArticleActivity readArticleActivity; private final WebView webView; - private final ScrollView scrollView; + private final NestedScrollView scrollView; private final Handler handler; private final Vector textList = new Vector<>(); @@ -81,7 +81,7 @@ public class WebViewText implements TextInterface { private static final String LOG_TAG = "WebViewText"; - public WebViewText(WebView webView, ScrollView scrollView, ReadArticleActivity readArticleActivity) { + public WebViewText(WebView webView, NestedScrollView scrollView, ReadArticleActivity readArticleActivity) { this.webView = webView; this.scrollView = scrollView; this.readArticleActivity = readArticleActivity; diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/ArticleListsFragment.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/ArticleListsFragment.java index e2e6133ce..363d07dde 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/ArticleListsFragment.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/ArticleListsFragment.java @@ -30,20 +30,15 @@ public class ArticleListsFragment extends Fragment implements Sortable, Searchab private static final String STATE_SEARCH_QUERY = "search_query"; private static final EnumSet CHANGE_SET = EnumSet.of( - ArticlesChangedEvent.ChangeType.UNSPECIFIED, - ArticlesChangedEvent.ChangeType.ADDED, - ArticlesChangedEvent.ChangeType.DELETED, - ArticlesChangedEvent.ChangeType.FAVORITED, - ArticlesChangedEvent.ChangeType.UNFAVORITED, - ArticlesChangedEvent.ChangeType.ARCHIVED, - ArticlesChangedEvent.ChangeType.UNARCHIVED, - ArticlesChangedEvent.ChangeType.CREATED_DATE_CHANGED, - ArticlesChangedEvent.ChangeType.TITLE_CHANGED, - ArticlesChangedEvent.ChangeType.DOMAIN_CHANGED, + ArticlesChangedEvent.ChangeType.UNSPECIFIED, ArticlesChangedEvent.ChangeType.ADDED, + ArticlesChangedEvent.ChangeType.DELETED, ArticlesChangedEvent.ChangeType.FAVORITED, + ArticlesChangedEvent.ChangeType.UNFAVORITED, ArticlesChangedEvent.ChangeType.ARCHIVED, + ArticlesChangedEvent.ChangeType.UNARCHIVED, ArticlesChangedEvent.ChangeType.CREATED_DATE_CHANGED, + ArticlesChangedEvent.ChangeType.TITLE_CHANGED, ArticlesChangedEvent.ChangeType.DOMAIN_CHANGED, ArticlesChangedEvent.ChangeType.ESTIMATED_READING_TIME_CHANGED); - private static final EnumSet CHANGE_SET_FORCE_CONTENT_UPDATE - = EnumSet.of(ArticlesChangedEvent.ChangeType.ESTIMATED_READING_TIME_CHANGED); + private static final EnumSet CHANGE_SET_FORCE_CONTENT_UPDATE = EnumSet + .of(ArticlesChangedEvent.ChangeType.ESTIMATED_READING_TIME_CHANGED); private ArticleListsPagerAdapter adapter; private ViewPager viewPager; @@ -63,44 +58,46 @@ public static ArticleListsFragment newInstance(String tag) { private String tag; - public ArticleListsFragment() {} + public ArticleListsFragment() { + } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if(getArguments() != null) { + if (getArguments() != null) { tag = getArguments().getString(PARAM_TAG); } - if(savedInstanceState != null) { + if (savedInstanceState != null) { Log.v(TAG, "onCreate() restoring state"); - if(sortOrder == null) { + if (sortOrder == null) { sortOrder = Sortable.SortOrder.values()[savedInstanceState.getInt(STATE_SORT_ORDER)]; } - if(searchQuery == null) { + if (searchQuery == null) { searchQuery = savedInstanceState.getString(STATE_SEARCH_QUERY); } } - if(sortOrder == null) sortOrder = SortOrder.DESC; + if (sortOrder == null) + sortOrder = SortOrder.DESC; } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_article_lists, container, false); adapter = new ArticleListsPagerAdapter(getChildFragmentManager(), tag); getChildFragmentManager().registerFragmentLifecycleCallbacks(new FragmentManager.FragmentLifecycleCallbacks() { @Override - public void onFragmentCreated(@NonNull FragmentManager fm, @NonNull Fragment f, @Nullable Bundle savedInstanceState) { + public void onFragmentCreated(@NonNull FragmentManager fm, @NonNull Fragment f, + @Nullable Bundle savedInstanceState) { if (f instanceof ArticleListFragment) setParametersToFragment((ArticleListFragment) f); } }, false); - viewPager = (ViewPager)view.findViewById(R.id.articles_list_pager); + viewPager = (ViewPager) view.findViewById(R.id.articles_list_pager); viewPager.setAdapter(adapter); viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override @@ -111,7 +108,7 @@ public void onPageSelected(int position) { } }); - TabLayout tabLayout = (TabLayout)view.findViewById(R.id.articles_list_tab_layout); + TabLayout tabLayout = (TabLayout) view.findViewById(R.id.articles_list_tab_layout); tabLayout.setupWithViewPager(viewPager); viewPager.setCurrentItem(1); @@ -125,8 +122,10 @@ public void onSaveInstanceState(Bundle outState) { Log.v(TAG, "onSaveInstanceState()"); - if(sortOrder != null) outState.putInt(STATE_SORT_ORDER, sortOrder.ordinal()); - if(searchQuery != null) outState.putString(STATE_SEARCH_QUERY, searchQuery); + if (sortOrder != null) + outState.putInt(STATE_SORT_ORDER, sortOrder.ordinal()); + if (searchQuery != null) + outState.putString(STATE_SEARCH_QUERY, searchQuery); } @Override @@ -151,24 +150,25 @@ public void onFeedsChangedEvent(FeedsChangedEvent event) { private void setParametersToFragment(ArticleListFragment fragment) { Log.v(TAG, "setParametersToFragment() started"); - if(fragment == null) return; + if (fragment == null) + return; setSortOrder(fragment, sortOrder); setSearchQueryOnFragment(fragment, searchQuery); } - private void setSortOrder(ArticleListFragment fragment, - Sortable.SortOrder sortOrder) { - if(fragment != null) fragment.setSortOrder(sortOrder); + private void setSortOrder(ArticleListFragment fragment, Sortable.SortOrder sortOrder) { + if (fragment != null) + fragment.setSortOrder(sortOrder); } private void setSearchQueryOnFragment(ArticleListFragment fragment, String searchQuery) { - if(fragment != null) fragment.setSearchQuery(searchQuery); + if (fragment != null) + fragment.setSearchQuery(searchQuery); } private ArticleListFragment getCurrentFragment() { - return adapter == null || viewPager == null ? null - : adapter.getCachedFragment(viewPager.getCurrentItem()); + return adapter == null || viewPager == null ? null : adapter.getCachedFragment(viewPager.getCurrentItem()); } private ArticleListFragment getFragment(int position) { @@ -176,21 +176,20 @@ private ArticleListFragment getFragment(int position) { } private void invalidateLists(FeedsChangedEvent event) { - if(!Collections.disjoint(event.getInvalidateAllChanges(), CHANGE_SET)) { - updateAllLists(!Collections.disjoint(event.getInvalidateAllChanges(), - CHANGE_SET_FORCE_CONTENT_UPDATE)); + if (!Collections.disjoint(event.getInvalidateAllChanges(), CHANGE_SET)) { + updateAllLists(!Collections.disjoint(event.getInvalidateAllChanges(), CHANGE_SET_FORCE_CONTENT_UPDATE)); return; } - if(!Collections.disjoint(event.getMainFeedChanges(), CHANGE_SET)) { + if (!Collections.disjoint(event.getMainFeedChanges(), CHANGE_SET)) { updateList(ArticleListsPagerAdapter.positionByFeedType(FeedsChangedEvent.FeedType.MAIN), !Collections.disjoint(event.getMainFeedChanges(), CHANGE_SET_FORCE_CONTENT_UPDATE)); } - if(!Collections.disjoint(event.getFavoriteFeedChanges(), CHANGE_SET)) { + if (!Collections.disjoint(event.getFavoriteFeedChanges(), CHANGE_SET)) { updateList(ArticleListsPagerAdapter.positionByFeedType(FeedsChangedEvent.FeedType.FAVORITE), !Collections.disjoint(event.getFavoriteFeedChanges(), CHANGE_SET_FORCE_CONTENT_UPDATE)); } - if(!Collections.disjoint(event.getArchiveFeedChanges(), CHANGE_SET)) { + if (!Collections.disjoint(event.getArchiveFeedChanges(), CHANGE_SET)) { updateList(ArticleListsPagerAdapter.positionByFeedType(FeedsChangedEvent.FeedType.ARCHIVE), !Collections.disjoint(event.getArchiveFeedChanges(), CHANGE_SET_FORCE_CONTENT_UPDATE)); } @@ -199,10 +198,11 @@ private void invalidateLists(FeedsChangedEvent event) { private void updateAllLists(boolean forceContentUpdate) { Log.d(TAG, "updateAllLists() started; forceContentUpdate: " + forceContentUpdate); - for(int i = 0; i < ArticleListsPagerAdapter.PAGES.length; i++) { + for (int i = 0; i < ArticleListsPagerAdapter.PAGES.length; i++) { ArticleListFragment f = getFragment(i); - if(f != null) { - if(forceContentUpdate) f.forceContentUpdate(); + if (f != null) { + if (forceContentUpdate) + f.forceContentUpdate(); f.invalidateList(); } else { Log.w(TAG, "updateAllLists() fragment is null; position: " + i); @@ -211,13 +211,13 @@ private void updateAllLists(boolean forceContentUpdate) { } private void updateList(int position, boolean forceContentUpdate) { - Log.d(TAG, String.format("updateList() position: %d, forceContentUpdate: %s", - position, forceContentUpdate)); + Log.d(TAG, String.format("updateList() position: %d, forceContentUpdate: %s", position, forceContentUpdate)); - if(position != -1) { + if (position != -1) { ArticleListFragment f = getFragment(position); - if(f != null) { - if(forceContentUpdate) f.forceContentUpdate(); + if (f != null) { + if (forceContentUpdate) + f.forceContentUpdate(); f.invalidateList(); } else { Log.w(TAG, "updateList() fragment is null"); @@ -231,16 +231,16 @@ public void scroll(boolean up) { ArticleListFragment currentFragment = getCurrentFragment(); - if( currentFragment != null && currentFragment.recyclerViewLayoutManager != null) { + if (currentFragment != null && currentFragment.recyclerViewLayoutManager != null) { LinearLayoutManager listLayout = currentFragment.recyclerViewLayoutManager; - int numberOfVisibleItems = - listLayout.findLastCompletelyVisibleItemPosition() - - listLayout.findFirstCompletelyVisibleItemPosition() + 1; + int numberOfVisibleItems = listLayout.findLastCompletelyVisibleItemPosition() + - listLayout.findFirstCompletelyVisibleItemPosition() + 1; int oldPositionOnTop = listLayout.findFirstCompletelyVisibleItemPosition(); - // scroll so that as many new articles are visible than possible with one overlap + // scroll so that as many new articles are visible than possible with one + // overlap int newPositionOnTop; if (up) { newPositionOnTop = oldPositionOnTop - numberOfVisibleItems + 1; diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/MainActivity.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/MainActivity.java index 2725deccc..1736a5fd4 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/MainActivity.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/MainActivity.java @@ -5,9 +5,6 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.res.ColorStateList; -import android.content.res.XmlResourceParser; -import android.os.Build; import android.os.Bundle; import androidx.annotation.IdRes; import androidx.annotation.NonNull; @@ -20,7 +17,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.SearchView; -import androidx.appcompat.widget.Toolbar; +import com.google.android.material.appbar.MaterialToolbar; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; @@ -30,6 +27,7 @@ import android.view.View; import android.widget.ImageView; import android.widget.ProgressBar; +import androidx.core.widget.ContentLoadingProgressBar; import android.widget.TextView; import android.widget.Toast; @@ -39,9 +37,7 @@ import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; -import org.xmlpull.v1.XmlPullParserException; -import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -62,8 +58,7 @@ import fr.gaulupeau.apps.Poche.ui.preferences.SettingsActivity; public class MainActivity extends AppCompatActivity - implements NavigationView.OnNavigationItemSelectedListener, - TagListFragment.OnFragmentInteractionListener { + implements NavigationView.OnNavigationItemSelectedListener, TagListFragment.OnFragmentInteractionListener { private static final String TAG = MainActivity.class.getSimpleName(); @@ -80,7 +75,7 @@ public class MainActivity extends AppCompatActivity private ConfigurationTestHelper configurationTestHelper; - private ProgressBar progressBar; + private ContentLoadingProgressBar progressBar; private NavigationView navigationView; private TextView lastUpdateTimeView; @@ -123,48 +118,53 @@ protected void onCreate(Bundle savedInstanceState) { settings = new Settings(this); - Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar); + MaterialToolbar toolbar = (MaterialToolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); - navigationView = (NavigationView)findViewById(R.id.nav_view); + navigationView = (NavigationView) findViewById(R.id.nav_view); navigationView.setNavigationItemSelectedListener(this); - if(navigationView != null) { + if (navigationView != null) { View headerView = navigationView.getHeaderView(0); - if(headerView != null) { - lastUpdateTimeView = (TextView)headerView.findViewById(R.id.lastUpdateTime); + if (headerView != null) { + lastUpdateTimeView = (TextView) headerView.findViewById(R.id.lastUpdateTime); } // Set white logo in the navigation bar in dark and dark (high contrast) theme if (headerView != null && Themes.getCurrentTheme() != null && Themes.getCurrentTheme().isDark()) { ImageView logo = headerView.findViewById(R.id.imageView); - logo.setImageDrawable(getDrawable(R.drawable.welcome_white)); + logo.setImageDrawable(getDrawable(R.drawable.ic_wallabag_logo)); } - // Set different colors for items in the navigation bar in dark (high contrast) theme - if (Themes.getCurrentTheme() != null && Themes.getCurrentTheme() == Themes.Theme.DARK_CONTRAST) { - @SuppressLint("ResourceType") XmlResourceParser parser = getResources().getXml(R.color.dark_contrast_menu_item); - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - navigationView.setItemTextColor(ColorStateList.createFromXml(getResources(), parser, getTheme())); - navigationView.setItemIconTintList(ColorStateList.createFromXml(getResources(), parser, getTheme())); - - } else { - navigationView.setItemTextColor(ColorStateList.createFromXml(getResources(), parser)); - navigationView.setItemIconTintList(ColorStateList.createFromXml(getResources(), parser)); - } - } catch (XmlPullParserException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - DrawerLayout drawer = (DrawerLayout)findViewById(R.id.drawer_layout); - ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( - this, drawer, toolbar, - R.string.navigation_drawer_open, + // Set different colors for items in the navigation bar in dark (high contrast) + // theme + // if (Themes.getCurrentTheme() != null && Themes.getCurrentTheme() == + // Themes.Theme.DARK_CONTRAST) { + // @SuppressLint("ResourceType") XmlResourceParser parser = + // getResources().getXml(R.color.dark_contrast_menu_item); + // try { + // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + // navigationView.setItemTextColor(ColorStateList.createFromXml(getResources(), + // parser, getTheme())); + // navigationView.setItemIconTintList(ColorStateList.createFromXml(getResources(), + // parser, getTheme())); + // + // } else { + // navigationView.setItemTextColor(ColorStateList.createFromXml(getResources(), + // parser)); + // navigationView.setItemIconTintList(ColorStateList.createFromXml(getResources(), + // parser)); + // } + // } catch (XmlPullParserException e) { + // e.printStackTrace(); + // } catch (IOException e) { + // e.printStackTrace(); + // } + // } + } + + DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.addDrawerListener(toggle); toggle.syncState(); @@ -179,14 +179,17 @@ public void onDrawerSlide(View drawerView, float slideOffset) { @Override public void onDrawerStateChanged(int newState) { - if(newState == DrawerLayout.STATE_IDLE) updated = false; + if (newState == DrawerLayout.STATE_IDLE) + updated = false; } private void updateTime() { - if(updated) return; + if (updated) + return; updated = true; - if(lastUpdateTimeView == null) return; + if (lastUpdateTimeView == null) + return; Log.d(TAG, "DrawerListener.updateTime() updating time"); @@ -194,8 +197,6 @@ private void updateTime() { } }); - progressBar = (ProgressBar)findViewById(R.id.progressBar); - firstSyncDone = settings.isFirstSyncDone(); offlineQueuePending = settings.isOfflineQueuePending(); @@ -205,12 +206,12 @@ private void updateTime() { String currentFragmentType = null; - if(savedInstanceState != null) { + if (savedInstanceState != null) { Log.v(TAG, "onCreate() restoring state"); Bundle bundle = savedInstanceState.getBundle(STATE_SAVED_FRAGMENT_STATES); - if(bundle != null) { - for(String key: bundle.keySet()) { + if (bundle != null) { + for (String key : bundle.keySet()) { savedFragmentStates.put(key, bundle.getParcelable(key)); } } @@ -221,11 +222,13 @@ private void updateTime() { performSearch(savedInstanceState.getString(STATE_SEARCH_QUERY)); } - if(searchQuery == null) performSearch(""); + if (searchQuery == null) + performSearch(""); - if(currentFragmentType == null) currentFragmentType = FRAGMENT_ARTICLE_LISTS; + if (currentFragmentType == null) + currentFragmentType = FRAGMENT_ARTICLE_LISTS; - if(savedInstanceState == null) { + if (savedInstanceState == null) { setCurrentFragment(currentFragmentType); } else { currentFragment = getSupportFragmentManager().findFragmentByTag(currentFragmentType); @@ -244,7 +247,7 @@ protected void onNewIntent(Intent intent) { } private void handleIntent(Intent intent) { - if(Intent.ACTION_SEARCH.equals(intent.getAction())) { + if (Intent.ACTION_SEARCH.equals(intent.getAction())) { String query = intent.getStringExtra(SearchManager.QUERY); Log.v(TAG, "handleIntent() search intent; query: " + query); @@ -258,10 +261,10 @@ protected void onSaveInstanceState(Bundle outState) { Log.v(TAG, "onSaveInstanceState()"); - if(!savedFragmentStates.isEmpty()) { + if (!savedFragmentStates.isEmpty()) { Bundle bundle = new Bundle(savedFragmentStates.size()); - for(Map.Entry e: savedFragmentStates.entrySet()) { + for (Map.Entry e : savedFragmentStates.entrySet()) { bundle.putParcelable(e.getKey(), e.getValue()); } @@ -289,18 +292,18 @@ protected void onResume() { super.onResume(); // TODO: check logic - if(checkConfigurationOnResume) { + if (checkConfigurationOnResume) { checkConfigurationOnResume = false; - if(!Settings.checkFirstRunInit(this)) { - if(!settings.isConfigurationOk() && checkConfigurationDialog == null) { + if (!Settings.checkFirstRunInit(this)) { + if (!settings.isConfigurationOk() && checkConfigurationDialog == null) { AlertDialog.Builder messageBox = new AlertDialog.Builder(this); - messageBox.setTitle(settings.isConfigurationErrorShown() - ? R.string.d_configurationIsQuestionable_title - : R.string.d_configurationChanged_title); - messageBox.setMessage(settings.isConfigurationErrorShown() - ? R.string.d_configurationIsQuestionable_message - : R.string.d_configurationChanged_message); + messageBox.setTitle( + settings.isConfigurationErrorShown() ? R.string.d_configurationIsQuestionable_title + : R.string.d_configurationChanged_title); + messageBox.setMessage( + settings.isConfigurationErrorShown() ? R.string.d_configurationIsQuestionable_message + : R.string.d_configurationChanged_message); messageBox.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@ -319,10 +322,10 @@ public void onDismiss(DialogInterface dialog) { } } - if(tryToUpdateOnResume) { + if (tryToUpdateOnResume) { tryToUpdateOnResume = false; - if(!firstSyncDone) { + if (!firstSyncDone) { updateAllFeedsIfDbIsEmpty(); } else { updateOnStartup(); @@ -346,8 +349,8 @@ protected void onDestroy() { @Override public void onBackPressed() { - DrawerLayout drawer = (DrawerLayout)findViewById(R.id.drawer_layout); - if(drawer.isDrawerOpen(GravityCompat.START)) { + DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); + if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else { super.onBackPressed(); @@ -358,14 +361,14 @@ public void onBackPressed() { public boolean onCreateOptionsMenu(Menu menu) { Log.d(TAG, "onCreateOptionsMenu()"); - if(searchMenuItemExpanded) { + if (searchMenuItemExpanded) { // options menu invalidation happened when searchMenuItem was expanded searchMenuItemExpanded = false; searchMenuItem = null; Log.i(TAG, "onCreateOptionsMenu() searchMenuItem was not collapsed!"); - Log.v(TAG, "onCreateOptionsMenu() searchQuery: " + searchQuery - + ", searchQueryPrevious: " + searchQueryPrevious); + Log.v(TAG, "onCreateOptionsMenu() searchQuery: " + searchQuery + ", searchQueryPrevious: " + + searchQueryPrevious); performSearch(searchQueryPrevious); } @@ -373,8 +376,7 @@ public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); searchMenuItem = menu.findItem(R.id.menu_main_search); - MenuItemCompat.setOnActionExpandListener( - searchMenuItem, new MenuItemCompat.OnActionExpandListener() { + MenuItemCompat.setOnActionExpandListener(searchMenuItem, new MenuItemCompat.OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { Log.v(TAG, "searchMenuItem expanded"); @@ -391,10 +393,10 @@ public boolean onMenuItemActionCollapse(MenuItem item) { } }); - final SearchView searchView = (SearchView)searchMenuItem.getActionView(); - if(searchView != null) { - searchView.setSearchableInfo(((SearchManager)getSystemService(Context.SEARCH_SERVICE)) - .getSearchableInfo(getComponentName())); + final SearchView searchView = (SearchView) searchMenuItem.getActionView(); + if (searchView != null) { + searchView.setSearchableInfo( + ((SearchManager) getSystemService(Context.SEARCH_SERVICE)).getSearchableInfo(getComponentName())); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override @@ -416,9 +418,9 @@ public boolean onQueryTextChange(String newText) { } checkPendingSearchUI(); - if(!offlineQueuePending) { + if (!offlineQueuePending) { MenuItem menuItem = menu.findItem(R.id.menu_main_syncQueue); - if(menuItem != null) { + if (menuItem != null) { menuItem.setVisible(false); } } @@ -428,22 +430,22 @@ public boolean onQueryTextChange(String newText) { @Override public boolean onOptionsItemSelected(MenuItem item) { - switch(item.getItemId()) { - case R.id.menu_main_changeSortOrder: - switchSortOrder(); - return true; + switch (item.getItemId()) { + case R.id.menu_main_changeSortOrder: + switchSortOrder(); + return true; - case R.id.menu_main_syncQueue: - syncQueue(); - return true; + case R.id.menu_main_syncQueue: + syncQueue(); + return true; - case R.id.menu_main_sweepDeletedArticles: - sweepDeletedArticles(); - return true; + case R.id.menu_main_sweepDeletedArticles: + sweepDeletedArticles(); + return true; - case R.id.menu_main_fullUpdate: - fullUpdate(true); - return true; + case R.id.menu_main_fullUpdate: + fullUpdate(true); + return true; } return super.onOptionsItemSelected(item); @@ -451,45 +453,41 @@ public boolean onOptionsItemSelected(MenuItem item) { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { - switch(item.getItemId()) { - case R.id.nav_mainLists: - setCurrentFragment(FRAGMENT_ARTICLE_LISTS); - break; - - case R.id.nav_tags: - setCurrentFragment(FRAGMENT_TAG_LIST); - break; - - case R.id.nav_add: - showAddBagDialog(); + switch (item.getItemId()) { + case R.id.nav_mainLists: + setCurrentFragment(FRAGMENT_ARTICLE_LISTS); + break; + + case R.id.nav_tags: + setCurrentFragment(FRAGMENT_TAG_LIST); + break; + + case R.id.nav_add: + showAddBagDialog(); + break; + + case R.id.nav_settings: + startActivity(new Intent(getBaseContext(), SettingsActivity.class)); + break; + + case R.id.nav_about: + Libs.ActivityStyle style; + switch (Themes.getCurrentTheme()) { + case DARK: + case DARK_CONTRAST: + style = Libs.ActivityStyle.DARK; break; - case R.id.nav_settings: - startActivity(new Intent(getBaseContext(), SettingsActivity.class)); - break; - - case R.id.nav_about: - Libs.ActivityStyle style; - switch(Themes.getCurrentTheme()) { - case DARK: - case DARK_CONTRAST: - style = Libs.ActivityStyle.DARK; - break; - - default: - style = Libs.ActivityStyle.LIGHT_DARK_TOOLBAR; - break; - } - new LibsBuilder() - .withActivityStyle(style) - .withAboutIconShown(true) - .withAboutVersionShown(true) - .withAboutDescription(getResources().getString(R.string.aboutText)) - .start(this); + default: + style = Libs.ActivityStyle.LIGHT_DARK_TOOLBAR; break; + } + new LibsBuilder().withActivityStyle(style).withAboutIconShown(true).withAboutVersionShown(true) + .withAboutDescription(getResources().getString(R.string.aboutText)).start(this); + break; } - DrawerLayout drawer = (DrawerLayout)findViewById(R.id.drawer_layout); + DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); return true; } @@ -505,7 +503,7 @@ public void onOfflineQueueChangedEvent(OfflineQueueChangedEvent event) { Log.d(TAG, "onOfflineQueueChangedEvent() offlineQueuePending: " + offlineQueuePending); - if(prevValue != offlineQueuePending) { + if (prevValue != offlineQueuePending) { Log.d(TAG, "onOfflineQueueChangedEvent() invalidating options menu"); invalidateOptionsMenu(); } @@ -515,14 +513,14 @@ public void onOfflineQueueChangedEvent(OfflineQueueChangedEvent event) { public void onFeedsChangedEvent(FeedsChangedEvent event) { Log.d(TAG, "Got FeedsChangedEvent"); - if(event.isInvalidateAll()) { + if (event.isInvalidateAll()) { firstSyncDone = settings.isFirstSyncDone(); } - if(currentFragment instanceof ArticleListsFragment) { - ((ArticleListsFragment)currentFragment).onFeedsChangedEvent(event); - } else if(currentFragment instanceof RecyclerViewListFragment) { - ((RecyclerViewListFragment)currentFragment).invalidateList(); + if (currentFragment instanceof ArticleListsFragment) { + ((ArticleListsFragment) currentFragment).onFeedsChangedEvent(event); + } else if (currentFragment instanceof RecyclerViewListFragment) { + ((RecyclerViewListFragment) currentFragment).invalidateList(); } } @@ -537,7 +535,8 @@ public void onUpdateArticlesStartedEvent(UpdateArticlesStartedEvent event) { public void onUpdateArticlesProgressEvent(UpdateArticlesProgressEvent event) { Log.d(TAG, "onUpdateArticlesProgressEvent"); - if(progressBar != null) { + progressBar = (ContentLoadingProgressBar) findViewById(R.id.progress_bar); + if (progressBar != null) { progressBar.setIndeterminate(false); progressBar.setMax(event.getTotal()); progressBar.setProgress(event.getCurrent()); @@ -548,7 +547,7 @@ public void onUpdateArticlesProgressEvent(UpdateArticlesProgressEvent event) { public void onUpdateArticlesFinishedEvent(UpdateArticlesFinishedEvent event) { Log.d(TAG, "onUpdateArticlesFinishedEvent"); - if(event.getResult().isSuccess()) { + if (event.getResult().isSuccess()) { firstSyncDone = true; tryToUpdateOnResume = false; } @@ -559,25 +558,28 @@ public void onUpdateArticlesFinishedEvent(UpdateArticlesFinishedEvent event) { } private void updateLastUpdateTime() { - if(lastUpdateTimeView == null) return; + if (lastUpdateTimeView == null) + return; Log.d(TAG, "updateLastUpdateTime() updating time"); long timestamp = settings.getLatestUpdateRunTimestamp(); - if(timestamp != 0) { - lastUpdateTimeView.setText(getString(R.string.lastUpdateTimeLabel, - DateUtils.getRelativeTimeSpanString(timestamp))); + if (timestamp != 0) { + lastUpdateTimeView + .setText(getString(R.string.lastUpdateTimeLabel, DateUtils.getRelativeTimeSpanString(timestamp))); } else { lastUpdateTimeView.setVisibility(View.INVISIBLE); } } private void updateStateChanged(boolean started) { - if(started == updateRunning) return; + if (started == updateRunning) + return; updateRunning = started; - if(progressBar != null) { + progressBar = (ContentLoadingProgressBar) findViewById(R.id.progress_bar); + if (progressBar != null) { progressBar.setVisibility(started ? View.VISIBLE : View.GONE); progressBar.setIndeterminate(true); } @@ -586,15 +588,18 @@ private void updateStateChanged(boolean started) { private void performSearch(String query) { setSearchQuery(query); - if(TextUtils.isEmpty(query)) return; + if (TextUtils.isEmpty(query)) + return; searchUIPending = true; checkPendingSearchUI(); } private void checkPendingSearchUI() { - if(searchMenuItem == null) return; - if(!searchUIPending) return; + if (searchMenuItem == null) + return; + if (!searchUIPending) + return; searchUIPending = false; @@ -602,8 +607,9 @@ private void checkPendingSearchUI() { } private void initSearchUI() { - final SearchView searchView = (SearchView)searchMenuItem.getActionView(); - if(searchView == null) return; + final SearchView searchView = (SearchView) searchMenuItem.getActionView(); + if (searchView == null) + return; final String searchQueryToRestore = searchQuery; @@ -620,23 +626,20 @@ public void run() { private void setParametersToFragment(Fragment fragment) { Log.v(TAG, "setParametersToFragment() started"); - if(fragment == null) return; + if (fragment == null) + return; setSortOrder(fragment); setSearchQueryOnFragment(fragment, searchQuery); } private void switchSortOrder() { - if(FRAGMENT_TAG_LIST.equals(currentFragmentType)) { - tagsSortOrder = tagsSortOrder == Sortable.SortOrder.DESC - ? Sortable.SortOrder.ASC - : Sortable.SortOrder.DESC; + if (FRAGMENT_TAG_LIST.equals(currentFragmentType)) { + tagsSortOrder = tagsSortOrder == Sortable.SortOrder.DESC ? Sortable.SortOrder.ASC : Sortable.SortOrder.DESC; settings.setTagListSortOrder(tagsSortOrder); } else { - sortOrder = sortOrder == Sortable.SortOrder.DESC - ? Sortable.SortOrder.ASC - : Sortable.SortOrder.DESC; + sortOrder = sortOrder == Sortable.SortOrder.DESC ? Sortable.SortOrder.ASC : Sortable.SortOrder.DESC; settings.setListSortOrder(sortOrder); } @@ -645,13 +648,12 @@ private void switchSortOrder() { } private void setSortOrder(Fragment fragment) { - setSortOrder(fragment, FRAGMENT_TAG_LIST.equals(currentFragmentType) - ? tagsSortOrder : sortOrder); + setSortOrder(fragment, FRAGMENT_TAG_LIST.equals(currentFragmentType) ? tagsSortOrder : sortOrder); } private void setSortOrder(Fragment fragment, Sortable.SortOrder sortOrder) { - if(fragment instanceof Sortable) { - ((Sortable)fragment).setSortOrder(sortOrder); + if (fragment instanceof Sortable) { + ((Sortable) fragment).setSortOrder(sortOrder); } } @@ -663,13 +665,13 @@ private void setSearchQuery(String searchQuery) { } private void setSearchQueryOnFragment(Fragment fragment, String searchQuery) { - if(fragment instanceof Searchable) { - ((Searchable)fragment).setSearchQuery(searchQuery); + if (fragment instanceof Searchable) { + ((Searchable) fragment).setSearchQuery(searchQuery); } } private void setCurrentFragment(String type) { - if(TextUtils.equals(currentFragmentType, type)) { + if (TextUtils.equals(currentFragmentType, type)) { Log.i(TAG, "setCurrentFragment() ignoring switch to the same type: " + type); return; } @@ -680,16 +682,14 @@ private void setCurrentFragment(String type) { private void setCurrentFragment(Fragment fragment, String type) { updateNavigationUI(type); - if(currentFragment != null && isFragmentStateSavable(currentFragmentType)) { + if (currentFragment != null && isFragmentStateSavable(currentFragmentType)) { Log.d(TAG, "setCurrentFragment() saving fragment state: " + currentFragmentType); - savedFragmentStates.put(currentFragmentType, getSupportFragmentManager() - .saveFragmentInstanceState(currentFragment)); + savedFragmentStates.put(currentFragmentType, + getSupportFragmentManager().saveFragmentInstanceState(currentFragment)); } - getSupportFragmentManager().beginTransaction() - .replace(R.id.main_content_frame, fragment, type) - .commit(); + getSupportFragmentManager().beginTransaction().replace(R.id.main_content_frame, fragment, type).commit(); currentFragment = fragment; currentFragmentType = type; @@ -702,27 +702,27 @@ private Fragment getFragment(String type) { Fragment fragment = getSupportFragmentManager().findFragmentByTag(type); - if(fragment == null) { + if (fragment == null) { Log.d(TAG, "getFragment() creating new instance"); - switch(type) { - case FRAGMENT_ARTICLE_LISTS: - fragment = ArticleListsFragment.newInstance(null); - break; + switch (type) { + case FRAGMENT_ARTICLE_LISTS: + fragment = ArticleListsFragment.newInstance(null); + break; - case FRAGMENT_TAG_LIST: - fragment = new TagListFragment(); - break; + case FRAGMENT_TAG_LIST: + fragment = new TagListFragment(); + break; - default: - throw new IllegalArgumentException("Fragment type is not supported: " + type); + default: + throw new IllegalArgumentException("Fragment type is not supported: " + type); } - if(isFragmentStateSavable(type)) { + if (isFragmentStateSavable(type)) { Log.d(TAG, "getFragment() fragment is savable"); Fragment.SavedState savedState = savedFragmentStates.get(type); - if(savedState != null) { + if (savedState != null) { Log.d(TAG, "getFragment() restoring fragment state"); fragment.setInitialSavedState(savedState); @@ -734,66 +734,70 @@ private Fragment getFragment(String type) { } private boolean isFragmentStateSavable(String type) { - if(type == null) return false; + if (type == null) + return false; - switch(type) { - case FRAGMENT_ARTICLE_LISTS: - case FRAGMENT_TAG_LIST: - return true; + switch (type) { + case FRAGMENT_ARTICLE_LISTS: + case FRAGMENT_TAG_LIST: + return true; } return false; } private void updateNavigationUI(String type) { - if(type == null || navigationView == null) return; + if (type == null || navigationView == null) + return; - if(FRAGMENT_TAGGED_ARTICLE_LISTS.equals(currentFragmentType)) { + if (FRAGMENT_TAGGED_ARTICLE_LISTS.equals(currentFragmentType)) { MenuItem item = navigationView.getMenu().findItem(R.id.nav_taggedLists); - if(item != null) { + if (item != null) { item.setVisible(false); item.setEnabled(false); } } CharSequence title = null; - @IdRes int itemID = 0; - switch(type) { - case FRAGMENT_ARTICLE_LISTS: - itemID = R.id.nav_mainLists; - break; - - case FRAGMENT_TAG_LIST: - itemID = R.id.nav_tags; - break; - - case FRAGMENT_TAGGED_ARTICLE_LISTS: - itemID = R.id.nav_taggedLists; - - if(selectedTag != null) { - title = getString(R.string.title_main_tag, selectedTag); - } + @IdRes + int itemID = 0; + switch (type) { + case FRAGMENT_ARTICLE_LISTS: + itemID = R.id.nav_mainLists; + break; + + case FRAGMENT_TAG_LIST: + itemID = R.id.nav_tags; + break; + + case FRAGMENT_TAGGED_ARTICLE_LISTS: + itemID = R.id.nav_taggedLists; + + if (selectedTag != null) { + title = getString(R.string.title_main_tag, selectedTag); + } - MenuItem item = navigationView.getMenu().findItem(itemID); - if(item != null) { - if(title != null) item.setTitle(title); - item.setVisible(true); - item.setEnabled(true); - } - break; + MenuItem item = navigationView.getMenu().findItem(itemID); + if (item != null) { + if (title != null) + item.setTitle(title); + item.setVisible(true); + item.setEnabled(true); + } + break; } - if(itemID != 0) { + if (itemID != 0) { navigationView.setCheckedItem(itemID); - if(title == null) { + if (title == null) { MenuItem item = navigationView.getMenu().findItem(itemID); - if(item != null) { + if (item != null) { title = item.getTitle(); } } } - if(title != null) { + if (title != null) { setTitle(title); } } @@ -813,7 +817,7 @@ public void onRecyclerViewListSwipeUpdate() { } private void syncQueue() { - if(!WallabagConnection.isNetworkAvailable()) { + if (!WallabagConnection.isNetworkAvailable()) { Toast.makeText(this, getString(R.string.txtNetOffline), Toast.LENGTH_SHORT).show(); return; } @@ -822,7 +826,7 @@ private void syncQueue() { } private void sweepDeletedArticles() { - if(!WallabagConnection.isNetworkAvailable()) { + if (!WallabagConnection.isNetworkAvailable()) { Toast.makeText(this, getString(R.string.txtNetOffline), Toast.LENGTH_SHORT).show(); return; } @@ -831,15 +835,14 @@ private void sweepDeletedArticles() { } private void updateAllFeedsIfDbIsEmpty() { - if(settings.isConfigurationOk() && !settings.isFirstSyncDone()) { + if (settings.isConfigurationOk() && !settings.isFirstSyncDone()) { fullUpdate(false); } } private void updateOnStartup() { long delay = 5 * 60 * 1000; // 5 minutes - if(settings.isAutoSyncOnStartupEnabled() && settings.isConfigurationOk() - && settings.isFirstSyncDone() + if (settings.isAutoSyncOnStartupEnabled() && settings.isConfigurationOk() && settings.isFirstSyncDone() && settings.getLatestUpdateRunTimestamp() + delay < System.currentTimeMillis()) { updateArticles(false, Updater.UpdateType.FAST); } @@ -852,20 +855,20 @@ private void fullUpdate(boolean showErrors) { private boolean updateArticles(boolean showErrors, Updater.UpdateType updateType) { boolean result = false; - if(updateRunning) { - if(showErrors) { + if (updateRunning) { + if (showErrors) { Toast.makeText(this, R.string.previousUpdateNotFinished, Toast.LENGTH_SHORT).show(); } - } else if(!settings.isConfigurationOk()) { - if(showErrors) { + } else if (!settings.isConfigurationOk()) { + if (showErrors) { Toast.makeText(this, getString(R.string.txtConfigNotSet), Toast.LENGTH_SHORT).show(); } - } else if(WallabagConnection.isNetworkAvailable()) { + } else if (WallabagConnection.isNetworkAvailable()) { ServiceHelper.syncAndUpdate(this, settings, updateType, false); result = true; } else { - if(showErrors) { + if (showErrors) { Toast.makeText(this, getString(R.string.txtNetOffline), Toast.LENGTH_SHORT).show(); } } @@ -876,26 +879,26 @@ private boolean updateArticles(boolean showErrors, Updater.UpdateType updateType private void testConfiguration() { cancelConfigurationTest(); - configurationTestHelper = new ConfigurationTestHelper( - this, new ConfigurationTestHelper.ResultHandler() { + configurationTestHelper = new ConfigurationTestHelper(this, new ConfigurationTestHelper.ResultHandler() { @Override public void onConfigurationTestSuccess(String url) { updateAllFeedsIfDbIsEmpty(); } @Override - public void onConnectionTestFail( - WallabagWebService.ConnectionTestResult result, String details) {} + public void onConnectionTestFail(WallabagWebService.ConnectionTestResult result, String details) { + } @Override - public void onApiAccessTestFail(TestApiAccessTask.Result result, String details) {} + public void onApiAccessTestFail(TestApiAccessTask.Result result, String details) { + } }, null, settings, true); configurationTestHelper.test(); } private void cancelConfigurationTest() { - if(configurationTestHelper != null) { + if (configurationTestHelper != null) { configurationTestHelper.cancel(); configurationTestHelper = null; } @@ -913,7 +916,7 @@ private void showAddBagDialog() { builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - TextView textView = (TextView)view.findViewById(R.id.page_url); + TextView textView = (TextView) view.findViewById(R.id.page_url); ServiceHelper.addLink(getBaseContext(), textView.getText().toString()); } }); @@ -924,19 +927,19 @@ public void onClick(DialogInterface dialog, int which) { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if(currentFragment instanceof ArticleListsFragment) { + if (currentFragment instanceof ArticleListsFragment) { switch (keyCode) { - case KeyEvent.KEYCODE_PAGE_UP: - case KeyEvent.KEYCODE_PAGE_DOWN: - ((ArticleListsFragment) currentFragment).scroll(keyCode == KeyEvent.KEYCODE_PAGE_UP); + case KeyEvent.KEYCODE_PAGE_UP: + case KeyEvent.KEYCODE_PAGE_DOWN: + ((ArticleListsFragment) currentFragment).scroll(keyCode == KeyEvent.KEYCODE_PAGE_UP); + return true; + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + if (settings.isVolumeButtonsScrollingEnabled()) { + ((ArticleListsFragment) currentFragment).scroll(keyCode == KeyEvent.KEYCODE_VOLUME_UP); return true; - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: - if (settings.isVolumeButtonsScrollingEnabled()) { - ((ArticleListsFragment) currentFragment).scroll(keyCode == KeyEvent.KEYCODE_VOLUME_UP); - return true; - } - break; + } + break; } } diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/ManageArticleTagsActivity.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/ManageArticleTagsActivity.java index 4f7a3084d..263b654b7 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/ManageArticleTagsActivity.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/ManageArticleTagsActivity.java @@ -182,12 +182,14 @@ public void onClick(View v) { } suggestedTagsView = (RecyclerView)findViewById(R.id.manageTags_suggestionList); + suggestedTagsView.setHasFixedSize(true); if(suggestedTagsView != null) { suggestedTagsView.setLayoutManager(new LinearLayoutManager(this)); suggestedTagsView.setAdapter(suggestedTagsAdapter); } currentTagsView = (RecyclerView)findViewById(R.id.manageTags_currentList); + currentTagsView.setHasFixedSize(true); if(currentTagsView != null) { currentTagsView.setLayoutManager(new LinearLayoutManager(this)); currentTagsView.setAdapter(currentTagsAdapter); diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/ReadArticleActivity.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/ReadArticleActivity.java index a8b1ac557..47c3be856 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/ReadArticleActivity.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/ReadArticleActivity.java @@ -11,8 +11,15 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; + import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; + +import com.google.android.material.appbar.CollapsingToolbarLayout; + +import androidx.appcompat.widget.Toolbar; +import androidx.core.widget.NestedScrollView; + import android.text.TextUtils; import android.util.Log; import android.view.GestureDetector; @@ -32,11 +39,11 @@ import android.widget.Button; import android.widget.ImageButton; import android.widget.LinearLayout; -import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; import com.di72nn.stuff.wallabag.apiwrapper.WallabagService; +import com.google.android.material.button.MaterialButton; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -71,8 +78,8 @@ public class ReadArticleActivity extends BaseActionBarActivity { - public static final String EXTRA_ID = "ReadArticleActivity.id"; - public static final String EXTRA_LIST_ARCHIVED = "ReadArticleActivity.archived"; + public static final String EXTRA_ID = "ReadArticleActivity.id"; + public static final String EXTRA_LIST_ARCHIVED = "ReadArticleActivity.archived"; public static final String EXTRA_LIST_FAVORITES = "ReadArticleActivity.favorites"; private static final String TAG = ReadArticleActivity.class.getSimpleName(); @@ -80,30 +87,22 @@ public class ReadArticleActivity extends BaseActionBarActivity { private static final String TAG_TTS_FRAGMENT = "ttsFragment"; private static final EnumSet CHANGE_SET_ACTIONS = EnumSet.of( - ArticlesChangedEvent.ChangeType.FAVORITED, - ArticlesChangedEvent.ChangeType.UNFAVORITED, - ArticlesChangedEvent.ChangeType.ARCHIVED, - ArticlesChangedEvent.ChangeType.UNARCHIVED); + ArticlesChangedEvent.ChangeType.FAVORITED, ArticlesChangedEvent.ChangeType.UNFAVORITED, + ArticlesChangedEvent.ChangeType.ARCHIVED, ArticlesChangedEvent.ChangeType.UNARCHIVED); private static final EnumSet CHANGE_SET_CONTENT = EnumSet.of( - ArticlesChangedEvent.ChangeType.CONTENT_CHANGED, - ArticlesChangedEvent.ChangeType.TITLE_CHANGED, - ArticlesChangedEvent.ChangeType.DOMAIN_CHANGED, + ArticlesChangedEvent.ChangeType.CONTENT_CHANGED, ArticlesChangedEvent.ChangeType.TITLE_CHANGED, + ArticlesChangedEvent.ChangeType.DOMAIN_CHANGED, ArticlesChangedEvent.ChangeType.URL_CHANGED, ArticlesChangedEvent.ChangeType.PUBLISHED_AT_CHANGED, ArticlesChangedEvent.ChangeType.AUTHORS_CHANGED, - ArticlesChangedEvent.ChangeType.URL_CHANGED, ArticlesChangedEvent.ChangeType.ESTIMATED_READING_TIME_CHANGED, ArticlesChangedEvent.ChangeType.FETCHED_IMAGES_CHANGED); private static final EnumSet CHANGE_SET_PREV_NEXT = EnumSet.of( - ArticlesChangedEvent.ChangeType.UNSPECIFIED, - ArticlesChangedEvent.ChangeType.ADDED, - ArticlesChangedEvent.ChangeType.DELETED, - ArticlesChangedEvent.ChangeType.ARCHIVED, - ArticlesChangedEvent.ChangeType.UNARCHIVED, - ArticlesChangedEvent.ChangeType.FAVORITED, - ArticlesChangedEvent.ChangeType.UNFAVORITED, - ArticlesChangedEvent.ChangeType.CREATED_DATE_CHANGED); + ArticlesChangedEvent.ChangeType.UNSPECIFIED, ArticlesChangedEvent.ChangeType.ADDED, + ArticlesChangedEvent.ChangeType.DELETED, ArticlesChangedEvent.ChangeType.ARCHIVED, + ArticlesChangedEvent.ChangeType.UNARCHIVED, ArticlesChangedEvent.ChangeType.FAVORITED, + ArticlesChangedEvent.ChangeType.UNFAVORITED, ArticlesChangedEvent.ChangeType.CREATED_DATE_CHANGED); private Boolean contextFavorites; private Boolean contextArchived; @@ -112,36 +111,35 @@ public class ReadArticleActivity extends BaseActionBarActivity { private ArticleDao articleDao; - private int fontSize; + private int fontSize; private boolean volumeButtonsScrolling; private boolean tapToScroll; private boolean disableTouchOptionEnabled; private boolean disableTouch; - private int disableTouchKeyCode; - private float screenScrollingPercent; + private int disableTouchKeyCode; + private float screenScrollingPercent; private boolean smoothScrolling; - private int scrolledOverBottom; - private boolean swipeArticles; + private int scrolledOverBottom; - private ScrollView scrollView; - private View scrollViewLastChild; - private WebView webViewContent; - private TextView loadingPlaceholder; - private LinearLayout bottomTools; - private View hrBar; - private TtsFragment ttsFragment; + private NestedScrollView scrollView; + private View scrollViewLastChild; + private WebView webViewContent; + private TextView loadingPlaceholder; + private LinearLayout bottomTools; + // private View hrBar; + private TtsFragment ttsFragment; private Article article; - private String articleTitle; - private String articleDomain; - private String articleUrl; - private String articleLanguage; - private Double articleProgress; + private String articleTitle; + private String articleDomain; + private String articleUrl; + private String articleLanguage; + private Double articleProgress; private Long previousArticleID; private Long nextArticleID; - private int webViewHeightBeforeUpdate; + private int webViewHeightBeforeUpdate; private Runnable positionRestorationRunnable; private boolean isResumed; @@ -152,17 +150,15 @@ public void onCreate(Bundle savedInstanceState) { settings = App.getInstance().getSettings(); - if(settings.isFullscreenArticleView()) { + if (settings.isFullscreenArticleView()) { requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().setFlags( - WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN - ); - ActionBar actionBar = super.getSupportActionBar(); - if(actionBar != null) actionBar.hide(); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + // if(toolbar != null) toolbar.(); + // TODO: Hide app bar } - if(settings.isKeepScreenOn()) { + if (settings.isKeepScreenOn()) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } @@ -172,17 +168,17 @@ public void onCreate(Bundle savedInstanceState) { Intent intent = getIntent(); long articleID = intent.getLongExtra(EXTRA_ID, -1); Log.d(TAG, "onCreate() articleId: " + articleID); - if(intent.hasExtra(EXTRA_LIST_FAVORITES)) { + if (intent.hasExtra(EXTRA_LIST_FAVORITES)) { contextFavorites = intent.getBooleanExtra(EXTRA_LIST_FAVORITES, false); } - if(intent.hasExtra(EXTRA_LIST_ARCHIVED)) { + if (intent.hasExtra(EXTRA_LIST_ARCHIVED)) { contextArchived = intent.getBooleanExtra(EXTRA_LIST_ARCHIVED, false); } DaoSession session = DbConnection.getSession(); articleDao = session.getArticleDao(); - if(!loadArticle(articleID)) { + if (!loadArticle(articleID)) { Log.e(TAG, "onCreate: Did not find article with ID: " + articleID); finish(); return; @@ -197,23 +193,35 @@ public void onCreate(Bundle savedInstanceState) { screenScrollingPercent = settings.getScreenScrollingPercent(); smoothScrolling = settings.isScreenScrollingSmooth(); scrolledOverBottom = settings.getScrolledOverBottom(); - swipeArticles = settings.getSwipeArticles(); - - setTitle(articleTitle); // article is loaded - update menu invalidateOptionsMenu(); - scrollView = (ScrollView)findViewById(R.id.scroll); + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + // display back arrow + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); + } + + // Must set on collapsing layout to enable the animation + // TODO: after MD library supports multi-line title should we set title here + // https://github.com/material-components/material-components-android/pull/413 +// CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar_layout); +// collapsingToolbarLayout.setTitle(articleTitle); + + scrollView = findViewById(R.id.scroll); scrollViewLastChild = scrollView.getChildAt(scrollView.getChildCount() - 1); - webViewContent = (WebView)findViewById(R.id.webViewContent); - loadingPlaceholder = (TextView)findViewById(R.id.tv_loading_article); - bottomTools = (LinearLayout)findViewById(R.id.bottomTools); - hrBar = findViewById(R.id.view1); + webViewContent = findViewById(R.id.webViewContent); + loadingPlaceholder = findViewById(R.id.tv_loading_article); + bottomTools = findViewById(R.id.bottomTools); + // hrBar = findViewById(R.id.view1); initWebView(); - if(ttsFragment != null) { + if (ttsFragment != null) { // is it ever executed? ttsFragment.onDocumentLoadStart(articleDomain, articleTitle, articleLanguage); } @@ -222,16 +230,15 @@ public void onCreate(Bundle savedInstanceState) { initButtons(); - if(settings.isTtsVisible() && ttsFragment == null) { - ttsFragment = (TtsFragment)getSupportFragmentManager() - .findFragmentByTag(TAG_TTS_FRAGMENT); + if (settings.isTtsVisible() && ttsFragment == null) { + ttsFragment = (TtsFragment) getSupportFragmentManager().findFragmentByTag(TAG_TTS_FRAGMENT); - if(ttsFragment == null) { + if (ttsFragment == null) { toggleTTS(false); } } - if(disableTouch) { + if (disableTouch) { showDisableTouchToast(); } @@ -243,7 +250,7 @@ public void onResume() { super.onResume(); isResumed = true; - if(onPageFinishedCallPostponedUntilResume) { + if (onPageFinishedCallPostponedUntilResume) { onPageFinishedCallPostponedUntilResume = false; onPageFinished(); @@ -259,7 +266,7 @@ public void onPause() { @Override public void onStop() { - if(loadingFinished && article != null) { + if (loadingFinished && article != null) { cancelPositionRestoration(); OperationsHelper.setArticleProgress(this, article.getArticleId(), getReadingPosition()); @@ -283,7 +290,7 @@ public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.option_article, menu); - if(article != null) { + if (article != null) { boolean unread = article.getArchive() != null && !article.getArchive(); menu.findItem(R.id.menuArticleMarkAsRead).setVisible(unread); menu.findItem(R.id.menuArticleMarkAsUnread).setVisible(!unread); @@ -300,7 +307,7 @@ public boolean onCreateOptionsMenu(Menu menu) { @Override public boolean onOptionsItemSelected(MenuItem item) { - switch(item.getItemId()) { + switch (item.getItemId()) { case R.id.menuArticleMarkAsRead: case R.id.menuArticleMarkAsUnread: markAsReadAndClose(); @@ -369,7 +376,7 @@ public boolean dispatchKeyEvent(KeyEvent event) { } if (triggerAction) { - if(code == disableTouchKeyCode && (disableTouch || disableTouchOptionEnabled)) { + if (code == disableTouchKeyCode && (disableTouch || disableTouchOptionEnabled)) { disableTouch = !disableTouch; settings.setDisableTouchLastState(disableTouch); @@ -424,13 +431,13 @@ public void onArticlesChangedEvent(ArticlesChangedEvent event) { Log.d(TAG, "onArticlesChangedEvent() started"); boolean updatePrevNext = false; - if(!Collections.disjoint(event.getInvalidateAllChanges(), CHANGE_SET_PREV_NEXT)) { + if (!Collections.disjoint(event.getInvalidateAllChanges(), CHANGE_SET_PREV_NEXT)) { updatePrevNext = true; } else { EnumSet changes; - if(contextArchived != null) { + if (contextArchived != null) { changes = contextArchived ? event.getArchiveFeedChanges() : event.getMainFeedChanges(); - } else if(contextFavorites != null && contextFavorites) { + } else if (contextFavorites != null && contextFavorites) { changes = event.getFavoriteFeedChanges(); } else { changes = EnumSet.copyOf(event.getMainFeedChanges()); @@ -438,19 +445,20 @@ public void onArticlesChangedEvent(ArticlesChangedEvent event) { changes.addAll(event.getFavoriteFeedChanges()); } - if(!Collections.disjoint(changes, CHANGE_SET_PREV_NEXT)) { + if (!Collections.disjoint(changes, CHANGE_SET_PREV_NEXT)) { updatePrevNext = true; } } - if(updatePrevNext) { + if (updatePrevNext) { Log.d(TAG, "onArticleChangedEvent() prev/next buttons changed"); updatePrevNextButtons(); } EnumSet changes = event.getArticleChanges(article); - if(changes == null) return; + if (changes == null) + return; Log.d(TAG, "onArticlesChangedEvent() changes: " + changes); @@ -459,7 +467,7 @@ public void onArticlesChangedEvent(ArticlesChangedEvent event) { boolean updateTitle; boolean updateURL; - if(changes.contains(FeedsChangedEvent.ChangeType.UNSPECIFIED)) { + if (changes.contains(FeedsChangedEvent.ChangeType.UNSPECIFIED)) { updateActions = true; updateContent = true; updateTitle = true; @@ -471,7 +479,7 @@ public void onArticlesChangedEvent(ArticlesChangedEvent event) { updateURL = changes.contains(FeedsChangedEvent.ChangeType.URL_CHANGED); } - if(updateActions) { + if (updateActions) { Log.d(TAG, "onArticleChangedEvent() actions changed"); updateMarkAsReadButtonView(); @@ -479,34 +487,34 @@ public void onArticlesChangedEvent(ArticlesChangedEvent event) { invalidateOptionsMenu(); } - if(updateTitle) { + if (updateTitle) { Log.d(TAG, "onArticleChangedEvent() title changed"); - articleTitle = article.getTitle(); - setTitle(articleTitle); +// articleTitle = article.getTitle(); +// CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar_layout); +// collapsingToolbarLayout.setTitle(articleTitle); } - if(updateURL) { + if (updateURL) { Log.d(TAG, "onArticleChangedEvent() URL changed"); articleUrl = article.getUrl(); } - if(updateContent) { + if (updateContent) { Log.d(TAG, "onArticleChangedEvent() content changed"); -// prepareToRestorePosition(true); + // prepareToRestorePosition(true); loadArticleToWebView(); -// restorePositionAfterUpdate(); + // restorePositionAfterUpdate(); } } private void showDisableTouchToast() { - Toast.makeText(this, disableTouch - ? R.string.message_disableTouch_inputDisabled - : R.string.message_disableTouch_inputEnabled, + Toast.makeText(this, + disableTouch ? R.string.message_disableTouch_inputDisabled : R.string.message_disableTouch_inputEnabled, Toast.LENGTH_SHORT).show(); } @@ -518,12 +526,11 @@ private void initWebView() { @Override public boolean onConsoleMessage(ConsoleMessage cm) { boolean result = false; - if(ttsFragment != null) { + if (ttsFragment != null) { result = ttsFragment.onWebViewConsoleMessage(cm); } - if(!result) { - Log.d("WebView.onCM", String.format("%s @ %d: %s", cm.message(), - cm.lineNumber(), cm.sourceId())); + if (!result) { + Log.d("WebView.onCM", String.format("%s @ %d: %s", cm.message(), cm.lineNumber(), cm.sourceId())); } return true; } @@ -541,8 +548,9 @@ public void onPageFinished(WebView view, String url) { @SuppressWarnings("deprecation") // can't use newer method until API 21 @Override public boolean shouldOverrideUrlLoading(WebView webView, String url) { - // If we try to open current URL, do not propose to save it, directly open browser - if(url.equals(articleUrl)) { + // If we try to open current URL, do not propose to save it, directly open + // browser + if (url.equals(articleUrl)) { openURL(url); } else { handleUrlClicked(url); @@ -552,17 +560,17 @@ public boolean shouldOverrideUrlLoading(WebView webView, String url) { } @Override - public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, - String host, String realm) { + public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) { Log.d(TAG, "onReceivedHttpAuthRequest() host: " + host + ", realm: " + realm); - if(!TextUtils.isEmpty(host)) { + if (!TextUtils.isEmpty(host)) { String httpAuthHost = settings.getUrl(); try { httpAuthHost = new URL(httpAuthHost).getHost(); - } catch(Exception ignored) {} + } catch (Exception ignored) { + } - if(host.contains(httpAuthHost)) { + if (host.contains(httpAuthHost)) { Log.d(TAG, "onReceivedHttpAuthRequest() host match"); handler.proceed(settings.getHttpAuthUsername(), settings.getHttpAuthPassword()); return; @@ -574,42 +582,43 @@ public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, }); - if(fontSize != 100) setFontSize(webViewContent, fontSize); + if (fontSize != 100) + setFontSize(webViewContent, fontSize); - GestureDetector.SimpleOnGestureListener gestureListener - = new GestureDetector.SimpleOnGestureListener() { + GestureDetector.SimpleOnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener() { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // note: e1 - previous event, e2 - current event // velocity* - velocity in pixels per second - if(!swipeArticles) return false; - if(e1 == null || e2 == null) return false; - if(e1.getPointerCount() > 1 || e2.getPointerCount() > 1) return false; + if (e1 == null || e2 == null) + return false; + if (e1.getPointerCount() > 1 || e2.getPointerCount() > 1) + return false; -// if(Math.abs(e1.getY() - e2.getY()) > 150) { -// Log.d("FLING", "not a horizontal fling (distance)"); -// return false; // not a horizontal move (distance) -// } + // if(Math.abs(e1.getY() - e2.getY()) > 150) { + // Log.d("FLING", "not a horizontal fling (distance)"); + // return false; // not a horizontal move (distance) + // } - if(Math.abs(velocityX) < 80) { + if (Math.abs(velocityX) < 80) { Log.v("FLING", "too slow"); return false; // too slow } - if(Math.abs(velocityX / velocityY) < 3) { + if (Math.abs(velocityX / velocityY) < 3) { Log.v("FLING", "not a horizontal fling"); return false; // not a horizontal fling } float diff = e1.getX() - e2.getX(); - if(Math.abs(diff) < 80) { // configurable + if (Math.abs(diff) < 80) { // configurable Log.v("FLING", "too small distance"); return false; // too small distance } - if(diff > 0) { // right-to-left: next + if (diff > 0) { // right-to-left: next Log.v("FLING", "right-to-left: next"); openNextArticle(); } else { // left-to-right: prev @@ -621,20 +630,22 @@ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float ve @Override public boolean onSingleTapConfirmed(MotionEvent e) { - if(!tapToScroll) return false; + if (!tapToScroll) + return false; - if(e.getPointerCount() > 1) return false; + if (e.getPointerCount() > 1) + return false; int viewHeight = scrollView.getHeight(); float y = e.getY() - scrollView.getScrollY(); - if(y > viewHeight * 0.25 && y < viewHeight * 0.75) { + if (y > viewHeight * 0.25 && y < viewHeight * 0.75) { int viewWidth = scrollView.getWidth(); float x = e.getX(); - if(x < viewWidth * 0.3) { // left part + if (x < viewWidth * 0.3) { // left part scroll(true, screenScrollingPercent, smoothScrolling, false); - } else if(x > viewWidth * 0.7) { // right part + } else if (x > viewWidth * 0.7) { // right part scroll(false, screenScrollingPercent, smoothScrolling, false); } } @@ -654,15 +665,15 @@ public boolean onTouch(View v, MotionEvent event) { } private void loadArticleToWebView() { - webViewContent.loadDataWithBaseURL("file:///android_asset/", getHtmlPage(), - "text/html", "utf-8", null); + String page = getHtmlPage(); + webViewContent.loadDataWithBaseURL("file:///android_asset/", page, "text/html", "utf-8", null); } private String getHtmlPage() { String cssName; boolean highContrast = false; boolean weightedFont = false; - switch(Themes.getCurrentTheme()) { + switch (Themes.getCurrentTheme()) { case E_INK: weightedFont = true; case LIGHT_CONTRAST: @@ -685,18 +696,21 @@ private String getHtmlPage() { } List additionalClasses = new ArrayList<>(1); - if(highContrast) additionalClasses.add("high-contrast"); - if(weightedFont) additionalClasses.add("weighted-font"); - if(settings.isArticleFontSerif()) additionalClasses.add("serif-font"); - if(settings.isArticleTextAlignmentJustify()) additionalClasses.add("text-align-justify"); - additionalClasses.add(settings.getHandlePreformattedTextOption()); + if (highContrast) + additionalClasses.add("high-contrast"); + if (weightedFont) + additionalClasses.add("weighted-font"); + if (settings.isArticleFontSerif()) + additionalClasses.add("serif-font"); + if (settings.isArticleTextAlignmentJustify()) + additionalClasses.add("text-align-justify"); String classAttr; - if(!additionalClasses.isEmpty()) { + if (!additionalClasses.isEmpty()) { StringBuilder sb = new StringBuilder(); sb.append(" class=\""); - for(String cl: additionalClasses) { + for (String cl : additionalClasses) { sb.append(cl).append(' '); } sb.append('"'); @@ -709,19 +723,20 @@ private String getHtmlPage() { String htmlBase; try { htmlBase = readRawString(R.raw.webview_htmlbase); - } catch(Exception e) { + } catch (Exception e) { // should not happen throw new RuntimeException("Couldn't load raw resource", e); } String htmlContent = getHtmlContent(); List imgURLs = ImageCacheUtils.findImageUrlsInHtml(htmlContent); - if(imgURLs != null && imgURLs.size() > 0) { + if (imgURLs != null && imgURLs.size() > 0) { String wbgURL = ImageCacheUtils.getWallabagUrl(); - for(String imageURL: imgURLs) { - if(imageURL.startsWith(ImageCacheUtils.WALLABAG_RELATIVE_URL_PATH)) { + for (String imageURL : imgURLs) { + if (imageURL.startsWith(ImageCacheUtils.WALLABAG_RELATIVE_URL_PATH)) { htmlContent = htmlContent.replace(imageURL, wbgURL + imageURL); - Log.d(TAG, "getHtmlPage() prefixing wallabag server URL " + wbgURL + " to the image path " + imageURL); + Log.d(TAG, + "getHtmlPage() prefixing wallabag server URL " + wbgURL + " to the image path " + imageURL); } } } @@ -736,29 +751,31 @@ private String getHtmlPage() { dateAndAuthor += " " + article.getAuthors(); } - return String.format(htmlBase, cssName, classAttr, TextUtils.htmlEncode(articleTitle), - articleUrl, articleDomain, dateAndAuthor, htmlContent); + int estimatedReadingTime = article.getEstimatedReadingTime(settings.getReadingSpeed()); + String estimatedReadingTimeString = getString(R.string.content_estimatedReadingTime, + estimatedReadingTime > 0 ? estimatedReadingTime : "< 1"); + + String result = String.format(htmlBase, cssName, classAttr, TextUtils.htmlEncode(articleTitle), articleUrl, + articleDomain, dateAndAuthor, estimatedReadingTimeString, htmlContent); + int a = 1; + return result; } private String getHtmlContent() { String htmlContent = article.getContent(); - int estimatedReadingTime = article.getEstimatedReadingTime(settings.getReadingSpeed()); - String estimatedReadingTimeString = getString(R.string.content_estimatedReadingTime, - estimatedReadingTime > 0 ? estimatedReadingTime : "< 1"); - String previewPicture = ""; - if(!TextUtils.isEmpty(article.getPreviewPictureURL())) { + if (!TextUtils.isEmpty(article.getPreviewPictureURL())) { previewPicture = "
"; } - htmlContent = estimatedReadingTimeString + previewPicture + htmlContent; - if(BuildConfig.DEBUG) Log.d(TAG, "getHtmlContent() htmlContent: " + htmlContent); + htmlContent = previewPicture + htmlContent; + if (BuildConfig.DEBUG) + Log.d(TAG, "getHtmlContent() htmlContent: " + htmlContent); - if(settings.isImageCacheEnabled()) { + if (settings.isImageCacheEnabled()) { Log.d(TAG, "getHtmlContent() replacing image links to cached versions in htmlContent"); - htmlContent = ImageCacheUtils.replaceImagesInHtmlContent( - htmlContent, article.getArticleId().longValue()); + htmlContent = ImageCacheUtils.replaceImagesInHtmlContent(htmlContent, article.getArticleId().longValue()); } return htmlContent; @@ -770,20 +787,19 @@ private void initButtons() { } private void updateMarkAsReadButtonView() { - Button buttonMarkRead = (Button)findViewById(R.id.btnMarkRead); - Button buttonMarkUnread = (Button)findViewById(R.id.btnMarkUnread); + MaterialButton buttonMarkRead = findViewById(R.id.btnMarkRead); + MaterialButton buttonMarkUnread = findViewById(R.id.btnMarkUnread); boolean archived = article.getArchive(); - buttonMarkRead.setVisibility(!archived ? View.VISIBLE: View.GONE); - buttonMarkUnread.setVisibility(archived ? View.VISIBLE: View.GONE); - - OnClickListener onClickListener = - new OnClickListener() { - @Override - public void onClick(View v) { - markAsReadAndClose(); - } - }; + buttonMarkRead.setVisibility(!archived ? View.VISIBLE : View.GONE); + buttonMarkUnread.setVisibility(archived ? View.VISIBLE : View.GONE); + + OnClickListener onClickListener = new OnClickListener() { + @Override + public void onClick(View v) { + markAsReadAndClose(); + } + }; buttonMarkRead.setOnClickListener(onClickListener); buttonMarkUnread.setOnClickListener(onClickListener); @@ -797,8 +813,8 @@ private void updatePrevNextButtons() { } private void updatePrevNextButtonViews() { - ImageButton buttonGoPrevious = (ImageButton)findViewById(R.id.btnGoPrevious); - ImageButton buttonGoNext = (ImageButton)findViewById(R.id.btnGoNext); + MaterialButton buttonGoPrevious = findViewById(R.id.btnGoPrevious); + MaterialButton buttonGoNext = findViewById(R.id.btnGoNext); buttonGoPrevious.setVisibility(previousArticleID == null ? View.GONE : View.VISIBLE); buttonGoNext.setVisibility(nextArticleID == null ? View.GONE : View.VISIBLE); @@ -822,67 +838,65 @@ private void loadingFinished() { loadingPlaceholder.setVisibility(View.GONE); bottomTools.setVisibility(View.VISIBLE); - hrBar.setVisibility(View.VISIBLE); + // hrBar.setVisibility(View.VISIBLE); // should there be a pause between visibility change and position restoration? restoreReadingPosition(); - if(ttsFragment != null) { + if (ttsFragment != null) { ttsFragment.onDocumentLoadFinished(webViewContent, scrollView); } } private void handleUrlClicked(final String url) { Log.d(TAG, "handleUrlClicked() url: " + url); - if(TextUtils.isEmpty(url)) return; + if (TextUtils.isEmpty(url)) + return; // TODO: fancy dialog AlertDialog.Builder builder = new AlertDialog.Builder(this); @SuppressLint("InflateParams") // it's ok to inflate with null for AlertDialog - View v = getLayoutInflater().inflate(R.layout.dialog_title_url, null); + View v = getLayoutInflater().inflate(R.layout.dialog_title_url, null); - TextView tv = (TextView)v.findViewById(R.id.tv_dialog_title_url); + TextView tv = v.findViewById(R.id.tv_dialog_title_url); tv.setText(url); builder.setCustomTitle(v); - builder.setItems( - new CharSequence[]{ - getString(R.string.d_urlAction_openInBrowser), - getString(R.string.d_urlAction_addToWallabag), - getString(R.string.d_urlAction_copyToClipboard), - getString(R.string.menuShare) - }, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - switch (which) { - case 0: - openURL(url); - break; - case 1: - ServiceHelper.addLink(ReadArticleActivity.this, url); - break; - case 2: - copyURLToClipboard(url); - break; - case 3: - shareArticle(null, url); - break; - } - } - }); + builder.setItems(new CharSequence[]{getString(R.string.d_urlAction_openInBrowser), + getString(R.string.d_urlAction_addToWallabag), getString(R.string.d_urlAction_copyToClipboard), + getString(R.string.menuShare)}, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case 0: + openURL(url); + break; + case 1: + ServiceHelper.addLink(ReadArticleActivity.this, url); + break; + case 2: + copyURLToClipboard(url); + break; + case 3: + shareArticle(null, url); + break; + } + } + }); builder.show(); } private void openURL(String url) { Log.d(TAG, "openURL() url: " + url); - if(TextUtils.isEmpty(url)) return; + if (TextUtils.isEmpty(url)) + return; Uri uri = Uri.parse(url); - if(uri.getScheme() == null) { + if (uri.getScheme() == null) { Log.i(TAG, "openURL() scheme is null, appending default scheme"); uri = Uri.parse("http://" + url); } @@ -891,7 +905,7 @@ private void openURL(String url) { Intent intent = new Intent(Intent.ACTION_VIEW, uri); try { startActivity(intent); - } catch(ActivityNotFoundException e) { + } catch (ActivityNotFoundException e) { Log.w(TAG, "openURL() failed to open URL", e); Toast.makeText(this, R.string.message_couldNotOpenUrl, Toast.LENGTH_SHORT).show(); } @@ -908,21 +922,22 @@ private void toggleFavorite() { } private void shareArticle() { - shareArticle(articleTitle, articleUrl); + shareArticle(articleTitle, articleUrl); } - private void shareArticle(String articleTitle , String articleUrl) { + private void shareArticle(String articleTitle, String articleUrl) { String shareText = articleUrl; - if(!TextUtils.isEmpty(articleTitle)) shareText = articleTitle + " " + shareText; - + if (!TextUtils.isEmpty(articleTitle)) + shareText = articleTitle + " " + shareText; - if(settings.isAppendWallabagMentionEnabled()) { + if (settings.isAppendWallabagMentionEnabled()) { shareText += getString(R.string.share_text_extra); } Intent send = new Intent(Intent.ACTION_SEND); send.setType("text/plain"); - if(!TextUtils.isEmpty(articleTitle)) send.putExtra(Intent.EXTRA_SUBJECT, articleTitle); + if (!TextUtils.isEmpty(articleTitle)) + send.putExtra(Intent.EXTRA_SUBJECT, articleTitle); send.putExtra(Intent.EXTRA_TEXT, shareText); startActivity(Intent.createChooser(send, getString(R.string.share_article_title))); @@ -953,14 +968,14 @@ private void showChangeTitleDialog() { @SuppressLint("InflateParams") // ok for dialogs final View view = getLayoutInflater().inflate(R.layout.dialog_change_title, null); - ((TextView)view.findViewById(R.id.editText_title)).setText(articleTitle); + ((TextView) view.findViewById(R.id.editText_title)).setText(articleTitle); builder.setView(view); builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - TextView textView = (TextView)view.findViewById(R.id.editText_title); + TextView textView = view.findViewById(R.id.editText_title); changeTitle(textView.getText().toString()); } }); @@ -985,7 +1000,7 @@ private void openOriginal() { } private void copyURLToClipboard() { - copyURLToClipboard(articleUrl); + copyURLToClipboard(articleUrl); } private void copyURLToClipboard(String url) { @@ -997,9 +1012,8 @@ private void copyURLToClipboard(String url) { private void showDownloadFileDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.dialog_title_downloadFileFormat) - .setItems(R.array.options_downloadFormat_values, - new DialogInterface.OnClickListener() { + builder.setTitle(R.string.dialog_title_downloadFileFormat).setItems(R.array.options_downloadFormat_values, + new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { String selectedFormat = getResources() .getStringArray(R.array.options_downloadFormat_values)[which]; @@ -1007,14 +1021,13 @@ public void onClick(DialogInterface dialog, int which) { WallabagService.ResponseFormat format; try { format = WallabagService.ResponseFormat.valueOf(selectedFormat); - } catch(IllegalArgumentException e) { - Log.e(TAG, "showDownloadFileDialog() unknown selected format: " - + selectedFormat); + } catch (IllegalArgumentException e) { + Log.e(TAG, "showDownloadFileDialog() unknown selected format: " + selectedFormat); format = WallabagService.ResponseFormat.PDF; } - ServiceHelper.downloadArticleAsFile(getApplicationContext(), - article.getArticleId(), format, null); + ServiceHelper.downloadArticleAsFile(getApplicationContext(), article.getArticleId(), format, + null); } }); builder.show(); @@ -1025,7 +1038,8 @@ private void changeFontSize(boolean increase) { int step = 5; fontSize += step * (increase ? 1 : -1); - if(!increase && fontSize < 5) fontSize = 5; + if (!increase && fontSize < 5) + fontSize = 5; setFontSize(webViewContent, fontSize); @@ -1035,21 +1049,23 @@ private void changeFontSize(boolean increase) { } private void openArticle(Long id) { - if(ttsFragment != null) { + if (ttsFragment != null) { ttsFragment.onOpenNewArticle(); } Intent intent = new Intent(this, ReadArticleActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.putExtra(ReadArticleActivity.EXTRA_ID, id); - if(contextFavorites != null) intent.putExtra(EXTRA_LIST_FAVORITES, contextFavorites); - if(contextArchived != null) intent.putExtra(EXTRA_LIST_ARCHIVED, contextArchived); + if (contextFavorites != null) + intent.putExtra(EXTRA_LIST_FAVORITES, contextFavorites); + if (contextArchived != null) + intent.putExtra(EXTRA_LIST_ARCHIVED, contextArchived); startActivity(intent); } public boolean openPreviousArticle() { - if(previousArticleID != null) { + if (previousArticleID != null) { openArticle(previousArticleID); return true; } @@ -1059,7 +1075,7 @@ public boolean openPreviousArticle() { } public boolean openNextArticle() { - if(nextArticleID != null) { + if (nextArticleID != null) { openArticle(nextArticleID); return true; } @@ -1069,32 +1085,33 @@ public boolean openNextArticle() { } private void scroll(boolean up, float percent, boolean smooth, boolean keyUsed) { - if(scrollView == null) return; + if (scrollView == null) + return; int viewHeight = scrollView.getHeight(); int yOffset = scrollView.getScrollY(); int newYOffset = yOffset; - int step = (int)(viewHeight * percent / 100); - if(up) { + int step = (int) (viewHeight * percent / 100); + if (up) { newYOffset -= step; } else { newYOffset += step; } - if(newYOffset != yOffset) { - if(smooth) { + if (newYOffset != yOffset) { + if (smooth) { scrollView.smoothScrollTo(scrollView.getScrollX(), newYOffset); } else { scrollView.scrollTo(scrollView.getScrollX(), newYOffset); } } - if(!up && keyUsed && newYOffset + viewHeight > scrollViewLastChild.getBottom()) { - if(scrolledOverBottom > 1) { + if (!up && keyUsed && newYOffset + viewHeight > scrollViewLastChild.getBottom()) { + if (scrolledOverBottom > 1) { scrolledOverBottom--; - Toast.makeText(this, getString(R.string.scrolledOverBottom, scrolledOverBottom), - Toast.LENGTH_SHORT).show(); + Toast.makeText(this, getString(R.string.scrolledOverBottom, scrolledOverBottom), Toast.LENGTH_SHORT) + .show(); } else { Toast.makeText(this, R.string.markedAsRead, Toast.LENGTH_SHORT).show(); markAsReadAndClose(); @@ -1109,13 +1126,14 @@ private double getReadingPosition() { int viewHeight = scrollView.getHeight(); int totalHeight = scrollView.getChildAt(0).getHeight(); - Log.v(TAG, "getReadingPosition() yOffset: " + yOffset + ", viewHeight: " + viewHeight - + ", totalHeight: " + totalHeight); + Log.v(TAG, "getReadingPosition() yOffset: " + yOffset + ", viewHeight: " + viewHeight + ", totalHeight: " + + totalHeight); totalHeight -= viewHeight; double position = totalHeight >= 0 ? yOffset * 1. / totalHeight : 0; - if(position > 100) position = 100; + if (position > 100) + position = 100; Log.d(TAG, "getReadingPosition() position: " + position); @@ -1125,16 +1143,15 @@ private double getReadingPosition() { private void restoreReadingPosition() { Log.d(TAG, "restoreReadingPosition() articleProgress: " + articleProgress); - if(articleProgress != null) { + if (articleProgress != null) { int viewHeight = scrollView.getHeight(); int totalHeight = scrollView.getChildAt(0).getHeight(); - Log.v(TAG, "restoreReadingPosition() viewHeight: " + viewHeight - + ", totalHeight: " + totalHeight); + Log.v(TAG, "restoreReadingPosition() viewHeight: " + viewHeight + ", totalHeight: " + totalHeight); totalHeight -= viewHeight; - int yOffset = totalHeight > 0 ? ((int)Math.round(articleProgress * totalHeight)) : 0; + int yOffset = totalHeight > 0 ? ((int) Math.round(articleProgress * totalHeight)) : 0; Log.v(TAG, "restoreReadingPosition() yOffset: " + yOffset); @@ -1144,27 +1161,21 @@ private void restoreReadingPosition() { public boolean toggleTTS(boolean autoPlay) { boolean result; - if(ttsFragment == null) { + if (ttsFragment == null) { ttsFragment = TtsFragment.newInstance(autoPlay); - getSupportFragmentManager() - .beginTransaction() - .add(R.id.viewMain, ttsFragment, TAG_TTS_FRAGMENT) - .commit(); + getSupportFragmentManager().beginTransaction().add(R.id.viewMain, ttsFragment, TAG_TTS_FRAGMENT).commit(); settings.setTtsVisible(true); ttsFragment.onDocumentLoadStart(articleDomain, articleTitle, articleLanguage); - if(loadingFinished) { + if (loadingFinished) { ttsFragment.onDocumentLoadFinished(webViewContent, scrollView); } result = true; } else { - getSupportFragmentManager() - .beginTransaction() - .remove(ttsFragment) - .commit(); + getSupportFragmentManager().beginTransaction().remove(ttsFragment).commit(); ttsFragment = null; @@ -1181,7 +1192,8 @@ public boolean toggleTTS(boolean autoPlay) { private boolean loadArticle(long id) { article = getArticle(id); - if(article == null) return false; + if (article == null) + return false; articleTitle = article.getTitle(); Log.d(TAG, "loadArticle() articleTitle: " + articleTitle); @@ -1204,17 +1216,23 @@ private Article getArticle(long articleID) { private Long getAdjacentArticle(boolean previous) { QueryBuilder
qb = articleDao.queryBuilder(); - if(previous) qb.where(ArticleDao.Properties.ArticleId.gt(article.getArticleId())); - else qb.where(ArticleDao.Properties.ArticleId.lt(article.getArticleId())); + if (previous) + qb.where(ArticleDao.Properties.ArticleId.gt(article.getArticleId())); + else + qb.where(ArticleDao.Properties.ArticleId.lt(article.getArticleId())); - if(contextFavorites != null) qb.where(ArticleDao.Properties.Favorite.eq(contextFavorites)); - if(contextArchived != null) qb.where(ArticleDao.Properties.Archive.eq(contextArchived)); + if (contextFavorites != null) + qb.where(ArticleDao.Properties.Favorite.eq(contextFavorites)); + if (contextArchived != null) + qb.where(ArticleDao.Properties.Archive.eq(contextArchived)); - if(previous) qb.orderAsc(ArticleDao.Properties.ArticleId); - else qb.orderDesc(ArticleDao.Properties.ArticleId); + if (previous) + qb.orderAsc(ArticleDao.Properties.ArticleId); + else + qb.orderDesc(ArticleDao.Properties.ArticleId); List
l = qb.limit(1).list(); - if(!l.isEmpty()) { + if (!l.isEmpty()) { return l.get(0).getId(); } @@ -1228,16 +1246,17 @@ private String readRawString(int id) throws IOException { StringBuilder sb = new StringBuilder(); String s; - while((s = reader.readLine()) != null) { + while ((s = reader.readLine()) != null) { sb.append(s).append('\n'); } return sb.toString(); } finally { - if(reader != null) { + if (reader != null) { try { reader.close(); - } catch(IOException ignored) {} + } catch (IOException ignored) { + } } } } @@ -1245,10 +1264,10 @@ private String readRawString(int id) throws IOException { private void onPageFinished() { Log.d(TAG, "onPageFinished() started"); - if(!isResumed) { + if (!isResumed) { onPageFinishedCallPostponedUntilResume = true; - if(ttsFragment != null) { + if (ttsFragment != null) { ttsFragment.onDocumentLoadFinished(webViewContent, scrollView); } return; @@ -1261,10 +1280,9 @@ private void onPageFinished() { @Override public void run() { // "< 50" is workaround for https://github.com/wallabag/android-app/issues/178 - if(webViewContent.getHeight() < 50) { - if(++counter > 1000) { - Log.d(TAG, "onPageFinished() exiting by counter" + - "; calling loadingFinished() anyway"); + if (webViewContent.getHeight() < 50) { + if (++counter > 1000) { + Log.d(TAG, "onPageFinished() exiting by counter" + "; calling loadingFinished() anyway"); loadingFinished(); return; } @@ -1280,7 +1298,8 @@ public void run() { } private void prepareToRestorePosition(boolean savePosition) { - if(savePosition) articleProgress = getReadingPosition(); + if (savePosition) + articleProgress = getReadingPosition(); webViewHeightBeforeUpdate = webViewContent.getHeight(); } @@ -1293,14 +1312,13 @@ private void restorePositionAfterUpdate() { @Override public void run() { - if(webViewContent.getHeight() == webViewHeightBeforeUpdate) { - if(++counter > 1000) { + if (webViewContent.getHeight() == webViewHeightBeforeUpdate) { + if (++counter > 1000) { Log.d(TAG, "restorePositionAfterUpdate() giving up"); return; } - Log.v(TAG, "restorePositionAfterUpdate() scheduling another postDelay" + - "; counter: " + counter); + Log.v(TAG, "restorePositionAfterUpdate() scheduling another postDelay" + "; counter: " + counter); webViewContent.postDelayed(this, 10); } else { Log.d(TAG, "restorePositionAfterUpdate() restoring position"); @@ -1311,15 +1329,16 @@ public void run() { } private void cancelPositionRestoration() { - if(positionRestorationRunnable != null) { + if (positionRestorationRunnable != null) { Log.d(TAG, "cancelPositionRestoration() trying to cancel previous task"); - if(webViewContent != null) webViewContent.removeCallbacks(positionRestorationRunnable); + if (webViewContent != null) + webViewContent.removeCallbacks(positionRestorationRunnable); positionRestorationRunnable = null; } } private void setFontSize(WebView view, int size) { - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { setFontSizeNew(view, size); } else { setFontSizeOld(view, size); diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/RecyclerViewListFragment.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/RecyclerViewListFragment.java index db8c97595..4087d7423 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/RecyclerViewListFragment.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/RecyclerViewListFragment.java @@ -75,6 +75,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, recyclerViewLayoutManager = new LinearLayoutManager(getActivity()); recyclerView.setLayoutManager(recyclerViewLayoutManager); + recyclerView.setHasFixedSize(true); scrollListener = new EndlessRecyclerViewScrollListener(recyclerViewLayoutManager) { @Override diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/Themes.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/Themes.java index acb94dc90..4d3e1c5dc 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/Themes.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/Themes.java @@ -50,44 +50,44 @@ public static void checkTheme(Activity activity) { public enum Theme { LIGHT( R.string.themeName_light, - R.style.LightTheme, - R.style.LightTheme_NoActionBar, - R.style.ProxyTheme + R.style.MyTheme_DayNight, + R.style.MyTheme_DayNight, + R.style.MyTheme_DayNight ), LIGHT_CONTRAST( R.string.themeName_light_contrast, - R.style.LightThemeContrast, - R.style.LightThemeContrast_NoActionBar, - R.style.ProxyTheme + R.style.MyTheme_DayNight, + R.style.MyTheme_DayNight, + R.style.MyTheme_DayNight ), E_INK( R.string.themeName_eink, - R.style.LightThemeContrast, - R.style.LightThemeContrast_NoActionBar, - R.style.ProxyTheme + R.style.MyTheme_DayNight, + R.style.MyTheme_DayNight, + R.style.MyTheme_DayNight ), DARK( R.string.themeName_dark, - R.style.DarkTheme, - R.style.DarkTheme_NoActionBar, - R.style.ProxyThemeDark + R.style.MyTheme_DayNight, + R.style.MyTheme_DayNight, + R.style.MyTheme_DayNight ), DARK_CONTRAST( R.string.themeName_dark_contrast, - R.style.DarkThemeContrast, - R.style.DarkThemeContrast_NoActionBar, - R.style.ProxyThemeDark + R.style.MyTheme_DayNight, + R.style.MyTheme_DayNight, + R.style.MyTheme_DayNight ), SOLARIZED( R.string.themeName_solarized, - R.style.SolarizedTheme, - R.style.SolarizedTheme_NoActionBar, - R.style.ProxyTheme + R.style.MyTheme_DayNight, + R.style.MyTheme_DayNight, + R.style.MyTheme_DayNight ); private int nameId; diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/FloatEditTextPreference.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/FloatEditTextPreference.java index 49a3030c2..cfbe7c84e 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/FloatEditTextPreference.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/FloatEditTextPreference.java @@ -3,7 +3,7 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; -import android.preference.EditTextPreference; +import androidx.preference.EditTextPreference; import android.util.AttributeSet; /** diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/IntEditTextPreference.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/IntEditTextPreference.java index 04582fc98..85843b8c1 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/IntEditTextPreference.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/IntEditTextPreference.java @@ -3,7 +3,7 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; -import android.preference.EditTextPreference; +import androidx.preference.EditTextPreference; import android.util.AttributeSet; /** diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/IntListPreference.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/IntListPreference.java index b93f5668d..b4d6bcc4a 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/IntListPreference.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/IntListPreference.java @@ -3,7 +3,7 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; -import android.preference.ListPreference; +import androidx.preference.ListPreference; import android.util.AttributeSet; /** diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/LongListPreference.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/LongListPreference.java index 38d5f0554..cf89783ce 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/LongListPreference.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/LongListPreference.java @@ -3,7 +3,7 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; -import android.preference.ListPreference; +import androidx.preference.ListPreference; import android.util.AttributeSet; /** diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/SettingsActivity.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/SettingsActivity.java index 7e630741d..7b2bc31ac 100644 --- a/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/SettingsActivity.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ui/preferences/SettingsActivity.java @@ -5,11 +5,6 @@ import android.app.AlarmManager; import android.content.DialogInterface; import android.content.SharedPreferences; -import android.preference.EditTextPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceFragment; -import androidx.appcompat.app.AlertDialog; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; @@ -18,8 +13,20 @@ import android.widget.TextView; import android.widget.Toast; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.preference.EditTextPreference; +import androidx.preference.ListPreference; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + import java.util.ArrayList; import java.util.List; +import java.util.Locale; import fr.gaulupeau.apps.InThePoche.R; import fr.gaulupeau.apps.Poche.App; @@ -27,495 +34,347 @@ import fr.gaulupeau.apps.Poche.data.OperationsHelper; import fr.gaulupeau.apps.Poche.data.Settings; import fr.gaulupeau.apps.Poche.data.StorageHelper; -import fr.gaulupeau.apps.Poche.events.ArticlesChangedEvent; -import fr.gaulupeau.apps.Poche.events.EventHelper; -import fr.gaulupeau.apps.Poche.events.FeedsChangedEvent; import fr.gaulupeau.apps.Poche.network.ClientCredentials; -import fr.gaulupeau.apps.Poche.network.WallabagWebService; import fr.gaulupeau.apps.Poche.network.WallabagServiceWrapper; +import fr.gaulupeau.apps.Poche.network.WallabagWebService; import fr.gaulupeau.apps.Poche.network.tasks.TestApiAccessTask; -import fr.gaulupeau.apps.Poche.service.AlarmHelper; -import fr.gaulupeau.apps.Poche.service.ServiceHelper; -import fr.gaulupeau.apps.Poche.ui.BaseActionBarActivity; import fr.gaulupeau.apps.Poche.ui.Themes; -public class SettingsActivity extends BaseActionBarActivity { +public class SettingsActivity extends AppCompatActivity implements + PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { + + private static final String TITLE_TAG = fr.gaulupeau.apps.Poche.ui.preferences.SettingsActivity.HeaderFragment.class.getSimpleName(); + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - if(savedInstanceState == null) { - getFragmentManager().beginTransaction() - .replace(android.R.id.content, new SettingsFragment()) + setContentView(R.layout.settings_activity); + if (savedInstanceState == null) { + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.settings, new HeaderFragment()) .commit(); + } else { + setTitle(savedInstanceState.getCharSequence(TITLE_TAG)); + } + getSupportFragmentManager().addOnBackStackChangedListener( + new FragmentManager.OnBackStackChangedListener() { + @Override + public void onBackStackChanged() { + if (getSupportFragmentManager().getBackStackEntryCount() == 0) { + setTitle(R.string.title_activity_settings); + } + } + }); + + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); } } - public static class SettingsFragment extends PreferenceFragment + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + // Save current activity title so we can set it again after a configuration change + outState.putCharSequence(TITLE_TAG, getTitle()); + } + + @Override + public boolean onSupportNavigateUp() { + if (getSupportFragmentManager().popBackStackImmediate()) { + return true; + } + return super.onSupportNavigateUp(); + } + + @Override + public boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref) { + // Instantiate the new Fragment + final Bundle args = pref.getExtras(); + final Fragment fragment = getSupportFragmentManager().getFragmentFactory().instantiate( + getClassLoader(), + pref.getFragment()); + fragment.setArguments(args); + fragment.setTargetFragment(caller, 0); + // Replace the existing Fragment with the new Fragment + getSupportFragmentManager().beginTransaction() + .replace(R.id.settings, fragment) + .addToBackStack(null) + .commit(); + setTitle(pref.getTitle()); + return true; + } + + public static class HeaderFragment extends PreferenceFragmentCompat { + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.preferences, rootKey); + + // Connection wizard preference appears in the root screen instead of the Connection + // screen + Preference connectionWizardPreference = findPreference(getString(R.string.pref_key_connection_wizard)); + if (connectionWizardPreference != null) { + connectionWizardPreference.setOnPreferenceClickListener(preference -> { + Activity activity = getActivity(); + if (activity != null) { + ConnectionWizardActivity.runWizard(activity, true); + + activity.finish(); + } + return true; + }); + } + } + } + + public static class ConnectionFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener, SharedPreferences.OnSharedPreferenceChangeListener, ConfigurationTestHelper.ResultHandler, ConfigurationTestHelper.GetCredentialsHandler { - - private static final String TAG = SettingsFragment.class.getSimpleName(); - - private static final int[] SUMMARIES_TO_INITIATE = { - R.string.pref_key_connection_url, - R.string.pref_key_connection_advanced_httpAuthUsername, - R.string.pref_key_connection_advanced_httpAuthPassword, - R.string.pref_key_connection_username, - R.string.pref_key_connection_password, - R.string.pref_key_connection_api_clientID, - R.string.pref_key_connection_api_clientSecret, - R.string.pref_key_ui_theme, - R.string.pref_key_ui_article_fontSize, - R.string.pref_key_ui_screenScrolling_percent, - R.string.pref_key_autoSync_interval, - R.string.pref_key_autoSync_type, - R.string.pref_key_storage_dbPath - }; - private Settings settings; - private boolean autoSyncChanged; - private boolean oldAutoSyncEnabled; - private long oldAutoSyncInterval; - - private boolean autoSyncQueueChanged; - private boolean oldAutoSyncQueueEnabled; - - private boolean checkUserChanged; private String oldUrl; private String oldHttpAuthUsername; private String oldUsername; private String oldApiClientID; - private boolean invalidateConfiguration; - private boolean serviceWrapperReinitializationNeeded; - - private boolean imageCachingChanged; - private boolean oldImageCacheEnabled; - - private boolean readingSpeedChanged; - private int oldReadingSpeed; - - private boolean keepScreenOnChanged; - private boolean oldkeepScreenOn; - - private ConfigurationTestHelper configurationTestHelper; - - public SettingsFragment() {} - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.preferences); - - settings = new Settings(App.getInstance()); - - setOnClickListener(R.string.pref_key_connection_wizard); - setOnClickListener(R.string.pref_key_connection_autofill); - setOnClickListener(R.string.pref_key_sync_syncTypes_description); - setOnClickListener(R.string.pref_key_ui_disableTouch_keyCode); - setOnClickListener(R.string.pref_key_misc_wipeDB); - - ListPreference themeListPreference = (ListPreference)findPreference( - getString(R.string.pref_key_ui_theme)); - if(themeListPreference != null) { - Themes.Theme[] themes = Themes.Theme.values(); - String[] themeEntries = new String[themes.length]; - String[] themeEntryValues = new String[themes.length]; - for(int i = 0; i < themes.length; i++) { - themeEntries[i] = getString(themes[i].getNameId()); - themeEntryValues[i] = themes[i].toString(); - } + public void onGetCredentialsResult(ClientCredentials clientCredentials) { + setTextPreference(R.string.pref_key_connection_api_clientID, + clientCredentials.clientID); + setTextPreference(R.string.pref_key_connection_api_clientSecret, + clientCredentials.clientSecret); + } - themeListPreference.setEntries(themeEntries); - themeListPreference.setEntryValues(themeEntryValues); - } + @Override + public void onGetCredentialsFail() { + } - ListPreference autoSyncIntervalListPreference = (ListPreference)findPreference( - getString(R.string.pref_key_autoSync_interval)); - if(autoSyncIntervalListPreference != null) { - // may set arbitrary values on Android API 19+ - autoSyncIntervalListPreference.setEntries(new String[] { - getString(R.string.pref_option_autoSync_interval_15m), - getString(R.string.pref_option_autoSync_interval_30m), - getString(R.string.pref_option_autoSync_interval_1h), - getString(R.string.pref_option_autoSync_interval_12h), - getString(R.string.pref_option_autoSync_interval_24h) - }); - autoSyncIntervalListPreference.setEntryValues(new String[] { - String.valueOf(AlarmManager.INTERVAL_FIFTEEN_MINUTES), - String.valueOf(AlarmManager.INTERVAL_HALF_HOUR), - String.valueOf(AlarmManager.INTERVAL_HOUR), - String.valueOf(AlarmManager.INTERVAL_HALF_DAY), - String.valueOf(AlarmManager.INTERVAL_DAY) - }); - } + @Override + public void onConfigurationTestSuccess(String url) { + Log.d(TITLE_TAG, String.format("onConfigurationTestSuccess(%s)", url)); - Preference handleHttpSchemePreference = findPreference( - getString(R.string.pref_key_misc_handleHttpScheme)); - if(handleHttpSchemePreference != null) { - handleHttpSchemePreference.setDefaultValue(settings.isHandlingHttpScheme()); - handleHttpSchemePreference.setOnPreferenceChangeListener(this); + if (url != null) { + setTextPreference(R.string.pref_key_connection_url, url); } - ListPreference dbPathListPreference = (ListPreference)findPreference( - getString(R.string.pref_key_storage_dbPath)); - if(dbPathListPreference != null) { - List entriesList = new ArrayList<>(2); - List entryValuesList = new ArrayList<>(2); - - entriesList.add(getString(R.string.pref_name_storage_dbPath_internalStorage)); - entryValuesList.add(""); - - if(StorageHelper.isExternalStorageWritable()) { - entriesList.add(getString(R.string.pref_name_storage_dbPath_externalStorage)); - entryValuesList.add(StorageHelper.getExternalStoragePath()); - } - - dbPathListPreference.setEntries(entriesList.toArray(new String[0])); - dbPathListPreference.setEntryValues(entryValuesList.toArray(new String[0])); - - dbPathListPreference.setOnPreferenceChangeListener(this); - } + settings.setConfigurationOk(true); + settings.setConfigurationErrorShown(false); - for(int keyID: SUMMARIES_TO_INITIATE) { - updateSummary(keyID); - } + Toast.makeText(getActivity(), R.string.settings_parametersAutofilled, + Toast.LENGTH_SHORT).show(); } @Override - public void onStart() { - super.onStart(); - - Log.d(TAG, "onStart() started"); - - resetChanges(); - - settings.getSharedPreferences().registerOnSharedPreferenceChangeListener(this); + public void onConnectionTestFail(WallabagWebService.ConnectionTestResult result, + String details) { } @Override - public void onStop() { - Log.d(TAG, "onStop() started"); - - settings.getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); - - if(configurationTestHelper != null) { - configurationTestHelper.cancel(); - configurationTestHelper = null; - } - - applyChanges(); - - super.onStop(); + public void onApiAccessTestFail(TestApiAccessTask.Result result, String details) { } - private void resetChanges() { - Log.d(TAG, "resetChanges() started"); - autoSyncChanged = false; - oldAutoSyncEnabled = settings.isAutoSyncEnabled(); - oldAutoSyncInterval = settings.getAutoSyncInterval(); + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.connection_preferences, rootKey); - autoSyncQueueChanged = false; - oldAutoSyncQueueEnabled = settings.isAutoSyncQueueEnabled(); + settings = new Settings(App.getInstance()); - checkUserChanged = false; oldUrl = settings.getUrl(); oldHttpAuthUsername = settings.getHttpAuthUsername(); oldUsername = settings.getUsername(); oldApiClientID = settings.getApiClientID(); - imageCachingChanged = false; - oldImageCacheEnabled = settings.isImageCacheEnabled(); - - readingSpeedChanged = false; - oldReadingSpeed = settings.getReadingSpeed(); - - keepScreenOnChanged = false; - oldkeepScreenOn = settings.isKeepScreenOn(); - } - private void applyChanges() { - Log.d(TAG, "applyChanges() started"); - - if(autoSyncChanged) { - autoSyncChanged = false; - Log.d(TAG, "applyChanges() autoSyncChanged is true"); - - boolean newAutoSyncEnabled = settings.isAutoSyncEnabled(); - long newAutoSyncInterval = settings.getAutoSyncInterval(); - if(newAutoSyncEnabled != oldAutoSyncEnabled) { - if(newAutoSyncEnabled) { - AlarmHelper.setAlarm(getActivity(), newAutoSyncInterval, true); - } else { - AlarmHelper.unsetAlarm(getActivity(), true); - } - } else if(newAutoSyncEnabled) { - if(newAutoSyncInterval != oldAutoSyncInterval) { - AlarmHelper.updateAlarmInterval(getActivity(), newAutoSyncInterval); - } - } - } - - if(autoSyncQueueChanged) { - autoSyncQueueChanged = false; - Log.d(TAG, "applyChanges() autoSyncQueueChanged is true"); - - boolean newAutoSyncQueueEnabled = settings.isAutoSyncQueueEnabled(); - if(newAutoSyncQueueEnabled != oldAutoSyncQueueEnabled) { - if(newAutoSyncQueueEnabled) { - if(settings.isOfflineQueuePending()) { - Settings.enableConnectivityChangeReceiver(getActivity(), true); - } - } else { - Settings.enableConnectivityChangeReceiver(getActivity(), false); - } - } - } - - if(checkUserChanged) { - checkUserChanged = false; - - boolean userChanged = false; - if(!TextUtils.equals(settings.getUrl(), oldUrl) - || !TextUtils.equals(settings.getUsername(), oldUsername) - || !TextUtils.equals(settings.getApiClientID(), oldApiClientID)) { - userChanged = true; - } else if(!TextUtils.equals(settings.getHttpAuthUsername(), oldHttpAuthUsername) - && (settings.getUsername() == null || settings.getUsername().isEmpty())) { - userChanged = true; - } - - if(userChanged) { - settings.setApiRefreshToken(""); - settings.setApiAccessToken(""); - - OperationsHelper.wipeDB(settings); - } - } - - if(invalidateConfiguration) { - invalidateConfiguration = false; - - Log.i(TAG, "applyChanges() setting isConfigurationOk(false)"); - settings.setConfigurationOk(false); - } - - if(serviceWrapperReinitializationNeeded) { - serviceWrapperReinitializationNeeded = false; - - Log.i(TAG, "applyChanges() calling WallabagServiceWrapper.resetInstance()"); - WallabagServiceWrapper.resetInstance(); - } - - if(imageCachingChanged) { - imageCachingChanged = false; - - if(!oldImageCacheEnabled && settings.isImageCacheEnabled() - && settings.isFirstSyncDone()) { - Log.i(TAG, "applyChanges() image caching changed, starting image fetching"); - ServiceHelper.fetchImages(App.getInstance()); - } - } - - if(readingSpeedChanged) { - readingSpeedChanged = false; - - if(oldReadingSpeed != settings.getReadingSpeed()) { - Log.i(TAG, "applyChanges() reading speed changed, posting event"); - - ArticlesChangedEvent event = new ArticlesChangedEvent(); - event.invalidateAll(FeedsChangedEvent.ChangeType.ESTIMATED_READING_TIME_CHANGED); - EventHelper.postEvent(event); - } - } - - if(keepScreenOnChanged) { - keepScreenOnChanged = false; - - if(!oldkeepScreenOn) { - Log.i(TAG, "applyChanges() keep screen on changed, keep screen on"); - } + Preference connectionAutofillPreference = findPreference(getString(R.string.pref_key_connection_autofill)); + if (connectionAutofillPreference != null) { + connectionAutofillPreference.setOnPreferenceClickListener(this); } } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { - Log.d(TAG, String.format("onPreferenceChange(key: %s, newValue: %s)", + Log.d(TITLE_TAG, String.format("onPreferenceChange(key: %s, newValue: %s)", preference.getKey(), newValue)); - - int keyID = Settings.getPrefKeyIDByValue(preference.getKey()); - switch(keyID) { - case R.string.pref_key_misc_handleHttpScheme: - settings.setHandleHttpScheme((Boolean)newValue); - break; - - case R.string.pref_key_storage_dbPath: - if(TextUtils.equals(settings.getDbPath(), (String)newValue)) { - Log.d(TAG, "onPreferenceChange() new DbPath is the same"); - } else if(settings.moveDb((String)newValue)) { // TODO: do in a background thread - DbConnection.resetSession(); - - Toast.makeText(getActivity(), R.string.pref_name_storage_dbPath_dbMoved, - Toast.LENGTH_SHORT).show(); - } else { - Log.e(TAG, "onPreferenceChange() couldn't move DB; ignoring preference change"); - return false; - } - break; - } - return true; } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - Log.d(TAG, "onSharedPreferenceChanged(" + key + ")"); + Log.d(TITLE_TAG, "onSharedPreferenceChanged(" + key + ")"); boolean themeChanged = false; int keyResID = Settings.getPrefKeyIDByValue(key); - switch(keyResID) { - case R.string.pref_key_ui_theme: - themeChanged = true; - break; - - case R.string.pref_key_autoSync_enabled: - autoSyncChanged = true; - break; - - case R.string.pref_key_autoSync_interval: - autoSyncChanged = true; - break; - - case R.string.pref_key_autoSyncQueue_enabled: - autoSyncQueueChanged = true; - break; + switch (keyResID) { case R.string.pref_key_connection_advanced_customSSLSettings: case R.string.pref_key_connection_url: - Log.d(TAG, "onSharedPreferenceChanged() serviceWrapperReinitializationNeeded"); - serviceWrapperReinitializationNeeded = true; + Log.d(TITLE_TAG, "onSharedPreferenceChanged() serviceWrapperReinitializationNeeded"); + Log.i(TITLE_TAG, "applyChanges() calling WallabagServiceWrapper.resetInstance()"); + WallabagServiceWrapper.resetInstance(); case R.string.pref_key_connection_advanced_httpAuthUsername: case R.string.pref_key_connection_advanced_httpAuthPassword: case R.string.pref_key_connection_username: case R.string.pref_key_connection_password: case R.string.pref_key_connection_api_clientID: case R.string.pref_key_connection_api_clientSecret: - Log.i(TAG, "onSharedPreferenceChanged() invalidateConfiguration"); - invalidateConfiguration = true; - break; - - case R.string.pref_key_imageCache_enabled: - imageCachingChanged = true; - break; - - case R.string.pref_key_ui_readingSpeed: - readingSpeedChanged = true; - break; - - case R.string.pref_key_ui_keepScreenOn: - keepScreenOnChanged = true; + Log.i(TITLE_TAG, "onSharedPreferenceChanged() invalidateConfiguration"); break; } - switch(keyResID) { + switch (keyResID) { case R.string.pref_key_connection_url: case R.string.pref_key_connection_advanced_httpAuthUsername: case R.string.pref_key_connection_username: case R.string.pref_key_connection_api_clientID: - checkUserChanged = true; + boolean userChanged = false; + if(!TextUtils.equals(settings.getUrl(), oldUrl) + || !TextUtils.equals(settings.getUsername(), oldUsername) + || !TextUtils.equals(settings.getApiClientID(), oldApiClientID)) { + userChanged = true; + } else if(!TextUtils.equals(settings.getHttpAuthUsername(), oldHttpAuthUsername) + && (settings.getUsername() == null || settings.getUsername().isEmpty())) { + userChanged = true; + } + + if(userChanged) { + settings.setApiRefreshToken(""); + settings.setApiAccessToken(""); + + OperationsHelper.wipeDB(settings); + } break; } // not optimal :/ updateSummary(keyResID); - - if(themeChanged) { - Log.d(TAG, "onSharedPreferenceChanged() theme changed"); - - Themes.init(); - - Activity activity = getActivity(); - if(activity != null) Themes.checkTheme(activity); - } } @Override public boolean onPreferenceClick(Preference preference) { - switch(Settings.getPrefKeyIDByValue(preference.getKey())) { - case R.string.pref_key_connection_wizard: { - Activity activity = getActivity(); - if(activity != null) { - ConnectionWizardActivity.runWizard(activity, true); - - activity.finish(); - } - - return true; - } + switch (Settings.getPrefKeyIDByValue(preference.getKey())) { case R.string.pref_key_connection_autofill: { - configurationTestHelper = new ConfigurationTestHelper( + ConfigurationTestHelper configurationTestHelper = new ConfigurationTestHelper( getActivity(), this, this, settings, false); configurationTestHelper.test(); return true; } - case R.string.pref_key_sync_syncTypes_description: { - Activity activity = getActivity(); - if(activity != null) { - new AlertDialog.Builder(activity) - .setTitle(R.string.pref_name_sync_syncTypes) - .setMessage(R.string.pref_desc_sync_syncTypes_text) - .setPositiveButton(R.string.ok, null) - .show(); - } - return true; - } - case R.string.pref_key_ui_disableTouch_keyCode: { + } + + return false; + } + + private void setTextPreference(int preferenceID, String value) { + EditTextPreference preference = (EditTextPreference) + findPreference(getString(preferenceID)); + + if (preference != null) { + preference.setText(value); + } + } + + private void updateSummary(int keyResID) { +// String key = getString(keyResID); +// +// switch (keyResID) { +// case R.string.pref_key_connection_url: +// EditTextPreference preference = (EditTextPreference) +// findPreference(key); +// if (preference != null) { +// String value = preference.getText(); +// setSummary(key, (value == null || value.isEmpty()) +// ? getString(R.string.pref_desc_connection_url) : value); +// } +// break; +// +// case R.string.pref_key_connection_username: +// case R.string.pref_key_connection_api_clientID: +// case R.string.pref_key_connection_advanced_httpAuthUsername: +// setEditTextSummaryFromContent(key); +// break; +// case R.string.pref_key_connection_password: +// case R.string.pref_key_connection_api_clientSecret: +// case R.string.pref_key_connection_advanced_httpAuthPassword: +// setPasswordSummary(key); +// break; +// +// } + } + } + + public static class UIFragment extends PreferenceFragmentCompat { + private static final int[] SUMMARIES_TO_INITIATE = { + R.string.pref_key_ui_theme, + R.string.pref_key_ui_article_fontSize, + R.string.pref_key_ui_screenScrolling_percent + }; + + private Settings settings; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.ui_preferences, rootKey); + + settings = new Settings(App.getInstance()); + + Preference uiDisableTouchPreference = findPreference(getString(R.string.pref_key_ui_disableTouch_keyCode)); + if (uiDisableTouchPreference != null) { + uiDisableTouchPreference.setOnPreferenceClickListener(preference -> { showDisableTouchSetKeyCodeDialog(); return true; - } - case R.string.pref_key_misc_wipeDB: { + }); + } + + Preference uiThemePreference = findPreference(getString(R.string.pref_key_ui_theme)); + if (uiThemePreference != null) { + uiThemePreference.setOnPreferenceChangeListener((preference, result) -> { + Log.d(TITLE_TAG, "onSharedPreferenceChanged() theme changed"); + + Themes.init(); + Activity activity = getActivity(); - if(activity != null) { - new AlertDialog.Builder(activity) - .setTitle(R.string.pref_name_misc_wipeDB_confirmTitle) - .setMessage(R.string.pref_name_misc_wipeDB_confirmMessage) - .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - OperationsHelper.wipeDB(App.getInstance().getSettings()); - } - }) - .setNegativeButton(R.string.negative_answer, null) - .show(); - } + if (activity != null) Themes.checkTheme(activity); return true; - } + }); } - return false; + ListPreference themeListPreference = (ListPreference) findPreference( + getString(R.string.pref_key_ui_theme)); + if (themeListPreference != null) { + Themes.Theme[] themes = Themes.Theme.values(); + String[] themeEntries = new String[themes.length]; + String[] themeEntryValues = new String[themes.length]; + for (int i = 0; i < themes.length; i++) { + themeEntries[i] = getString(themes[i].getNameId()); + themeEntryValues[i] = themes[i].toString(); + } + + themeListPreference.setEntries(themeEntries); + themeListPreference.setEntryValues(themeEntryValues); + } } + private void showDisableTouchSetKeyCodeDialog() { Activity activity = getActivity(); - if(activity != null) { + if (activity != null) { AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setTitle(R.string.d_disableTouch_changeKey_title); - @SuppressLint("InflateParams") - final View view = activity.getLayoutInflater().inflate(R.layout.dialog_set_key, null); - final TextView keyCodeTextView = (TextView)view.findViewById(R.id.tv_keyCode); + @SuppressLint("InflateParams") final View view = activity.getLayoutInflater().inflate(R.layout.dialog_set_key, null); + final TextView keyCodeTextView = view.findViewById(R.id.tv_keyCode); - setIntToTextView(keyCodeTextView, settings.getDisableTouchKeyCode()); + // Just a Int so US locale works + keyCodeTextView.setText(String.format(Locale.US, "%d", settings.getDisableTouchKeyCode())); builder.setView(view); @@ -524,7 +383,7 @@ private void showDisableTouchSetKeyCodeDialog() { public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { if (event.getAction() != KeyEvent.ACTION_DOWN) return false; - setIntToTextView(keyCodeTextView, keyCode); + keyCodeTextView.setText(String.format(Locale.US, "%d", keyCode)); return false; } @@ -536,7 +395,8 @@ public void onClick(DialogInterface dialog, int which) { try { settings.setDisableTouchKeyCode(Integer.parseInt( keyCodeTextView.getText().toString())); - } catch(NumberFormatException ignored) {} + } catch (NumberFormatException ignored) { + } } }); builder.setNegativeButton(android.R.string.cancel, null); @@ -545,142 +405,137 @@ public void onClick(DialogInterface dialog, int which) { builder.show(); } } + } - @SuppressLint("SetTextI18n") - private void setIntToTextView(TextView textView, int value) { - textView.setText(Integer.toString(value)); - } - - @Override - public void onGetCredentialsResult(ClientCredentials clientCredentials) { - setTextPreference(R.string.pref_key_connection_api_clientID, - clientCredentials.clientID); - setTextPreference(R.string.pref_key_connection_api_clientSecret, - clientCredentials.clientSecret); - } + public static class SyncFragment extends PreferenceFragmentCompat { + private static final int[] SUMMARIES_TO_INITIATE = { + R.string.pref_key_autoSync_interval, + R.string.pref_key_autoSync_type + }; @Override - public void onGetCredentialsFail() {} + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.sync_preferences, rootKey); - @Override - public void onConfigurationTestSuccess(String url) { - Log.d(TAG, String.format("onConfigurationTestSuccess(%s)", url)); + // Show sync types description dialog + Preference sync_type_preference = findPreference(getString(R.string.pref_key_sync_syncTypes_description)); + if (sync_type_preference != null) { + sync_type_preference.setOnPreferenceClickListener(preference -> { + Activity activity = getActivity(); + if (activity != null) { + new AlertDialog.Builder(activity) + .setTitle(R.string.pref_name_sync_syncTypes) + .setMessage(R.string.pref_desc_sync_syncTypes_text) + .setPositiveButton(R.string.ok, null) + .show(); + } + return true; + }); + } - if(url != null) { - setTextPreference(R.string.pref_key_connection_url, url); + // Set sync interval + ListPreference autoSyncIntervalListPreference = (ListPreference) findPreference( + getString(R.string.pref_key_autoSync_interval)); + if (autoSyncIntervalListPreference != null) { + // may set arbitrary values on Android API 19+ + autoSyncIntervalListPreference.setEntries(new String[]{ + getString(R.string.pref_option_autoSync_interval_15m), + getString(R.string.pref_option_autoSync_interval_30m), + getString(R.string.pref_option_autoSync_interval_1h), + getString(R.string.pref_option_autoSync_interval_12h), + getString(R.string.pref_option_autoSync_interval_24h) + }); + autoSyncIntervalListPreference.setEntryValues(new String[]{ + String.valueOf(AlarmManager.INTERVAL_FIFTEEN_MINUTES), + String.valueOf(AlarmManager.INTERVAL_HALF_HOUR), + String.valueOf(AlarmManager.INTERVAL_HOUR), + String.valueOf(AlarmManager.INTERVAL_HALF_DAY), + String.valueOf(AlarmManager.INTERVAL_DAY) + }); } + } - settings.setConfigurationOk(true); - settings.setConfigurationErrorShown(false); - invalidateConfiguration = false; + } - Toast.makeText(getActivity(), R.string.settings_parametersAutofilled, - Toast.LENGTH_SHORT).show(); - } + public static class MiscellaneousFragment extends PreferenceFragmentCompat { + private static final int[] SUMMARIES_TO_INITIATE = { + R.string.pref_key_storage_dbPath + }; + private Settings settings; @Override - public void onConnectionTestFail(WallabagWebService.ConnectionTestResult result, - String details) {} + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.miscellaneous_preferences, rootKey); - @Override - public void onApiAccessTestFail(TestApiAccessTask.Result result, String details) {} + settings = new Settings(App.getInstance()); - private void setOnClickListener(int keyResID) { - Preference preference = findPreference(getString(keyResID)); - if(preference != null) { - preference.setOnPreferenceClickListener(this); + Preference wipe_db_preference = findPreference(getString(R.string.pref_key_misc_wipeDB)); + if (wipe_db_preference != null) { + wipe_db_preference.setOnPreferenceClickListener(preference -> { + Activity activity = getActivity(); + if (activity != null) { + new AlertDialog.Builder(activity) + .setTitle(R.string.pref_name_misc_wipeDB_confirmTitle) + .setMessage(R.string.pref_name_misc_wipeDB_confirmMessage) + .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + OperationsHelper.wipeDB(App.getInstance().getSettings()); + } + }) + .setNegativeButton(R.string.negative_answer, null) + .show(); + } + return true; + }); } - } - private void setTextPreference(int preferenceID, String value) { - EditTextPreference preference = (EditTextPreference) - findPreference(getString(preferenceID)); - if(preference != null) { - preference.setText(value); + Preference handleHttpSchemePreference = findPreference( + getString(R.string.pref_key_misc_handleHttpScheme)); + if (handleHttpSchemePreference != null) { + handleHttpSchemePreference.setDefaultValue(settings.isHandlingHttpScheme()); + handleHttpSchemePreference.setOnPreferenceChangeListener((preference, newValue) -> { + settings.setHandleHttpScheme((Boolean) newValue); + return true; + }); } - } - private void updateSummary(int keyResID) { - String key = getString(keyResID); + ListPreference dbPathListPreference = (ListPreference) findPreference( + getString(R.string.pref_key_storage_dbPath)); + if (dbPathListPreference != null) { + List entriesList = new ArrayList<>(2); + List entryValuesList = new ArrayList<>(2); - switch(keyResID) { - case R.string.pref_key_connection_url: - EditTextPreference preference = (EditTextPreference) - findPreference(key); - if(preference != null) { - String value = preference.getText(); - setSummary(key, (value == null || value.isEmpty()) - ? getString(R.string.pref_desc_connection_url) : value); - } - break; + entriesList.add(getString(R.string.pref_name_storage_dbPath_internalStorage)); + entryValuesList.add(""); - case R.string.pref_key_connection_username: - case R.string.pref_key_connection_api_clientID: - case R.string.pref_key_connection_advanced_httpAuthUsername: - case R.string.pref_key_ui_article_fontSize: - case R.string.pref_key_ui_screenScrolling_percent: - setEditTextSummaryFromContent(key); - break; + if (StorageHelper.isExternalStorageWritable()) { + entriesList.add(getString(R.string.pref_name_storage_dbPath_externalStorage)); + entryValuesList.add(StorageHelper.getExternalStoragePath()); + } - case R.string.pref_key_ui_theme: - case R.string.pref_key_autoSync_interval: - case R.string.pref_key_autoSync_type: - setListSummaryFromContent(key); - break; + dbPathListPreference.setEntries(entriesList.toArray(new String[0])); + dbPathListPreference.setEntryValues(entryValuesList.toArray(new String[0])); - case R.string.pref_key_connection_password: - case R.string.pref_key_connection_api_clientSecret: - case R.string.pref_key_connection_advanced_httpAuthPassword: - setPasswordSummary(key); - break; + dbPathListPreference.setOnPreferenceChangeListener((preference, newValue) -> { + if (TextUtils.equals(settings.getDbPath(), (String) newValue)) { + Log.d(TITLE_TAG, "onPreferenceChange() new DbPath is the same"); + } else if (settings.moveDb((String) newValue)) { // TODO: do in a background thread + DbConnection.resetSession(); - case R.string.pref_key_storage_dbPath: - ListPreference dbPathListPreference = (ListPreference)findPreference( - getString(R.string.pref_key_storage_dbPath)); - if(dbPathListPreference != null) { - CharSequence value = dbPathListPreference.getEntry(); - if(TextUtils.isEmpty(value)) { - dbPathListPreference.setSummary(R.string.pref_name_storage_dbPath_internalStorage); - } else if(value.equals(StorageHelper.getExternalStoragePath())) { - dbPathListPreference.setSummary(R.string.pref_name_storage_dbPath_externalStorage); - } else { - dbPathListPreference.setSummary(value); - } + Toast.makeText(getActivity(), R.string.pref_name_storage_dbPath_dbMoved, + Toast.LENGTH_SHORT).show(); + } else { + Log.e(TITLE_TAG, "onPreferenceChange() couldn't move DB; ignoring preference change"); + return false; } - break; - } - } - - private void setSummary(String key, String text) { - Preference preference = findPreference(key); - if(preference != null) { - preference.setSummary(text); - } - } - - private void setEditTextSummaryFromContent(String key) { - EditTextPreference preference = (EditTextPreference)findPreference(key); - if(preference != null) { - preference.setSummary(preference.getText()); - } - } - - private void setListSummaryFromContent(String key) { - ListPreference preference = (ListPreference)findPreference(key); - if(preference != null) { - preference.setSummary(preference.getEntry()); + return true; + }); } } - private void setPasswordSummary(String key) { - EditTextPreference preference = (EditTextPreference)findPreference(key); - if(preference != null) { - String value = preference.getText(); - preference.setSummary(value == null || value.isEmpty() ? "" : "********"); - } - } } diff --git a/app/src/main/res/anim/bottom_sheet_slide_in.xml b/app/src/main/res/anim/bottom_sheet_slide_in.xml new file mode 100644 index 000000000..75b489191 --- /dev/null +++ b/app/src/main/res/anim/bottom_sheet_slide_in.xml @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/app/src/main/res/anim/bottom_sheet_slide_out.xml b/app/src/main/res/anim/bottom_sheet_slide_out.xml new file mode 100644 index 000000000..465f9730e --- /dev/null +++ b/app/src/main/res/anim/bottom_sheet_slide_out.xml @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable-hdpi/ic_action_next_item.png b/app/src/main/res/drawable-hdpi/ic_action_next_item.png deleted file mode 100644 index fc998a511..000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_action_next_item.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_action_previous_item.png b/app/src/main/res/drawable-hdpi/ic_action_previous_item.png deleted file mode 100644 index 10fcec8a6..000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_action_previous_item.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_action_refresh.png b/app/src/main/res/drawable-hdpi/ic_action_refresh.png deleted file mode 100644 index dae27903e..000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_action_refresh.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_refresh.png b/app/src/main/res/drawable-mdpi/ic_action_refresh.png deleted file mode 100644 index 94ab6f4c5..000000000 Binary files a/app/src/main/res/drawable-mdpi/ic_action_refresh.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/welcome.png b/app/src/main/res/drawable-mdpi/welcome.png deleted file mode 100755 index 8aeb2b3d7..000000000 Binary files a/app/src/main/res/drawable-mdpi/welcome.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/welcome_white.png b/app/src/main/res/drawable-mdpi/welcome_white.png deleted file mode 100755 index 1919b2a8c..000000000 Binary files a/app/src/main/res/drawable-mdpi/welcome_white.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_refresh.png b/app/src/main/res/drawable-xhdpi/ic_action_refresh.png deleted file mode 100644 index ab4ab9da6..000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_action_refresh.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_refresh.png b/app/src/main/res/drawable-xxhdpi/ic_action_refresh.png deleted file mode 100644 index 44ee117ee..000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_refresh.png and /dev/null differ diff --git a/app/src/main/res/drawable/ic_account_circle_24dp.xml b/app/src/main/res/drawable/ic_account_circle_24dp.xml new file mode 100644 index 000000000..3e6344ab0 --- /dev/null +++ b/app/src/main/res/drawable/ic_account_circle_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_black_24dp.xml b/app/src/main/res/drawable/ic_add_24dp.xml similarity index 78% rename from app/src/main/res/drawable/ic_add_black_24dp.xml rename to app/src/main/res/drawable/ic_add_24dp.xml index 0258249cc..c443e922b 100644 --- a/app/src/main/res/drawable/ic_add_black_24dp.xml +++ b/app/src/main/res/drawable/ic_add_24dp.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?colorOnSurface"> diff --git a/app/src/main/res/drawable/ic_before_24dp.xml b/app/src/main/res/drawable/ic_before_24dp.xml new file mode 100644 index 000000000..e794c28de --- /dev/null +++ b/app/src/main/res/drawable/ic_before_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_cloud_24dp.xml b/app/src/main/res/drawable/ic_cloud_24dp.xml new file mode 100644 index 000000000..c11445a0b --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_black_24dp.xml b/app/src/main/res/drawable/ic_delete_24dp.xml similarity index 81% rename from app/src/main/res/drawable/ic_delete_black_24dp.xml rename to app/src/main/res/drawable/ic_delete_24dp.xml index 39e64d698..192880452 100644 --- a/app/src/main/res/drawable/ic_delete_black_24dp.xml +++ b/app/src/main/res/drawable/ic_delete_24dp.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?colorOnSurface"> diff --git a/app/src/main/res/drawable/ic_done_24dp.xml b/app/src/main/res/drawable/ic_done_24dp.xml new file mode 100644 index 000000000..c108a0bd7 --- /dev/null +++ b/app/src/main/res/drawable/ic_done_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_done_black_24dp.xml b/app/src/main/res/drawable/ic_done_black_24dp.xml deleted file mode 100644 index 83ee7bb4e..000000000 --- a/app/src/main/res/drawable/ic_done_black_24dp.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_done_solarized_24dp.xml b/app/src/main/res/drawable/ic_done_solarized_24dp.xml deleted file mode 100644 index 7196f0d21..000000000 --- a/app/src/main/res/drawable/ic_done_solarized_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_done_white_24dp.xml b/app/src/main/res/drawable/ic_done_white_24dp.xml deleted file mode 100644 index 6541ee3e3..000000000 --- a/app/src/main/res/drawable/ic_done_white_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_fast_forward_24dp.xml b/app/src/main/res/drawable/ic_fast_forward_24dp.xml index fd9249f61..f80224d03 100644 --- a/app/src/main/res/drawable/ic_fast_forward_24dp.xml +++ b/app/src/main/res/drawable/ic_fast_forward_24dp.xml @@ -1,8 +1,9 @@ + android:width="24dp" + android:height="24dp" + android:tint="?colorOnSurface" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> diff --git a/app/src/main/res/drawable/ic_fast_rewind_24dp.xml b/app/src/main/res/drawable/ic_fast_rewind_24dp.xml index 6d7685e7a..15c5d39c3 100644 --- a/app/src/main/res/drawable/ic_fast_rewind_24dp.xml +++ b/app/src/main/res/drawable/ic_fast_rewind_24dp.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?colorOnSurface"> diff --git a/app/src/main/res/drawable/ic_favorite_24dp.xml b/app/src/main/res/drawable/ic_favorite_24dp.xml new file mode 100644 index 000000000..8b28112a4 --- /dev/null +++ b/app/src/main/res/drawable/ic_favorite_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_favorite_outline_24dp.xml b/app/src/main/res/drawable/ic_favorite_outline_24dp.xml new file mode 100644 index 000000000..024b2911b --- /dev/null +++ b/app/src/main/res/drawable/ic_favorite_outline_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_file_download_24dp.xml b/app/src/main/res/drawable/ic_file_download_24dp.xml index e43b8645a..6fd93116b 100644 --- a/app/src/main/res/drawable/ic_file_download_24dp.xml +++ b/app/src/main/res/drawable/ic_file_download_24dp.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?colorOnSurface"> diff --git a/app/src/main/res/drawable/ic_info_outline_black_24dp.xml b/app/src/main/res/drawable/ic_info_outline_24dp.xml similarity index 67% rename from app/src/main/res/drawable/ic_info_outline_black_24dp.xml rename to app/src/main/res/drawable/ic_info_outline_24dp.xml index cf53e145c..3f66d8d8b 100644 --- a/app/src/main/res/drawable/ic_info_outline_black_24dp.xml +++ b/app/src/main/res/drawable/ic_info_outline_24dp.xml @@ -1,8 +1,9 @@ + android:width="24dp" + android:height="24dp" + android:tint="?colorOnSurface" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> diff --git a/app/src/main/res/drawable/ic_list_black_24dp.xml b/app/src/main/res/drawable/ic_list_24dp.xml similarity index 82% rename from app/src/main/res/drawable/ic_list_black_24dp.xml rename to app/src/main/res/drawable/ic_list_24dp.xml index 4c2fb8834..6e32ba49d 100644 --- a/app/src/main/res/drawable/ic_list_black_24dp.xml +++ b/app/src/main/res/drawable/ic_list_24dp.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?colorOnSurface"> diff --git a/app/src/main/res/drawable/ic_mark_unread_24dp.xml b/app/src/main/res/drawable/ic_mark_unread_24dp.xml new file mode 100644 index 000000000..daf9f20ca --- /dev/null +++ b/app/src/main/res/drawable/ic_mark_unread_24dp.xml @@ -0,0 +1,6 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_24dp.xml b/app/src/main/res/drawable/ic_menu_24dp.xml index 84b1d3b4f..098986543 100644 --- a/app/src/main/res/drawable/ic_menu_24dp.xml +++ b/app/src/main/res/drawable/ic_menu_24dp.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?colorOnSurface"> diff --git a/app/src/main/res/drawable/ic_messages_24dp.xml b/app/src/main/res/drawable/ic_messages_24dp.xml new file mode 100644 index 000000000..d75652b6f --- /dev/null +++ b/app/src/main/res/drawable/ic_messages_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_more_horiz_24dp.xml b/app/src/main/res/drawable/ic_more_horiz_24dp.xml index 2acd55b29..dab5b236e 100644 --- a/app/src/main/res/drawable/ic_more_horiz_24dp.xml +++ b/app/src/main/res/drawable/ic_more_horiz_24dp.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?colorOnSurface"> diff --git a/app/src/main/res/drawable/ic_musical_notes_24dp.xml b/app/src/main/res/drawable/ic_musical_notes_24dp.xml index 8b3bd637d..d3dc6cabc 100644 --- a/app/src/main/res/drawable/ic_musical_notes_24dp.xml +++ b/app/src/main/res/drawable/ic_musical_notes_24dp.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?colorOnSurface"> diff --git a/app/src/main/res/drawable/ic_next_24dp.xml b/app/src/main/res/drawable/ic_next_24dp.xml new file mode 100644 index 000000000..64ea74687 --- /dev/null +++ b/app/src/main/res/drawable/ic_next_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_play_arrow_24dp.xml b/app/src/main/res/drawable/ic_play_arrow_24dp.xml index bf9b895ac..805761b0e 100644 --- a/app/src/main/res/drawable/ic_play_arrow_24dp.xml +++ b/app/src/main/res/drawable/ic_play_arrow_24dp.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?colorOnSurface"> diff --git a/app/src/main/res/drawable/ic_redo_24dp.xml b/app/src/main/res/drawable/ic_redo_24dp.xml index 424e788f5..e6b5bcf19 100644 --- a/app/src/main/res/drawable/ic_redo_24dp.xml +++ b/app/src/main/res/drawable/ic_redo_24dp.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?colorOnSurface"> diff --git a/app/src/main/res/drawable/ic_refresh_24dp.xml b/app/src/main/res/drawable/ic_refresh_24dp.xml new file mode 100644 index 000000000..32550e832 --- /dev/null +++ b/app/src/main/res/drawable/ic_refresh_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_running_24dp.xml b/app/src/main/res/drawable/ic_running_24dp.xml index e88d5160f..3e5c2df0e 100644 --- a/app/src/main/res/drawable/ic_running_24dp.xml +++ b/app/src/main/res/drawable/ic_running_24dp.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?colorOnSurface"> + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 07aba89fe..4c984e8b0 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,7 +6,7 @@ android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" - android:fitsSystemWindows="true" + android:theme="@style/ThemeOverlay.MyTheme.NavigationView" tools:openDrawer="start"> - - + - - - - - - - + android:layout_height="wrap_content" + app:layout_scrollFlags="scroll|enterAlways" + app:titleTextColor="?colorOnBackground" /> diff --git a/app/src/main/res/layout/article.xml b/app/src/main/res/layout/article.xml index 75ae797ff..6e8d599d8 100644 --- a/app/src/main/res/layout/article.xml +++ b/app/src/main/res/layout/article.xml @@ -1,29 +1,49 @@ - - + + + + + + + + tools:ignore="UselessParent" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> - - -