From 7e311e55679e67b21dab98eea12e881137e6608b Mon Sep 17 00:00:00 2001 From: Mauricio Colli Date: Sat, 19 Oct 2019 21:31:14 -0300 Subject: [PATCH 1/6] Fix mess with tab handling and enable ignored tests again - Fix typo in a string resource - Reorder tabs so the default kiosk is on top of the others --- .../newpipe/fragments/MainFragment.java | 22 ++---- .../list/kiosk/DefaultKioskFragment.java | 51 +++++++++++++ .../settings/tabs/ChooseTabsFragment.java | 24 +++--- .../org/schabi/newpipe/settings/tabs/Tab.java | 75 ++++++++----------- .../newpipe/settings/tabs/TabsJsonHelper.java | 27 ++++--- app/src/main/res/values/strings.xml | 2 +- .../schabi/newpipe/settings/tabs/TabTest.java | 2 - .../settings/tabs/TabsJsonHelperTest.java | 24 +++--- 8 files changed, 127 insertions(+), 100 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/DefaultKioskFragment.java diff --git a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java index e0661a49f..085056302 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java @@ -159,27 +159,17 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte pagerAdapter.notifyDataSetChanged(); viewPager.setOffscreenPageLimit(pagerAdapter.getCount()); - updateTabsIcon(); - updateTabsContentDescription(); + updateTabsIconAndDescription(); updateCurrentTitle(); } - private void updateTabsIcon() { + private void updateTabsIconAndDescription() { for (int i = 0; i < tabsList.size(); i++) { final TabLayout.Tab tabToSet = tabLayout.getTabAt(i); if (tabToSet != null) { - tabToSet.setIcon(tabsList.get(i).getTabIconRes(activity)); - } - } - } - - private void updateTabsContentDescription() { - for (int i = 0; i < tabsList.size(); i++) { - final TabLayout.Tab tabToSet = tabLayout.getTabAt(i); - if (tabToSet != null) { - final Tab t = tabsList.get(i); - tabToSet.setIcon(t.getTabIconRes(activity)); - tabToSet.setContentDescription(t.getTabName(activity)); + final Tab tab = tabsList.get(i); + tabToSet.setIcon(tab.getTabIconRes(requireContext())); + tabToSet.setContentDescription(tab.getTabName(requireContext())); } } } @@ -217,7 +207,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte Throwable throwable = null; Fragment fragment = null; try { - fragment = tab.getFragment(); + fragment = tab.getFragment(requireContext()); } catch (ExtractionException e) { throwable = e; } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/DefaultKioskFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/DefaultKioskFragment.java new file mode 100644 index 000000000..35b68b094 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/DefaultKioskFragment.java @@ -0,0 +1,51 @@ +package org.schabi.newpipe.fragments.list.kiosk; + +import android.os.Bundle; + +import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.kiosk.KioskList; +import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.util.KioskTranslator; +import org.schabi.newpipe.util.ServiceHelper; + +public class DefaultKioskFragment extends KioskFragment { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (serviceId < 0) { + updateSelectedDefaultKiosk(); + } + } + + @Override + public void onResume() { + super.onResume(); + + if (serviceId != ServiceHelper.getSelectedServiceId(requireContext())) { + if (currentWorker != null) currentWorker.dispose(); + updateSelectedDefaultKiosk(); + reloadContent(); + } + } + + private void updateSelectedDefaultKiosk() { + try { + serviceId = ServiceHelper.getSelectedServiceId(requireContext()); + + final KioskList kioskList = NewPipe.getService(serviceId).getKioskList(); + kioskId = kioskList.getDefaultKioskId(); + url = kioskList.getListLinkHandlerFactoryByType(kioskId).fromId(kioskId).getUrl(); + + kioskTranslatedName = KioskTranslator.getTranslatedKioskName(kioskId, requireContext()); + name = kioskTranslatedName; + + currentInfo = null; + currentNextPageUrl = null; + } catch (ExtractionException e) { + onUnrecoverableError(e, UserAction.REQUESTED_KIOSK, "none", "Loading default kiosk from selected service", 0); + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java index 4297fb13e..6aba2783f 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java @@ -231,7 +231,7 @@ public class ChooseTabsFragment extends Fragment { break; case DEFAULT_KIOSK: if (!tabList.contains(tab)) { - returnList.add(new ChooseTabListItem(tab.getTabId(), getString(R.string.default_kiosk_page_sumatry), + returnList.add(new ChooseTabListItem(tab.getTabId(), getString(R.string.default_kiosk_page_summary), ThemeHelper.resolveResourceIdFromAttr(context, R.attr.ic_hot))); } break; @@ -305,23 +305,25 @@ public class ChooseTabsFragment extends Fragment { return; } - String tabName = tab.getTabName(requireContext()); + final String tabName; switch (type) { case BLANK: - tabName = requireContext().getString(R.string.blank_page_summary); - break; - case KIOSK: - tabName = NewPipe.getNameOfService(((Tab.KioskTab) tab).getKioskServiceId()) + "/" + tabName; - break; - case CHANNEL: - tabName = NewPipe.getNameOfService(((Tab.ChannelTab) tab).getChannelServiceId()) + "/" + tabName; + tabName = getString(R.string.blank_page_summary); break; case DEFAULT_KIOSK: - tabName = requireContext().getString(R.string.default_kiosk_page_sumatry); + tabName = getString(R.string.default_kiosk_page_summary); + break; + case KIOSK: + tabName = NewPipe.getNameOfService(((Tab.KioskTab) tab).getKioskServiceId()) + "/" + tab.getTabName(requireContext()); + break; + case CHANNEL: + tabName = NewPipe.getNameOfService(((Tab.ChannelTab) tab).getChannelServiceId()) + "/" + tab.getTabName(requireContext()); + break; + default: + tabName = tab.getTabName(requireContext()); break; } - tabNameView.setText(tabName); tabIconView.setImageResource(tab.getTabIconRes(requireContext())); } diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java index 64ba3683b..f80a8bb7f 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java @@ -1,6 +1,7 @@ package org.schabi.newpipe.settings.tabs; import android.content.Context; + import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -9,18 +10,20 @@ import androidx.fragment.app.Fragment; import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonSink; -import org.jsoup.helper.StringUtil; -import org.schabi.newpipe.App; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.fragments.BlankFragment; import org.schabi.newpipe.fragments.list.channel.ChannelFragment; +import org.schabi.newpipe.fragments.list.kiosk.DefaultKioskFragment; import org.schabi.newpipe.fragments.list.kiosk.KioskFragment; import org.schabi.newpipe.local.bookmark.BookmarkFragment; import org.schabi.newpipe.local.feed.FeedFragment; import org.schabi.newpipe.local.history.StatisticsPlaylistFragment; import org.schabi.newpipe.local.subscription.SubscriptionFragment; +import org.schabi.newpipe.report.ErrorActivity; +import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.util.KioskTranslator; import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.ThemeHelper; @@ -40,7 +43,7 @@ public abstract class Tab { /** * Return a instance of the fragment that this tab represent. */ - public abstract Fragment getFragment() throws ExtractionException; + public abstract Fragment getFragment(Context context) throws ExtractionException; @Override public boolean equals(Object obj) { @@ -115,12 +118,6 @@ public abstract class Tab { return new KioskTab(jsonObject); case CHANNEL: return new ChannelTab(jsonObject); - case DEFAULT_KIOSK: - DefaultKioskTab tab = new DefaultKioskTab(); - if(!StringUtil.isBlank(tab.getKioskId())){ - return tab; - } - return null; } } @@ -133,13 +130,13 @@ public abstract class Tab { public enum Type { BLANK(new BlankTab()), + DEFAULT_KIOSK(new DefaultKioskTab()), SUBSCRIPTIONS(new SubscriptionsTab()), FEED(new FeedTab()), BOOKMARKS(new BookmarksTab()), HISTORY(new HistoryTab()), KIOSK(new KioskTab()), - CHANNEL(new ChannelTab()), - DEFAULT_KIOSK(new DefaultKioskTab()); + CHANNEL(new ChannelTab()); private Tab tab; @@ -176,7 +173,7 @@ public abstract class Tab { } @Override - public BlankFragment getFragment() { + public BlankFragment getFragment(Context context) { return new BlankFragment(); } } @@ -201,7 +198,7 @@ public abstract class Tab { } @Override - public SubscriptionFragment getFragment() { + public SubscriptionFragment getFragment(Context context) { return new SubscriptionFragment(); } @@ -227,7 +224,7 @@ public abstract class Tab { } @Override - public FeedFragment getFragment() { + public FeedFragment getFragment(Context context) { return new FeedFragment(); } } @@ -252,7 +249,7 @@ public abstract class Tab { } @Override - public BookmarkFragment getFragment() { + public BookmarkFragment getFragment(Context context) { return new BookmarkFragment(); } } @@ -277,7 +274,7 @@ public abstract class Tab { } @Override - public StatisticsPlaylistFragment getFragment() { + public StatisticsPlaylistFragment getFragment(Context context) { return new StatisticsPlaylistFragment(); } } @@ -327,7 +324,7 @@ public abstract class Tab { } @Override - public KioskFragment getFragment() throws ExtractionException { + public KioskFragment getFragment(Context context) throws ExtractionException { return KioskFragment.getInstance(kioskServiceId, kioskId); } @@ -394,7 +391,7 @@ public abstract class Tab { } @Override - public ChannelFragment getFragment() { + public ChannelFragment getFragment(Context context) { return ChannelFragment.getInstance(channelServiceId, channelUrl, channelName); } @@ -428,22 +425,6 @@ public abstract class Tab { public static class DefaultKioskTab extends Tab { public static final int ID = 7; - private int kioskServiceId; - private String kioskId; - - protected DefaultKioskTab() { - initKiosk(); - } - - public void initKiosk() { - this.kioskServiceId = ServiceHelper.getSelectedServiceId(App.getApp()); - try { - this.kioskId = NewPipe.getService(this.kioskServiceId).getKioskList().getDefaultKioskId(); - } catch (ExtractionException e) { - this.kioskId = ""; - } - } - @Override public int getTabId() { return ID; @@ -451,27 +432,31 @@ public abstract class Tab { @Override public String getTabName(Context context) { - return KioskTranslator.getTranslatedKioskName(kioskId, context); + return KioskTranslator.getTranslatedKioskName(getDefaultKioskId(context), context); } @DrawableRes @Override public int getTabIconRes(Context context) { - final int kioskIcon = KioskTranslator.getKioskIcons(kioskId, context); - - if (kioskIcon <= 0) { - throw new IllegalStateException("Kiosk ID is not valid: \"" + kioskId + "\""); - } - - return kioskIcon; + return KioskTranslator.getKioskIcons(getDefaultKioskId(context), context); } @Override - public KioskFragment getFragment() throws ExtractionException { - return KioskFragment.getInstance(kioskServiceId, kioskId); + public DefaultKioskFragment getFragment(Context context) throws ExtractionException { + return new DefaultKioskFragment(); } - public String getKioskId() { + private String getDefaultKioskId(Context context) { + final int kioskServiceId = ServiceHelper.getSelectedServiceId(context); + + String kioskId = ""; + try { + final StreamingService service = NewPipe.getService(kioskServiceId); + kioskId = service.getKioskList().getDefaultKioskId(); + } catch (ExtractionException e) { + ErrorActivity.reportError(context, e, null, null, + ErrorActivity.ErrorInfo.make(UserAction.REQUESTED_KIOSK, "none", "Loading default kiosk from selected service", 0)); + } return kioskId; } } diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/TabsJsonHelper.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/TabsJsonHelper.java index 9553e47e1..9f54d59f6 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/TabsJsonHelper.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/TabsJsonHelper.java @@ -1,7 +1,5 @@ package org.schabi.newpipe.settings.tabs; -import androidx.annotation.Nullable; - import com.grack.nanojson.JsonArray; import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonParser; @@ -9,18 +7,25 @@ import com.grack.nanojson.JsonParserException; import com.grack.nanojson.JsonStringWriter; import com.grack.nanojson.JsonWriter; -import org.jsoup.helper.StringUtil; - import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import androidx.annotation.Nullable; + /** * Class to get a JSON representation of a list of tabs, and the other way around. */ public class TabsJsonHelper { private static final String JSON_TABS_ARRAY_KEY = "tabs"; + private static final List FALLBACK_INITIAL_TABS_LIST = Collections.unmodifiableList(Arrays.asList( + Tab.Type.DEFAULT_KIOSK.getTab(), + Tab.Type.SUBSCRIPTIONS.getTab(), + Tab.Type.BOOKMARKS.getTab() + )); + public static class InvalidJsonException extends Exception { private InvalidJsonException() { super(); @@ -83,16 +88,6 @@ public class TabsJsonHelper { return returnTabs; } - public static List getDefaultTabs(){ - List tabs = new ArrayList<>(); - Tab.DefaultKioskTab tab = new Tab.DefaultKioskTab(); - if(!StringUtil.isBlank(tab.getKioskId())){ - tabs.add(tab); - } - tabs.add(Tab.Type.SUBSCRIPTIONS.getTab()); - tabs.add(Tab.Type.BOOKMARKS.getTab()); - return Collections.unmodifiableList(tabs); - } /** * Get a JSON representation from a list of tabs. * @@ -112,4 +107,8 @@ public class TabsJsonHelper { jsonWriter.end(); return jsonWriter.done(); } + + public static List getDefaultTabs(){ + return FALLBACK_INITIAL_TABS_LIST; + } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6449833ea..a34b00ea9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -379,7 +379,7 @@ Selection Blank Page Kiosk Page - Default Kiosk + Default Kiosk Subscription Page Feed Page Channel Page diff --git a/app/src/test/java/org/schabi/newpipe/settings/tabs/TabTest.java b/app/src/test/java/org/schabi/newpipe/settings/tabs/TabTest.java index 4b3fbc2e0..45c7c0fff 100644 --- a/app/src/test/java/org/schabi/newpipe/settings/tabs/TabTest.java +++ b/app/src/test/java/org/schabi/newpipe/settings/tabs/TabTest.java @@ -1,6 +1,5 @@ package org.schabi.newpipe.settings.tabs; -import org.junit.Ignore; import org.junit.Test; import java.util.HashSet; @@ -9,7 +8,6 @@ import java.util.Set; import static org.junit.Assert.assertTrue; public class TabTest { - @Ignore @Test public void checkIdDuplication() { final Set usedIds = new HashSet<>(); diff --git a/app/src/test/java/org/schabi/newpipe/settings/tabs/TabsJsonHelperTest.java b/app/src/test/java/org/schabi/newpipe/settings/tabs/TabsJsonHelperTest.java index 20785e548..1f951159f 100644 --- a/app/src/test/java/org/schabi/newpipe/settings/tabs/TabsJsonHelperTest.java +++ b/app/src/test/java/org/schabi/newpipe/settings/tabs/TabsJsonHelperTest.java @@ -5,7 +5,6 @@ import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonParser; import com.grack.nanojson.JsonParserException; -import org.junit.Ignore; import org.junit.Test; import java.util.Arrays; @@ -21,19 +20,19 @@ public class TabsJsonHelperTest { private static final String JSON_TABS_ARRAY_KEY = "tabs"; private static final String JSON_TAB_ID_KEY = "tab_id"; - @Ignore @Test public void testEmptyAndNullRead() throws TabsJsonHelper.InvalidJsonException { + final List defaultTabs = TabsJsonHelper.getDefaultTabs(); + final String emptyTabsJson = "{\"" + JSON_TABS_ARRAY_KEY + "\":[]}"; List items = TabsJsonHelper.getTabsFromJson(emptyTabsJson); - assertTrue(!items.isEmpty()); + assertEquals(items, defaultTabs); final String nullSource = null; items = TabsJsonHelper.getTabsFromJson(nullSource); - assertTrue(!items.isEmpty()); + assertEquals(items, defaultTabs); } - @Ignore @Test public void testInvalidIdRead() throws TabsJsonHelper.InvalidJsonException { final int blankTabId = Tab.Type.BLANK.getTabId(); @@ -84,17 +83,17 @@ public class TabsJsonHelperTest { return jsonObject.getArray(JSON_TABS_ARRAY_KEY).size() == 0; } - @Ignore @Test public void testSaveAndReading() throws JsonParserException { // Saving final Tab.BlankTab blankTab = new Tab.BlankTab(); + final Tab.DefaultKioskTab defaultKioskTab = new Tab.DefaultKioskTab(); final Tab.SubscriptionsTab subscriptionsTab = new Tab.SubscriptionsTab(); final Tab.ChannelTab channelTab = new Tab.ChannelTab(666, "https://example.org", "testName"); final Tab.KioskTab kioskTab = new Tab.KioskTab(123, "trending_key"); - final List tabs = Arrays.asList(blankTab, subscriptionsTab, channelTab, kioskTab); - String returnedJson = TabsJsonHelper.getJsonToSave(tabs); + final List tabs = Arrays.asList(blankTab, defaultKioskTab, subscriptionsTab, channelTab, kioskTab); + final String returnedJson = TabsJsonHelper.getJsonToSave(tabs); // Reading final JsonObject jsonObject = JsonParser.object().from(returnedJson); @@ -106,16 +105,19 @@ public class TabsJsonHelperTest { final Tab.BlankTab blankTabFromReturnedJson = requireNonNull((Tab.BlankTab) Tab.from(((JsonObject) tabsFromArray.get(0)))); assertEquals(blankTab.getTabId(), blankTabFromReturnedJson.getTabId()); - final Tab.SubscriptionsTab subscriptionsTabFromReturnedJson = requireNonNull((Tab.SubscriptionsTab) Tab.from(((JsonObject) tabsFromArray.get(1)))); + final Tab.DefaultKioskTab defaultKioskTabFromReturnedJson = requireNonNull((Tab.DefaultKioskTab) Tab.from(((JsonObject) tabsFromArray.get(1)))); + assertEquals(defaultKioskTab.getTabId(), defaultKioskTabFromReturnedJson.getTabId()); + + final Tab.SubscriptionsTab subscriptionsTabFromReturnedJson = requireNonNull((Tab.SubscriptionsTab) Tab.from(((JsonObject) tabsFromArray.get(2)))); assertEquals(subscriptionsTab.getTabId(), subscriptionsTabFromReturnedJson.getTabId()); - final Tab.ChannelTab channelTabFromReturnedJson = requireNonNull((Tab.ChannelTab) Tab.from(((JsonObject) tabsFromArray.get(2)))); + final Tab.ChannelTab channelTabFromReturnedJson = requireNonNull((Tab.ChannelTab) Tab.from(((JsonObject) tabsFromArray.get(3)))); assertEquals(channelTab.getTabId(), channelTabFromReturnedJson.getTabId()); assertEquals(channelTab.getChannelServiceId(), channelTabFromReturnedJson.getChannelServiceId()); assertEquals(channelTab.getChannelUrl(), channelTabFromReturnedJson.getChannelUrl()); assertEquals(channelTab.getChannelName(), channelTabFromReturnedJson.getChannelName()); - final Tab.KioskTab kioskTabFromReturnedJson = requireNonNull((Tab.KioskTab) Tab.from(((JsonObject) tabsFromArray.get(3)))); + final Tab.KioskTab kioskTabFromReturnedJson = requireNonNull((Tab.KioskTab) Tab.from(((JsonObject) tabsFromArray.get(4)))); assertEquals(kioskTab.getTabId(), kioskTabFromReturnedJson.getTabId()); assertEquals(kioskTab.getKioskServiceId(), kioskTabFromReturnedJson.getKioskServiceId()); assertEquals(kioskTab.getKioskId(), kioskTabFromReturnedJson.getKioskId()); From 58a626dedb16df61c431710058e5e95798bcfbf9 Mon Sep 17 00:00:00 2001 From: Mauricio Colli Date: Sat, 19 Oct 2019 21:31:15 -0300 Subject: [PATCH 2/6] Fix broken view pager tabs implementation - Fragments were being recreated from scratch (losing their state) every time some configuration change occurred (e.g. screen rotation). - Use `FragmentStatePagerAdapter` instead, as it is built to work with them and manage their states. --- .../newpipe/fragments/MainFragment.java | 69 ++++++++----------- .../org/schabi/newpipe/settings/tabs/Tab.java | 19 +++++ 2 files changed, 48 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java index 085056302..79199a14d 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java @@ -1,5 +1,6 @@ package org.schabi.newpipe.fragments; +import android.content.Context; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -15,7 +16,7 @@ import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; +import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.viewpager.widget.ViewPager; import com.google.android.material.tabs.TabLayout; @@ -52,32 +53,19 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte super.onCreate(savedInstanceState); setHasOptionsMenu(true); - destroyOldFragments(); - tabsManager = TabsManager.getManager(activity); tabsManager.setSavedTabsListener(() -> { if (DEBUG) { Log.d(TAG, "TabsManager.SavedTabsChangeListener: onTabsChanged called, isResumed = " + isResumed()); } if (isResumed()) { - updateTabs(); + setupTabs(); } else { hasTabsChanged = true; } }); } - private void destroyOldFragments() { - for (Fragment fragment : getChildFragmentManager().getFragments()) { - if (fragment != null) { - getChildFragmentManager() - .beginTransaction() - .remove(fragment) - .commitNowAllowingStateLoss(); - } - } - } - @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_main, container, false); @@ -90,23 +78,17 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte tabLayout = rootView.findViewById(R.id.main_tab_layout); viewPager = rootView.findViewById(R.id.pager); - /* Nested fragment, use child fragment here to maintain backstack in view pager. */ - pagerAdapter = new SelectedTabsPagerAdapter(getChildFragmentManager()); - viewPager.setAdapter(pagerAdapter); - tabLayout.setupWithViewPager(viewPager); tabLayout.addOnTabSelectedListener(this); - updateTabs(); + + setupTabs(); } @Override public void onResume() { super.onResume(); - if (hasTabsChanged) { - hasTabsChanged = false; - updateTabs(); - } + if (hasTabsChanged) setupTabs(); } @Override @@ -153,14 +135,21 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte // Tabs //////////////////////////////////////////////////////////////////////////*/ - public void updateTabs() { + public void setupTabs() { tabsList.clear(); tabsList.addAll(tabsManager.getTabs()); - pagerAdapter.notifyDataSetChanged(); - viewPager.setOffscreenPageLimit(pagerAdapter.getCount()); + if (pagerAdapter == null || !pagerAdapter.sameTabs(tabsList)) { + pagerAdapter = new SelectedTabsPagerAdapter(requireContext(), getChildFragmentManager(), tabsList); + } + // Clear previous tabs/fragments and set new adapter + viewPager.setAdapter(pagerAdapter); + viewPager.setOffscreenPageLimit(tabsList.size()); + updateTabsIconAndDescription(); updateCurrentTitle(); + + hasTabsChanged = false; } private void updateTabsIconAndDescription() { @@ -194,26 +183,30 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte updateCurrentTitle(); } - private class SelectedTabsPagerAdapter extends FragmentPagerAdapter { + private static class SelectedTabsPagerAdapter extends FragmentStatePagerAdapter { + private final Context context; + private final List internalTabsList; - private SelectedTabsPagerAdapter(FragmentManager fragmentManager) { - super(fragmentManager); + private SelectedTabsPagerAdapter(Context context, FragmentManager fragmentManager, List tabsList) { + super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); + this.context = context; + this.internalTabsList = new ArrayList<>(tabsList); } @Override public Fragment getItem(int position) { - final Tab tab = tabsList.get(position); + final Tab tab = internalTabsList.get(position); Throwable throwable = null; Fragment fragment = null; try { - fragment = tab.getFragment(requireContext()); + fragment = tab.getFragment(context); } catch (ExtractionException e) { throwable = e; } if (throwable != null) { - ErrorActivity.reportError(activity, throwable, activity.getClass(), null, + ErrorActivity.reportError(context, throwable, null, null, ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash)); return new BlankFragment(); } @@ -234,15 +227,11 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte @Override public int getCount() { - return tabsList.size(); + return internalTabsList.size(); } - @Override - public void destroyItem(ViewGroup container, int position, Object object) { - getChildFragmentManager() - .beginTransaction() - .remove((Fragment) object) - .commitNowAllowingStateLoss(); + public boolean sameTabs(List tabsToCompare) { + return internalTabsList.equals(tabsToCompare); } } } diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java index f80a8bb7f..cba3c4534 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java @@ -28,6 +28,8 @@ import org.schabi.newpipe.util.KioskTranslator; import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.ThemeHelper; +import java.util.Objects; + public abstract class Tab { Tab() { } @@ -47,6 +49,8 @@ public abstract class Tab { @Override public boolean equals(Object obj) { + if (obj == this) return true; + return obj instanceof Tab && obj.getClass().equals(this.getClass()) && ((Tab) obj).getTabId() == this.getTabId(); } @@ -340,6 +344,13 @@ public abstract class Tab { kioskId = jsonObject.getString(JSON_KIOSK_ID_KEY, ""); } + @Override + public boolean equals(Object obj) { + return super.equals(obj) && + kioskServiceId == ((KioskTab) obj).kioskServiceId + && Objects.equals(kioskId, ((KioskTab) obj).kioskId); + } + public int getKioskServiceId() { return kioskServiceId; } @@ -409,6 +420,14 @@ public abstract class Tab { channelName = jsonObject.getString(JSON_CHANNEL_NAME_KEY, ""); } + @Override + public boolean equals(Object obj) { + return super.equals(obj) && + channelServiceId == ((ChannelTab) obj).channelServiceId + && Objects.equals(channelUrl, ((ChannelTab) obj).channelUrl) + && Objects.equals(channelName, ((ChannelTab) obj).channelName); + } + public int getChannelServiceId() { return channelServiceId; } From a5b7666188d0e05b9d22890a3e1199e89f3fbb6b Mon Sep 17 00:00:00 2001 From: Mauricio Colli Date: Sat, 19 Oct 2019 21:31:16 -0300 Subject: [PATCH 3/6] Clear the item list when starting loading --- .../org/schabi/newpipe/fragments/list/BaseListInfoFragment.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java index 764af271a..9a8e1fd17 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java @@ -111,6 +111,8 @@ public abstract class BaseListInfoFragment super.startLoading(forceLoad); showListFooter(false); + infoListAdapter.clearStreamItemList(); + currentInfo = null; if (currentWorker != null) currentWorker.dispose(); currentWorker = loadResult(forceLoad) From 38a0395d45e5c7e365d6ca42bf3120e509e5c706 Mon Sep 17 00:00:00 2001 From: Mauricio Colli Date: Sat, 19 Oct 2019 21:31:17 -0300 Subject: [PATCH 4/6] Enable toolbar title visibility when setting a new one --- app/src/main/java/org/schabi/newpipe/BaseFragment.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/org/schabi/newpipe/BaseFragment.java b/app/src/main/java/org/schabi/newpipe/BaseFragment.java index ccdb806ef..d4795cde2 100644 --- a/app/src/main/java/org/schabi/newpipe/BaseFragment.java +++ b/app/src/main/java/org/schabi/newpipe/BaseFragment.java @@ -107,6 +107,7 @@ public abstract class BaseFragment extends Fragment { if (DEBUG) Log.d(TAG, "setTitle() called with: title = [" + title + "]"); if((!useAsFrontPage || mIsVisibleToUser) && (activity != null && activity.getSupportActionBar() != null)) { + activity.getSupportActionBar().setDisplayShowTitleEnabled(true); activity.getSupportActionBar().setTitle(title); } } From 544cae4fb410d382e06180cbcd1d4504e1266d29 Mon Sep 17 00:00:00 2001 From: Mauricio Colli Date: Sat, 19 Oct 2019 21:31:19 -0300 Subject: [PATCH 5/6] Use tab position from parameters instead of relying on the view pager --- .../org/schabi/newpipe/fragments/MainFragment.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java index 79199a14d..720e0f216 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java @@ -147,7 +147,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte viewPager.setOffscreenPageLimit(tabsList.size()); updateTabsIconAndDescription(); - updateCurrentTitle(); + updateTitleForTab(viewPager.getCurrentItem()); hasTabsChanged = false; } @@ -163,14 +163,14 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte } } - private void updateCurrentTitle() { - setTitle(tabsList.get(viewPager.getCurrentItem()).getTabName(requireContext())); + private void updateTitleForTab(int tabPosition) { + setTitle(tabsList.get(tabPosition).getTabName(requireContext())); } @Override public void onTabSelected(TabLayout.Tab selectedTab) { if (DEBUG) Log.d(TAG, "onTabSelected() called with: selectedTab = [" + selectedTab + "]"); - updateCurrentTitle(); + updateTitleForTab(selectedTab.getPosition()); } @Override @@ -180,7 +180,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte @Override public void onTabReselected(TabLayout.Tab tab) { if (DEBUG) Log.d(TAG, "onTabReselected() called with: tab = [" + tab + "]"); - updateCurrentTitle(); + updateTitleForTab(tab.getPosition()); } private static class SelectedTabsPagerAdapter extends FragmentStatePagerAdapter { From bc283bce4e8c99a4d6e6a60d5071bbaec453a2c2 Mon Sep 17 00:00:00 2001 From: Mauricio Colli Date: Sun, 20 Oct 2019 12:31:46 -0300 Subject: [PATCH 6/6] Make the KioskFragment aware of changes in the preferred content country --- .../fragments/list/kiosk/KioskFragment.java | 17 +++++++++++++++++ .../settings/ContentSettingsFragment.java | 3 +++ 2 files changed, 20 insertions(+) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java index 6eaa2ea70..d082b8078 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java @@ -4,6 +4,8 @@ import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; + +import android.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -17,10 +19,12 @@ import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.kiosk.KioskInfo; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory; +import org.schabi.newpipe.extractor.localization.ContentCountry; import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.KioskTranslator; +import org.schabi.newpipe.util.Localization; import icepick.State; import io.reactivex.Single; @@ -52,6 +56,8 @@ public class KioskFragment extends BaseListInfoFragment { @State protected String kioskId = ""; protected String kioskTranslatedName; + @State + protected ContentCountry contentCountry; /*////////////////////////////////////////////////////////////////////////// @@ -87,6 +93,7 @@ public class KioskFragment extends BaseListInfoFragment { kioskTranslatedName = KioskTranslator.getTranslatedKioskName(kioskId, activity); name = kioskTranslatedName; + contentCountry = Localization.getPreferredContentCountry(requireContext()); } @Override @@ -108,6 +115,15 @@ public class KioskFragment extends BaseListInfoFragment { return inflater.inflate(R.layout.fragment_kiosk, container, false); } + @Override + public void onResume() { + super.onResume(); + + if (!Localization.getPreferredContentCountry(requireContext()).equals(contentCountry)) { + reloadContent(); + } + } + /*////////////////////////////////////////////////////////////////////////// // Menu //////////////////////////////////////////////////////////////////////////*/ @@ -127,6 +143,7 @@ public class KioskFragment extends BaseListInfoFragment { @Override public Single loadResult(boolean forceReload) { + contentCountry = Localization.getPreferredContentCountry(requireContext()); return ExtractorHelper.getKioskInfo(serviceId, url, forceReload); diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java index 39c1d890e..0c7a4b46e 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java @@ -17,6 +17,7 @@ import com.nononsenseapps.filepicker.Utils; import com.nostra13.universalimageloader.core.ImageLoader; import org.schabi.newpipe.R; +import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.localization.ContentCountry; import org.schabi.newpipe.extractor.localization.Localization; import org.schabi.newpipe.report.ErrorActivity; @@ -128,6 +129,8 @@ public class ContentSettingsFragment extends BasePreferenceFragment { if (!selectedLocalization.equals(initialSelectedLocalization) || !selectedContentCountry.equals(initialSelectedContentCountry)) { Toast.makeText(requireContext(), R.string.localization_changes_requires_app_restart, Toast.LENGTH_LONG).show(); + + NewPipe.setupLocalization(selectedLocalization, selectedContentCountry); } }