From be328e48b450114ae13e7f16fabf80d0297cc967 Mon Sep 17 00:00:00 2001 From: haanhvu Date: Tue, 21 Jan 2025 20:37:38 +0700 Subject: [PATCH] First step for #1318: Create initial New Tab page that has Wolvic logo and add an option in Display Settings to set New Tab page as homepage This should be released when all the steps have been done and #1318 is closed. --- .../wolvic/ui/viewmodel/WindowViewModel.java | 63 +++++++++++- .../igalia/wolvic/ui/views/NewTabView.java | 42 ++++++++ .../wolvic/ui/views/library/LibraryPanel.java | 1 + .../ui/widgets/NavigationBarWidget.java | 22 ++++- .../igalia/wolvic/ui/widgets/TrayWidget.java | 2 +- .../wolvic/ui/widgets/WindowWidget.java | 96 +++++++++++++++---- .../com/igalia/wolvic/ui/widgets/Windows.java | 30 +++++- .../widgets/settings/DisplayOptionsView.java | 52 +++++++++- .../com/igalia/wolvic/utils/UrlUtils.java | 8 +- .../res/layout/navigation_bar_navigation.xml | 6 +- app/src/main/res/layout/new_tab.xml | 18 ++++ app/src/main/res/layout/options_display.xml | 11 ++- app/src/main/res/layout/tray.xml | 6 +- app/src/main/res/values/options_values.xml | 7 ++ app/src/main/res/values/strings.xml | 16 +++- 15 files changed, 333 insertions(+), 47 deletions(-) create mode 100644 app/src/common/shared/com/igalia/wolvic/ui/views/NewTabView.java create mode 100644 app/src/main/res/layout/new_tab.xml diff --git a/app/src/common/shared/com/igalia/wolvic/ui/viewmodel/WindowViewModel.java b/app/src/common/shared/com/igalia/wolvic/ui/viewmodel/WindowViewModel.java index c44a285ed4a..125f1296c0b 100644 --- a/app/src/common/shared/com/igalia/wolvic/ui/viewmodel/WindowViewModel.java +++ b/app/src/common/shared/com/igalia/wolvic/ui/viewmodel/WindowViewModel.java @@ -37,6 +37,7 @@ public class WindowViewModel extends AndroidViewModel { private int mURLWebsiteColor; private MutableLiveData url; + private MutableLiveData urlForwardFromNewTab; private MutableLiveData hint; private MutableLiveData isWindowVisible; private MutableLiveData placement; @@ -53,7 +54,9 @@ public class WindowViewModel extends AndroidViewModel { private MutableLiveData isActiveWindow; private MediatorLiveData isTitleBarVisible; private MutableLiveData currentContentType; + public MutableLiveData lastContentType; private MediatorLiveData isNativeContentVisible; + private MutableLiveData backToNewTabEnabled; private MutableLiveData isLoading; private MutableLiveData isMicrophoneEnabled; private MutableLiveData isBookmarked; @@ -64,6 +67,7 @@ public class WindowViewModel extends AndroidViewModel { private MutableLiveData isPopUpAvailable; private MutableLiveData isPopUpBlocked; private MutableLiveData canGoForward; + private MutableLiveData canGoForwardFromNewTab; private MutableLiveData canGoBack; private MutableLiveData isInVRVideo; private MutableLiveData autoEnteredVRVideo; @@ -92,6 +96,7 @@ public WindowViewModel(Application application) { mURLWebsiteColor = typedValue.data; url = new MutableLiveData<>(new SpannableString("")); + urlForwardFromNewTab = new MutableLiveData<>(new SpannableString("")); hint = new MutableLiveData<>(""); isWindowVisible = new MutableLiveData<>(new ObservableBoolean(true)); placement = new MutableLiveData<>(Windows.WindowPlacement.FRONT); @@ -134,11 +139,15 @@ public WindowViewModel(Application application) { isTitleBarVisible.setValue(new ObservableBoolean(true)); currentContentType = new MutableLiveData<>(Windows.ContentType.WEB_CONTENT); + lastContentType = new MutableLiveData<>(Windows.ContentType.WEB_CONTENT); + isNativeContentVisible = new MediatorLiveData<>(); isNativeContentVisible.addSource(currentContentType, contentType -> isNativeContentVisible.setValue(new ObservableBoolean(contentType != Windows.ContentType.WEB_CONTENT)) ); - isNativeContentVisible.setValue(new ObservableBoolean(currentContentType.getValue() != Windows.ContentType.WEB_CONTENT)); + isNativeContentVisible.setValue(new ObservableBoolean(currentContentType.getValue() != Windows.ContentType.WEB_CONTENT && currentContentType.getValue() != Windows.ContentType.NEW_TAB)); + + backToNewTabEnabled = new MutableLiveData<>(new ObservableBoolean(false)); isLoading = new MutableLiveData<>(new ObservableBoolean(false)); isMicrophoneEnabled = new MutableLiveData<>(new ObservableBoolean(true)); @@ -150,6 +159,7 @@ public WindowViewModel(Application application) { isPopUpAvailable = new MutableLiveData<>(new ObservableBoolean(false)); isPopUpBlocked = new MutableLiveData<>(new ObservableBoolean(false)); canGoForward = new MutableLiveData<>(new ObservableBoolean(false)); + canGoForwardFromNewTab = new MutableLiveData<>(new ObservableBoolean(false)); canGoBack = new MutableLiveData<>(new ObservableBoolean(false)); isInVRVideo = new MutableLiveData<>(new ObservableBoolean(false)); autoEnteredVRVideo = new MutableLiveData<>(new ObservableBoolean(false)); @@ -239,9 +249,12 @@ public void onChanged(ObservableBoolean o) { @Override public void onChanged(Spannable aUrl) { String url = aUrl.toString(); - if (isNativeContentVisible.getValue().get()) { + if (isNativeContentVisible.getValue().get() && currentContentType.getValue() != Windows.ContentType.NEW_TAB) { url = getApplication().getString(R.string.url_library_title); + } else if (currentContentType.getValue() == Windows.ContentType.NEW_TAB) { + url = getApplication().getString(R.string.url_new_tab_title); + } else { if (UrlUtils.isPrivateAboutPage(getApplication(), url) || (UrlUtils.isDataUri(url) && isPrivateSession.getValue().get())) { @@ -336,6 +349,7 @@ public void onChanged(ObservableBoolean o) { public void refresh() { url.postValue(url.getValue()); + urlForwardFromNewTab.postValue(urlForwardFromNewTab.getValue()); hint.postValue(getHintValue()); isWindowVisible.postValue(isWindowVisible.getValue()); placement.postValue(placement.getValue()); @@ -352,6 +366,7 @@ public void refresh() { isPopUpAvailable.postValue(isPopUpAvailable.getValue()); isPopUpBlocked.postValue(isPopUpBlocked.getValue()); canGoForward.postValue(canGoForward.getValue()); + canGoForwardFromNewTab.postValue(canGoForwardFromNewTab.getValue()); canGoBack.postValue(canGoBack.getValue()); isInVRVideo.postValue(isInVRVideo.getValue()); autoEnteredVRVideo.postValue(autoEnteredVRVideo.getValue()); @@ -374,10 +389,18 @@ public MutableLiveData getUrl() { return url; } + public MutableLiveData getUrlForwardFromNewTab() { + if (urlForwardFromNewTab == null) { + urlForwardFromNewTab = new MutableLiveData<>(new SpannableString("")); + } + return urlForwardFromNewTab; + } + public void setUrl(@Nullable String url) { if (url == null) { return; } + setUrl(new SpannableString(url)); } @@ -421,9 +444,17 @@ private void setUrl(@Nullable Spannable url) { spannable.setSpan(color1, 0, index + 3, 0); spannable.setSpan(color2, index + 3, aURL.length(), 0); this.url.postValue(spannable); + //TODO: Allow other about links outside of library + if (currentContentType.getValue() == Windows.ContentType.WEB_CONTENT && lastContentType.getValue() == Windows.ContentType.NEW_TAB && !aURL.startsWith("about")) { + urlForwardFromNewTab.postValue(spannable); + } } else { this.url.postValue(url); + //TODO: Allow other about links outside of library + if (currentContentType.getValue() == Windows.ContentType.WEB_CONTENT && lastContentType.getValue() == Windows.ContentType.NEW_TAB && !aURL.startsWith("about")) { + urlForwardFromNewTab.postValue(url); + } } } } @@ -434,9 +465,12 @@ public MutableLiveData getHint() { } private String getHintValue() { - if (isNativeContentVisible.getValue().get()) { + if (isNativeContentVisible.getValue().get() && currentContentType.getValue() != Windows.ContentType.NEW_TAB) { return getApplication().getString(R.string.url_library_title); + } else if (currentContentType.getValue() == Windows.ContentType.NEW_TAB) { + return getApplication().getString(R.string.url_new_tab_title); + } else { return getApplication().getString(R.string.search_placeholder); } @@ -571,6 +605,11 @@ public void setIsActiveWindow(boolean isActiveWindow) { } public void setCurrentContentType(Windows.ContentType contentType) { + // No need to store lastContentType when we switch content types in library + if (!currentContentType.getValue().isLibraryContent() || !contentType.isLibraryContent()) { + lastContentType.postValue(currentContentType.getValue()); + } + currentContentType.postValue(contentType); } @@ -583,6 +622,15 @@ public MutableLiveData getIsNativeContentVisible() { return isNativeContentVisible; } + public void enableBackToNewTab(boolean backToNewTabEnabled) { + this.backToNewTabEnabled.postValue(new ObservableBoolean(backToNewTabEnabled)); + } + + @NonNull + public MutableLiveData getBackToNewTabEnabled() { + return backToNewTabEnabled; + } + @NonNull public MutableLiveData getIsLoading() { return isLoading; @@ -673,6 +721,15 @@ public void setCanGoForward(boolean canGoForward) { this.canGoForward.postValue(new ObservableBoolean(canGoForward)); } + @NonNull + public MutableLiveData getCanGoForwardFromNewTab() { + return canGoForwardFromNewTab; + } + + public void setCanGoForwardFromNewTab(boolean canGoForwardFromNewTab) { + this.canGoForwardFromNewTab.postValue(new ObservableBoolean(canGoForwardFromNewTab)); + } + @NonNull public MutableLiveData getCanGoBack() { return canGoBack; diff --git a/app/src/common/shared/com/igalia/wolvic/ui/views/NewTabView.java b/app/src/common/shared/com/igalia/wolvic/ui/views/NewTabView.java new file mode 100644 index 00000000000..3bedd8eca0b --- /dev/null +++ b/app/src/common/shared/com/igalia/wolvic/ui/views/NewTabView.java @@ -0,0 +1,42 @@ +package com.igalia.wolvic.ui.views; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.view.LayoutInflater; +import android.widget.FrameLayout; + +import androidx.databinding.DataBindingUtil; + +import com.igalia.wolvic.R; +import com.igalia.wolvic.VRBrowserActivity; +import com.igalia.wolvic.databinding.NewTabBinding; +import com.igalia.wolvic.ui.widgets.WidgetManagerDelegate; + +public class NewTabView extends FrameLayout { + + private WidgetManagerDelegate mWidgetManager; + + private NewTabBinding mBinding; + + public NewTabView(Context context) { + super(context); + initialize(); + } + + protected void initialize() { + mWidgetManager = ((VRBrowserActivity) getContext()); + updateUI(); + } + + @SuppressLint("ClickableViewAccessibility") + public void updateUI() { + removeAllViews(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); + + mBinding = DataBindingUtil.inflate(inflater, R.layout.new_tab, this, true); + mBinding.setLifecycleOwner((VRBrowserActivity)getContext()); + + mBinding.executePendingBindings(); + } +} \ No newline at end of file diff --git a/app/src/common/shared/com/igalia/wolvic/ui/views/library/LibraryPanel.java b/app/src/common/shared/com/igalia/wolvic/ui/views/library/LibraryPanel.java index 7140d88953f..ab2d3ff5df3 100644 --- a/app/src/common/shared/com/igalia/wolvic/ui/views/library/LibraryPanel.java +++ b/app/src/common/shared/com/igalia/wolvic/ui/views/library/LibraryPanel.java @@ -177,6 +177,7 @@ public void onDestroy() { mSystemNotificationsView.onDestroy(); } + @NonNull public Windows.ContentType getSelectedPanelType() { if (mCurrentView == mBookmarksView) { return Windows.ContentType.BOOKMARKS; diff --git a/app/src/common/shared/com/igalia/wolvic/ui/widgets/NavigationBarWidget.java b/app/src/common/shared/com/igalia/wolvic/ui/widgets/NavigationBarWidget.java index 9c972344935..337ae31b94f 100644 --- a/app/src/common/shared/com/igalia/wolvic/ui/widgets/NavigationBarWidget.java +++ b/app/src/common/shared/com/igalia/wolvic/ui/widgets/NavigationBarWidget.java @@ -247,6 +247,8 @@ private void updateUI() { if (getSession().canGoBack()) { getSession().goBack(); + } else if (mViewModel.getBackToNewTabEnabled().getValue().get()) { + getSession().loadUri(UrlUtils.ABOUT_NEWTAB); } if (mAudio != null) { @@ -257,7 +259,18 @@ private void updateUI() { mBinding.navigationBarNavigation.forwardButton.setOnClickListener(v -> { v.requestFocusFromTouch(); - getSession().goForward(); + if (mViewModel.getCanGoForwardFromNewTab().getValue().get()) { + String forwardUrl = mViewModel.getUrlForwardFromNewTab().getValue().toString(); + getSession().loadUri(forwardUrl); + + mAttachedWindow.hideNewTab(true); + + mViewModel.setCurrentContentType(Windows.ContentType.WEB_CONTENT); + mViewModel.setUrl(forwardUrl); + mViewModel.setCanGoForwardFromNewTab(false); + } else { + getSession().goForward(); + } if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); } @@ -1024,7 +1037,10 @@ public void onLocationChange(@NonNull WSession session, @Nullable String url) { updateTrackingProtection(); } - mBinding.navigationBarNavigation.reloadButton.setEnabled(!UrlUtils.isPrivateAboutPage(getContext(), url)); + mBinding.navigationBarNavigation.reloadButton.setEnabled( + mViewModel.getCurrentContentType().getValue() != Windows.ContentType.NEW_TAB + && !mViewModel.getIsNativeContentVisible().getValue().get() + && !UrlUtils.isPrivateAboutPage(getContext(), url)); } // Content delegate @@ -1390,7 +1406,7 @@ public void onSwitchMode() { public void onAddons() { hideMenu(); - mAttachedWindow.showPanel(Windows.ContentType.ADDONS); + mAttachedWindow.showLibraryPanel(Windows.ContentType.ADDONS); } @Override diff --git a/app/src/common/shared/com/igalia/wolvic/ui/widgets/TrayWidget.java b/app/src/common/shared/com/igalia/wolvic/ui/widgets/TrayWidget.java index 8c600061750..bef517a2f07 100644 --- a/app/src/common/shared/com/igalia/wolvic/ui/widgets/TrayWidget.java +++ b/app/src/common/shared/com/igalia/wolvic/ui/widgets/TrayWidget.java @@ -605,7 +605,7 @@ public void attachToWindow(@NonNull WindowWidget aWindow) { } private Observer mCurrentContentTypeObserver = contentType -> { - if (contentType == Windows.ContentType.WEB_CONTENT) { + if (contentType == Windows.ContentType.WEB_CONTENT || contentType == Windows.ContentType.NEW_TAB) { animateButtonPadding(mBinding.bookmarksButton, mMaxPadding, ICON_ANIMATION_DURATION); animateButtonPadding(mBinding.downloadsButton, mMaxPadding, ICON_ANIMATION_DURATION); } else if (contentType == Windows.ContentType.DOWNLOADS) { diff --git a/app/src/common/shared/com/igalia/wolvic/ui/widgets/WindowWidget.java b/app/src/common/shared/com/igalia/wolvic/ui/widgets/WindowWidget.java index 821e68f7313..46e99cfea22 100644 --- a/app/src/common/shared/com/igalia/wolvic/ui/widgets/WindowWidget.java +++ b/app/src/common/shared/com/igalia/wolvic/ui/widgets/WindowWidget.java @@ -62,6 +62,7 @@ import com.igalia.wolvic.telemetry.TelemetryService; import com.igalia.wolvic.ui.adapters.WebApp; import com.igalia.wolvic.ui.viewmodel.WindowViewModel; +import com.igalia.wolvic.ui.views.NewTabView; import com.igalia.wolvic.ui.views.library.LibraryPanel; import com.igalia.wolvic.ui.widgets.dialogs.PromptDialogWidget; import com.igalia.wolvic.ui.widgets.dialogs.SelectionActionWidget; @@ -134,6 +135,7 @@ public class WindowWidget extends UIWidget implements SessionChangeListener, private Session mSession; private int mWindowId; private LibraryPanel mLibrary; + private NewTabView mNewTab; private Windows.WindowPlacement mWindowPlacement = Windows.WindowPlacement.FRONT; private Windows.WindowPlacement mWindowPlacementBeforeFullscreen = Windows.WindowPlacement.FRONT; private float mMaxWindowScale = 3; @@ -217,6 +219,7 @@ private void initialize(Context aContext) { setupListeners(mSession); mLibrary = new LibraryPanel(aContext); + mNewTab = new NewTabView(aContext); SessionStore.get().getBookmarkStore().addListener(mBookmarksListener); @@ -501,31 +504,30 @@ public int getWindowHeight() { return mWidgetPlacement.height; } + @NonNull public Windows.ContentType getSelectedPanel() { return mLibrary.getSelectedPanelType(); } private void hideLibraryPanel() { - if (mViewModel.getIsNativeContentVisible().getValue().get()) { + if (getCurrentContentType().isLibraryContent()) { hidePanel(true); } } Runnable mRestoreFirstPaint; - public void showPanel(Windows.ContentType panelType) { - if (panelType == Windows.ContentType.WEB_CONTENT) { - hidePanel(); - } else { - showPanel(panelType, true); - } + public void showLibraryPanel(Windows.ContentType panelType) { + assert panelType != Windows.ContentType.NEW_TAB && panelType != Windows.ContentType.WEB_CONTENT && panelType != Windows.ContentType.NOTIFICATIONS; + showLibraryPanel(panelType, true); } - private void showPanel(Windows.ContentType contentType, boolean switchSurface) { + private void showLibraryPanel(Windows.ContentType contentType, boolean switchSurface) { if (mLibrary == null) { return; } + hideNewTab(false); mViewModel.setIsFindInPage(false); mViewModel.setCurrentContentType(contentType); mViewModel.setUrl(contentType.URL); @@ -533,12 +535,14 @@ private void showPanel(Windows.ContentType contentType, boolean switchSurface) { setView(mLibrary, switchSurface); mLibrary.selectPanel(contentType); mLibrary.onShow(); - if (mRestoreFirstPaint == null && !isFirstPaintReady() && (mFirstDrawCallback != null) && (mSurface != null)) { - final Runnable firstDrawCallback = mFirstDrawCallback; + if (mRestoreFirstPaint == null) { onFirstContentfulPaint(mSession.getWSession()); mRestoreFirstPaint = () -> { setFirstPaintReady(false); - setFirstDrawCallback(firstDrawCallback); + if (mFirstDrawCallback != null) { + final Runnable firstDrawCallback = mFirstDrawCallback; + setFirstDrawCallback(firstDrawCallback); + } if (mWidgetManager != null) { mWidgetManager.updateWidget(WindowWidget.this); } @@ -549,6 +553,32 @@ private void showPanel(Windows.ContentType contentType, boolean switchSurface) { } } + public void showNewTab() { + if (mNewTab != null) { + mViewModel.setIsFindInPage(false); + mViewModel.setCurrentContentType(Windows.ContentType.NEW_TAB); + mViewModel.setUrl(Windows.ContentType.NEW_TAB.URL); + setView(mNewTab, true); + if (mRestoreFirstPaint == null) { + onFirstContentfulPaint(mSession.getWSession()); + mRestoreFirstPaint = () -> { + setFirstPaintReady(false); + if (mFirstDrawCallback != null) { + final Runnable firstDrawCallback = mFirstDrawCallback; + setFirstDrawCallback(firstDrawCallback); + } + if (mWidgetManager != null) { + mWidgetManager.updateWidget(WindowWidget.this); + } + }; + } + } + if (mViewModel.getBackToNewTabEnabled().getValue().get()) { + mViewModel.enableBackToNewTab(false); + mViewModel.setCanGoForwardFromNewTab(true); + } + } + public void hidePanel() { hidePanel(true); } @@ -557,12 +587,33 @@ private void hidePanel(boolean switchSurface) { if (mView != null && mLibrary != null) { unsetView(mLibrary, switchSurface); mLibrary.onHide(); - mViewModel.setCurrentContentType(Windows.ContentType.WEB_CONTENT); } if (switchSurface && mRestoreFirstPaint != null) { mRestoreFirstPaint.run(); mRestoreFirstPaint = null; } + if (mViewModel.lastContentType.getValue() == Windows.ContentType.NEW_TAB) { + showNewTab(); + } else { + mViewModel.setCurrentContentType(Windows.ContentType.WEB_CONTENT); + } + } + + public void hideNewTab(boolean enableBackToNewTab) { + if (mViewModel.getCurrentContentType().getValue() == Windows.ContentType.NEW_TAB) { + mViewModel.enableBackToNewTab(enableBackToNewTab); + hideNewTab(); + } + } + + private void hideNewTab() { + if (mView != null && mNewTab != null) { + unsetView(mNewTab, true); + } + if (mRestoreFirstPaint != null) { + mRestoreFirstPaint.run(); + mRestoreFirstPaint = null; + } } public void pauseCompositor() { @@ -2003,24 +2054,31 @@ WResult onLoadRequest(WSession aSession, @NonNull LoadRequest aReq Uri uri = Uri.parse(aRequest.uri); if (UrlUtils.isAboutPage(uri.toString())) { - if(UrlUtils.isBookmarksUrl(uri.toString())) { - showPanel(Windows.ContentType.BOOKMARKS); + if(UrlUtils.isBookmarksUrl(uri.toString())) { + showLibraryPanel(Windows.ContentType.BOOKMARKS); } else if (UrlUtils.isHistoryUrl(uri.toString())) { - showPanel(Windows.ContentType.HISTORY); + showLibraryPanel(Windows.ContentType.HISTORY); } else if (UrlUtils.isDownloadsUrl(uri.toString())) { - showPanel(Windows.ContentType.DOWNLOADS); + showLibraryPanel(Windows.ContentType.DOWNLOADS); } else if (UrlUtils.isAddonsUrl(uri.toString())) { - showPanel(Windows.ContentType.ADDONS); + showLibraryPanel(Windows.ContentType.ADDONS); + + } else if (UrlUtils.isNewTabUrl(uri.toString())) { + showNewTab(); } else { - hideLibraryPanel(); - } + hideLibraryPanel(); + hideNewTab(true); + } } else { hideLibraryPanel(); + hideNewTab(true); + mViewModel.setCurrentContentType(Windows.ContentType.WEB_CONTENT); + mViewModel.setUrl(uri.toString()); } if ("file".equalsIgnoreCase(uri.getScheme())) { diff --git a/app/src/common/shared/com/igalia/wolvic/ui/widgets/Windows.java b/app/src/common/shared/com/igalia/wolvic/ui/widgets/Windows.java index 7c65403cc57..65bbef865a6 100644 --- a/app/src/common/shared/com/igalia/wolvic/ui/widgets/Windows.java +++ b/app/src/common/shared/com/igalia/wolvic/ui/widgets/Windows.java @@ -98,6 +98,7 @@ class WindowState { int textureHeight; float worldWidth; int tabIndex = -1; + // NOTE: Enum values may be null when deserialized by GSON. ContentType contentType = ContentType.WEB_CONTENT; @@ -120,7 +121,8 @@ public void load(@NonNull WindowWidget aWindow, WindowsState aState, int aTabInd tabIndex = aTabIndex; if (aWindow.isNativeContentVisible()) { contentType = aWindow.getSelectedPanel(); - + } else if (aWindow.getCurrentContentType() == ContentType.NEW_TAB) { + contentType = ContentType.NEW_TAB; } else { contentType = ContentType.WEB_CONTENT; } @@ -171,13 +173,28 @@ public enum ContentType { HISTORY(UrlUtils.ABOUT_HISTORY), DOWNLOADS(UrlUtils.ABOUT_DOWNLOADS), ADDONS(UrlUtils.ABOUT_ADDONS), - NOTIFICATIONS(UrlUtils.ABOUT_NOTIFICATIONS); + NOTIFICATIONS(UrlUtils.ABOUT_NOTIFICATIONS), + NEW_TAB(UrlUtils.ABOUT_NEWTAB); @NonNull public final String URL; + ContentType(@NonNull String url) { this.URL = url; } + + public boolean isLibraryContent() { + switch (this) { + case BOOKMARKS: + case WEB_APPS: + case HISTORY: + case DOWNLOADS: + case ADDONS: + return true; + default: + return false; + } + }; } public enum WindowPlacement{ @@ -389,6 +406,9 @@ private WindowWidget addRestoredWindow(@NonNull WindowState aState, @Nullable Se case ADDONS: newWindow.getSession().loadUri(UrlUtils.ABOUT_ADDONS); break; + case NEW_TAB: + newWindow.getSession().loadUri(UrlUtils.ABOUT_NEWTAB); + break; case WEB_CONTENT: break; } @@ -636,7 +656,7 @@ public void exitImmersiveMode() { } private void closeLibraryPanelInFocusedWindowIfNeeded() { - if (!mFocusedWindow.isNativeContentVisible()) + if (!mFocusedWindow.getCurrentContentType().isLibraryContent()) return; mFocusedWindow.hidePanel(); } @@ -1205,7 +1225,7 @@ public void onBookmarksClicked() { if (mFocusedWindow.getCurrentContentType() == ContentType.BOOKMARKS) { mFocusedWindow.hidePanel(); } else { - mFocusedWindow.showPanel(ContentType.BOOKMARKS); + mFocusedWindow.showLibraryPanel(ContentType.BOOKMARKS); } } @@ -1214,7 +1234,7 @@ public void onDownloadsClicked() { if (mFocusedWindow.getCurrentContentType() == ContentType.DOWNLOADS) { mFocusedWindow.hidePanel(); } else { - mFocusedWindow.showPanel(ContentType.DOWNLOADS); + mFocusedWindow.showLibraryPanel(ContentType.DOWNLOADS); } } diff --git a/app/src/common/shared/com/igalia/wolvic/ui/widgets/settings/DisplayOptionsView.java b/app/src/common/shared/com/igalia/wolvic/ui/widgets/settings/DisplayOptionsView.java index abf9348e248..e6b7f08312f 100644 --- a/app/src/common/shared/com/igalia/wolvic/ui/widgets/settings/DisplayOptionsView.java +++ b/app/src/common/shared/com/igalia/wolvic/ui/widgets/settings/DisplayOptionsView.java @@ -21,6 +21,9 @@ import com.igalia.wolvic.ui.views.settings.SwitchSetting; import com.igalia.wolvic.ui.widgets.WidgetManagerDelegate; import com.igalia.wolvic.ui.widgets.WidgetPlacement; +import com.igalia.wolvic.utils.UrlUtils; + +import java.util.Objects; import java.util.ArrayList; import java.util.List; @@ -86,6 +89,10 @@ protected void updateUI() { SettingsStore.WindowSizePreset windowSizePreset = SettingsStore.WindowSizePreset.fromValues(windowWidth, windowHeight); setWindowsSizePreset(windowSizePreset.ordinal(), false); + int homepageId = getHomepageId(SettingsStore.getInstance(getContext()).getHomepage()); + mBinding.homepage.setOnCheckedChangeListener(mHomepageChangeListener); + setHomepage(homepageId, false); + mBinding.autoplaySwitch.setOnCheckedChangeListener(mAutoplayListener); setAutoplay(SettingsStore.getInstance(getContext()).isAutoplayEnabled(), false); @@ -180,6 +187,10 @@ public boolean isEditing() { setWindowsSizePreset(checkedId, true); }; + private RadioGroupSetting.OnCheckedChangeListener mHomepageChangeListener = (radioGroup, checkedId, doApply) -> { + setHomepage(checkedId, true); + }; + private SwitchSetting.OnCheckedChangeListener mAutoplayListener = (compoundButton, enabled, apply) -> { setAutoplay(enabled, true); }; @@ -263,6 +274,11 @@ public boolean isEditing() { if (mBinding.windowsSize.getCheckedRadioButtonId() != SettingsStore.WINDOW_SIZE_PRESET_DEFAULT.ordinal()) { setWindowsSizePreset(SettingsStore.WINDOW_SIZE_PRESET_DEFAULT.ordinal(), true); } + + int defaultHomepageId = getHomepageId(mDefaultHomepageUrl); + if (mBinding.homepage.getCheckedRadioButtonId() != defaultHomepageId) { + setHomepage(defaultHomepageId, true); + } float prevDensity = SettingsStore.getInstance(getContext()).getDisplayDensity(); restart = restart | setDisplayDensity(SettingsStore.DISPLAY_DENSITY_DEFAULT); @@ -365,11 +381,39 @@ private void setSoundEffect(boolean value, boolean doApply) { } } + private void setHomepage(int checkedId, boolean doApply) { + mBinding.homepage.setOnCheckedChangeListener(null); + mBinding.homepage.setChecked(checkedId, doApply); + mBinding.homepage.setOnCheckedChangeListener(mHomepageChangeListener); + + if (checkedId == 0) { + mBinding.homepageEdit.setVisibility(View.GONE); + SettingsStore.getInstance(getContext()).setHomepage(UrlUtils.ABOUT_NEWTAB); + } else if (checkedId == 1) { + mBinding.homepageEdit.setVisibility(View.GONE); + SettingsStore.getInstance(getContext()).setHomepage(mDefaultHomepageUrl); + } else if (checkedId == 2) { + mBinding.homepageEdit.setVisibility(View.VISIBLE); + } + } + + private int getHomepageId(String homepage) { + if (Objects.equals(homepage, UrlUtils.ABOUT_NEWTAB)) { + return 0; + } else if (Objects.equals(homepage, getContext().getString(R.string.HOMEPAGE_URL))) { + return 1; + } else { + return 2; + } + } + private void setHomepage(String newHomepage) { - mBinding.homepageEdit.setOnClickListener(null); - mBinding.homepageEdit.setFirstText(newHomepage); - SettingsStore.getInstance(getContext()).setHomepage(newHomepage); - mBinding.homepageEdit.setOnClickListener(mHomepageListener); + if (mBinding.homepageEdit.getVisibility() == VISIBLE) { + mBinding.homepageEdit.setOnClickListener(null); + mBinding.homepageEdit.setFirstText(newHomepage); + SettingsStore.getInstance(getContext()).setHomepage(newHomepage); + mBinding.homepageEdit.setOnClickListener(mHomepageListener); + } } private void setWindowDistance(float value, boolean doApply) { diff --git a/app/src/common/shared/com/igalia/wolvic/utils/UrlUtils.java b/app/src/common/shared/com/igalia/wolvic/utils/UrlUtils.java index 9b496b2ab62..6ceedac1ad9 100644 --- a/app/src/common/shared/com/igalia/wolvic/utils/UrlUtils.java +++ b/app/src/common/shared/com/igalia/wolvic/utils/UrlUtils.java @@ -188,6 +188,12 @@ public static boolean isBookmarksUrl(@Nullable String url) { return url != null && url.equalsIgnoreCase(ABOUT_BOOKMARKS); } + public static final String ABOUT_NEWTAB = "about://newtab"; + + public static boolean isNewTabUrl(@Nullable String url) { + return url != null && url.equalsIgnoreCase(ABOUT_NEWTAB); + } + public static final String ABOUT_DOWNLOADS = "about://downloads"; public static boolean isDownloadsUrl(@Nullable String url) { @@ -246,7 +252,7 @@ public static boolean isPrivateUrl(@Nullable String url) { public static boolean isAboutPage(@Nullable String url) { return isHistoryUrl(url) || isBookmarksUrl(url) || isDownloadsUrl(url) || isAddonsUrl(url) || - isWebAppsUrl(url) || isNotificationsUrl(url) || isPrivateUrl(url); + isWebAppsUrl(url) || isNotificationsUrl(url) || isPrivateUrl(url) || isNewTabUrl(url); } public static boolean isContentFeed(Context aContext, @Nullable String url) { diff --git a/app/src/main/res/layout/navigation_bar_navigation.xml b/app/src/main/res/layout/navigation_bar_navigation.xml index ae12d97b38d..f9b15014dd9 100644 --- a/app/src/main/res/layout/navigation_bar_navigation.xml +++ b/app/src/main/res/layout/navigation_bar_navigation.xml @@ -4,6 +4,7 @@ + @@ -34,7 +35,7 @@ android:src="@drawable/ic_icon_back" android:tint="@color/midnight" android:tooltipText="@string/back_tooltip" - android:enabled="@{viewmodel.canGoBack}" + android:enabled="@{viewmodel.canGoBack || viewmodel.backToNewTabEnabled}" app:privateMode="@{viewmodel.isPrivateSession}" /> + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/options_display.xml b/app/src/main/res/layout/options_display.xml index 137ea71ce24..d71fa5282f9 100644 --- a/app/src/main/res/layout/options_display.xml +++ b/app/src/main/res/layout/options_display.xml @@ -96,15 +96,22 @@ android:layout_height="wrap_content" app:description="@string/settings_window_size" /> + + + app:highlightedTextColor="@color/fog" + android:visibility="gone" /> - + \ No newline at end of file diff --git a/app/src/main/res/values/options_values.xml b/app/src/main/res/values/options_values.xml index 9619e594885..26abe7b9048 100644 --- a/app/src/main/res/values/options_values.xml +++ b/app/src/main/res/values/options_values.xml @@ -85,6 +85,13 @@ 2 + + + @string/developer_options_homepage_new_tab + @string/developer_options_homepage_wolvic + @string/developer_options_homepage_other + + @string/privacy_options_tracking_etp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9d5afa6d0ce..50df2489fd7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -609,6 +609,15 @@ %1$d×%2$d + + wolvic.com + + + New Tab + + + Other + User-Agent Mode @@ -1828,10 +1837,6 @@ tray and the Downloads view is closed. The button it labels, when pressed, closes the Downloads view. --> Close Downloads - - Open Library - Close Library @@ -1963,6 +1968,9 @@ Library + + New Tab + Clear