Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Weblate 2017-10-24 23:56:06 +02:00
commit 0e409bb993
35 changed files with 1417 additions and 23 deletions

View File

@ -34,6 +34,8 @@ Do not report crashes in the GitHub issue tracker. NewPipe has an automated cras
* Make sure your PR is up-to-date with the rest of the code. Often, a simple click on "Update branch" will do the job, but if not, you are asked to merge the master branch manually and resolve the problems on your own. That will make the maintainers' jobs way easier. * Make sure your PR is up-to-date with the rest of the code. Often, a simple click on "Update branch" will do the job, but if not, you are asked to merge the master branch manually and resolve the problems on your own. That will make the maintainers' jobs way easier.
* Please show intention to maintain your features and code after you contributed it. Unmaintained code is a hassle for the core developers, and just adds work. If you do not intend to maintain features you contributed, please think again about sumission, or clearly state that in the description of your PR. * Please show intention to maintain your features and code after you contributed it. Unmaintained code is a hassle for the core developers, and just adds work. If you do not intend to maintain features you contributed, please think again about sumission, or clearly state that in the description of your PR.
* Respond yourselves if someone requests changes or otherwise raises issues about your PRs. * Respond yourselves if someone requests changes or otherwise raises issues about your PRs.
* Check if your contributions align with the [fdroid inclusion guidelines](https://f-droid.org/en/docs/Inclusion_Policy/).
* Check if your submission can be build with the current fdroid build server setup.
## Communication ## Communication

View File

@ -48,7 +48,7 @@ dependencies {
exclude module: 'support-annotations' exclude module: 'support-annotations'
} }
compile 'com.github.TeamNewPipe:NewPipeExtractor:1df3f67' compile 'com.github.TeamNewPipe:NewPipeExtractor:7899cd1'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19' testCompile 'org.mockito:mockito-core:1.10.19'

View File

@ -119,6 +119,12 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
}); });
} }
if(sharedPreferences.getBoolean(Constants.KEY_MAIN_PAGE_CHANGE, false)) {
if (DEBUG) Log.d(TAG, "main page has changed, recreating main fragment...");
sharedPreferences.edit().putBoolean(Constants.KEY_MAIN_PAGE_CHANGE, false).apply();
NavigationHelper.openMainActivity(this);
}
} }
@Override @Override

View File

@ -10,22 +10,22 @@ import org.schabi.newpipe.util.NavigationHelper;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
/* /**
* Copyright (C) Christian Schabesberger 2017 <chris.schabesberger@mailbox.org> * Copyright (C) Christian Schabesberger 2017 <chris.schabesberger@mailbox.org>
* RouterActivity .java is part of NewPipe. * RouterActivity.java is part of NewPipe.
* *
* OpenHitboxStreams is free software: you can redistribute it and/or modify * NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* OpenHitboxStreams is distributed in the hope that it will be useful, * NewPipe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with OpenHitboxStreams. If not, see <http://www.gnu.org/licenses/>. * along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**

View File

@ -50,6 +50,8 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
protected Button errorButtonRetry; protected Button errorButtonRetry;
protected TextView errorTextView; protected TextView errorTextView;
protected boolean useAsFrontPage = false;
@Override @Override
public void onViewCreated(View rootView, Bundle savedInstanceState) { public void onViewCreated(View rootView, Bundle savedInstanceState) {
super.onViewCreated(rootView, savedInstanceState); super.onViewCreated(rootView, savedInstanceState);
@ -62,6 +64,10 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
wasLoading.set(isLoading.get()); wasLoading.set(isLoading.get());
} }
public void useAsFrontPage(boolean value) {
useAsFrontPage = value;
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Init // Init
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/

View File

@ -1,5 +1,6 @@
package org.schabi.newpipe.fragments; package org.schabi.newpipe.fragments;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout; import android.support.design.widget.TabLayout;
@ -8,21 +9,50 @@ import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.support.v7.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.schabi.newpipe.BaseFragment; import org.schabi.newpipe.BaseFragment;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
import org.schabi.newpipe.fragments.list.feed.FeedFragment;
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
import org.schabi.newpipe.fragments.subscription.SubscriptionFragment; import org.schabi.newpipe.fragments.subscription.SubscriptionFragment;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.KioskTranslator;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import java.util.concurrent.ExecutionException;
public class MainFragment extends BaseFragment implements TabLayout.OnTabSelectedListener { public class MainFragment extends BaseFragment implements TabLayout.OnTabSelectedListener {
private ViewPager viewPager; private ViewPager viewPager;
private boolean showBlankTab = false;
private static final int FALLBACK_SERVICE_ID = 0; // Youtbe
private static final String FALLBACK_CHANNEL_URL =
"https://www.youtube.com/channel/UC-9-kyTW8ZkZNDHQJ6FgpwQ";
private static final String FALLBACK_CHANNEL_NAME = "Music";
private static final String FALLBACK_KIOSK_ID = "Trending";
public int currentServiceId = -1;
/*//////////////////////////////////////////////////////////////////////////
// Konst
//////////////////////////////////////////////////////////////////////////*/
private static final int KIOSK_MENU_OFFSETT = 2000;
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Fragment's LifeCycle // Fragment's LifeCycle
@ -36,6 +66,8 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
currentServiceId = Integer.parseInt(PreferenceManager.getDefaultSharedPreferences(getActivity())
.getString(getString(R.string.current_service_key), "0"));
return inflater.inflate(R.layout.fragment_main, container, false); return inflater.inflate(R.layout.fragment_main, container, false);
} }
@ -63,6 +95,16 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "], inflater = [" + inflater + "]"); if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "], inflater = [" + inflater + "]");
inflater.inflate(R.menu.main_fragment_menu, menu); inflater.inflate(R.menu.main_fragment_menu, menu);
SubMenu kioskMenu = menu.addSubMenu(getString(R.string.kiosk));
try {
createKioskMenu(kioskMenu, inflater);
} catch (Exception e) {
ErrorActivity.reportError(activity, e,
activity.getClass(),
null,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"none", "", R.string.app_ui_crash));
}
ActionBar supportActionBar = activity.getSupportActionBar(); ActionBar supportActionBar = activity.getSupportActionBar();
if (supportActionBar != null) { if (supportActionBar != null) {
@ -112,6 +154,14 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
@Override @Override
public Fragment getItem(int position) { public Fragment getItem(int position) {
switch (position) { switch (position) {
case 0:
if(PreferenceManager.getDefaultSharedPreferences(getActivity())
.getString(getString(R.string.main_page_content_key), getString(R.string.blank_page_key))
.equals(getString(R.string.subscription_page_key))) {
return new SubscriptionFragment();
} else {
return getMainPageFramgent();
}
case 1: case 1:
return new SubscriptionFragment(); return new SubscriptionFragment();
default: default:
@ -126,7 +176,93 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
@Override @Override
public int getCount() { public int getCount() {
return this.tabTitles.length; if(PreferenceManager.getDefaultSharedPreferences(getActivity())
.getString(getString(R.string.main_page_content_key), getString(R.string.blank_page_key))
.equals(getString(R.string.subscription_page_key))) {
return 1;
} else {
return 2;
}
}
}
/*//////////////////////////////////////////////////////////////////////////
// Main page content
//////////////////////////////////////////////////////////////////////////*/
private Fragment getMainPageFramgent() {
try {
SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(getActivity());
final String setMainPage = preferences.getString(getString(R.string.main_page_content_key),
getString(R.string.main_page_selectd_kiosk_id));
if(setMainPage.equals(getString(R.string.blank_page_key))) {
return new BlankFragment();
} else if(setMainPage.equals(getString(R.string.kiosk_page_key))) {
int serviceId = preferences.getInt(getString(R.string.main_page_selected_service),
FALLBACK_SERVICE_ID);
String kioskId = preferences.getString(getString(R.string.main_page_selectd_kiosk_id),
FALLBACK_KIOSK_ID);
KioskFragment fragment = KioskFragment.getInstance(serviceId, kioskId
);
fragment.useAsFrontPage(true);
return fragment;
} else if(setMainPage.equals(getString(R.string.feed_page_key))) {
FeedFragment fragment = new FeedFragment();
fragment.useAsFrontPage(true);
return fragment;
} else if(setMainPage.equals(getString(R.string.channel_page_key))) {
int serviceId = preferences.getInt(getString(R.string.main_page_selected_service),
FALLBACK_SERVICE_ID);
String url = preferences.getString(getString(R.string.main_page_selected_channel_url),
FALLBACK_CHANNEL_URL);
String name = preferences.getString(getString(R.string.main_page_selected_channel_name),
FALLBACK_CHANNEL_NAME);
ChannelFragment fragment = ChannelFragment.getInstance(serviceId, url, name);
fragment.useAsFrontPage(true);
return fragment;
} else {
return new BlankFragment();
}
} catch (Exception e) {
ErrorActivity.reportError(activity, e,
activity.getClass(),
null,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"none", "", R.string.app_ui_crash));
return new BlankFragment();
}
}
/*//////////////////////////////////////////////////////////////////////////
// Select Kiosk
//////////////////////////////////////////////////////////////////////////*/
private void createKioskMenu(Menu menu, MenuInflater menuInflater)
throws Exception {
StreamingService service = NewPipe.getService(currentServiceId);
KioskList kl = service.getKioskList();
int i = 0;
for(final String ks : kl.getAvailableKiosks()) {
menu.add(0, KIOSK_MENU_OFFSETT + i, Menu.NONE,
KioskTranslator.getTranslatedKioskName(ks, getContext()))
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
try {
NavigationHelper.openKioskFragment(getFragmentManager(), currentServiceId, ks);
} catch (Exception e) {
ErrorActivity.reportError(activity, e,
activity.getClass(),
null,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"none", "", R.string.app_ui_crash));
}
return true;
}
});
i++;
} }
} }
} }

View File

@ -135,7 +135,9 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
@Override @Override
public void selected(StreamInfoItem selectedItem) { public void selected(StreamInfoItem selectedItem) {
onItemSelected(selectedItem); onItemSelected(selectedItem);
NavigationHelper.openVideoDetailFragment(getFragmentManager(), selectedItem.service_id, selectedItem.url, selectedItem.name); NavigationHelper.openVideoDetailFragment(
useAsFrontPage?getParentFragment().getFragmentManager():getFragmentManager(),
selectedItem.service_id, selectedItem.url, selectedItem.name);
} }
}); });
@ -143,7 +145,9 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
@Override @Override
public void selected(ChannelInfoItem selectedItem) { public void selected(ChannelInfoItem selectedItem) {
onItemSelected(selectedItem); onItemSelected(selectedItem);
NavigationHelper.openChannelFragment(getFragmentManager(), selectedItem.service_id, selectedItem.url, selectedItem.name); NavigationHelper.openChannelFragment(
useAsFrontPage?getParentFragment().getFragmentManager():getFragmentManager(),
selectedItem.service_id, selectedItem.url, selectedItem.name);
} }
}); });
@ -151,7 +155,9 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
@Override @Override
public void selected(PlaylistInfoItem selectedItem) { public void selected(PlaylistInfoItem selectedItem) {
onItemSelected(selectedItem); onItemSelected(selectedItem);
NavigationHelper.openPlaylistFragment(getFragmentManager(), selectedItem.service_id, selectedItem.url, selectedItem.name); NavigationHelper.openPlaylistFragment(
useAsFrontPage?getParentFragment().getFragmentManager():getFragmentManager(),
selectedItem.service_id, selectedItem.url, selectedItem.name);
} }
}); });

View File

@ -7,6 +7,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -88,7 +89,8 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_channel, container, false); View v = inflater.inflate(R.layout.fragment_channel, container, false);
return v;
} }
@Override @Override
@ -109,6 +111,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
headerTitleView = headerRootLayout.findViewById(R.id.channel_title_view); headerTitleView = headerRootLayout.findViewById(R.id.channel_title_view);
headerSubscribersTextView = headerRootLayout.findViewById(R.id.channel_subscriber_view); headerSubscribersTextView = headerRootLayout.findViewById(R.id.channel_subscriber_view);
headerSubscribeButton = headerRootLayout.findViewById(R.id.channel_subscribe_button); headerSubscribeButton = headerRootLayout.findViewById(R.id.channel_subscribe_button);
return headerRootLayout; return headerRootLayout;
} }
@ -118,15 +121,21 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "], inflater = [" + inflater + "]");
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_channel, menu); ActionBar supportActionBar = activity.getSupportActionBar();
if(useAsFrontPage) {
supportActionBar.setDisplayHomeAsUpEnabled(false);
//supportActionBar.setDisplayShowTitleEnabled(false);
} else {
inflater.inflate(R.menu.menu_channel, menu);
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "], inflater = [" + inflater + "]");
menuRssButton = menu.findItem(R.id.menu_item_rss);
if (currentInfo != null) {
menuRssButton.setVisible(!TextUtils.isEmpty(currentInfo.feed_url));
}
menuRssButton = menu.findItem(R.id.menu_item_rss);
if (currentInfo != null) {
menuRssButton.setVisible(!TextUtils.isEmpty(currentInfo.feed_url));
} }
} }
@Override @Override

View File

@ -36,10 +36,8 @@ import io.reactivex.MaybeObserver;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer; import io.reactivex.functions.Consumer;
import io.reactivex.functions.Predicate; import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;
public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Void> { public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Void> {
@ -121,6 +119,11 @@ public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Voi
if (supportActionBar != null) { if (supportActionBar != null) {
supportActionBar.setTitle(R.string.fragment_whats_new); supportActionBar.setTitle(R.string.fragment_whats_new);
} }
if(useAsFrontPage) {
supportActionBar.setDisplayHomeAsUpEnabled(false);
//supportActionBar.setDisplayShowTitleEnabled(false);
}
} }
@Override @Override

View File

@ -0,0 +1,158 @@
package org.schabi.newpipe.fragments.list.kiosk;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.UrlIdHandler;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.KioskTranslator;
import org.schabi.newpipe.util.NavigationHelper;
import io.reactivex.Single;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
/**
* Created by Christian Schabesberger on 23.09.17.
*
* Copyright (C) Christian Schabesberger 2017 <chris.schabesberger@mailbox.org>
* KioskFragment.java is part of NewPipe.
*
* NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NewPipe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private View headerRootLayout;
private TextView headerTitleView;
public static KioskFragment getInstance(int serviceId)
throws ExtractionException {
return getInstance(serviceId, NewPipe.getService(serviceId)
.getKioskList()
.getDefaultKioskId());
}
public static KioskFragment getInstance(int serviceId, String kioskId)
throws ExtractionException {
KioskFragment instance = new KioskFragment();
StreamingService service = NewPipe.getService(serviceId);
UrlIdHandler kioskTypeUrlIdHandler = service.getKioskList()
.getUrlIdHandlerByType(kioskId);
instance.setInitialData(serviceId,
kioskTypeUrlIdHandler.getUrl(kioskId),
kioskId);
return instance;
}
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_kiosk, container, false);
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
ActionBar supportActionBar = activity.getSupportActionBar();
if (supportActionBar != null && useAsFrontPage) {
//supportActionBar.setDisplayShowTitleEnabled(false);
supportActionBar.setDisplayHomeAsUpEnabled(false);
}
}
/*//////////////////////////////////////////////////////////////////////////
// Load and handle
//////////////////////////////////////////////////////////////////////////*/
@Override
public Single<KioskInfo> loadResult(boolean forceReload) {
String contentCountry = PreferenceManager
.getDefaultSharedPreferences(activity)
.getString(getString(R.string.search_language_key),
getString(R.string.default_language_value));
return ExtractorHelper.getKioskInfo(serviceId, url, contentCountry, forceReload);
}
@Override
public Single<ListExtractor.NextItemsResult> loadMoreItemsLogic() {
return ExtractorHelper.getMoreKioskItems(serviceId, url, currentNextItemsUrl);
}
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@Override
public void showLoading() {
super.showLoading();
animateView(itemsList, false, 100);
}
@Override
public void handleResult(@NonNull final KioskInfo result) {
super.handleResult(result);
String title = KioskTranslator.getTranslatedKioskName(result.id, getActivity());
ActionBar supportActionBar = activity.getSupportActionBar();
supportActionBar.setTitle(title);
if (!result.errors.isEmpty()) {
showSnackBarError(result.errors,
UserAction.REQUESTED_PLAYLIST,
NewPipe.getNameOfService(result.service_id), result.url, 0);
}
}
@Override
public void handleNextItems(ListExtractor.NextItemsResult result) {
super.handleNextItems(result);
if (!result.errors.isEmpty()) {
showSnackBarError(result.errors,
UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(serviceId)
, "Get next page of: " + url, 0);
}
}
}

View File

@ -62,6 +62,8 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
activity.getSupportActionBar().setDisplayShowTitleEnabled(true);
activity.setTitle(R.string.tab_subscriptions);
return inflater.inflate(R.layout.fragment_subscription, container, false); return inflater.inflate(R.layout.fragment_subscription, container, false);
} }

View File

@ -19,8 +19,8 @@ public abstract class BasePreferenceFragment extends PreferenceFragmentCompat {
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); defaultPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
super.onCreate(savedInstanceState);
} }
@Override @Override

View File

@ -1,12 +1,175 @@
package org.schabi.newpipe.settings; package org.schabi.newpipe.settings;
import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import org.schabi.newpipe.R; 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.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.KioskTranslator;
public class ContentSettingsFragment extends BasePreferenceFragment { public class ContentSettingsFragment extends BasePreferenceFragment {
@Override @Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.content_settings); addPreferencesFromResource(R.xml.content_settings);
final ListPreference mainPageContentPref = (ListPreference) findPreference(getString(R.string.main_page_content_key));
mainPageContentPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValueO) {
final String newValue = newValueO.toString();
final String mainPrefOldValue =
defaultPreferences.getString(getString(R.string.main_page_content_key), "blank_page");
final String mainPrefOldSummary = getMainPagePrefSummery(mainPrefOldValue, mainPageContentPref);
if(newValue.equals(getString(R.string.kiosk_page_key))) {
SelectKioskFragment selectKioskFragment = new SelectKioskFragment();
selectKioskFragment.setOnSelectedLisener(new SelectKioskFragment.OnSelectedLisener() {
@Override
public void onKioskSelected(String kioskId, int service_id) {
defaultPreferences.edit()
.putInt(getString(R.string.main_page_selected_service), service_id).apply();
defaultPreferences.edit()
.putString(getString(R.string.main_page_selectd_kiosk_id), kioskId).apply();
String serviceName = "";
try {
serviceName = NewPipe.getService(service_id).getServiceInfo().name;
} catch (ExtractionException e) {
onError(e);
}
String kioskName = KioskTranslator.getTranslatedKioskName(kioskId,
getContext());
String summary =
String.format(getString(R.string.service_kosk_string),
serviceName,
kioskName);
mainPageContentPref.setSummary(summary);
}
});
selectKioskFragment.setOnCancelListener(new SelectKioskFragment.OnCancelListener() {
@Override
public void onCancel() {
mainPageContentPref.setSummary(mainPrefOldSummary);
mainPageContentPref.setValue(mainPrefOldValue);
}
});
selectKioskFragment.show(getFragmentManager(), "select_kiosk");
} else if(newValue.equals(getString(R.string.channel_page_key))) {
SelectChannelFragment selectChannelFragment = new SelectChannelFragment();
selectChannelFragment.setOnSelectedLisener(new SelectChannelFragment.OnSelectedLisener() {
@Override
public void onChannelSelected(String url, String name, int service) {
defaultPreferences.edit()
.putInt(getString(R.string.main_page_selected_service), service).apply();
defaultPreferences.edit()
.putString(getString(R.string.main_page_selected_channel_url), url).apply();
defaultPreferences.edit()
.putString(getString(R.string.main_page_selected_channel_name), name).apply();
mainPageContentPref.setSummary(name);
}
});
selectChannelFragment.setOnCancelListener(new SelectChannelFragment.OnCancelListener() {
@Override
public void onCancel() {
mainPageContentPref.setSummary(mainPrefOldSummary);
mainPageContentPref.setValue(mainPrefOldValue);
}
});
selectChannelFragment.show(getFragmentManager(), "select_channel");
} else {
mainPageContentPref.setSummary(getMainPageSummeryByKey(newValue));
}
defaultPreferences.edit().putBoolean(Constants.KEY_MAIN_PAGE_CHANGE, true).apply();
return true;
}
});
}
@Override
public void onResume() {
super.onResume();
final String mainPageContentKey = getString(R.string.main_page_content_key);
final Preference mainPagePref = findPreference(getString(R.string.main_page_content_key));
final String bpk = getString(R.string.blank_page_key);
if(defaultPreferences.getString(mainPageContentKey, bpk)
.equals(getString(R.string.channel_page_key))) {
mainPagePref.setSummary(defaultPreferences.getString(getString(R.string.main_page_selected_channel_name), "error"));
} else if(defaultPreferences.getString(mainPageContentKey, bpk)
.equals(getString(R.string.kiosk_page_key))) {
try {
StreamingService service = NewPipe.getService(
defaultPreferences.getInt(
getString(R.string.main_page_selected_service), 0));
String kioskName = KioskTranslator.getTranslatedKioskName(
defaultPreferences.getString(
getString(R.string.main_page_selectd_kiosk_id), "Trending"),
getContext());
String summary =
String.format(getString(R.string.service_kosk_string),
service.getServiceInfo().name,
kioskName);
mainPagePref.setSummary(summary);
} catch (Exception e) {
onError(e);
}
}
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
private String getMainPagePrefSummery(final String mainPrefOldValue, final ListPreference mainPageContentPref) {
if(mainPrefOldValue.equals(getString(R.string.channel_page_key))) {
return defaultPreferences.getString(getString(R.string.main_page_selected_channel_name), "error");
} else {
return mainPageContentPref.getSummary().toString();
}
}
private int getMainPageSummeryByKey(final String key) {
if(key.equals(getString(R.string.blank_page_key))) {
return R.string.blank_page_summary;
} else if(key.equals(getString(R.string.kiosk_page_key))) {
return R.string.kiosk_page_summary;
} else if(key.equals(getString(R.string.feed_page_key))) {
return R.string.feed_page_summary;
} else if(key.equals(getString(R.string.subscription_page_key))) {
return R.string.subscription_page_summary;
} else if(key.equals(getString(R.string.channel_page_key))) {
return R.string.channel_page_summary;
}
return R.string.blank_page_summary;
}
/*//////////////////////////////////////////////////////////////////////////
// Error
//////////////////////////////////////////////////////////////////////////*/
protected boolean onError(Throwable e) {
final Activity activity = getActivity();
ErrorActivity.reportError(activity, e,
activity.getClass(),
null,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"none", "", R.string.app_ui_crash));
return true;
} }
} }

View File

@ -0,0 +1,238 @@
package org.schabi.newpipe.settings;
import android.app.Activity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
import org.schabi.newpipe.fragments.subscription.SubscriptionService;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import java.util.List;
import java.util.Vector;
import de.hdodenhof.circleimageview.CircleImageView;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
/**
* Created by Christian Schabesberger on 26.09.17.
* SelectChannelFragment.java is part of NewPipe.
*
* NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NewPipe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public class SelectChannelFragment extends DialogFragment {
private SelectChannelAdapter channelAdapter;
private SubscriptionService subscriptionService;
private ImageLoader imageLoader = ImageLoader.getInstance();
private ProgressBar progressBar;
private TextView emptyView;
private RecyclerView recyclerView;
private List<SubscriptionEntity> subscriptions = new Vector<>();
/*//////////////////////////////////////////////////////////////////////////
// Interfaces
//////////////////////////////////////////////////////////////////////////*/
public interface OnSelectedLisener {
void onChannelSelected(String url, String name, int service);
}
OnSelectedLisener onSelectedLisener = null;
public void setOnSelectedLisener(OnSelectedLisener listener) {
onSelectedLisener = listener;
}
public interface OnCancelListener {
void onCancel();
}
OnCancelListener onCancelListener = null;
public void setOnCancelListener(OnCancelListener listener) {
onCancelListener = listener;
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.select_channel_fragment, container, false);
recyclerView = (RecyclerView) v.findViewById(R.id.items_list);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
channelAdapter = new SelectChannelAdapter();
recyclerView.setAdapter(channelAdapter);
progressBar = v.findViewById(R.id.progressBar);
emptyView = v.findViewById(R.id.empty_state_view);
progressBar.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
emptyView.setVisibility(View.GONE);
subscriptionService = SubscriptionService.getInstance();
subscriptionService.getSubscription().toObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(getSubscriptionObserver());
return v;
}
/*//////////////////////////////////////////////////////////////////////////
// Handle actions
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCancel(final DialogInterface dialogInterface) {
super.onCancel(dialogInterface);
if(onCancelListener != null) {
onCancelListener.onCancel();
}
}
private void clickedItem(int position) {
if(onSelectedLisener != null) {
SubscriptionEntity entry = subscriptions.get(position);
onSelectedLisener.onChannelSelected(entry.getUrl(), entry.getName(), entry.getServiceId());
}
dismiss();
}
/*//////////////////////////////////////////////////////////////////////////
// Item handling
//////////////////////////////////////////////////////////////////////////*/
private void displayChannels(List<SubscriptionEntity> subscriptions) {
this.subscriptions = subscriptions;
progressBar.setVisibility(View.GONE);
if(subscriptions.isEmpty()) {
emptyView.setVisibility(View.VISIBLE);
return;
}
recyclerView.setVisibility(View.VISIBLE);
}
private Observer<List<SubscriptionEntity>> getSubscriptionObserver() {
return new Observer<List<SubscriptionEntity>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(List<SubscriptionEntity> subscriptions) {
displayChannels(subscriptions);
}
@Override
public void onError(Throwable exception) {
onError(exception);
}
@Override
public void onComplete() {
}
};
}
private class SelectChannelAdapter extends
RecyclerView.Adapter<SelectChannelAdapter.SelectChannelItemHolder> {
@Override
public SelectChannelItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View item = LayoutInflater.from(parent.getContext())
.inflate(R.layout.select_channel_item, parent, false);
return new SelectChannelItemHolder(item);
}
@Override
public void onBindViewHolder(SelectChannelItemHolder holder, final int position) {
SubscriptionEntity entry = subscriptions.get(position);
holder.titleView.setText(entry.getName());
holder.view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
clickedItem(position);
}
});
imageLoader.displayImage(entry.getAvatarUrl(), holder.thumbnailView, DISPLAY_IMAGE_OPTIONS);
}
@Override
public int getItemCount() {
return subscriptions.size();
}
public class SelectChannelItemHolder extends RecyclerView.ViewHolder {
public SelectChannelItemHolder(View v) {
super(v);
this.view = v;
thumbnailView = v.findViewById(R.id.itemThumbnailView);
titleView = v.findViewById(R.id.itemTitleView);
}
public View view;
public CircleImageView thumbnailView;
public TextView titleView;
}
}
/*//////////////////////////////////////////////////////////////////////////
// Error
//////////////////////////////////////////////////////////////////////////*/
protected boolean onError(Throwable e) {
final Activity activity = getActivity();
ErrorActivity.reportError(activity, e,
activity.getClass(),
null,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"none", "", R.string.app_ui_crash));
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// ImageLoaderOptions
//////////////////////////////////////////////////////////////////////////*/
/**
* Base display options
*/
public static final DisplayImageOptions DISPLAY_IMAGE_OPTIONS =
new DisplayImageOptions.Builder()
.cacheInMemory(true)
.build();
}

View File

@ -0,0 +1,192 @@
package org.schabi.newpipe.settings;
import android.app.Activity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.fragments.subscription.SubscriptionService;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.KioskTranslator;
import org.schabi.newpipe.util.ServiceIconMapper;
import java.util.List;
import java.util.Vector;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* Created by Christian Schabesberger on 09.10.17.
* SelectKioskFragment.java is part of NewPipe.
*
* NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NewPipe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public class SelectKioskFragment extends DialogFragment {
RecyclerView recyclerView = null;
SelectKioskAdapter selectKioskAdapter = null;
/*//////////////////////////////////////////////////////////////////////////
// Interfaces
//////////////////////////////////////////////////////////////////////////*/
public interface OnSelectedLisener {
void onKioskSelected(String kioskId, int service_id);
}
OnSelectedLisener onSelectedLisener = null;
public void setOnSelectedLisener(OnSelectedLisener listener) {
onSelectedLisener = listener;
}
public interface OnCancelListener {
void onCancel();
}
OnCancelListener onCancelListener = null;
public void setOnCancelListener(OnCancelListener listener) {
onCancelListener = listener;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.select_kiosk_fragment, container, false);
recyclerView = (RecyclerView) v.findViewById(R.id.items_list);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
try {
selectKioskAdapter = new SelectKioskAdapter();
} catch (Exception e) {
onError(e);
}
recyclerView.setAdapter(selectKioskAdapter);
return v;
}
/*//////////////////////////////////////////////////////////////////////////
// Handle actions
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCancel(final DialogInterface dialogInterface) {
super.onCancel(dialogInterface);
if(onCancelListener != null) {
onCancelListener.onCancel();
}
}
private void clickedItem(SelectKioskAdapter.Entry entry) {
if(onSelectedLisener != null) {
onSelectedLisener.onKioskSelected(entry.kioskId, entry.serviceId);
}
dismiss();
}
private class SelectKioskAdapter
extends RecyclerView.Adapter<SelectKioskAdapter.SelectKioskItemHolder> {
public class Entry {
public Entry (int i, int si, String ki, String kn){
icon = i; serviceId=si; kioskId=ki; kioskName = kn;
}
int icon;
int serviceId;
String kioskId;
String kioskName;
}
private List<Entry> kioskList = new Vector<>();
public SelectKioskAdapter()
throws Exception {
for(StreamingService service : NewPipe.getServices()) {
for(String kioskId : service.getKioskList().getAvailableKiosks()) {
String name = String.format(getString(R.string.service_kosk_string),
service.getServiceInfo().name,
KioskTranslator.getTranslatedKioskName(kioskId, getContext()));
kioskList.add(new Entry(
//ServiceIconMapper.getIconResource(service.getServiceId()),
ServiceIconMapper.getIconResource(-1),
service.getServiceId(),
kioskId,
name));
}
}
}
public int getItemCount() {
//todo: uncommend this line on multyservice support
//return kioskList.size();
return 1;
}
public SelectKioskItemHolder onCreateViewHolder(ViewGroup parent, int type) {
View item = LayoutInflater.from(parent.getContext())
.inflate(R.layout.select_kiosk_item, parent, false);
return new SelectKioskItemHolder(item);
}
public class SelectKioskItemHolder extends RecyclerView.ViewHolder {
public SelectKioskItemHolder(View v) {
super(v);
this.view = v;
thumbnailView = v.findViewById(R.id.itemThumbnailView);
titleView = v.findViewById(R.id.itemTitleView);
}
public View view;
public ImageView thumbnailView;
public TextView titleView;
}
public void onBindViewHolder(SelectKioskItemHolder holder, final int position) {
final Entry entry = kioskList.get(position);
holder.titleView.setText(entry.kioskName);
holder.thumbnailView.setImageDrawable(ContextCompat.getDrawable(getContext(), entry.icon));
holder.view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
clickedItem(entry);
}
});
}
}
/*//////////////////////////////////////////////////////////////////////////
// Error
//////////////////////////////////////////////////////////////////////////*/
protected boolean onError(Throwable e) {
final Activity activity = getActivity();
ErrorActivity.reportError(activity, e,
activity.getClass(),
null,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"none", "", R.string.app_ui_crash));
return true;
}
}

View File

@ -9,6 +9,7 @@ public class Constants {
public static final String KEY_QUERY = "key_query"; public static final String KEY_QUERY = "key_query";
public static final String KEY_THEME_CHANGE = "key_theme_change"; public static final String KEY_THEME_CHANGE = "key_theme_change";
public static final String KEY_MAIN_PAGE_CHANGE = "key_main_page_change";
public static final int NO_SERVICE_ID = -1; public static final int NO_SERVICE_ID = -1;
} }

View File

@ -26,6 +26,7 @@ import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.extractor.ListExtractor.NextItemsResult; import org.schabi.newpipe.extractor.ListExtractor.NextItemsResult;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.search.SearchEngine; import org.schabi.newpipe.extractor.search.SearchEngine;
import org.schabi.newpipe.extractor.search.SearchResult; import org.schabi.newpipe.extractor.search.SearchResult;
@ -138,6 +139,24 @@ public final class ExtractorHelper {
}); });
} }
public static Single<KioskInfo> getKioskInfo(final int serviceId, final String url, final String contentCountry, boolean forceLoad) {
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<KioskInfo>() {
@Override
public KioskInfo call() throws Exception {
return KioskInfo.getInfo(NewPipe.getService(serviceId), url, contentCountry);
}
}));
}
public static Single<NextItemsResult> getMoreKioskItems(final int serviceId, final String url, final String nextStreamsUrl) {
return Single.fromCallable(new Callable<NextItemsResult>() {
@Override
public NextItemsResult call() throws Exception {
return KioskInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl);
}
});
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Utils // Utils
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/

View File

@ -0,0 +1,38 @@
package org.schabi.newpipe.util;
import android.content.Context;
import org.schabi.newpipe.R;
/**
* Created by Chrsitian Schabesberger on 28.09.17.
* KioskTranslator.java is part of NewPipe.
*
* NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NewPipe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public class KioskTranslator {
public static String getTranslatedKioskName(String kioskId, Context c) {
switch(kioskId) {
case "Trending":
return c.getString(R.string.trending);
case "Top 50":
return c.getString(R.string.top_50);
case "New & hot":
return c.getString(R.string.new_and_hot);
default:
return kioskId;
}
}
}

View File

@ -23,6 +23,7 @@ import org.schabi.newpipe.fragments.MainFragment;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment; import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.fragments.list.channel.ChannelFragment; import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
import org.schabi.newpipe.fragments.list.feed.FeedFragment; import org.schabi.newpipe.fragments.list.feed.FeedFragment;
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment; import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment;
import org.schabi.newpipe.fragments.list.search.SearchFragment; import org.schabi.newpipe.fragments.list.search.SearchFragment;
import org.schabi.newpipe.history.HistoryActivity; import org.schabi.newpipe.history.HistoryActivity;
@ -93,7 +94,7 @@ public class NavigationHelper {
if (!popped) openMainFragment(fragmentManager); if (!popped) openMainFragment(fragmentManager);
} }
private static void openMainFragment(FragmentManager fragmentManager) { public static void openMainFragment(FragmentManager fragmentManager) {
InfoCache.getInstance().trimCache(); InfoCache.getInstance().trimCache();
fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
@ -163,6 +164,15 @@ public class NavigationHelper {
.commit(); .commit();
} }
public static void openKioskFragment(FragmentManager fragmentManager, int serviceId, String kioskId)
throws ExtractionException {
fragmentManager.beginTransaction()
.setCustomAnimations(R.animator.custom_fade_in, R.animator.custom_fade_out, R.animator.custom_fade_in, R.animator.custom_fade_out)
.replace(R.id.fragment_holder, KioskFragment.getInstance(serviceId, kioskId))
.addToBackStack(null)
.commit();
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Through Intents // Through Intents
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/

View File

@ -0,0 +1,35 @@
package org.schabi.newpipe.util;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.NewPipe;
/**
* Created by Chrsitian Schabesberger on 09.10.17.
* ServiceIconMapper.java is part of NewPipe.
*
* NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NewPipe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public class ServiceIconMapper {
public static int getIconResource(int service_id) {
switch(service_id) {
case 0:
return R.drawable.youtube;
case 1:
return R.drawable.soud_cloud;
default:
return R.drawable.service;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/items_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:windowBackground"
android:scrollbars="vertical"
tools:listitem="@layout/list_stream_item"/>
<ProgressBar
android:id="@+id/loading_progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="true"
android:visibility="gone"
tools:visibility="visible"/>
<LinearLayout
android:id="@+id/empty_state_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical"
android:paddingTop="90dp"
android:visibility="gone"
tools:visibility="visible">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="10dp"
android:fontFamily="monospace"
android:text="(╯°-°)╯"
android:textSize="35sp"
tools:ignore="HardcodedText,UnusedAttribute"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/empty_view_no_videos"
android:textSize="24sp"/>
</LinearLayout>
<!--ERROR PANEL-->
<include
android:id="@+id/error_panel"
layout="@layout/error_retry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginTop="50dp"
android:visibility="gone"
tools:visibility="visible"/>
</RelativeLayout>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="13dp">
<TextView
android:id="@+id/titleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/select_a_channel"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:layout_marginBottom="10dp"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/items_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/select_channel_item">
</android.support.v7.widget.RecyclerView>
<TextView
android:id="@+id/empty_state_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItem"
android:text="@string/no_channel_subscribed_yet"
android:layout_margin="10dp"/>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
</LinearLayout>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:padding="5dp">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/itemThumbnailView"
android:layout_width="48dp"
android:layout_height="42dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginRight="5dp"
android:contentDescription="@string/list_thumbnail_view_description"
android:src="@drawable/buddy"
tools:ignore="RtlHardcoded"/>
<TextView
android:id="@+id/itemTitleView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginBottom="@dimen/video_item_search_image_right_margin"
android:layout_toRightOf="@+id/itemThumbnailView"
android:layout_toEndOf="@+id/itemThumbnailView"
android:ellipsize="end"
android:lines="1"
android:textAppearance="?android:attr/textAppearanceListItem"
tools:text="Channel Title, Lorem ipsum"/>
</RelativeLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="13dp">
<TextView
android:id="@+id/titleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/select_a_kiosk"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/items_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/select_kiosk_item">
</android.support.v7.widget.RecyclerView>
</LinearLayout>

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:padding="5dp">
<ImageView
android:id="@+id/itemThumbnailView"
android:layout_width="48dp"
android:layout_height="42dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginRight="5dp"
android:src="@drawable/service"
tools:ignore="RtlHardcoded"/>
<TextView
android:id="@+id/itemTitleView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginBottom="@dimen/video_item_search_image_right_margin"
android:layout_toRightOf="@+id/itemThumbnailView"
android:layout_toEndOf="@+id/itemThumbnailView"
android:ellipsize="end"
android:lines="1"
android:textAppearance="?android:attr/textAppearanceListItem"
tools:text="Channel Title, Lorem ipsum"/>
</RelativeLayout>

View File

@ -20,6 +20,6 @@
<item android:id="@+id/action_about" <item android:id="@+id/action_about"
android:orderInCategory="1000" android:orderInCategory="1000"
android:title="@string/action_about" /> android:title="@string/action_about"/>
</menu> </menu>

View File

@ -67,4 +67,6 @@
<dimen name="playlist_detail_uploader_image_size">24dp</dimen> <dimen name="playlist_detail_uploader_image_size">24dp</dimen>
<dimen name="playlist_detail_uploader_layout_height">28dp</dimen> <dimen name="playlist_detail_uploader_layout_height">28dp</dimen>
<!-- Kiosk view Dimensions-->
<dimen name="kiosk_title_text_size">30sp</dimen>
</resources> </resources>

View File

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources translatable="false"> <resources translatable="false">
<!-- Service -->
<string name="current_service_key" translatable="false">current_service</string>
<!-- Key values --> <!-- Key values -->
<string name="download_path_key" translatable="false">download_path</string> <string name="download_path_key" translatable="false">download_path</string>
<string name="download_path_audio_key" translatable="false">download_path_audio</string> <string name="download_path_audio_key" translatable="false">download_path_audio</string>
@ -89,6 +92,7 @@
<item>@string/black_theme_title</item> <item>@string/black_theme_title</item>
</string-array> </string-array>
<!-- Content & History -->
<string name="show_search_suggestions_key" translatable="false">show_search_suggestions</string> <string name="show_search_suggestions_key" translatable="false">show_search_suggestions</string>
<string name="show_play_with_kodi_key" translatable="false">show_play_with_kodi</string> <string name="show_play_with_kodi_key" translatable="false">show_play_with_kodi</string>
<string name="show_next_video_key" translatable="false">show_next_video</string> <string name="show_next_video_key" translatable="false">show_next_video</string>
@ -98,6 +102,23 @@
<string name="use_tor_key" translatable="false">use_tor</string> <string name="use_tor_key" translatable="false">use_tor</string>
<string name="enable_search_history_key" translatable="false">enable_search_history</string> <string name="enable_search_history_key" translatable="false">enable_search_history</string>
<string name="enable_watch_history_key" translatable="false">enable_watch_history</string> <string name="enable_watch_history_key" translatable="false">enable_watch_history</string>
<string name="main_page_content_key" translatable="false">main_page_content</string>
<string name="blank_page_key" translatable="false">blank_page</string>
<string name="feed_page_key" translatable="false">feed_page</string>
<string name="subscription_page_key" translatable="false">subscription_page_key</string>
<string name="kiosk_page_key" translatable="false">kiosk_page</string>
<string name="channel_page_key" translatable="false">channel_page</string>
<string-array name="main_page_content_pages" translatable="false">
<item>@string/blank_page_key</item>
<item>@string/kiosk_page_key</item>
<item>@string/feed_page_key</item>
<item>@string/subscription_page_key</item>
<item>@string/channel_page_key</item>
</string-array>
<string name="main_page_selected_service" translatable="false">main_page_selected_service</string>
<string name="main_page_selected_channel_name" translatable="false">main_page_selected_channel_name</string>
<string name="main_page_selected_channel_url" translatable="false">main_page_selected_channel_url</string>
<string name="main_page_selectd_kiosk_id" translatable="false">main_page_selectd_kiosk_id</string>
<!-- FileName Downloads --> <!-- FileName Downloads -->
<string name="settings_file_charset_key" translatable="false">file_rename</string> <string name="settings_file_charset_key" translatable="false">file_rename</string>

View File

@ -266,4 +266,29 @@
<string name="history_cleared">History cleared</string> <string name="history_cleared">History cleared</string>
<string name="item_deleted">Item deleted</string> <string name="item_deleted">Item deleted</string>
<string name="delete_item_search_history">Do you want to delete this item from search history?</string> <string name="delete_item_search_history">Do you want to delete this item from search history?</string>
<!-- Content -->
<string name="main_page_content">Content of main page</string>
<string name="blank_page_summary">Blank Page</string>
<string name="kiosk_page_summary">Kiosk Page</string>
<string name="subscription_page_summary">Subscription Page</string>
<string name="feed_page_summary">Feed Page</string>
<string name="channel_page_summary">Channel Page</string>
<string-array name="main_page_content_names">
<item>@string/blank_page_summary</item>
<item>@string/kiosk_page_summary</item>
<item>@string/feed_page_summary</item>
<item>@string/subscription_page_summary</item>
<item>@string/channel_page_summary</item>
</string-array>
<string name="select_a_channel">Select a channel</string>
<string name="no_channel_subscribed_yet">No channel subscribed yet</string>
<string name="select_a_kiosk">Select a kiosk</string>
<!-- Kiosk Names -->
<string name="kiosk">Kiosk</string>
<string name="trending">Trending</string>
<string name="top_50">Top 50</string>
<string name="new_and_hot">New &amp; hot</string>
<string name="service_kosk_string">%1$s/%2$s</string>
</resources> </resources>

View File

@ -21,5 +21,12 @@
android:key="@string/show_search_suggestions_key" android:key="@string/show_search_suggestions_key"
android:summary="@string/show_search_suggestions_summary" android:summary="@string/show_search_suggestions_summary"
android:title="@string/show_search_suggestions_title"/> android:title="@string/show_search_suggestions_title"/>
<ListPreference
android:defaultValue="@string/kiosk_page_key"
android:entries="@array/main_page_content_names"
android:entryValues="@array/main_page_content_pages"
android:key="@string/main_page_content_key"
android:title="@string/main_page_content"
android:summary="%s"/>
</PreferenceScreen> </PreferenceScreen>

109
assets/service.svg Normal file
View File

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="200"
height="200"
viewBox="0 0 200 200"
id="svg2"
version="1.1"
inkscape:version="0.91 r"
sodipodi:docname="service.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="81.080602"
inkscape:cy="119.84418"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="1865"
inkscape:window-height="1056"
inkscape:window-x="55"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-852.36216)">
<g
id="g4487"
transform="matrix(0.60000002,0,0,0.60000002,-242.14286,250.23051)">
<ellipse
ry="75"
rx="100"
cy="1052.3622"
cx="100"
id="path4152"
style="opacity:0.997;fill:#6c6c6c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
r="60"
cy="942.36218"
cx="100"
id="path4154"
style="opacity:0.997;fill:#6c6c6c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
id="g4209">
<rect
y="852.36218"
x="0"
height="200"
width="200"
id="rect4136"
style="opacity:0.997;fill:#999999;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.6875;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
ry="100" />
<g
id="g4204">
<circle
style="fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:#6c6c6c;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
id="path3354"
cx="32"
cy="952.36218"
r="17" />
<circle
style="fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:#6c6c6c;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
id="path3354-7"
cx="168"
cy="952.36218"
r="17"
inkscape:transform-center-x="194.28572"
inkscape:transform-center-y="3.8095239" />
<circle
style="fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:#6c6c6c;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
id="path3354-5"
cx="100"
cy="952.36218"
r="17" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-bin.zip