diff --git a/app/src/main/java/org/xbmc/kore/ui/AddonDetailsFragment.java b/app/src/main/java/org/xbmc/kore/ui/AddonDetailsFragment.java index d454c40..f16dc8b 100644 --- a/app/src/main/java/org/xbmc/kore/ui/AddonDetailsFragment.java +++ b/app/src/main/java/org/xbmc/kore/ui/AddonDetailsFragment.java @@ -16,6 +16,8 @@ package org.xbmc.kore.ui; import android.annotation.TargetApi; +import android.content.Context; +import android.content.SharedPreferences; import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Bundle; @@ -45,6 +47,10 @@ import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.Utils; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + import butterknife.ButterKnife; import butterknife.InjectView; import butterknife.OnClick; @@ -52,7 +58,7 @@ import butterknife.OnClick; /** * Presents addon details */ -public class AddonDetailsFragment extends Fragment { +public class AddonDetailsFragment extends SharedElementFragment { private static final String TAG = LogUtils.makeLogTag(AddonDetailsFragment.class); public static final String BUNDLE_KEY_ADDONID = "addon_id"; @@ -65,6 +71,7 @@ public class AddonDetailsFragment extends Fragment { public static final String BUNDLE_KEY_FANART = "fanart"; public static final String BUNDLE_KEY_POSTER = "poster"; public static final String BUNDLE_KEY_ENABLED = "enabled"; + public static final String BUNDLE_KEY_BROWSABLE = "browsable"; private HostManager hostManager; private HostInfo hostInfo; @@ -80,6 +87,7 @@ public class AddonDetailsFragment extends Fragment { // Buttons @InjectView(R.id.fab) ImageButton fabButton; @InjectView(R.id.enable_disable) ImageButton enabledButton; + @InjectView(R.id.pin_unpin) ImageButton pinButton; // Detail views @InjectView(R.id.media_panel) ScrollView mediaPanel; @@ -112,6 +120,7 @@ public class AddonDetailsFragment extends Fragment { args.putString(BUNDLE_KEY_FANART, vh.fanart); args.putString(BUNDLE_KEY_POSTER, vh.poster); args.putBoolean(BUNDLE_KEY_ENABLED, vh.enabled); + args.putBoolean(BUNDLE_KEY_BROWSABLE, vh.browsable); if( Utils.isLollipopOrLater()) { args.putString(POSTER_TRANS_NAME, vh.artView.getTransitionName()); @@ -170,6 +179,8 @@ public class AddonDetailsFragment extends Fragment { setImages(bundle.getString(BUNDLE_KEY_POSTER), bundle.getString(BUNDLE_KEY_FANART)); setupEnableButton(bundle.getBoolean(BUNDLE_KEY_ENABLED, false)); + if (bundle.getBoolean(BUNDLE_KEY_BROWSABLE, true)) + updatePinButton(); // Pad main content view to overlap with bottom system bar // UIUtils.setPaddingForSystemBars(getActivity(), mediaPanel, false, false, true); @@ -288,6 +299,7 @@ public class AddonDetailsFragment extends Fragment { * Returns the shared element if visible * @return View if visible, null otherwise */ + @Override public View getSharedElement() { if (UIUtils.isViewInBounds(mediaPanel, mediaPoster)) { return mediaPoster; @@ -318,4 +330,48 @@ public class AddonDetailsFragment extends Fragment { } }, callbackHandler); } + + @OnClick(R.id.pin_unpin) + public void onPinClicked(View v) { + final boolean enable = (v.getTag() == null)? true : !(Boolean)v.getTag(); + + String name = mediaTitle.getText().toString(); + String path = addonId; + + SharedPreferences prefs = getActivity().getSharedPreferences("addons", Context.MODE_PRIVATE); + Set bookmarked = new HashSet<>(prefs.getStringSet("bookmarked", Collections.emptySet())); + if (enable) + bookmarked.add(path); + else + bookmarked.remove(path); + prefs + .edit() + .putStringSet("bookmarked", bookmarked) + .putString("name_" + path, name) + .commit(); + Toast.makeText(getActivity(), enable? R.string.addon_pinned : R.string.addon_unpinned, Toast.LENGTH_SHORT).show(); + setupPinButton(enable); + } + + private void setupPinButton(boolean enabled) { + // Enabled button + if (enabled) { + Resources.Theme theme = getActivity().getTheme(); + TypedArray styledAttributes = theme.obtainStyledAttributes(new int[]{ + R.attr.colorAccent}); + pinButton.setColorFilter(styledAttributes.getColor(0, + getActivity().getResources().getColor(R.color.accent_default))); + styledAttributes.recycle(); + } else { + pinButton.clearColorFilter(); + } + pinButton.setTag(enabled); + pinButton.setVisibility(View.VISIBLE); + } + + private void updatePinButton() { + SharedPreferences prefs = getActivity().getSharedPreferences("addons", Context.MODE_PRIVATE); + Set bookmarked = prefs.getStringSet("bookmarked", Collections.emptySet()); + setupPinButton(bookmarked.contains(addonId)); + } } diff --git a/app/src/main/java/org/xbmc/kore/ui/AddonListContainerFragment.java b/app/src/main/java/org/xbmc/kore/ui/AddonListContainerFragment.java new file mode 100644 index 0000000..690bdb2 --- /dev/null +++ b/app/src/main/java/org/xbmc/kore/ui/AddonListContainerFragment.java @@ -0,0 +1,112 @@ +/* + * Copyright 2016 Synced Synapse. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.xbmc.kore.ui; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.astuetz.PagerSlidingTabStrip; + +import org.xbmc.kore.R; +import org.xbmc.kore.utils.LogUtils; +import org.xbmc.kore.utils.TabsAdapter; +import org.xbmc.kore.utils.UIUtils; + +import java.util.Collections; +import java.util.Set; + +import butterknife.ButterKnife; +import butterknife.InjectView; + +/** + * Container for the TV Show overview and Episodes list + */ +public class AddonListContainerFragment extends Fragment { + private static final String TAG = LogUtils.makeLogTag(AddonListContainerFragment.class); + + private TabsAdapter tabsAdapter; + + @InjectView(R.id.pager_tab_strip) PagerSlidingTabStrip pagerTabStrip; + @InjectView(R.id.pager) ViewPager viewPager; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + if (container == null) { + // We're not being shown or there's nothing to show + return null; + } + + ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_default_view_pager, container, false); + ButterKnife.inject(this, root); + + tabsAdapter = new TabsAdapter(getActivity(), getChildFragmentManager()); + SharedPreferences prefs = getActivity().getSharedPreferences("addons", Context.MODE_PRIVATE); + Set bookmarked = prefs.getStringSet("bookmarked", Collections.emptySet()); + long baseFragmentId = 70 + bookmarked.size() * 100; + tabsAdapter.addTab(AddonListFragment.class, new Bundle(), R.string.addons, baseFragmentId); + for (String path: bookmarked) { + String name = prefs.getString("name_" + path, "Content"); + Bundle addon = new Bundle(); + addon.putString(AddonDetailsFragment.BUNDLE_KEY_NAME, name); + addon.putParcelable(MediaFileListFragment.ROOT_PATH, new MediaFileListFragment.FileLocation(name, "plugin://" + path, true)); + tabsAdapter.addTab(MediaFileListFragment.class, addon, name, ++baseFragmentId); + } + viewPager.setAdapter(tabsAdapter); + pagerTabStrip.setViewPager(viewPager); + + return root; + } + + @Override + public void onActivityCreated (Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + setHasOptionsMenu(false); + } + + public Fragment getCurrentTabFragment() { + return tabsAdapter.getItem(viewPager.getCurrentItem()); + } + + public View getSharedElement() { + View view = getView(); + if (view == null) + return null; + + //Note: this works as R.id.poster is only used in TVShowOverviewFragment. + //If the same id is used in other fragments in the TabsAdapter we + //need to check which fragment is currently displayed + View artView = view.findViewById(R.id.poster); + View scrollView = view.findViewById(R.id.media_panel); + if (( artView != null ) && + ( scrollView != null ) && + UIUtils.isViewInBounds(scrollView, artView)) { + return artView; + } + + return null; + } +} diff --git a/app/src/main/java/org/xbmc/kore/ui/AddonListFragment.java b/app/src/main/java/org/xbmc/kore/ui/AddonListFragment.java index 1692fee..bfee6b8 100644 --- a/app/src/main/java/org/xbmc/kore/ui/AddonListFragment.java +++ b/app/src/main/java/org/xbmc/kore/ui/AddonListFragment.java @@ -265,6 +265,7 @@ public class AddonListFragment extends Fragment viewHolder.fanart = addonDetails.fanart; viewHolder.poster = addonDetails.thumbnail; viewHolder.enabled = addonDetails.enabled; + viewHolder.browsable = AddonType.Types.XBMC_PYTHON_PLUGINSOURCE.equals(addonDetails.type); viewHolder.titleView.setText(viewHolder.addonName); viewHolder.detailsView.setText(addonDetails.summary); @@ -297,5 +298,6 @@ public class AddonListFragment extends Fragment String fanart; String poster; Boolean enabled; + Boolean browsable; } } diff --git a/app/src/main/java/org/xbmc/kore/ui/AddonOverviewFragment.java b/app/src/main/java/org/xbmc/kore/ui/AddonOverviewFragment.java new file mode 100644 index 0000000..b15c668 --- /dev/null +++ b/app/src/main/java/org/xbmc/kore/ui/AddonOverviewFragment.java @@ -0,0 +1,150 @@ +/* + * Copyright 2016 Synced Synapse. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.xbmc.kore.ui; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.astuetz.PagerSlidingTabStrip; + +import org.xbmc.kore.R; +import org.xbmc.kore.utils.LogUtils; +import org.xbmc.kore.utils.TabsAdapter; +import org.xbmc.kore.utils.UIUtils; +import org.xbmc.kore.utils.Utils; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import butterknife.ButterKnife; +import butterknife.InjectView; + +/** + * Container for the TV Show overview and Episodes list + */ +public class AddonOverviewFragment extends SharedElementFragment { + private static final String TAG = LogUtils.makeLogTag(AddonOverviewFragment.class); + + private TabsAdapter tabsAdapter; + + @InjectView(R.id.pager_tab_strip) PagerSlidingTabStrip pagerTabStrip; + @InjectView(R.id.pager) ViewPager viewPager; + + /** + * Create a new instance of this, initialized to show the addon addonId + */ + @TargetApi(21) + public static AddonOverviewFragment newInstance(AddonListFragment.ViewHolder vh) { + AddonOverviewFragment fragment = new AddonOverviewFragment(); + + Bundle args = new Bundle(); + args.putString(AddonDetailsFragment.BUNDLE_KEY_ADDONID, vh.addonId); + args.putString(AddonDetailsFragment.BUNDLE_KEY_NAME, vh.addonName); + args.putString(AddonDetailsFragment.BUNDLE_KEY_AUTHOR, vh.author); + args.putString(AddonDetailsFragment.BUNDLE_KEY_VERSION, vh.version); + args.putString(AddonDetailsFragment.BUNDLE_KEY_SUMMARY, vh.summary); + args.putString(AddonDetailsFragment.BUNDLE_KEY_DESCRIPTION, vh.description); + args.putString(AddonDetailsFragment.BUNDLE_KEY_FANART, vh.fanart); + args.putString(AddonDetailsFragment.BUNDLE_KEY_POSTER, vh.poster); + args.putBoolean(AddonDetailsFragment.BUNDLE_KEY_ENABLED, vh.enabled); + args.putBoolean(AddonDetailsFragment.BUNDLE_KEY_BROWSABLE, vh.browsable); + + if( Utils.isLollipopOrLater()) { + args.putString(AddonDetailsFragment.POSTER_TRANS_NAME, vh.artView.getTransitionName()); + } + fragment.setArguments(args); + return fragment; + } + + public Bundle contentArgs(Bundle details) { + String name = details.getString(AddonDetailsFragment.BUNDLE_KEY_NAME, "Content"); + String path = details.getString(AddonDetailsFragment.BUNDLE_KEY_ADDONID); + + Bundle content = new Bundle(); + content.putString(AddonDetailsFragment.BUNDLE_KEY_NAME, name); + MediaFileListFragment.FileLocation rootPath = new MediaFileListFragment.FileLocation(name, "plugin://" + path, true); + rootPath.setRootDir(true); + content.putParcelable(MediaFileListFragment.ROOT_PATH, rootPath); + content.putBoolean(MediaFileListFragment.DELAY_LOAD, true); + return content; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + Bundle args = getArguments(); + + if ((container == null) || (args == null)) { + // We're not being shown or there's nothing to show + return null; + } + + ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_default_view_pager, container, false); + ButterKnife.inject(this, root); + + long baseFragmentId = 1000; + tabsAdapter = new TabsAdapter(getActivity(), getChildFragmentManager()) + .addTab(AddonDetailsFragment.class, args, R.string.addon_overview, baseFragmentId++) + .addTab(MediaFileListFragment.class, contentArgs(args), R.string.addon_content, baseFragmentId++) + ; + viewPager.setAdapter(tabsAdapter); + pagerTabStrip.setViewPager(viewPager); + + return root; + } + + @Override + public void onActivityCreated (Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + setHasOptionsMenu(false); + } + + public Fragment getCurrentTabFragment() { + return tabsAdapter.getItem(viewPager.getCurrentItem()); + } + + @Override + public View getSharedElement() { + View view = getView(); + if (view == null) + return null; + + //Note: this works as R.id.poster is only used in TVShowOverviewFragment. + //If the same id is used in other fragments in the TabsAdapter we + //need to check which fragment is currently displayed + View artView = view.findViewById(R.id.poster); + View scrollView = view.findViewById(R.id.media_panel); + if (( artView != null ) && + ( scrollView != null ) && + UIUtils.isViewInBounds(scrollView, artView)) { + return artView; + } + + return null; + } +} diff --git a/app/src/main/java/org/xbmc/kore/ui/AddonsActivity.java b/app/src/main/java/org/xbmc/kore/ui/AddonsActivity.java index 5bd3fc6..18d3a88 100644 --- a/app/src/main/java/org/xbmc/kore/ui/AddonsActivity.java +++ b/app/src/main/java/org/xbmc/kore/ui/AddonsActivity.java @@ -70,7 +70,7 @@ public class AddonsActivity extends BaseActivity navigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout)); if (savedInstanceState == null) { - AddonListFragment addonListFragment = new AddonListFragment(); + AddonListContainerFragment addonListFragment = new AddonListContainerFragment(); // Setup animations if (Utils.isLollipopOrLater()) { @@ -206,7 +206,11 @@ public class AddonsActivity extends BaseActivity selectedAddonTitle = vh.addonName; // Replace list fragment - final AddonDetailsFragment addonDetailsFragment = AddonDetailsFragment.newInstance(vh); + final SharedElementFragment addonDetailsFragment = + vh.browsable + ? AddonOverviewFragment.newInstance(vh) + : AddonDetailsFragment.newInstance(vh) + ; FragmentTransaction fragTrans = getSupportFragmentManager().beginTransaction(); // Set up transitions diff --git a/app/src/main/java/org/xbmc/kore/ui/MediaFileListFragment.java b/app/src/main/java/org/xbmc/kore/ui/MediaFileListFragment.java index 36fdf07..e180b0c 100644 --- a/app/src/main/java/org/xbmc/kore/ui/MediaFileListFragment.java +++ b/app/src/main/java/org/xbmc/kore/ui/MediaFileListFragment.java @@ -52,6 +52,7 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Queue; +import java.util.regex.Pattern; /** * Presents a list of files of different types (Video/Music) @@ -63,6 +64,8 @@ public class MediaFileListFragment extends AbstractListFragment { public static final String PATH_CONTENTS = "pathContents"; public static final String ROOT_PATH_CONTENTS = "rootPathContents"; public static final String ROOT_VISITED = "rootVisited"; + public static final String ROOT_PATH = "rootPath"; + public static final String DELAY_LOAD = "delayLoad"; private static final String ADDON_SOURCE = "addons:"; private HostManager hostManager; @@ -76,6 +79,7 @@ public class MediaFileListFragment extends AbstractListFragment { int playlistId = PlaylistType.MUSIC_PLAYLISTID; // this is the ID of the music player // private MediaFileListAdapter adapter = null; boolean browseRootAlready = false; + FileLocation loadOnVisible = null; ArrayList rootFileLocation = new ArrayList(); Queue mediaQueueFileLocation = new LinkedList<>(); @@ -125,8 +129,10 @@ public class MediaFileListFragment extends AbstractListFragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = super.onCreateView(inflater, container, savedInstanceState); Bundle args = getArguments(); + FileLocation rootPath = null; if (args != null) { - mediaType = args.getString(MEDIA_TYPE, Files.Media.MUSIC); + rootPath = args.getParcelable(ROOT_PATH); + mediaType = args.getString(MEDIA_TYPE, Files.Media.FILES); if (mediaType.equalsIgnoreCase(Files.Media.VIDEO)) { playlistId = PlaylistType.VIDEO_PLAYLISTID; } else if (mediaType.equalsIgnoreCase(Files.Media.PICTURES)) { @@ -139,7 +145,8 @@ public class MediaFileListFragment extends AbstractListFragment { emptyView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - browseSources(); + if (!atRootDirectory()) + browseSources(); } }); @@ -156,12 +163,28 @@ public class MediaFileListFragment extends AbstractListFragment { browseRootAlready = savedInstanceState.getBoolean(ROOT_VISITED); ((MediaFileListAdapter) getAdapter()).setFilelistItems(list); } + else if (rootPath != null) { + loadOnVisible = rootPath; + // setUserVisibleHint may have already fired + setUserVisibleHint(getUserVisibleHint() || !args.getBoolean(DELAY_LOAD, false)); + } else { browseSources(); } return root; } + @Override + public void setUserVisibleHint (boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + if (isVisibleToUser && loadOnVisible != null) { + FileLocation rootPath = loadOnVisible; + loadOnVisible = null; + browseRootAlready = true; + browseDirectory(rootPath); + } + } + void handleFileSelect(FileLocation f) { // if selection is a directory, browse the the level below if (f.isDirectory) { @@ -308,11 +331,12 @@ public class MediaFileListFragment extends AbstractListFragment { ArrayList flList = new ArrayList(); - // insert the parent directory as the first item in the list - FileLocation fl = new FileLocation("..", parentDirectory, true); - fl.setRootDir(dir.isRootDir()); - flList.add(0, fl); - + if (dir.hasParent) { + // insert the parent directory as the first item in the list + FileLocation fl = new FileLocation("..", parentDirectory, true); + fl.setRootDir(dir.isRootDir()); + flList.add(0, fl); + } for (ListType.ItemFile i : result) { flList.add(FileLocation.newInstanceFromItemFile(getActivity(), i)); } @@ -630,6 +654,7 @@ public class MediaFileListFragment extends AbstractListFragment { public final String file; public final boolean isDirectory; + public final boolean hasParent; private boolean isRoot; @@ -640,10 +665,13 @@ public class MediaFileListFragment extends AbstractListFragment { this(title, path, isDir, null, null, null); } + static final Pattern noParent = Pattern.compile("plugin://[^/]*/?"); public FileLocation(String title, String path, boolean isDir, String details, String sizeDuration, String artUrl) { this.title = title; this.file = path; this.isDirectory = isDir; + this.hasParent = !noParent.matcher(path).matches(); + this.isRoot = false; this.details = details; @@ -698,6 +726,7 @@ public class MediaFileListFragment extends AbstractListFragment { this.title = in.readString(); this.file = in.readString(); this.isDirectory = (in.readInt() != 0); + this.hasParent = (in.readInt() != 0); this.isRoot = (in.readInt() != 0); this.details = in.readString(); @@ -713,6 +742,7 @@ public class MediaFileListFragment extends AbstractListFragment { out.writeString(title); out.writeString(file); out.writeInt(isDirectory ? 1 : 0); + out.writeInt(hasParent ? 1 : 0); out.writeInt(isRoot ? 1 : 0); out.writeString(details); diff --git a/app/src/main/java/org/xbmc/kore/ui/SharedElementFragment.java b/app/src/main/java/org/xbmc/kore/ui/SharedElementFragment.java new file mode 100644 index 0000000..19c56ce --- /dev/null +++ b/app/src/main/java/org/xbmc/kore/ui/SharedElementFragment.java @@ -0,0 +1,8 @@ +package org.xbmc.kore.ui; + +import android.support.v4.app.Fragment; +import android.view.View; + +public abstract class SharedElementFragment extends Fragment { + public abstract View getSharedElement(); +} diff --git a/app/src/main/java/org/xbmc/kore/utils/TabsAdapter.java b/app/src/main/java/org/xbmc/kore/utils/TabsAdapter.java index ae845c5..7741376 100644 --- a/app/src/main/java/org/xbmc/kore/utils/TabsAdapter.java +++ b/app/src/main/java/org/xbmc/kore/utils/TabsAdapter.java @@ -38,12 +38,21 @@ public class TabsAdapter extends FragmentPagerAdapter { private final Bundle args; private final int titleRes; private final long fragmentId; + private final String titleString; TabInfo(Class fragmentClass, Bundle args, int titleRes, long fragmentId) { this.fragmentClass = fragmentClass; this.args = args; this.titleRes = titleRes; this.fragmentId = fragmentId; + this.titleString = null; + } + TabInfo(Class fragmentClass, Bundle args, String titleString, long fragmentId) { + this.fragmentClass = fragmentClass; + this.args = args; + this.titleRes = 0; + this.fragmentId = fragmentId; + this.titleString = titleString; } } @@ -59,6 +68,12 @@ public class TabsAdapter extends FragmentPagerAdapter { return this; } + public TabsAdapter addTab(Class fragmentClass, Bundle args, String titleString, long fragmentId) { + TabInfo info = new TabInfo(fragmentClass, args, titleString, fragmentId); + tabInfos.add(info); + return this; + } + @Override public int getCount() { return tabInfos.size(); @@ -101,7 +116,7 @@ public class TabsAdapter extends FragmentPagerAdapter { TabInfo tabInfo = tabInfos.get(position); if (tabInfo != null) { // return context.getString(tabInfo.titleRes).toUpperCase(Locale.getDefault()); - return context.getString(tabInfo.titleRes); + return tabInfo.titleString == null? context.getString(tabInfo.titleRes) : tabInfo.titleString; } return null; } diff --git a/app/src/main/res/layout/fragment_addon_details.xml b/app/src/main/res/layout/fragment_addon_details.xml index f675055..912ae69 100644 --- a/app/src/main/res/layout/fragment_addon_details.xml +++ b/app/src/main/res/layout/fragment_addon_details.xml @@ -97,6 +97,14 @@ android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent"/> + Overview Episodes + Overview + Content + Artists Albums Genres @@ -299,6 +302,9 @@ Enable/Disable Addon Addon enabled Addon disabled + Pin/Unpin Addon + Addon pinned + Addon unpinned Hide watched