Merge branch 'tablet_ui' of https://github.com/nv95/NewPipe into tablet_ui
@ -49,12 +49,13 @@ ext {
|
||||
icepickLibVersion = '3.2.0'
|
||||
stethoLibVersion = '1.5.0'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2') {
|
||||
exclude module: 'support-annotations'
|
||||
}
|
||||
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:1eff8c5708'
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:fef71aeccc37'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'org.mockito:mockito-core:2.8.9'
|
||||
@ -93,6 +94,9 @@ dependencies {
|
||||
debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanaryLibVersion"
|
||||
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryLibVersion"
|
||||
|
||||
|
||||
implementation "com.squareup.okhttp3:okhttp:$okHttpLibVersion"
|
||||
debugImplementation "com.facebook.stetho:stetho-okhttp3:$stethoLibVersion"
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
|
||||
implementation 'com.android.support:cardview-v7:27.1.1'
|
||||
}
|
||||
|
@ -76,10 +76,6 @@
|
||||
android:name=".about.AboutActivity"
|
||||
android:label="@string/title_activity_about"/>
|
||||
|
||||
<activity
|
||||
android:name=".history.HistoryActivity"
|
||||
android:label="@string/title_activity_history"/>
|
||||
|
||||
<service android:name=".local.subscription.services.SubscriptionsImportService"/>
|
||||
<service android:name=".local.subscription.services.SubscriptionsExportService"/>
|
||||
|
||||
@ -122,6 +118,7 @@
|
||||
<activity
|
||||
android:name=".ReCaptchaActivity"
|
||||
android:label="@string/reCaptchaActivity"/>
|
||||
<activity android:name=".download.ExtSDDownloadFailedActivity" />
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
|
@ -4,6 +4,7 @@ import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
@ -11,7 +12,10 @@ import android.view.View;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.squareup.leakcanary.RefWatcher;
|
||||
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
|
||||
import icepick.Icepick;
|
||||
import icepick.State;
|
||||
|
||||
public abstract class BaseFragment extends Fragment {
|
||||
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
|
||||
@ -20,6 +24,15 @@ public abstract class BaseFragment extends Fragment {
|
||||
protected AppCompatActivity activity;
|
||||
public static final ImageLoader imageLoader = ImageLoader.getInstance();
|
||||
|
||||
//These values are used for controlling framgents when they are part of the frontpage
|
||||
@State
|
||||
protected boolean useAsFrontPage = false;
|
||||
protected boolean mIsVisibleToUser = false;
|
||||
|
||||
public void useAsFrontPage(boolean value) {
|
||||
useAsFrontPage = value;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Fragment's Lifecycle
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
@ -72,6 +85,12 @@ public abstract class BaseFragment extends Fragment {
|
||||
if (refWatcher != null) refWatcher.watch(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
mIsVisibleToUser = isVisibleToUser;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Init
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
@ -88,8 +107,15 @@ public abstract class BaseFragment extends Fragment {
|
||||
|
||||
public void setTitle(String title) {
|
||||
if (DEBUG) Log.d(TAG, "setTitle() called with: title = [" + title + "]");
|
||||
if (activity != null && activity.getSupportActionBar() != null) {
|
||||
if((!useAsFrontPage || mIsVisibleToUser)
|
||||
&& (activity != null && activity.getSupportActionBar() != null)) {
|
||||
activity.getSupportActionBar().setTitle(title);
|
||||
}
|
||||
}
|
||||
|
||||
protected FragmentManager getFM() {
|
||||
return getParentFragment() == null
|
||||
? getFragmentManager()
|
||||
: getParentFragment().getFragmentManager();
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@ -43,18 +44,22 @@ import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.fragments.BackPressable;
|
||||
import org.schabi.newpipe.fragments.MainFragment;
|
||||
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
|
||||
import org.schabi.newpipe.fragments.list.search.SearchFragment;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.util.Constants;
|
||||
import org.schabi.newpipe.util.KioskTranslator;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.PermissionHelper;
|
||||
import org.schabi.newpipe.util.ServiceHelper;
|
||||
@ -72,6 +77,19 @@ public class MainActivity extends AppCompatActivity {
|
||||
private NavigationView drawerItems = null;
|
||||
private TextView headerServiceView = null;
|
||||
|
||||
private boolean servicesShown = false;
|
||||
private ImageView serviceArrow;
|
||||
|
||||
private static final int ITEM_ID_SUBSCRIPTIONS = - 1;
|
||||
private static final int ITEM_ID_FEED = - 2;
|
||||
private static final int ITEM_ID_BOOKMARKS = - 3;
|
||||
private static final int ITEM_ID_DOWNLOADS = - 4;
|
||||
private static final int ITEM_ID_HISTORY = - 5;
|
||||
private static final int ITEM_ID_SETTINGS = 0;
|
||||
private static final int ITEM_ID_ABOUT = 1;
|
||||
|
||||
private static final int ORDER = 0;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Activity's LifeCycle
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
@ -85,42 +103,66 @@ public class MainActivity extends AppCompatActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window w = getWindow();
|
||||
w.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
}
|
||||
|
||||
if (getSupportFragmentManager() != null && getSupportFragmentManager().getBackStackEntryCount() == 0) {
|
||||
initFragments();
|
||||
}
|
||||
|
||||
setSupportActionBar(findViewById(R.id.toolbar));
|
||||
try {
|
||||
setupDrawer();
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupDrawer() {
|
||||
private void setupDrawer() throws Exception {
|
||||
final Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
drawer = findViewById(R.id.drawer_layout);
|
||||
drawerItems = findViewById(R.id.navigation);
|
||||
|
||||
for(StreamingService s : NewPipe.getServices()) {
|
||||
final String title = s.getServiceInfo().getName() +
|
||||
(ServiceHelper.isBeta(s) ? " (beta)" : "");
|
||||
final MenuItem item = drawerItems.getMenu()
|
||||
.add(R.id.menu_services_group, s.getServiceId(), 0, title);
|
||||
item.setIcon(ServiceHelper.getIcon(s.getServiceId()));
|
||||
//Tabs
|
||||
int currentServiceId = ServiceHelper.getSelectedServiceId(this);
|
||||
StreamingService service = NewPipe.getService(currentServiceId);
|
||||
|
||||
int kioskId = 0;
|
||||
|
||||
for (final String ks : service.getKioskList().getAvailableKiosks()) {
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_tabs_group, kioskId, 0, KioskTranslator.getTranslatedKioskName(ks, this))
|
||||
.setIcon(KioskTranslator.getKioskIcons(ks, this));
|
||||
kioskId ++;
|
||||
}
|
||||
|
||||
drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(true);
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_tabs_group, ITEM_ID_SUBSCRIPTIONS, ORDER, R.string.tab_subscriptions)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_channel));
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_tabs_group, ITEM_ID_FEED, ORDER, R.string.fragment_whats_new)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.rss));
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_tabs_group, ITEM_ID_BOOKMARKS, ORDER, R.string.tab_bookmarks)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_bookmark));
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_tabs_group, ITEM_ID_DOWNLOADS, ORDER, R.string.downloads)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.download));
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_tabs_group, ITEM_ID_HISTORY, ORDER, R.string.action_history)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.history));
|
||||
|
||||
toggle = new ActionBarDrawerToggle(this, drawer, toolbar,
|
||||
R.string.drawer_open, R.string.drawer_close) {
|
||||
@Override
|
||||
public void onDrawerClosed(View view) { super.onDrawerClosed(view); }
|
||||
//Settings and About
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_options_about_group, ITEM_ID_SETTINGS, ORDER, R.string.settings)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.settings));
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_options_about_group, ITEM_ID_ABOUT, ORDER, R.string.tab_about)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.info));
|
||||
|
||||
@Override
|
||||
public void onDrawerOpened(View drawerView) { super.onDrawerOpened(drawerView); }
|
||||
|
||||
@Override
|
||||
public void onDrawerSlide(View drawerView, float slideOffset) {
|
||||
super.onDrawerSlide(drawerView, 0);
|
||||
}
|
||||
};
|
||||
toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.drawer_open, R.string.drawer_close);
|
||||
toggle.syncState();
|
||||
drawer.addDrawerListener(toggle);
|
||||
drawer.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
|
||||
@ -133,51 +175,179 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
public void onDrawerClosed(View drawerView) {
|
||||
if(servicesShown) {
|
||||
toggleServices();
|
||||
}
|
||||
if (lastService != ServiceHelper.getSelectedServiceId(MainActivity.this)) {
|
||||
new Handler(Looper.getMainLooper()).post(MainActivity.this::recreate);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
drawerItems.setNavigationItemSelectedListener(this::changeService);
|
||||
|
||||
setupDrawerFooter();
|
||||
drawerItems.setNavigationItemSelectedListener(this::drawerItemSelected);
|
||||
setupDrawerHeader();
|
||||
}
|
||||
|
||||
|
||||
private boolean changeService(MenuItem item) {
|
||||
if (item.getGroupId() != R.id.menu_services_group)
|
||||
private boolean drawerItemSelected(MenuItem item) {
|
||||
switch (item.getGroupId()) {
|
||||
case R.id.menu_services_group:
|
||||
changeService(item);
|
||||
break;
|
||||
case R.id.menu_tabs_group:
|
||||
try {
|
||||
tabSelected(item);
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError(this, e);
|
||||
}
|
||||
break;
|
||||
case R.id.menu_options_about_group:
|
||||
optionsAboutSelected(item);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(false);
|
||||
ServiceHelper.setSelectedServiceId(this, item.getItemId());
|
||||
drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(true);
|
||||
}
|
||||
|
||||
drawer.closeDrawers();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setupDrawerFooter() {
|
||||
ImageButton settings = findViewById(R.id.drawer_settings);
|
||||
ImageButton downloads = findViewById(R.id.drawer_downloads);
|
||||
ImageButton history = findViewById(R.id.drawer_history);
|
||||
private void changeService(MenuItem item) {
|
||||
drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(false);
|
||||
ServiceHelper.setSelectedServiceId(this, item.getItemId());
|
||||
drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(true);
|
||||
}
|
||||
|
||||
settings.setOnClickListener(view -> NavigationHelper.openSettings(this));
|
||||
downloads.setOnClickListener(view ->NavigationHelper.openDownloads(this));
|
||||
history.setOnClickListener(view ->
|
||||
NavigationHelper.openStatisticFragment(getSupportFragmentManager()));
|
||||
private void tabSelected(MenuItem item) throws ExtractionException {
|
||||
switch(item.getItemId()) {
|
||||
case ITEM_ID_SUBSCRIPTIONS:
|
||||
NavigationHelper.openSubscriptionFragment(getSupportFragmentManager());
|
||||
break;
|
||||
case ITEM_ID_FEED:
|
||||
NavigationHelper.openWhatsNewFragment(getSupportFragmentManager());
|
||||
break;
|
||||
case ITEM_ID_BOOKMARKS:
|
||||
NavigationHelper.openBookmarksFragment(getSupportFragmentManager());
|
||||
break;
|
||||
case ITEM_ID_DOWNLOADS:
|
||||
NavigationHelper.openDownloads(this);
|
||||
break;
|
||||
case ITEM_ID_HISTORY:
|
||||
NavigationHelper.openStatisticFragment(getSupportFragmentManager());
|
||||
break;
|
||||
default:
|
||||
int currentServiceId = ServiceHelper.getSelectedServiceId(this);
|
||||
StreamingService service = NewPipe.getService(currentServiceId);
|
||||
String serviceName = "";
|
||||
|
||||
int kioskId = 0;
|
||||
for (final String ks : service.getKioskList().getAvailableKiosks()) {
|
||||
if(kioskId == item.getItemId()) {
|
||||
serviceName = ks;
|
||||
}
|
||||
kioskId ++;
|
||||
}
|
||||
|
||||
NavigationHelper.openKioskFragment(getSupportFragmentManager(), currentServiceId, serviceName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void optionsAboutSelected(MenuItem item) {
|
||||
switch(item.getItemId()) {
|
||||
case ITEM_ID_SETTINGS:
|
||||
NavigationHelper.openSettings(this);
|
||||
break;
|
||||
case ITEM_ID_ABOUT:
|
||||
NavigationHelper.openAbout(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setupDrawerHeader() {
|
||||
headerServiceView = findViewById(R.id.drawer_header_service_view);
|
||||
Button action = findViewById(R.id.drawer_header_action_button);
|
||||
NavigationView navigationView = findViewById(R.id.navigation);
|
||||
View hView = navigationView.getHeaderView(0);
|
||||
|
||||
serviceArrow = hView.findViewById(R.id.drawer_arrow);
|
||||
headerServiceView = hView.findViewById(R.id.drawer_header_service_view);
|
||||
Button action = hView.findViewById(R.id.drawer_header_action_button);
|
||||
action.setOnClickListener(view -> {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse("https://newpipe.schabi.org/blog/"));
|
||||
startActivity(intent);
|
||||
drawer.closeDrawers();
|
||||
toggleServices();
|
||||
});
|
||||
}
|
||||
|
||||
private void toggleServices() {
|
||||
servicesShown = !servicesShown;
|
||||
|
||||
drawerItems.getMenu().removeGroup(R.id.menu_services_group);
|
||||
drawerItems.getMenu().removeGroup(R.id.menu_tabs_group);
|
||||
drawerItems.getMenu().removeGroup(R.id.menu_options_about_group);
|
||||
|
||||
if(servicesShown) {
|
||||
showServices();
|
||||
} else {
|
||||
try {
|
||||
showTabs();
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showServices() {
|
||||
serviceArrow.setImageResource(R.drawable.ic_arrow_up_white);
|
||||
|
||||
for(StreamingService s : NewPipe.getServices()) {
|
||||
final String title = s.getServiceInfo().getName() +
|
||||
(ServiceHelper.isBeta(s) ? " (beta)" : "");
|
||||
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_services_group, s.getServiceId(), ORDER, title)
|
||||
.setIcon(ServiceHelper.getIcon(s.getServiceId()));
|
||||
}
|
||||
drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(true);
|
||||
}
|
||||
|
||||
private void showTabs() throws ExtractionException {
|
||||
serviceArrow.setImageResource(R.drawable.ic_arrow_down_white);
|
||||
|
||||
//Tabs
|
||||
int currentServiceId = ServiceHelper.getSelectedServiceId(this);
|
||||
StreamingService service = NewPipe.getService(currentServiceId);
|
||||
|
||||
int kioskId = 0;
|
||||
|
||||
for (final String ks : service.getKioskList().getAvailableKiosks()) {
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_tabs_group, kioskId, ORDER, KioskTranslator.getTranslatedKioskName(ks, this))
|
||||
.setIcon(KioskTranslator.getKioskIcons(ks, this));
|
||||
kioskId ++;
|
||||
}
|
||||
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_tabs_group, ITEM_ID_SUBSCRIPTIONS, ORDER, R.string.tab_subscriptions)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_channel));
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_tabs_group, ITEM_ID_FEED, ORDER, R.string.fragment_whats_new)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.rss));
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_tabs_group, ITEM_ID_BOOKMARKS, ORDER, R.string.tab_bookmarks)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_bookmark));
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_tabs_group, ITEM_ID_DOWNLOADS, ORDER, R.string.downloads)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.download));
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_tabs_group, ITEM_ID_HISTORY, ORDER, R.string.action_history)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.history));
|
||||
|
||||
//Settings and About
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_options_about_group, ITEM_ID_SETTINGS, ORDER, R.string.settings)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.settings));
|
||||
drawerItems.getMenu()
|
||||
.add(R.id.menu_options_about_group, ITEM_ID_ABOUT, ORDER, R.string.tab_about)
|
||||
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.info));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
@ -345,9 +515,6 @@ public class MainActivity extends AppCompatActivity {
|
||||
case R.id.action_history:
|
||||
NavigationHelper.openStatisticFragment(getSupportFragmentManager());
|
||||
return true;
|
||||
case R.id.action_about:
|
||||
NavigationHelper.openAbout(this);
|
||||
return true;
|
||||
case R.id.action_settings:
|
||||
NavigationHelper.openSettings(this);
|
||||
return true;
|
||||
|
@ -0,0 +1,38 @@
|
||||
package org.schabi.newpipe.download;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||
import org.schabi.newpipe.util.ServiceHelper;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
public class ExtSDDownloadFailedActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
ThemeHelper.setTheme(this, ServiceHelper.getSelectedServiceId(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.download_to_sdcard_error_title)
|
||||
.setMessage(R.string.download_to_sdcard_error_message)
|
||||
.setPositiveButton(R.string.yes, (DialogInterface dialogInterface, int i) -> {
|
||||
NewPipeSettings.resetDownloadFolders(this);
|
||||
finish();
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, (DialogInterface dialogInterface, int i) -> {
|
||||
dialogInterface.dismiss();
|
||||
finish();
|
||||
})
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
}
|
@ -51,9 +51,6 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
|
||||
protected Button errorButtonRetry;
|
||||
protected TextView errorTextView;
|
||||
|
||||
@State
|
||||
protected boolean useAsFrontPage = false;
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View rootView, Bundle savedInstanceState) {
|
||||
super.onViewCreated(rootView, savedInstanceState);
|
||||
@ -66,9 +63,6 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
|
||||
wasLoading.set(isLoading.get());
|
||||
}
|
||||
|
||||
public void useAsFrontPage(boolean value) {
|
||||
useAsFrontPage = value;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Init
|
||||
@ -93,12 +87,7 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
|
||||
RxView.clicks(errorButtonRetry)
|
||||
.debounce(300, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Consumer<Object>() {
|
||||
@Override
|
||||
public void accept(Object o) throws Exception {
|
||||
onRetryButtonClicked();
|
||||
}
|
||||
});
|
||||
.subscribe(o -> onRetryButtonClicked());
|
||||
}
|
||||
|
||||
protected void onRetryButtonClicked() {
|
||||
|
@ -14,24 +14,16 @@ public class BlankFragment extends BaseFragment {
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
|
||||
if(activity != null && activity.getSupportActionBar() != null) {
|
||||
activity.getSupportActionBar()
|
||||
.setTitle("NewPipe");
|
||||
}
|
||||
setTitle("NewPipe");
|
||||
return inflater.inflate(R.layout.fragment_blank, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
if(isVisibleToUser) {
|
||||
if(activity != null && activity.getSupportActionBar() != null) {
|
||||
activity.getSupportActionBar()
|
||||
.setTitle("NewPipe");
|
||||
}
|
||||
setTitle("NewPipe");
|
||||
// leave this inline. Will make it harder for copy cats.
|
||||
// If you are a Copy cat FUCK YOU.
|
||||
// I WILL FIND YOU, AND I WILL ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.schabi.newpipe.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
@ -17,20 +18,16 @@ import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.SubMenu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.schabi.newpipe.BaseFragment;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
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.local.feed.FeedFragment;
|
||||
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
|
||||
import org.schabi.newpipe.local.bookmark.BookmarkFragment;
|
||||
import org.schabi.newpipe.local.feed.FeedFragment;
|
||||
import org.schabi.newpipe.local.history.StatisticsPlaylistFragment;
|
||||
import org.schabi.newpipe.local.subscription.SubscriptionFragment;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
@ -39,20 +36,29 @@ import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.ServiceHelper;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class MainFragment extends BaseFragment implements TabLayout.OnTabSelectedListener {
|
||||
|
||||
public int currentServiceId = -1;
|
||||
private ViewPager viewPager;
|
||||
private List<String> tabs = new ArrayList<>();
|
||||
static PagerAdapter adapter;
|
||||
TabLayout tabLayout;
|
||||
private SharedPreferences prefs;
|
||||
private Bundle savedInstanceStateBundle;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Constants
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
private static final String TAB_NUMBER_BLANK = "0";
|
||||
private static final String TAB_NUMBER_KIOSK = "1";
|
||||
private static final String TAB_NUMBER_SUBSCIRPTIONS = "2";
|
||||
private static final String TAB_NUMBER_FEED = "3";
|
||||
private static final String TAB_NUMBER_BOOKMARKS = "4";
|
||||
private static final String TAB_NUMBER_HISTORY = "5";
|
||||
private static final String TAB_NUMBER_CHANNEL = "6";
|
||||
|
||||
private static final int FALLBACK_SERVICE_ID = ServiceList.YouTube.getServiceId();
|
||||
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";
|
||||
private static final int KIOSK_MENU_OFFSET = 2000;
|
||||
SharedPreferences.OnSharedPreferenceChangeListener listener;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Fragment's LifeCycle
|
||||
@ -60,13 +66,23 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
savedInstanceStateBundle = savedInstanceState;
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
listener = (prefs, key) -> {
|
||||
if(key.equals("saveUsedTabs")) {
|
||||
mainPageChanged();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
currentServiceId = ServiceHelper.getSelectedServiceId(activity);
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
prefs.registerOnSharedPreferenceChangeListener(listener);
|
||||
|
||||
return inflater.inflate(R.layout.fragment_main, container, false);
|
||||
}
|
||||
|
||||
@ -74,28 +90,114 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||
protected void initViews(View rootView, Bundle savedInstanceState) {
|
||||
super.initViews(rootView, savedInstanceState);
|
||||
|
||||
TabLayout tabLayout = rootView.findViewById(R.id.main_tab_layout);
|
||||
tabLayout = rootView.findViewById(R.id.main_tab_layout);
|
||||
viewPager = rootView.findViewById(R.id.pager);
|
||||
|
||||
/* Nested fragment, use child fragment here to maintain backstack in view pager. */
|
||||
PagerAdapter adapter = new PagerAdapter(getChildFragmentManager());
|
||||
adapter = new PagerAdapter(getChildFragmentManager());
|
||||
viewPager.setAdapter(adapter);
|
||||
viewPager.setOffscreenPageLimit(adapter.getCount());
|
||||
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
|
||||
int channelIcon = ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.ic_channel);
|
||||
int whatsHotIcon = ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.ic_hot);
|
||||
int bookmarkIcon = ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.ic_bookmark);
|
||||
|
||||
if (isSubscriptionsPageOnlySelected()) {
|
||||
tabLayout.getTabAt(0).setIcon(channelIcon);
|
||||
tabLayout.getTabAt(1).setIcon(bookmarkIcon);
|
||||
} else {
|
||||
tabLayout.getTabAt(0).setIcon(whatsHotIcon);
|
||||
tabLayout.getTabAt(1).setIcon(channelIcon);
|
||||
tabLayout.getTabAt(2).setIcon(bookmarkIcon);
|
||||
mainPageChanged();
|
||||
}
|
||||
|
||||
|
||||
public void mainPageChanged() {
|
||||
getTabOrder();
|
||||
adapter.notifyDataSetChanged();
|
||||
viewPager.setOffscreenPageLimit(adapter.getCount());
|
||||
setIcons();
|
||||
setFirstTitle();
|
||||
}
|
||||
|
||||
private void setFirstTitle() {
|
||||
if((tabs.size() > 0)
|
||||
&& activity != null) {
|
||||
String tabInformation = tabs.get(0);
|
||||
if (tabInformation.startsWith(TAB_NUMBER_KIOSK + "\t")) {
|
||||
String kiosk[] = tabInformation.split("\t");
|
||||
if (kiosk.length == 3) {
|
||||
setTitle(kiosk[1]);
|
||||
}
|
||||
} else if (tabInformation.startsWith(TAB_NUMBER_CHANNEL + "\t")) {
|
||||
|
||||
String channelInfo[] = tabInformation.split("\t");
|
||||
if(channelInfo.length==4) {
|
||||
setTitle(channelInfo[2]);
|
||||
}
|
||||
} else {
|
||||
switch (tabInformation) {
|
||||
case TAB_NUMBER_BLANK:
|
||||
setTitle(getString(R.string.app_name));
|
||||
break;
|
||||
case TAB_NUMBER_SUBSCIRPTIONS:
|
||||
setTitle(getString(R.string.tab_subscriptions));
|
||||
break;
|
||||
case TAB_NUMBER_FEED:
|
||||
setTitle(getString(R.string.fragment_whats_new));
|
||||
break;
|
||||
case TAB_NUMBER_BOOKMARKS:
|
||||
setTitle(getString(R.string.tab_bookmarks));
|
||||
break;
|
||||
case TAB_NUMBER_HISTORY:
|
||||
setTitle(getString(R.string.title_activity_history));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void setIcons() {
|
||||
for (int i = 0; i < tabs.size(); i++) {
|
||||
String tabInformation = tabs.get(i);
|
||||
|
||||
TabLayout.Tab tabToSet = tabLayout.getTabAt(i);
|
||||
Context c = getContext();
|
||||
|
||||
if (tabToSet != null && c != null) {
|
||||
|
||||
if (tabInformation.startsWith(TAB_NUMBER_KIOSK + "\t")) {
|
||||
String kiosk[] = tabInformation.split("\t");
|
||||
if (kiosk.length == 3) {
|
||||
tabToSet.setIcon(KioskTranslator.getKioskIcons(kiosk[1], getContext()));
|
||||
}
|
||||
} else if (tabInformation.startsWith(TAB_NUMBER_CHANNEL + "\t")) {
|
||||
tabToSet.setIcon(ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.ic_channel));
|
||||
} else {
|
||||
switch (tabInformation) {
|
||||
case TAB_NUMBER_BLANK:
|
||||
tabToSet.setIcon(ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.ic_hot));
|
||||
break;
|
||||
case TAB_NUMBER_SUBSCIRPTIONS:
|
||||
tabToSet.setIcon(ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.ic_channel));
|
||||
break;
|
||||
case TAB_NUMBER_FEED:
|
||||
tabToSet.setIcon(ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.rss));
|
||||
break;
|
||||
case TAB_NUMBER_BOOKMARKS:
|
||||
tabToSet.setIcon(ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.ic_bookmark));
|
||||
break;
|
||||
case TAB_NUMBER_HISTORY:
|
||||
tabToSet.setIcon(ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.history));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void getTabOrder() {
|
||||
tabs.clear();
|
||||
|
||||
String save = prefs.getString("saveUsedTabs", "1\tTrending\t0\n2\n4\n");
|
||||
String tabsArray[] = save.trim().split("\n");
|
||||
|
||||
Collections.addAll(tabs, tabsArray);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@ -107,16 +209,6 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "], inflater = [" + inflater + "]");
|
||||
inflater.inflate(R.menu.main_fragment_menu, menu);
|
||||
SubMenu kioskMenu = menu.addSubMenu(Menu.NONE, Menu.NONE, 200, 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();
|
||||
if (supportActionBar != null) {
|
||||
@ -165,115 +257,77 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return isSubscriptionsPageOnlySelected() ? new SubscriptionFragment() : getMainPageFragment();
|
||||
case 1:
|
||||
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 BookmarkFragment();
|
||||
} else {
|
||||
return new SubscriptionFragment();
|
||||
}
|
||||
case 2:
|
||||
return new BookmarkFragment();
|
||||
default:
|
||||
return new BlankFragment();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
//return getString(this.tabTitles[position]);
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return isSubscriptionsPageOnlySelected() ? 2 : 3;
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Main page content
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private boolean isSubscriptionsPageOnlySelected() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
.getString(getString(R.string.main_page_content_key), getString(R.string.blank_page_key))
|
||||
.equals(getString(R.string.subscription_page_key));
|
||||
}
|
||||
|
||||
private Fragment getMainPageFragment() {
|
||||
if (getActivity() == null) return new BlankFragment();
|
||||
String tabInformation = tabs.get(position);
|
||||
|
||||
if(tabInformation.startsWith(TAB_NUMBER_KIOSK + "\t")) {
|
||||
String kiosk[] = tabInformation.split("\t");
|
||||
if(kiosk.length==3) {
|
||||
KioskFragment fragment = null;
|
||||
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 = KioskFragment.getInstance(Integer.parseInt(kiosk[2]), kiosk[1]);
|
||||
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));
|
||||
}
|
||||
}
|
||||
} else if(tabInformation.startsWith(TAB_NUMBER_CHANNEL + "\t")) {
|
||||
String channelInfo[] = tabInformation.split("\t");
|
||||
if(channelInfo.length==4) {
|
||||
ChannelFragment fragment = ChannelFragment.getInstance(Integer.parseInt(channelInfo[3]), channelInfo[1], channelInfo[2]);
|
||||
fragment.useAsFrontPage(true);
|
||||
return fragment;
|
||||
} else {
|
||||
return new BlankFragment();
|
||||
}
|
||||
} else {
|
||||
switch (tabInformation) {
|
||||
case TAB_NUMBER_BLANK:
|
||||
return new BlankFragment();
|
||||
case TAB_NUMBER_SUBSCIRPTIONS:
|
||||
SubscriptionFragment sFragment = new SubscriptionFragment();
|
||||
sFragment.useAsFrontPage(true);
|
||||
return sFragment;
|
||||
case TAB_NUMBER_FEED:
|
||||
FeedFragment fFragment = new FeedFragment();
|
||||
fFragment.useAsFrontPage(true);
|
||||
return fFragment;
|
||||
case TAB_NUMBER_BOOKMARKS:
|
||||
BookmarkFragment bFragment = new BookmarkFragment();
|
||||
bFragment.useAsFrontPage(true);
|
||||
return bFragment;
|
||||
case TAB_NUMBER_HISTORY:
|
||||
StatisticsPlaylistFragment cFragment = new StatisticsPlaylistFragment();
|
||||
cFragment.useAsFrontPage(true);
|
||||
return cFragment;
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Select Kiosk
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
return new BlankFragment();
|
||||
}
|
||||
|
||||
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_OFFSET + i, Menu.NONE,
|
||||
KioskTranslator.getTranslatedKioskName(ks, getContext()))
|
||||
.setOnMenuItemClickListener(menuItem -> {
|
||||
try {
|
||||
NavigationHelper.openKioskFragment(getFragmentManager(), currentServiceId, ks);
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||
@Override
|
||||
public int getItemPosition(Object object) {
|
||||
// Causes adapter to reload all Fragments when
|
||||
// notifyDataSetChanged is called
|
||||
return POSITION_NONE;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
i++;
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return tabs.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
getFragmentManager()
|
||||
.beginTransaction()
|
||||
.remove((Fragment)object)
|
||||
.commitNowAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1247,10 +1247,10 @@ public class VideoDetailFragment
|
||||
spinnerToolbar.setVisibility(View.GONE);
|
||||
break;
|
||||
default:
|
||||
if(info.getAudioStreams().isEmpty()) detailControlsBackground.setVisibility(View.GONE);
|
||||
if (!info.getVideoStreams().isEmpty()
|
||||
|| !info.getVideoOnlyStreams().isEmpty()) break;
|
||||
|
||||
detailControlsBackground.setVisibility(View.GONE);
|
||||
detailControlsPopup.setVisibility(View.GONE);
|
||||
spinnerToolbar.setVisibility(View.GONE);
|
||||
thumbnailPlayButton.setImageResource(R.drawable.ic_headset_white_24dp);
|
||||
|
@ -195,9 +195,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||
public void selected(ChannelInfoItem selectedItem) {
|
||||
try {
|
||||
onItemSelected(selectedItem);
|
||||
NavigationHelper.openChannelFragment(useAsFrontPage ?
|
||||
getParentFragment().getFragmentManager()
|
||||
: getFragmentManager(),
|
||||
NavigationHelper.openChannelFragment(getFM(),
|
||||
selectedItem.getServiceId(),
|
||||
selectedItem.getUrl(),
|
||||
selectedItem.getName());
|
||||
@ -212,10 +210,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||
public void selected(PlaylistInfoItem selectedItem) {
|
||||
try {
|
||||
onItemSelected(selectedItem);
|
||||
NavigationHelper.openPlaylistFragment(
|
||||
useAsFrontPage
|
||||
? getParentFragment().getFragmentManager()
|
||||
: getFragmentManager(),
|
||||
NavigationHelper.openPlaylistFragment(getFM(),
|
||||
selectedItem.getServiceId(),
|
||||
selectedItem.getUrl(),
|
||||
selectedItem.getName());
|
||||
@ -236,9 +231,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||
|
||||
private void onStreamSelected(StreamInfoItem selectedItem) {
|
||||
onItemSelected(selectedItem);
|
||||
NavigationHelper.openVideoDetailFragment(useAsFrontPage
|
||||
? getParentFragment().getFragmentManager()
|
||||
: getFragmentManager(),
|
||||
NavigationHelper.openVideoDetailFragment(getFM(),
|
||||
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,8 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||
|
||||
private MenuItem menuRssButton;
|
||||
|
||||
private boolean mIsVisibleToUser = false;
|
||||
|
||||
public static ChannelFragment getInstance(int serviceId, String url, String name) {
|
||||
ChannelFragment instance = new ChannelFragment();
|
||||
instance.setInitialData(serviceId, url, name);
|
||||
@ -104,6 +106,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
mIsVisibleToUser = isVisibleToUser;
|
||||
if(activity != null
|
||||
&& useAsFrontPage
|
||||
&& isVisibleToUser) {
|
||||
@ -166,9 +169,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||
context.getResources().getString(R.string.share)
|
||||
};
|
||||
|
||||
final DialogInterface.OnClickListener actions = new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
final DialogInterface.OnClickListener actions = (DialogInterface dialogInterface, int i) -> {
|
||||
final int index = Math.max(infoListAdapter.getItemsList().indexOf(item), 0);
|
||||
switch (i) {
|
||||
case 0:
|
||||
@ -198,7 +199,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
new InfoItemDialog(getActivity(), item, commands, actions).show();
|
||||
@ -255,12 +255,12 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||
private static final int BUTTON_DEBOUNCE_INTERVAL = 100;
|
||||
|
||||
private void monitorSubscription(final ChannelInfo info) {
|
||||
final Consumer<Throwable> onError = new Consumer<Throwable>() {
|
||||
@Override
|
||||
public void accept(Throwable throwable) throws Exception {
|
||||
final Consumer<Throwable> onError = (Throwable throwable) -> {
|
||||
animateView(headerSubscribeButton, false, 100);
|
||||
showSnackBarError(throwable, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(currentInfo.getServiceId()), "Get subscription status", 0);
|
||||
}
|
||||
showSnackBarError(throwable, UserAction.SUBSCRIPTION,
|
||||
NewPipe.getNameOfService(currentInfo.getServiceId()),
|
||||
"Get subscription status",
|
||||
0);
|
||||
};
|
||||
|
||||
final Observable<List<SubscriptionEntity>> observable = subscriptionService.subscriptionTable()
|
||||
@ -276,50 +276,38 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||
// so only update the UI for the latest emission ("sync" the subscribe button's state)
|
||||
.debounce(100, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Consumer<List<SubscriptionEntity>>() {
|
||||
@Override
|
||||
public void accept(List<SubscriptionEntity> subscriptionEntities) throws Exception {
|
||||
updateSubscribeButton(!subscriptionEntities.isEmpty());
|
||||
}
|
||||
}, onError));
|
||||
.subscribe((List<SubscriptionEntity> subscriptionEntities) ->
|
||||
updateSubscribeButton(!subscriptionEntities.isEmpty())
|
||||
, onError));
|
||||
|
||||
}
|
||||
|
||||
private Function<Object, Object> mapOnSubscribe(final SubscriptionEntity subscription) {
|
||||
return new Function<Object, Object>() {
|
||||
@Override
|
||||
public Object apply(@NonNull Object o) throws Exception {
|
||||
return (@NonNull Object o) -> {
|
||||
subscriptionService.subscriptionTable().insert(subscription);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Function<Object, Object> mapOnUnsubscribe(final SubscriptionEntity subscription) {
|
||||
return new Function<Object, Object>() {
|
||||
@Override
|
||||
public Object apply(@NonNull Object o) throws Exception {
|
||||
return (@NonNull Object o) -> {
|
||||
subscriptionService.subscriptionTable().delete(subscription);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateSubscription(final ChannelInfo info) {
|
||||
if (DEBUG) Log.d(TAG, "updateSubscription() called with: info = [" + info + "]");
|
||||
final Action onComplete = new Action() {
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
final Action onComplete = () -> {
|
||||
if (DEBUG) Log.d(TAG, "Updated subscription: " + info.getUrl());
|
||||
}
|
||||
};
|
||||
|
||||
final Consumer<Throwable> onError = new Consumer<Throwable>() {
|
||||
@Override
|
||||
public void accept(@NonNull Throwable throwable) throws Exception {
|
||||
onUnrecoverableError(throwable, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(info.getServiceId()), "Updating Subscription for " + info.getUrl(), R.string.subscription_update_failed);
|
||||
}
|
||||
};
|
||||
final Consumer<Throwable> onError = (@NonNull Throwable throwable) ->
|
||||
onUnrecoverableError(throwable,
|
||||
UserAction.SUBSCRIPTION,
|
||||
NewPipe.getNameOfService(info.getServiceId()),
|
||||
"Updating Subscription for " + info.getUrl(),
|
||||
R.string.subscription_update_failed);
|
||||
|
||||
disposables.add(subscriptionService.updateChannelInfo(info)
|
||||
.subscribeOn(Schedulers.io())
|
||||
@ -328,19 +316,16 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||
}
|
||||
|
||||
private Disposable monitorSubscribeButton(final Button subscribeButton, final Function<Object, Object> action) {
|
||||
final Consumer<Object> onNext = new Consumer<Object>() {
|
||||
@Override
|
||||
public void accept(@NonNull Object o) throws Exception {
|
||||
final Consumer<Object> onNext = (@NonNull Object o) -> {
|
||||
if (DEBUG) Log.d(TAG, "Changed subscription status to this channel!");
|
||||
}
|
||||
};
|
||||
|
||||
final Consumer<Throwable> onError = new Consumer<Throwable>() {
|
||||
@Override
|
||||
public void accept(@NonNull Throwable throwable) throws Exception {
|
||||
onUnrecoverableError(throwable, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(currentInfo.getServiceId()), "Subscription Change", R.string.subscription_change_failed);
|
||||
}
|
||||
};
|
||||
final Consumer<Throwable> onError = (@NonNull Throwable throwable) ->
|
||||
onUnrecoverableError(throwable,
|
||||
UserAction.SUBSCRIPTION,
|
||||
NewPipe.getNameOfService(currentInfo.getServiceId()),
|
||||
"Subscription Change",
|
||||
R.string.subscription_change_failed);
|
||||
|
||||
/* Emit clicks from main thread unto io thread */
|
||||
return RxView.clicks(subscribeButton)
|
||||
@ -352,9 +337,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||
}
|
||||
|
||||
private Consumer<List<SubscriptionEntity>> getSubscribeUpdateMonitor(final ChannelInfo info) {
|
||||
return new Consumer<List<SubscriptionEntity>>() {
|
||||
@Override
|
||||
public void accept(List<SubscriptionEntity> subscriptionEntities) throws Exception {
|
||||
return (List<SubscriptionEntity> subscriptionEntities) -> {
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "subscriptionService.subscriptionTable.doOnNext() called with: subscriptionEntities = [" + subscriptionEntities + "]");
|
||||
if (subscribeButtonMonitor != null) subscribeButtonMonitor.dispose();
|
||||
@ -364,14 +347,16 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||
SubscriptionEntity channel = new SubscriptionEntity();
|
||||
channel.setServiceId(info.getServiceId());
|
||||
channel.setUrl(info.getUrl());
|
||||
channel.setData(info.getName(), info.getAvatarUrl(), info.getDescription(), info.getSubscriberCount());
|
||||
channel.setData(info.getName(),
|
||||
info.getAvatarUrl(),
|
||||
info.getDescription(),
|
||||
info.getSubscriberCount());
|
||||
subscribeButtonMonitor = monitorSubscribeButton(headerSubscribeButton, mapOnSubscribe(channel));
|
||||
} else {
|
||||
if (DEBUG) Log.d(TAG, "Found subscription to this channel!");
|
||||
final SubscriptionEntity subscription = subscriptionEntities.get(0);
|
||||
subscribeButtonMonitor = monitorSubscribeButton(headerSubscribeButton, mapOnUnsubscribe(subscription));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -488,8 +473,11 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||
super.handleNextItems(result);
|
||||
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(), UserAction.REQUESTED_CHANNEL, NewPipe.getNameOfService(serviceId),
|
||||
"Get next page of: " + url, R.string.general_error);
|
||||
showSnackBarError(result.getErrors(),
|
||||
UserAction.REQUESTED_CHANNEL,
|
||||
NewPipe.getNameOfService(serviceId),
|
||||
"Get next page of: " + url,
|
||||
R.string.general_error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -517,6 +505,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
super.setTitle(title);
|
||||
headerTitleView.setText(title);
|
||||
if (!useAsFrontPage) headerTitleView.setText(title);
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
||||
protected String kioskId = "";
|
||||
protected String kioskTranslatedName;
|
||||
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Views
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
@ -167,7 +168,9 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
||||
super.handleResult(result);
|
||||
|
||||
name = kioskTranslatedName;
|
||||
if(!useAsFrontPage) {
|
||||
setTitle(kioskTranslatedName);
|
||||
}
|
||||
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(),
|
||||
|
@ -365,7 +365,7 @@ public class SearchFragment
|
||||
int itemId = 0;
|
||||
boolean isFirstItem = true;
|
||||
final Context c = getContext();
|
||||
for(String filter : service.getSearchQIHFactory().getAvailableContentFilter()) {
|
||||
for(String filter : service.getSearchQHFactory().getAvailableContentFilter()) {
|
||||
menuItemToFilterName.put(itemId, filter);
|
||||
MenuItem item = menu.add(1,
|
||||
itemId++,
|
||||
@ -575,8 +575,7 @@ public class SearchFragment
|
||||
.onNext(searchEditText.getText().toString()),
|
||||
throwable -> showSnackBarError(throwable,
|
||||
UserAction.DELETE_FROM_HISTORY, "none",
|
||||
"Deleting item failed", R.string.general_error)
|
||||
);
|
||||
"Deleting item failed", R.string.general_error));
|
||||
disposables.add(onDelete);
|
||||
})
|
||||
.show();
|
||||
@ -837,7 +836,10 @@ public class SearchFragment
|
||||
|
||||
@Override
|
||||
public void handleResult(@NonNull SearchInfo result) {
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
final List<Throwable> exceptions = result.getErrors();
|
||||
if (!exceptions.isEmpty()
|
||||
&& !(exceptions.size() == 1
|
||||
&& exceptions.get(0) instanceof SearchExtractor.NothingFoundException)){
|
||||
showSnackBarError(result.getErrors(), UserAction.SEARCHED,
|
||||
NewPipe.getNameOfService(serviceId), searchString, 0);
|
||||
}
|
||||
@ -864,6 +866,7 @@ public class SearchFragment
|
||||
showListFooter(false);
|
||||
currentPageUrl = result.getNextPageUrl();
|
||||
infoListAdapter.addInfoItemList(result.getItems());
|
||||
nextPageUrl = result.getNextPageUrl();
|
||||
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(), UserAction.SEARCHED,
|
||||
|
@ -6,7 +6,6 @@ import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -20,11 +19,9 @@ import org.schabi.newpipe.database.LocalItem;
|
||||
import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
|
||||
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
||||
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.local.BaseLocalListFragment;
|
||||
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
|
||||
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.OnClickGesture;
|
||||
@ -69,11 +66,10 @@ public final class BookmarkFragment
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
if (activity != null && activity.getSupportActionBar() != null) {
|
||||
activity.getSupportActionBar().setDisplayShowTitleEnabled(true);
|
||||
activity.setTitle(R.string.tab_subscriptions);
|
||||
}
|
||||
|
||||
if(!useAsFrontPage) {
|
||||
setTitle(activity.getString(R.string.tab_bookmarks));
|
||||
}
|
||||
return inflater.inflate(R.layout.fragment_bookmarks, container, false);
|
||||
}
|
||||
|
||||
@ -102,10 +98,7 @@ public final class BookmarkFragment
|
||||
itemListAdapter.setSelectedListener(new OnClickGesture<LocalItem>() {
|
||||
@Override
|
||||
public void selected(LocalItem selectedItem) {
|
||||
try {
|
||||
// Requires the parent fragment to find holder for fragment replacement
|
||||
if (getParentFragment() == null) return;
|
||||
final FragmentManager fragmentManager = getParentFragment().getFragmentManager();
|
||||
final FragmentManager fragmentManager = getFM();
|
||||
|
||||
if (selectedItem instanceof PlaylistMetadataEntry) {
|
||||
final PlaylistMetadataEntry entry = ((PlaylistMetadataEntry) selectedItem);
|
||||
@ -120,9 +113,6 @@ public final class BookmarkFragment
|
||||
entry.getUrl(),
|
||||
entry.getName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,6 +71,10 @@ public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Voi
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
|
||||
|
||||
if(!useAsFrontPage) {
|
||||
setTitle(activity.getString(R.string.fragment_whats_new));
|
||||
}
|
||||
return inflater.inflate(R.layout.fragment_feed, container, false);
|
||||
}
|
||||
|
||||
@ -105,20 +109,19 @@ public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Voi
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
/*@Override
|
||||
protected RecyclerView.LayoutManager getListLayoutManager() {
|
||||
boolean isPortrait = getResources().getDisplayMetrics().heightPixels > getResources().getDisplayMetrics().widthPixels;
|
||||
return new GridLayoutManager(activity, isPortrait ? 1 : 2);
|
||||
}*/
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
if (activity != null && isVisibleToUser) {
|
||||
setTitle(activity.getString(R.string.fragment_whats_new));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
|
||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
||||
if (supportActionBar != null) {
|
||||
supportActionBar.setTitle(R.string.fragment_whats_new);
|
||||
}
|
||||
|
||||
if(useAsFrontPage) {
|
||||
supportActionBar.setDisplayShowTitleEnabled(true);
|
||||
@ -176,19 +179,9 @@ public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Voi
|
||||
showLoading();
|
||||
showListFooter(true);
|
||||
subscriptionObserver = subscriptionService.getSubscription()
|
||||
.onErrorReturnItem(Collections.<SubscriptionEntity>emptyList())
|
||||
.onErrorReturnItem(Collections.emptyList())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Consumer<List<SubscriptionEntity>>() {
|
||||
@Override
|
||||
public void accept(List<SubscriptionEntity> subscriptionEntities) throws Exception {
|
||||
handleResult(subscriptionEntities);
|
||||
}
|
||||
}, new Consumer<Throwable>() {
|
||||
@Override
|
||||
public void accept(Throwable throwable) throws Exception {
|
||||
onError(throwable);
|
||||
}
|
||||
});
|
||||
.subscribe(this::handleResult, this::onError);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -239,13 +232,12 @@ public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Voi
|
||||
if (!itemsLoaded.contains(subscriptionEntity.getServiceId() + subscriptionEntity.getUrl())) {
|
||||
subscriptionService.getChannelInfo(subscriptionEntity)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.onErrorComplete(new Predicate<Throwable>() {
|
||||
@Override
|
||||
public boolean test(@io.reactivex.annotations.NonNull Throwable throwable) throws Exception {
|
||||
return FeedFragment.super.onError(throwable);
|
||||
}
|
||||
})
|
||||
.subscribe(getChannelInfoObserver(subscriptionEntity.getServiceId(), subscriptionEntity.getUrl()));
|
||||
.onErrorComplete(
|
||||
(@io.reactivex.annotations.NonNull Throwable throwable) ->
|
||||
FeedFragment.super.onError(throwable))
|
||||
.subscribe(
|
||||
getChannelInfoObserver(subscriptionEntity.getServiceId(),
|
||||
subscriptionEntity.getUrl()));
|
||||
} else {
|
||||
requestFeed(1);
|
||||
}
|
||||
@ -316,7 +308,10 @@ public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Voi
|
||||
|
||||
@Override
|
||||
public void onError(Throwable exception) {
|
||||
showSnackBarError(exception, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(serviceId), url, 0);
|
||||
showSnackBarError(exception,
|
||||
UserAction.SUBSCRIPTION,
|
||||
NewPipe.getNameOfService(serviceId),
|
||||
url, 0);
|
||||
requestFeed(1);
|
||||
onDone();
|
||||
}
|
||||
@ -361,12 +356,7 @@ public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Voi
|
||||
delayHandler.removeCallbacksAndMessages(null);
|
||||
// Add a little of a delay when requesting more items because the cache is so fast,
|
||||
// that the view seems stuck to the user when he scroll to the bottom
|
||||
delayHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
requestFeed(FEED_LOAD_COUNT);
|
||||
}
|
||||
}, 300);
|
||||
delayHandler.postDelayed(() -> requestFeed(FEED_LOAD_COUNT), 300);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -423,7 +413,9 @@ public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Voi
|
||||
int heightPixels = getResources().getDisplayMetrics().heightPixels;
|
||||
int itemHeightPixels = activity.getResources().getDimensionPixelSize(R.dimen.video_item_search_height);
|
||||
|
||||
int items = itemHeightPixels > 0 ? heightPixels / itemHeightPixels + OFF_SCREEN_ITEMS_COUNT : MIN_ITEMS_INITIAL_LOAD;
|
||||
int items = itemHeightPixels > 0
|
||||
? heightPixels / itemHeightPixels + OFF_SCREEN_ITEMS_COUNT
|
||||
: MIN_ITEMS_INITIAL_LOAD;
|
||||
return Math.max(MIN_ITEMS_INITIAL_LOAD, items);
|
||||
}
|
||||
|
||||
@ -441,8 +433,14 @@ public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Voi
|
||||
protected boolean onError(Throwable exception) {
|
||||
if (super.onError(exception)) return true;
|
||||
|
||||
int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error;
|
||||
onUnrecoverableError(exception, UserAction.SOMETHING_ELSE, "none", "Requesting feed", errorId);
|
||||
int errorId = exception instanceof ExtractionException
|
||||
? R.string.parsing_error
|
||||
: R.string.general_error;
|
||||
onUnrecoverableError(exception,
|
||||
UserAction.SOMETHING_ELSE,
|
||||
"none",
|
||||
"Requesting feed",
|
||||
errorId);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.database.LocalItem;
|
||||
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.fragments.list.BaseListFragment;
|
||||
import org.schabi.newpipe.local.BaseLocalListFragment;
|
||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||
@ -73,7 +74,7 @@ public class StatisticsPlaylistFragment
|
||||
return results;
|
||||
case MOST_PLAYED:
|
||||
Collections.sort(results, (left, right) ->
|
||||
((Long) right.watchCount).compareTo(left.watchCount));
|
||||
Long.compare(right.watchCount, left.watchCount));
|
||||
return results;
|
||||
default: return null;
|
||||
}
|
||||
@ -96,6 +97,14 @@ public class StatisticsPlaylistFragment
|
||||
return inflater.inflate(R.layout.fragment_playlist, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
if (activity != null && isVisibleToUser) {
|
||||
setTitle(activity.getString(R.string.title_activity_history));
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Fragment LifeCycle - Views
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -103,8 +112,10 @@ public class StatisticsPlaylistFragment
|
||||
@Override
|
||||
protected void initViews(View rootView, Bundle savedInstanceState) {
|
||||
super.initViews(rootView, savedInstanceState);
|
||||
if(!useAsFrontPage) {
|
||||
setTitle(getString(R.string.title_last_played));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View getListHeader() {
|
||||
@ -129,8 +140,10 @@ public class StatisticsPlaylistFragment
|
||||
public void selected(LocalItem selectedItem) {
|
||||
if (selectedItem instanceof StreamStatisticsEntry) {
|
||||
final StreamStatisticsEntry item = (StreamStatisticsEntry) selectedItem;
|
||||
NavigationHelper.openVideoDetailFragment(getFragmentManager(),
|
||||
item.serviceId, item.url, item.title);
|
||||
NavigationHelper.openVideoDetailFragment(getFM(),
|
||||
item.serviceId,
|
||||
item.url,
|
||||
item.title);
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,7 +354,7 @@ public class StatisticsPlaylistFragment
|
||||
final Disposable onDelete = recordManager.deleteStreamHistory(entry.streamId)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
howManyDelted -> {
|
||||
howManyDeleted -> {
|
||||
if(getView() != null) {
|
||||
Snackbar.make(getView(), R.string.one_item_deleted,
|
||||
Snackbar.LENGTH_SHORT).show();
|
||||
|
@ -13,6 +13,7 @@ import android.os.Parcelable;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
@ -209,7 +210,8 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
||||
}
|
||||
|
||||
private void setupImportFromItems(final ViewGroup listHolder) {
|
||||
final View previousBackupItem = addItemView(getString(R.string.previous_export), ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.ic_backup), listHolder);
|
||||
final View previousBackupItem = addItemView(getString(R.string.previous_export),
|
||||
ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.ic_backup), listHolder);
|
||||
previousBackupItem.setOnClickListener(item -> onImportPreviousSelected());
|
||||
|
||||
final int iconColor = ThemeHelper.isLightThemeSelected(getContext()) ? Color.BLACK : Color.WHITE;
|
||||
@ -241,8 +243,8 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
||||
}
|
||||
|
||||
private void onImportFromServiceSelected(int serviceId) {
|
||||
if (getParentFragment() == null) return;
|
||||
NavigationHelper.openSubscriptionsImportFragment(getParentFragment().getFragmentManager(), serviceId);
|
||||
FragmentManager fragmentManager = getFM();
|
||||
NavigationHelper.openSubscriptionsImportFragment(fragmentManager, serviceId);
|
||||
}
|
||||
|
||||
private void onImportPreviousSelected() {
|
||||
@ -320,21 +322,19 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
||||
infoListAdapter.setOnChannelSelectedListener(new OnClickGesture<ChannelInfoItem>() {
|
||||
@Override
|
||||
public void selected(ChannelInfoItem selectedItem) {
|
||||
try {
|
||||
// Requires the parent fragment to find holder for fragment replacement
|
||||
NavigationHelper.openChannelFragment(getParentFragment().getFragmentManager(),
|
||||
final FragmentManager fragmentManager = getFM();
|
||||
NavigationHelper.openChannelFragment(fragmentManager,
|
||||
selectedItem.getServiceId(),
|
||||
selectedItem.getUrl(),
|
||||
selectedItem.getName());
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//noinspection ConstantConditions
|
||||
whatsNewItemListHeader.setOnClickListener(v ->
|
||||
NavigationHelper.openWhatsNewFragment(getParentFragment().getFragmentManager()));
|
||||
whatsNewItemListHeader.setOnClickListener(v -> {
|
||||
FragmentManager fragmentManager = getFM();
|
||||
NavigationHelper.openWhatsNewFragment(fragmentManager);
|
||||
});
|
||||
importExportListHeader.setOnClickListener(v -> importExportOptions.switchState());
|
||||
}
|
||||
|
||||
@ -405,10 +405,13 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
||||
|
||||
private List<InfoItem> getSubscriptionItems(List<SubscriptionEntity> subscriptions) {
|
||||
List<InfoItem> items = new ArrayList<>();
|
||||
for (final SubscriptionEntity subscription : subscriptions) items.add(subscription.toChannelInfoItem());
|
||||
for (final SubscriptionEntity subscription : subscriptions) {
|
||||
items.add(subscription.toChannelInfoItem());
|
||||
}
|
||||
|
||||
Collections.sort(items,
|
||||
(InfoItem o1, InfoItem o2) -> o1.getName().compareToIgnoreCase(o2.getName()));
|
||||
(InfoItem o1, InfoItem o2) ->
|
||||
o1.getName().compareToIgnoreCase(o2.getName()));
|
||||
return items;
|
||||
}
|
||||
|
||||
@ -437,7 +440,11 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
||||
resetFragment();
|
||||
if (super.onError(exception)) return true;
|
||||
|
||||
onUnrecoverableError(exception, UserAction.SOMETHING_ELSE, "none", "Subscriptions", R.string.general_error);
|
||||
onUnrecoverableError(exception,
|
||||
UserAction.SOMETHING_ELSE,
|
||||
"none",
|
||||
"Subscriptions",
|
||||
R.string.general_error);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
@ -343,6 +344,7 @@ public final class BackgroundPlayer extends Service {
|
||||
|
||||
if (!shouldUpdateOnProgress) return;
|
||||
resetNotification();
|
||||
if(Build.VERSION.SDK_INT >= 26 /*Oreo*/) updateNotificationThumbnail();
|
||||
if (bigNotRemoteView != null) {
|
||||
bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, duration, currentProgress, false);
|
||||
bigNotRemoteView.setTextViewText(R.id.notificationTime, getTimeString(currentProgress) + " / " + getTimeString(duration));
|
||||
|
@ -51,6 +51,7 @@ import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
||||
|
||||
import org.schabi.newpipe.BuildConfig;
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
@ -69,6 +70,7 @@ import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueueAdapter;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||
import org.schabi.newpipe.player.resolver.MediaSourceTag;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||
import org.schabi.newpipe.util.SerializedCache;
|
||||
|
||||
@ -86,6 +88,7 @@ import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_INTERNAL
|
||||
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_PERIOD_TRANSITION;
|
||||
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK;
|
||||
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT;
|
||||
import static org.schabi.newpipe.report.UserAction.PLAY_STREAM;
|
||||
|
||||
/**
|
||||
* Base for the players, joining the common properties
|
||||
@ -96,7 +99,7 @@ import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK_ADJ
|
||||
public abstract class BasePlayer implements
|
||||
Player.EventListener, PlaybackListener, ImageLoadingListener {
|
||||
|
||||
public static final boolean DEBUG = true;
|
||||
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
||||
@NonNull public static final String TAG = "BasePlayer";
|
||||
|
||||
@NonNull final protected Context context;
|
||||
@ -363,7 +366,10 @@ public abstract class BasePlayer implements
|
||||
try {
|
||||
context.unregisterReceiver(broadcastReceiver);
|
||||
} catch (final IllegalArgumentException unregisteredException) {
|
||||
Log.e(TAG, "Broadcast receiver already unregistered.", unregisteredException);
|
||||
ErrorActivity.reportError(context, unregisteredException, null, null,
|
||||
ErrorActivity.ErrorInfo.make(PLAY_STREAM,
|
||||
"none",
|
||||
"play stream", R.string.general_error));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1001,6 +1007,8 @@ public abstract class BasePlayer implements
|
||||
try {
|
||||
metadata = (MediaSourceTag) simpleExoPlayer.getCurrentTag();
|
||||
} catch (IndexOutOfBoundsException | ClassCastException error) {
|
||||
if(DEBUG) Log.d(TAG, "Could not update metadata: " + error.getMessage());
|
||||
if(DEBUG) error.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1087,6 +1095,9 @@ public abstract class BasePlayer implements
|
||||
return simpleExoPlayer.isCurrentWindowDynamic();
|
||||
} catch (@NonNull IndexOutOfBoundsException ignored) {
|
||||
// Why would this even happen =(
|
||||
// But lets log it anyway. Save is save
|
||||
if(DEBUG) Log.d(TAG, "Could not update metadata: " + ignored.getMessage());
|
||||
if(DEBUG) ignored.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.content.res.AppCompatResources;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.util.DisplayMetrics;
|
||||
@ -46,7 +47,9 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
@ -82,6 +85,7 @@ import java.util.UUID;
|
||||
import static org.schabi.newpipe.player.BasePlayer.STATE_PLAYING;
|
||||
import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_DURATION;
|
||||
import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME;
|
||||
import static org.schabi.newpipe.util.AnimationUtils.Type.SCALE_AND_ALPHA;
|
||||
import static org.schabi.newpipe.util.AnimationUtils.Type.SLIDE_AND_ALPHA;
|
||||
import static org.schabi.newpipe.util.AnimationUtils.animateRotation;
|
||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||
@ -365,10 +369,16 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||
|
||||
@SuppressWarnings({"unused", "WeakerAccess"})
|
||||
private class VideoPlayerImpl extends VideoPlayer {
|
||||
private final float MAX_GESTURE_LENGTH = 0.75f;
|
||||
|
||||
private TextView titleTextView;
|
||||
private TextView channelTextView;
|
||||
private TextView volumeTextView;
|
||||
private TextView brightnessTextView;
|
||||
private RelativeLayout volumeRelativeLayout;
|
||||
private ProgressBar volumeProgressBar;
|
||||
private ImageView volumeImageView;
|
||||
private RelativeLayout brightnessRelativeLayout;
|
||||
private ProgressBar brightnessProgressBar;
|
||||
private ImageView brightnessImageView;
|
||||
private ImageButton queueButton;
|
||||
private ImageButton repeatButton;
|
||||
private ImageButton shuffleButton;
|
||||
@ -392,6 +402,8 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||
private RelativeLayout windowRootLayout;
|
||||
private View secondaryControls;
|
||||
|
||||
private int maxGestureLength;
|
||||
|
||||
VideoPlayerImpl(final Context context) {
|
||||
super("VideoPlayerImpl" + MainVideoPlayer.TAG, context);
|
||||
}
|
||||
@ -401,8 +413,12 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||
super.initViews(rootView);
|
||||
this.titleTextView = rootView.findViewById(R.id.titleTextView);
|
||||
this.channelTextView = rootView.findViewById(R.id.channelTextView);
|
||||
this.volumeTextView = rootView.findViewById(R.id.volumeTextView);
|
||||
this.brightnessTextView = rootView.findViewById(R.id.brightnessTextView);
|
||||
this.volumeRelativeLayout = rootView.findViewById(R.id.volumeRelativeLayout);
|
||||
this.volumeProgressBar = rootView.findViewById(R.id.volumeProgressBar);
|
||||
this.volumeImageView = rootView.findViewById(R.id.volumeImageView);
|
||||
this.brightnessRelativeLayout = rootView.findViewById(R.id.brightnessRelativeLayout);
|
||||
this.brightnessProgressBar = rootView.findViewById(R.id.brightnessProgressBar);
|
||||
this.brightnessImageView = rootView.findViewById(R.id.brightnessImageView);
|
||||
this.queueButton = rootView.findViewById(R.id.queueButton);
|
||||
this.repeatButton = rootView.findViewById(R.id.repeatButton);
|
||||
this.shuffleButton = rootView.findViewById(R.id.shuffleButton);
|
||||
@ -461,6 +477,20 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||
toggleOrientationButton.setOnClickListener(this);
|
||||
switchBackgroundButton.setOnClickListener(this);
|
||||
switchPopupButton.setOnClickListener(this);
|
||||
|
||||
getRootView().addOnLayoutChangeListener((view, l, t, r, b, ol, ot, or, ob) -> {
|
||||
if (l != ol || t != ot || r != or || b != ob) {
|
||||
// Use smaller value to be consistent between screen orientations
|
||||
// (and to make usage easier)
|
||||
int width = r - l, height = b - t;
|
||||
maxGestureLength = (int) (Math.min(width, height) * MAX_GESTURE_LENGTH);
|
||||
|
||||
if (DEBUG) Log.d(TAG, "maxGestureLength = " + maxGestureLength);
|
||||
|
||||
volumeProgressBar.setMax(maxGestureLength);
|
||||
brightnessProgressBar.setMax(maxGestureLength);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void minimize() {
|
||||
@ -872,12 +902,28 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||
return channelTextView;
|
||||
}
|
||||
|
||||
public TextView getVolumeTextView() {
|
||||
return volumeTextView;
|
||||
public RelativeLayout getVolumeRelativeLayout() {
|
||||
return volumeRelativeLayout;
|
||||
}
|
||||
|
||||
public TextView getBrightnessTextView() {
|
||||
return brightnessTextView;
|
||||
public ProgressBar getVolumeProgressBar() {
|
||||
return volumeProgressBar;
|
||||
}
|
||||
|
||||
public ImageView getVolumeImageView() {
|
||||
return volumeImageView;
|
||||
}
|
||||
|
||||
public RelativeLayout getBrightnessRelativeLayout() {
|
||||
return brightnessRelativeLayout;
|
||||
}
|
||||
|
||||
public ProgressBar getBrightnessProgressBar() {
|
||||
return brightnessProgressBar;
|
||||
}
|
||||
|
||||
public ImageView getBrightnessImageView() {
|
||||
return brightnessImageView;
|
||||
}
|
||||
|
||||
public ImageButton getRepeatButton() {
|
||||
@ -887,6 +933,10 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||
public ImageButton getPlayPauseButton() {
|
||||
return playPauseButton;
|
||||
}
|
||||
|
||||
public int getMaxGestureLength() {
|
||||
return maxGestureLength;
|
||||
}
|
||||
}
|
||||
|
||||
private class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener {
|
||||
@ -930,23 +980,10 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||
|
||||
private final boolean isPlayerGestureEnabled = PlayerHelper.isPlayerGestureEnabled(getApplicationContext());
|
||||
|
||||
private final float stepsBrightness = 15, stepBrightness = (1f / stepsBrightness), minBrightness = .01f;
|
||||
private float currentBrightness = getWindow().getAttributes().screenBrightness > 0
|
||||
? getWindow().getAttributes().screenBrightness
|
||||
: 0.5f;
|
||||
|
||||
private int currentVolume, maxVolume = playerImpl.getAudioReactor().getMaxVolume();
|
||||
private final float stepsVolume = 15, stepVolume = (float) Math.ceil(maxVolume / stepsVolume), minVolume = 0;
|
||||
|
||||
private final String brightnessUnicode = new String(Character.toChars(0x2600));
|
||||
private final String volumeUnicode = new String(Character.toChars(0x1F508));
|
||||
private final int maxVolume = playerImpl.getAudioReactor().getMaxVolume();
|
||||
|
||||
private final int MOVEMENT_THRESHOLD = 40;
|
||||
private final int eventsThreshold = 8;
|
||||
private boolean triggered = false;
|
||||
private int eventsNum;
|
||||
|
||||
// TODO: Improve video gesture controls
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||
if (!isPlayerGestureEnabled) return false;
|
||||
@ -956,63 +993,77 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||
", e1.getRaw = [" + e1.getRawX() + ", " + e1.getRawY() + "]" +
|
||||
", e2.getRaw = [" + e2.getRawX() + ", " + e2.getRawY() + "]" +
|
||||
", distanceXy = [" + distanceX + ", " + distanceY + "]");
|
||||
float abs = Math.abs(e2.getY() - e1.getY());
|
||||
if (!triggered) {
|
||||
triggered = abs > MOVEMENT_THRESHOLD;
|
||||
|
||||
if (!isMoving && (
|
||||
Math.abs(e2.getY() - e1.getY()) <= MOVEMENT_THRESHOLD
|
||||
|| Math.abs(distanceX) > Math.abs(distanceY)
|
||||
) || playerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (eventsNum++ % eventsThreshold != 0 || playerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED) return false;
|
||||
isMoving = true;
|
||||
// boolean up = !((e2.getY() - e1.getY()) > 0) && distanceY > 0; // Android's origin point is on top
|
||||
boolean up = distanceY > 0;
|
||||
|
||||
|
||||
if (e1.getX() > playerImpl.getRootView().getWidth() / 2) {
|
||||
double floor = Math.floor(up ? stepVolume : -stepVolume);
|
||||
currentVolume = (int) (playerImpl.getAudioReactor().getVolume() + floor);
|
||||
if (currentVolume >= maxVolume) currentVolume = maxVolume;
|
||||
if (currentVolume <= minVolume) currentVolume = (int) minVolume;
|
||||
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
|
||||
float currentProgressPercent =
|
||||
(float) playerImpl.getVolumeProgressBar().getProgress() / playerImpl.getMaxGestureLength();
|
||||
int currentVolume = (int) (maxVolume * currentProgressPercent);
|
||||
playerImpl.getAudioReactor().setVolume(currentVolume);
|
||||
|
||||
currentVolume = playerImpl.getAudioReactor().getVolume();
|
||||
if (DEBUG) Log.d(TAG, "onScroll().volumeControl, currentVolume = " + currentVolume);
|
||||
final String volumeText = volumeUnicode + " " + Math.round((((float) currentVolume) / maxVolume) * 100) + "%";
|
||||
playerImpl.getVolumeTextView().setText(volumeText);
|
||||
|
||||
if (playerImpl.getVolumeTextView().getVisibility() != View.VISIBLE) animateView(playerImpl.getVolumeTextView(), true, 200);
|
||||
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) playerImpl.getBrightnessTextView().setVisibility(View.GONE);
|
||||
final int resId =
|
||||
currentProgressPercent <= 0 ? R.drawable.ic_volume_off_white_72dp
|
||||
: currentProgressPercent < 0.25 ? R.drawable.ic_volume_mute_white_72dp
|
||||
: currentProgressPercent < 0.75 ? R.drawable.ic_volume_down_white_72dp
|
||||
: R.drawable.ic_volume_up_white_72dp;
|
||||
|
||||
playerImpl.getVolumeImageView().setImageDrawable(
|
||||
AppCompatResources.getDrawable(getApplicationContext(), resId)
|
||||
);
|
||||
|
||||
if (playerImpl.getVolumeRelativeLayout().getVisibility() != View.VISIBLE) {
|
||||
animateView(playerImpl.getVolumeRelativeLayout(), SCALE_AND_ALPHA, true, 200);
|
||||
}
|
||||
if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
|
||||
playerImpl.getBrightnessRelativeLayout().setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
WindowManager.LayoutParams lp = getWindow().getAttributes();
|
||||
currentBrightness += up ? stepBrightness : -stepBrightness;
|
||||
if (currentBrightness >= 1f) currentBrightness = 1f;
|
||||
if (currentBrightness <= minBrightness) currentBrightness = minBrightness;
|
||||
playerImpl.getBrightnessProgressBar().incrementProgressBy((int) distanceY);
|
||||
float currentProgressPercent =
|
||||
(float) playerImpl.getBrightnessProgressBar().getProgress() / playerImpl.getMaxGestureLength();
|
||||
WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
|
||||
layoutParams.screenBrightness = currentProgressPercent;
|
||||
getWindow().setAttributes(layoutParams);
|
||||
|
||||
lp.screenBrightness = currentBrightness;
|
||||
getWindow().setAttributes(lp);
|
||||
if (DEBUG) Log.d(TAG, "onScroll().brightnessControl, currentBrightness = " + currentBrightness);
|
||||
int brightnessNormalized = Math.round(currentBrightness * 100);
|
||||
if (DEBUG) Log.d(TAG, "onScroll().brightnessControl, currentBrightness = " + currentProgressPercent);
|
||||
|
||||
final String brightnessText = brightnessUnicode + " " + (brightnessNormalized == 1 ? 0 : brightnessNormalized) + "%";
|
||||
playerImpl.getBrightnessTextView().setText(brightnessText);
|
||||
final int resId =
|
||||
currentProgressPercent < 0.25 ? R.drawable.ic_brightness_low_white_72dp
|
||||
: currentProgressPercent < 0.75 ? R.drawable.ic_brightness_medium_white_72dp
|
||||
: R.drawable.ic_brightness_high_white_72dp;
|
||||
|
||||
if (playerImpl.getBrightnessTextView().getVisibility() != View.VISIBLE) animateView(playerImpl.getBrightnessTextView(), true, 200);
|
||||
if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) playerImpl.getVolumeTextView().setVisibility(View.GONE);
|
||||
playerImpl.getBrightnessImageView().setImageDrawable(
|
||||
AppCompatResources.getDrawable(getApplicationContext(), resId)
|
||||
);
|
||||
|
||||
if (playerImpl.getBrightnessRelativeLayout().getVisibility() != View.VISIBLE) {
|
||||
animateView(playerImpl.getBrightnessRelativeLayout(), SCALE_AND_ALPHA, true, 200);
|
||||
}
|
||||
if (playerImpl.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) {
|
||||
playerImpl.getVolumeRelativeLayout().setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void onScrollEnd() {
|
||||
if (DEBUG) Log.d(TAG, "onScrollEnd() called");
|
||||
triggered = false;
|
||||
eventsNum = 0;
|
||||
/* if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) playerImpl.getVolumeTextView().setVisibility(View.GONE);
|
||||
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) playerImpl.getBrightnessTextView().setVisibility(View.GONE);*/
|
||||
if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) {
|
||||
animateView(playerImpl.getVolumeTextView(), false, 200, 200);
|
||||
|
||||
if (playerImpl.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) {
|
||||
animateView(playerImpl.getVolumeRelativeLayout(), SCALE_AND_ALPHA, false, 200, 200);
|
||||
}
|
||||
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) {
|
||||
animateView(playerImpl.getBrightnessTextView(), false, 200, 200);
|
||||
if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
|
||||
animateView(playerImpl.getBrightnessRelativeLayout(), SCALE_AND_ALPHA, false, 200, 200);
|
||||
}
|
||||
|
||||
if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == STATE_PLAYING) {
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
package org.schabi.newpipe.player;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
@ -34,6 +36,7 @@ import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
@ -41,7 +44,9 @@ import android.view.GestureDetector;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.AnticipateInterpolator;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
@ -104,10 +109,13 @@ public final class PopupVideoPlayer extends Service {
|
||||
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
|
||||
|
||||
private WindowManager windowManager;
|
||||
private WindowManager.LayoutParams windowLayoutParams;
|
||||
private GestureDetector gestureDetector;
|
||||
private WindowManager.LayoutParams popupLayoutParams;
|
||||
private GestureDetector popupGestureDetector;
|
||||
|
||||
private View closeOverlayView;
|
||||
private FloatingActionButton closeOverlayButton;
|
||||
private WindowManager.LayoutParams closeOverlayLayoutParams;
|
||||
|
||||
private int shutdownFlingVelocity;
|
||||
private int tossFlingVelocity;
|
||||
|
||||
private float screenWidth, screenHeight;
|
||||
@ -122,6 +130,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
private VideoPlayerImpl playerImpl;
|
||||
private LockManager lockManager;
|
||||
private boolean isPopupClosing = false;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Service-Activity Binder
|
||||
@ -150,7 +159,10 @@ public final class PopupVideoPlayer extends Service {
|
||||
public int onStartCommand(final Intent intent, int flags, int startId) {
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "onStartCommand() called with: intent = [" + intent + "], flags = [" + flags + "], startId = [" + startId + "]");
|
||||
if (playerImpl.getPlayer() == null) initPopup();
|
||||
if (playerImpl.getPlayer() == null) {
|
||||
initPopup();
|
||||
initPopupCloseOverlay();
|
||||
}
|
||||
if (!playerImpl.isPlaying()) playerImpl.getPlayer().setPlayWhenReady(true);
|
||||
|
||||
playerImpl.handleIntent(intent);
|
||||
@ -160,15 +172,16 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
if (DEBUG) Log.d(TAG, "onConfigurationChanged() called with: newConfig = [" + newConfig + "]");
|
||||
updateScreenSize();
|
||||
updatePopupSize(windowLayoutParams.width, -1);
|
||||
checkPositionBounds();
|
||||
updatePopupSize(popupLayoutParams.width, -1);
|
||||
checkPopupPositionBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (DEBUG) Log.d(TAG, "onDestroy() called");
|
||||
onClose();
|
||||
closePopup();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -186,7 +199,6 @@ public final class PopupVideoPlayer extends Service {
|
||||
View rootView = View.inflate(this, R.layout.player_popup, null);
|
||||
playerImpl.setup(rootView);
|
||||
|
||||
shutdownFlingVelocity = PlayerHelper.getShutdownFlingVelocity(this);
|
||||
tossFlingVelocity = PlayerHelper.getTossFlingVelocity(this);
|
||||
|
||||
updateScreenSize();
|
||||
@ -200,27 +212,52 @@ public final class PopupVideoPlayer extends Service {
|
||||
WindowManager.LayoutParams.TYPE_PHONE :
|
||||
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
|
||||
windowLayoutParams = new WindowManager.LayoutParams(
|
||||
popupLayoutParams = new WindowManager.LayoutParams(
|
||||
(int) popupWidth, (int) getMinimumVideoHeight(popupWidth),
|
||||
layoutParamType,
|
||||
IDLE_WINDOW_FLAGS,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
windowLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
|
||||
windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
|
||||
popupLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
|
||||
popupLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
|
||||
|
||||
int centerX = (int) (screenWidth / 2f - popupWidth / 2f);
|
||||
int centerY = (int) (screenHeight / 2f - popupHeight / 2f);
|
||||
windowLayoutParams.x = popupRememberSizeAndPos ? sharedPreferences.getInt(POPUP_SAVED_X, centerX) : centerX;
|
||||
windowLayoutParams.y = popupRememberSizeAndPos ? sharedPreferences.getInt(POPUP_SAVED_Y, centerY) : centerY;
|
||||
popupLayoutParams.x = popupRememberSizeAndPos ? sharedPreferences.getInt(POPUP_SAVED_X, centerX) : centerX;
|
||||
popupLayoutParams.y = popupRememberSizeAndPos ? sharedPreferences.getInt(POPUP_SAVED_Y, centerY) : centerY;
|
||||
|
||||
checkPositionBounds();
|
||||
checkPopupPositionBounds();
|
||||
|
||||
MySimpleOnGestureListener listener = new MySimpleOnGestureListener();
|
||||
gestureDetector = new GestureDetector(this, listener);
|
||||
PopupWindowGestureListener listener = new PopupWindowGestureListener();
|
||||
popupGestureDetector = new GestureDetector(this, listener);
|
||||
rootView.setOnTouchListener(listener);
|
||||
playerImpl.getLoadingPanel().setMinimumWidth(windowLayoutParams.width);
|
||||
playerImpl.getLoadingPanel().setMinimumHeight(windowLayoutParams.height);
|
||||
windowManager.addView(rootView, windowLayoutParams);
|
||||
|
||||
playerImpl.getLoadingPanel().setMinimumWidth(popupLayoutParams.width);
|
||||
playerImpl.getLoadingPanel().setMinimumHeight(popupLayoutParams.height);
|
||||
windowManager.addView(rootView, popupLayoutParams);
|
||||
}
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
private void initPopupCloseOverlay() {
|
||||
if (DEBUG) Log.d(TAG, "initPopupCloseOverlay() called");
|
||||
closeOverlayView = View.inflate(this, R.layout.player_popup_close_overlay, null);
|
||||
closeOverlayButton = closeOverlayView.findViewById(R.id.closeButton);
|
||||
|
||||
final int layoutParamType = Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O ?
|
||||
WindowManager.LayoutParams.TYPE_PHONE :
|
||||
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
final int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
|
||||
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
|
||||
|
||||
closeOverlayLayoutParams = new WindowManager.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
layoutParamType,
|
||||
flags,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
closeOverlayLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
|
||||
closeOverlayLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
|
||||
|
||||
closeOverlayButton.setVisibility(View.GONE);
|
||||
windowManager.addView(closeOverlayView, closeOverlayLayoutParams);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@ -280,44 +317,105 @@ public final class PopupVideoPlayer extends Service {
|
||||
// Misc
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
public void onClose() {
|
||||
if (DEBUG) Log.d(TAG, "onClose() called");
|
||||
public void closePopup() {
|
||||
if (DEBUG) Log.d(TAG, "closePopup() called, isPopupClosing = " + isPopupClosing);
|
||||
if (isPopupClosing) return;
|
||||
isPopupClosing = true;
|
||||
|
||||
if (playerImpl != null) {
|
||||
if (playerImpl.getRootView() != null) {
|
||||
windowManager.removeView(playerImpl.getRootView());
|
||||
playerImpl.setRootView(null);
|
||||
}
|
||||
playerImpl.setRootView(null);
|
||||
playerImpl.stopActivityBinding();
|
||||
playerImpl.destroy();
|
||||
playerImpl = null;
|
||||
}
|
||||
|
||||
mBinder = null;
|
||||
if (lockManager != null) lockManager.releaseWifiAndCpu();
|
||||
if (notificationManager != null) notificationManager.cancel(NOTIFICATION_ID);
|
||||
mBinder = null;
|
||||
playerImpl = null;
|
||||
|
||||
animateOverlayAndFinishService();
|
||||
}
|
||||
|
||||
private void animateOverlayAndFinishService() {
|
||||
final int targetTranslationY = (int) (closeOverlayButton.getRootView().getHeight() - closeOverlayButton.getY());
|
||||
|
||||
closeOverlayButton.animate().setListener(null).cancel();
|
||||
closeOverlayButton.animate()
|
||||
.setInterpolator(new AnticipateInterpolator())
|
||||
.translationY(targetTranslationY)
|
||||
.setDuration(400)
|
||||
.setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
end();
|
||||
}
|
||||
|
||||
private void end() {
|
||||
windowManager.removeView(closeOverlayView);
|
||||
|
||||
stopForeground(true);
|
||||
stopSelf();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private void checkPositionBounds() {
|
||||
if (windowLayoutParams.x > screenWidth - windowLayoutParams.width)
|
||||
windowLayoutParams.x = (int) (screenWidth - windowLayoutParams.width);
|
||||
if (windowLayoutParams.x < 0) windowLayoutParams.x = 0;
|
||||
if (windowLayoutParams.y > screenHeight - windowLayoutParams.height)
|
||||
windowLayoutParams.y = (int) (screenHeight - windowLayoutParams.height);
|
||||
if (windowLayoutParams.y < 0) windowLayoutParams.y = 0;
|
||||
/**
|
||||
* @see #checkPopupPositionBounds(float, float)
|
||||
*/
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
private boolean checkPopupPositionBounds() {
|
||||
return checkPopupPositionBounds(screenWidth, screenHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if {@link #popupLayoutParams}' position is within a arbitrary boundary that goes from (0,0) to (boundaryWidth,boundaryHeight).
|
||||
* <p>
|
||||
* If it's out of these boundaries, {@link #popupLayoutParams}' position is changed and {@code true} is returned
|
||||
* to represent this change.
|
||||
*
|
||||
* @return if the popup was out of bounds and have been moved back to it
|
||||
*/
|
||||
private boolean checkPopupPositionBounds(final float boundaryWidth, final float boundaryHeight) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "checkPopupPositionBounds() called with: boundaryWidth = [" + boundaryWidth + "], boundaryHeight = [" + boundaryHeight + "]");
|
||||
}
|
||||
|
||||
if (popupLayoutParams.x < 0) {
|
||||
popupLayoutParams.x = 0;
|
||||
return true;
|
||||
} else if (popupLayoutParams.x > boundaryWidth - popupLayoutParams.width) {
|
||||
popupLayoutParams.x = (int) (boundaryWidth - popupLayoutParams.width);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (popupLayoutParams.y < 0) {
|
||||
popupLayoutParams.y = 0;
|
||||
return true;
|
||||
} else if (popupLayoutParams.y > boundaryHeight - popupLayoutParams.height) {
|
||||
popupLayoutParams.y = (int) (boundaryHeight - popupLayoutParams.height);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void savePositionAndSize() {
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(PopupVideoPlayer.this);
|
||||
sharedPreferences.edit().putInt(POPUP_SAVED_X, windowLayoutParams.x).apply();
|
||||
sharedPreferences.edit().putInt(POPUP_SAVED_Y, windowLayoutParams.y).apply();
|
||||
sharedPreferences.edit().putFloat(POPUP_SAVED_WIDTH, windowLayoutParams.width).apply();
|
||||
sharedPreferences.edit().putInt(POPUP_SAVED_X, popupLayoutParams.x).apply();
|
||||
sharedPreferences.edit().putInt(POPUP_SAVED_Y, popupLayoutParams.y).apply();
|
||||
sharedPreferences.edit().putFloat(POPUP_SAVED_WIDTH, popupLayoutParams.width).apply();
|
||||
}
|
||||
|
||||
private float getMinimumVideoHeight(float width) {
|
||||
@ -352,13 +450,13 @@ public final class PopupVideoPlayer extends Service {
|
||||
if (height == -1) height = (int) getMinimumVideoHeight(width);
|
||||
else height = (int) (height > maximumHeight ? maximumHeight : height < minimumHeight ? minimumHeight : height);
|
||||
|
||||
windowLayoutParams.width = width;
|
||||
windowLayoutParams.height = height;
|
||||
popupLayoutParams.width = width;
|
||||
popupLayoutParams.height = height;
|
||||
popupWidth = width;
|
||||
popupHeight = height;
|
||||
|
||||
if (DEBUG) Log.d(TAG, "updatePopupSize() updated values: width = [" + width + "], height = [" + height + "]");
|
||||
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
|
||||
windowManager.updateViewLayout(playerImpl.getRootView(), popupLayoutParams);
|
||||
}
|
||||
|
||||
protected void setRepeatModeRemote(final RemoteViews remoteViews, final int repeatMode) {
|
||||
@ -380,10 +478,10 @@ public final class PopupVideoPlayer extends Service {
|
||||
}
|
||||
|
||||
private void updateWindowFlags(final int flags) {
|
||||
if (windowLayoutParams == null || windowManager == null || playerImpl == null) return;
|
||||
if (popupLayoutParams == null || windowManager == null || playerImpl == null) return;
|
||||
|
||||
windowLayoutParams.flags = flags;
|
||||
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
|
||||
popupLayoutParams.flags = flags;
|
||||
windowManager.updateViewLayout(playerImpl.getRootView(), popupLayoutParams);
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -393,6 +491,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
private ImageView videoPlayPause;
|
||||
|
||||
private View extraOptionsView;
|
||||
private View closingOverlayView;
|
||||
|
||||
@Override
|
||||
public void handleIntent(Intent intent) {
|
||||
@ -413,12 +512,18 @@ public final class PopupVideoPlayer extends Service {
|
||||
fullScreenButton = rootView.findViewById(R.id.fullScreenButton);
|
||||
fullScreenButton.setOnClickListener(v -> onFullScreenButtonClicked());
|
||||
videoPlayPause = rootView.findViewById(R.id.videoPlayPause);
|
||||
videoPlayPause.setOnClickListener(this::onPlayPauseButtonPressed);
|
||||
|
||||
extraOptionsView = rootView.findViewById(R.id.extraOptionsView);
|
||||
closingOverlayView = rootView.findViewById(R.id.closingOverlay);
|
||||
rootView.addOnLayoutChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initListeners() {
|
||||
super.initListeners();
|
||||
videoPlayPause.setOnClickListener(v -> onPlayPause());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupSubtitleView(@NonNull SubtitleView view,
|
||||
final float captionScale,
|
||||
@ -429,10 +534,6 @@ public final class PopupVideoPlayer extends Service {
|
||||
view.setStyle(captionStyle);
|
||||
}
|
||||
|
||||
private void onPlayPauseButtonPressed(View ib) {
|
||||
onPlayPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayoutChange(final View view, int left, int top, int right, int bottom,
|
||||
int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
||||
@ -476,7 +577,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
}
|
||||
context.startActivity(intent);
|
||||
onClose();
|
||||
closePopup();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -634,7 +735,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
@Override
|
||||
public void onPlaybackShutdown() {
|
||||
super.onPlaybackShutdown();
|
||||
onClose();
|
||||
closePopup();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@ -660,7 +761,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
if (DEBUG) Log.d(TAG, "onBroadcastReceived() called with: intent = [" + intent + "]");
|
||||
switch (intent.getAction()) {
|
||||
case ACTION_CLOSE:
|
||||
onClose();
|
||||
closePopup();
|
||||
break;
|
||||
case ACTION_PLAY_PAUSE:
|
||||
onPlayPause();
|
||||
@ -791,12 +892,15 @@ public final class PopupVideoPlayer extends Service {
|
||||
public TextView getResizingIndicator() {
|
||||
return resizingIndicator;
|
||||
}
|
||||
|
||||
public View getClosingOverlayView() {
|
||||
return closingOverlayView;
|
||||
}
|
||||
}
|
||||
|
||||
private class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener {
|
||||
private class PopupWindowGestureListener extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener {
|
||||
private int initialPopupX, initialPopupY;
|
||||
private boolean isMoving;
|
||||
|
||||
private boolean isResizing;
|
||||
|
||||
@Override
|
||||
@ -832,10 +936,15 @@ public final class PopupVideoPlayer extends Service {
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
if (DEBUG) Log.d(TAG, "onDown() called with: e = [" + e + "]");
|
||||
initialPopupX = windowLayoutParams.x;
|
||||
initialPopupY = windowLayoutParams.y;
|
||||
popupWidth = windowLayoutParams.width;
|
||||
popupHeight = windowLayoutParams.height;
|
||||
|
||||
// Fix popup position when the user touch it, it may have the wrong one
|
||||
// because the soft input is visible (the draggable area is currently resized).
|
||||
checkPopupPositionBounds(closeOverlayView.getWidth(), closeOverlayView.getHeight());
|
||||
|
||||
initialPopupX = popupLayoutParams.x;
|
||||
initialPopupY = popupLayoutParams.y;
|
||||
popupWidth = popupLayoutParams.width;
|
||||
popupHeight = popupLayoutParams.height;
|
||||
return super.onDown(e);
|
||||
}
|
||||
|
||||
@ -843,20 +952,22 @@ public final class PopupVideoPlayer extends Service {
|
||||
public void onLongPress(MotionEvent e) {
|
||||
if (DEBUG) Log.d(TAG, "onLongPress() called with: e = [" + e + "]");
|
||||
updateScreenSize();
|
||||
checkPositionBounds();
|
||||
checkPopupPositionBounds();
|
||||
updatePopupSize((int) screenWidth, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||
if (isResizing || playerImpl == null) return super.onScroll(e1, e2, distanceX, distanceY);
|
||||
public boolean onScroll(MotionEvent initialEvent, MotionEvent movingEvent, float distanceX, float distanceY) {
|
||||
if (isResizing || playerImpl == null) return super.onScroll(initialEvent, movingEvent, distanceX, distanceY);
|
||||
|
||||
if (!isMoving) {
|
||||
animateView(closeOverlayButton, true, 200);
|
||||
}
|
||||
|
||||
if (playerImpl.getCurrentState() != BasePlayer.STATE_BUFFERING
|
||||
&& (!isMoving || playerImpl.getControlsRoot().getAlpha() != 1f)) playerImpl.showControls(0);
|
||||
isMoving = true;
|
||||
|
||||
float diffX = (int) (e2.getRawX() - e1.getRawX()), posX = (int) (initialPopupX + diffX);
|
||||
float diffY = (int) (e2.getRawY() - e1.getRawY()), posY = (int) (initialPopupY + diffY);
|
||||
float diffX = (int) (movingEvent.getRawX() - initialEvent.getRawX()), posX = (int) (initialPopupX + diffX);
|
||||
float diffY = (int) (movingEvent.getRawY() - initialEvent.getRawY()), posY = (int) (initialPopupY + diffY);
|
||||
|
||||
if (posX > (screenWidth - popupWidth)) posX = (int) (screenWidth - popupWidth);
|
||||
else if (posX < 0) posX = 0;
|
||||
@ -864,26 +975,49 @@ public final class PopupVideoPlayer extends Service {
|
||||
if (posY > (screenHeight - popupHeight)) posY = (int) (screenHeight - popupHeight);
|
||||
else if (posY < 0) posY = 0;
|
||||
|
||||
windowLayoutParams.x = (int) posX;
|
||||
windowLayoutParams.y = (int) posY;
|
||||
popupLayoutParams.x = (int) posX;
|
||||
popupLayoutParams.y = (int) posY;
|
||||
|
||||
final View closingOverlayView = playerImpl.getClosingOverlayView();
|
||||
if (isInsideClosingRadius(movingEvent)) {
|
||||
if (closingOverlayView.getVisibility() == View.GONE) {
|
||||
animateView(closingOverlayView, true, 250);
|
||||
}
|
||||
} else {
|
||||
if (closingOverlayView.getVisibility() == View.VISIBLE) {
|
||||
animateView(closingOverlayView, false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//noinspection PointlessBooleanExpression
|
||||
if (DEBUG && false) Log.d(TAG, "PopupVideoPlayer.onScroll = " +
|
||||
", e1.getRaw = [" + e1.getRawX() + ", " + e1.getRawY() + "]" +
|
||||
", e2.getRaw = [" + e2.getRawX() + ", " + e2.getRawY() + "]" +
|
||||
", distanceXy = [" + distanceX + ", " + distanceY + "]" +
|
||||
", posXy = [" + posX + ", " + posY + "]" +
|
||||
", popupWh = [" + popupWidth + " x " + popupHeight + "]");
|
||||
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
|
||||
if (DEBUG && false) {
|
||||
Log.d(TAG, "PopupVideoPlayer.onScroll = " +
|
||||
", e1.getRaw = [" + initialEvent.getRawX() + ", " + initialEvent.getRawY() + "]" + ", e1.getX,Y = [" + initialEvent.getX() + ", " + initialEvent.getY() + "]" +
|
||||
", e2.getRaw = [" + movingEvent.getRawX() + ", " + movingEvent.getRawY() + "]" + ", e2.getX,Y = [" + movingEvent.getX() + ", " + movingEvent.getY() + "]" +
|
||||
", distanceX,Y = [" + distanceX + ", " + distanceY + "]" +
|
||||
", posX,Y = [" + posX + ", " + posY + "]" +
|
||||
", popupW,H = [" + popupWidth + " x " + popupHeight + "]");
|
||||
}
|
||||
windowManager.updateViewLayout(playerImpl.getRootView(), popupLayoutParams);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void onScrollEnd() {
|
||||
private void onScrollEnd(MotionEvent event) {
|
||||
if (DEBUG) Log.d(TAG, "onScrollEnd() called");
|
||||
if (playerImpl == null) return;
|
||||
if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == STATE_PLAYING) {
|
||||
playerImpl.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
|
||||
}
|
||||
|
||||
if (isInsideClosingRadius(event)) {
|
||||
closePopup();
|
||||
} else {
|
||||
animateView(playerImpl.getClosingOverlayView(), false, 0);
|
||||
|
||||
if (!isPopupClosing) {
|
||||
animateView(closeOverlayButton, false, 200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -893,14 +1027,11 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
final float absVelocityX = Math.abs(velocityX);
|
||||
final float absVelocityY = Math.abs(velocityY);
|
||||
if (absVelocityX > shutdownFlingVelocity) {
|
||||
onClose();
|
||||
return true;
|
||||
} else if (Math.max(absVelocityX, absVelocityY) > tossFlingVelocity) {
|
||||
if (absVelocityX > tossFlingVelocity) windowLayoutParams.x = (int) velocityX;
|
||||
if (absVelocityY > tossFlingVelocity) windowLayoutParams.y = (int) velocityY;
|
||||
checkPositionBounds();
|
||||
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
|
||||
if (Math.max(absVelocityX, absVelocityY) > tossFlingVelocity) {
|
||||
if (absVelocityX > tossFlingVelocity) popupLayoutParams.x = (int) velocityX;
|
||||
if (absVelocityY > tossFlingVelocity) popupLayoutParams.y = (int) velocityY;
|
||||
checkPopupPositionBounds();
|
||||
windowManager.updateViewLayout(playerImpl.getRootView(), popupLayoutParams);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -908,7 +1039,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
gestureDetector.onTouchEvent(event);
|
||||
popupGestureDetector.onTouchEvent(event);
|
||||
if (playerImpl == null) return false;
|
||||
if (event.getPointerCount() == 2 && !isResizing) {
|
||||
if (DEBUG) Log.d(TAG, "onTouch() 2 finger pointer detected, enabling resizing.");
|
||||
@ -931,7 +1062,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
Log.d(TAG, "onTouch() ACTION_UP > v = [" + v + "], e1.getRaw = [" + event.getRawX() + ", " + event.getRawY() + "]");
|
||||
if (isMoving) {
|
||||
isMoving = false;
|
||||
onScrollEnd();
|
||||
onScrollEnd(event);
|
||||
}
|
||||
|
||||
if (isResizing) {
|
||||
@ -939,8 +1070,11 @@ public final class PopupVideoPlayer extends Service {
|
||||
animateView(playerImpl.getResizingIndicator(), false, 100, 0);
|
||||
playerImpl.changeState(playerImpl.getCurrentState());
|
||||
}
|
||||
|
||||
if (!isPopupClosing) {
|
||||
savePositionAndSize();
|
||||
}
|
||||
}
|
||||
|
||||
v.performClick();
|
||||
return true;
|
||||
@ -955,13 +1089,13 @@ public final class PopupVideoPlayer extends Service {
|
||||
final float diff = Math.abs(firstPointerX - secondPointerX);
|
||||
if (firstPointerX > secondPointerX) {
|
||||
// second pointer is the anchor (the leftmost pointer)
|
||||
windowLayoutParams.x = (int) (event.getRawX() - diff);
|
||||
popupLayoutParams.x = (int) (event.getRawX() - diff);
|
||||
} else {
|
||||
// first pointer is the anchor
|
||||
windowLayoutParams.x = (int) event.getRawX();
|
||||
popupLayoutParams.x = (int) event.getRawX();
|
||||
}
|
||||
|
||||
checkPositionBounds();
|
||||
checkPopupPositionBounds();
|
||||
updateScreenSize();
|
||||
|
||||
final int width = (int) Math.min(screenWidth, diff);
|
||||
@ -969,5 +1103,29 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private int distanceFromCloseButton(MotionEvent popupMotionEvent) {
|
||||
final int closeOverlayButtonX = closeOverlayButton.getLeft() + closeOverlayButton.getWidth() / 2;
|
||||
final int closeOverlayButtonY = closeOverlayButton.getTop() + closeOverlayButton.getHeight() / 2;
|
||||
|
||||
float fingerX = popupLayoutParams.x + popupMotionEvent.getX();
|
||||
float fingerY = popupLayoutParams.y + popupMotionEvent.getY();
|
||||
|
||||
return (int) Math.sqrt(Math.pow(closeOverlayButtonX - fingerX, 2) + Math.pow(closeOverlayButtonY - fingerY, 2));
|
||||
}
|
||||
|
||||
private float getClosingRadius() {
|
||||
final int buttonRadius = closeOverlayButton.getWidth() / 2;
|
||||
// 20% wider than the button itself
|
||||
return buttonRadius * 1.2f;
|
||||
}
|
||||
|
||||
private boolean isInsideClosingRadius(MotionEvent popupMotionEvent) {
|
||||
return distanceFromCloseButton(popupMotionEvent) <= getClosingRadius();
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.PopupMenu;
|
||||
@ -562,6 +563,12 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
if (player != null) {
|
||||
progressLiveSync.setClickable(!player.isLiveEdge());
|
||||
}
|
||||
|
||||
// this will make shure progressCurrentTime has the same width as progressEndTime
|
||||
final ViewGroup.LayoutParams endTimeParams = progressEndTime.getLayoutParams();
|
||||
final ViewGroup.LayoutParams currentTimeParams = progressCurrentTime.getLayoutParams();
|
||||
currentTimeParams.width = progressEndTime.getWidth();
|
||||
progressCurrentTime.setLayoutParams(currentTimeParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -251,10 +251,6 @@ public class PlayerHelper {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int getShutdownFlingVelocity(@NonNull final Context context) {
|
||||
return 6000;
|
||||
}
|
||||
|
||||
public static int getTossFlingVelocity(@NonNull final Context context) {
|
||||
return 2500;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import android.util.Log;
|
||||
|
||||
import org.reactivestreams.Subscriber;
|
||||
import org.reactivestreams.Subscription;
|
||||
import org.schabi.newpipe.BuildConfig;
|
||||
import org.schabi.newpipe.player.playqueue.events.AppendEvent;
|
||||
import org.schabi.newpipe.player.playqueue.events.ErrorEvent;
|
||||
import org.schabi.newpipe.player.playqueue.events.InitEvent;
|
||||
@ -41,7 +42,7 @@ import io.reactivex.subjects.BehaviorSubject;
|
||||
public abstract class PlayQueue implements Serializable {
|
||||
private final String TAG = "PlayQueue@" + Integer.toHexString(hashCode());
|
||||
|
||||
public static final boolean DEBUG = true;
|
||||
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
||||
|
||||
private ArrayList<PlayQueueItem> backup;
|
||||
private ArrayList<PlayQueueItem> streams;
|
||||
|
@ -15,7 +15,8 @@ public enum UserAction {
|
||||
REQUESTED_CHANNEL("requested channel"),
|
||||
REQUESTED_PLAYLIST("requested playlist"),
|
||||
REQUESTED_KIOSK("requested kiosk"),
|
||||
DELETE_FROM_HISTORY("delete from history");
|
||||
DELETE_FROM_HISTORY("delete from history"),
|
||||
PLAY_STREAM("Play stream");
|
||||
|
||||
|
||||
private final String message;
|
||||
|
@ -0,0 +1,41 @@
|
||||
package org.schabi.newpipe.settings;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
|
||||
public class AddTabsDialog {
|
||||
private final AlertDialog dialog;
|
||||
|
||||
public AddTabsDialog(@NonNull final Context context,
|
||||
@NonNull final String title,
|
||||
@NonNull final String[] commands,
|
||||
@NonNull final DialogInterface.OnClickListener actions) {
|
||||
|
||||
final View bannerView = View.inflate(context, R.layout.dialog_title, null);
|
||||
bannerView.setSelected(true);
|
||||
|
||||
TextView titleView = bannerView.findViewById(R.id.itemTitleView);
|
||||
titleView.setText(title);
|
||||
|
||||
TextView detailsView = bannerView.findViewById(R.id.itemAdditionalDetails);
|
||||
detailsView.setVisibility(View.GONE);
|
||||
|
||||
dialog = new AlertDialog.Builder(context)
|
||||
.setCustomTitle(bannerView)
|
||||
.setItems(commands, actions)
|
||||
.create();
|
||||
}
|
||||
|
||||
public void show() {
|
||||
dialog.show();
|
||||
}
|
||||
}
|
@ -0,0 +1,291 @@
|
||||
package org.schabi.newpipe.settings;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.CardView;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
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.util.ThemeHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ChoseTabsFragment extends Fragment {
|
||||
|
||||
public ChoseTabsFragment.SelectedTabsAdapter selectedTabsAdapter;
|
||||
|
||||
RecyclerView selectedTabsView;
|
||||
|
||||
List<String> selectedTabs = new ArrayList<>();
|
||||
private String saveString;
|
||||
public String[] availableTabs = new String[7];
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
((AppCompatActivity)getContext()).getSupportActionBar().setTitle(R.string.main_page_content);
|
||||
return inflater.inflate(R.layout.fragment_chose_tabs, container, false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View rootView, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(rootView, savedInstanceState);
|
||||
|
||||
tabNames();
|
||||
initUsedTabs();
|
||||
initButton(rootView);
|
||||
|
||||
selectedTabsView = rootView.findViewById(R.id.usedTabs);
|
||||
selectedTabsView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
selectedTabsAdapter = new ChoseTabsFragment.SelectedTabsAdapter();
|
||||
|
||||
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
|
||||
itemTouchHelper.attachToRecyclerView(selectedTabsView);
|
||||
selectedTabsAdapter.setOnItemSelectedListener(itemTouchHelper);
|
||||
|
||||
selectedTabsView.setAdapter(selectedTabsAdapter);
|
||||
}
|
||||
|
||||
private void saveChanges() {
|
||||
StringBuilder save = new StringBuilder();
|
||||
if(selectedTabs.size()==0) {
|
||||
save = new StringBuilder("0");
|
||||
} else {
|
||||
for(String s: selectedTabs) {
|
||||
save.append(s);
|
||||
save.append("\n");
|
||||
}
|
||||
}
|
||||
saveString = save.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
saveChanges();
|
||||
SharedPreferences sharedPreferences = android.preference.PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putString("saveUsedTabs", saveString);
|
||||
editor.commit();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
private void initUsedTabs() {
|
||||
String save = android.preference.PreferenceManager.getDefaultSharedPreferences(getContext()).getString("saveUsedTabs", "1\tTrending\t0\n2\n4\n");
|
||||
String tabs[] = save.trim().split("\n");
|
||||
selectedTabs.addAll(Arrays.asList(tabs));
|
||||
}
|
||||
|
||||
private void tabNames() {
|
||||
availableTabs[0] = getString(R.string.blank_page_summary);
|
||||
availableTabs[1] = getString(R.string.kiosk_page_summary);
|
||||
availableTabs[2] = getString(R.string.subscription_page_summary);
|
||||
availableTabs[3] = getString(R.string.feed_page_summary);
|
||||
availableTabs[4] = getString(R.string.tab_bookmarks);
|
||||
availableTabs[5] = getString(R.string.title_activity_history);
|
||||
availableTabs[6] = getString(R.string.channel_page_summary);
|
||||
}
|
||||
|
||||
private void initButton(View rootView) {
|
||||
FloatingActionButton fab = rootView.findViewById(R.id.floatingActionButton);
|
||||
fab.setImageResource(ThemeHelper.getIconByAttr(R.attr.ic_add, getContext()));
|
||||
fab.setOnClickListener(v -> {
|
||||
Dialog.OnClickListener onClickListener = (dialog, which) -> addTab(which);
|
||||
|
||||
new AddTabsDialog(getContext(),
|
||||
getString(R.string.tab_chose),
|
||||
availableTabs,
|
||||
onClickListener)
|
||||
.show();
|
||||
});
|
||||
|
||||
TypedValue typedValue = new TypedValue();
|
||||
getActivity().getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
|
||||
int color = typedValue.data;
|
||||
fab.setBackgroundTintList(ColorStateList.valueOf(color));
|
||||
}
|
||||
|
||||
|
||||
private void addTab(int position) {
|
||||
if(position==6) {
|
||||
SelectChannelFragment selectChannelFragment = new SelectChannelFragment();
|
||||
selectChannelFragment.setOnSelectedLisener((String url, String name, int service) -> {
|
||||
selectedTabs.add(position+"\t"+url+"\t"+name+"\t"+service);
|
||||
selectedTabsAdapter.notifyDataSetChanged();
|
||||
saveChanges();
|
||||
});
|
||||
selectChannelFragment.show(getFragmentManager(), "select_channel");
|
||||
} else if(position==1) {
|
||||
SelectKioskFragment selectKioskFragment = new SelectKioskFragment();
|
||||
selectKioskFragment.setOnSelectedLisener((String kioskId, int service_id) -> {
|
||||
selectedTabs.add(position+"\t"+kioskId+"\t"+service_id);
|
||||
selectedTabsAdapter.notifyDataSetChanged();
|
||||
saveChanges();
|
||||
});
|
||||
selectKioskFragment.show(getFragmentManager(), "select_kiosk");
|
||||
} else {
|
||||
selectedTabs.add(String.valueOf(position));
|
||||
selectedTabsAdapter.notifyDataSetChanged();
|
||||
saveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public class SelectedTabsAdapter extends RecyclerView.Adapter<ChoseTabsFragment.SelectedTabsAdapter.TabViewHolder>{
|
||||
private ItemTouchHelper itemTouchHelper;
|
||||
|
||||
public void setOnItemSelectedListener(ItemTouchHelper mItemTouchHelper) {
|
||||
itemTouchHelper = mItemTouchHelper;
|
||||
}
|
||||
|
||||
public void swapItems(int fromPosition, int toPosition) {
|
||||
String temp = selectedTabs.get(fromPosition);
|
||||
selectedTabs.set(fromPosition, selectedTabs.get(toPosition));
|
||||
selectedTabs.set(toPosition, temp);
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
saveChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChoseTabsFragment.SelectedTabsAdapter.TabViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
|
||||
LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
View view = inflater.inflate(R.layout.viewholder_chose_tabs, parent, false);
|
||||
return new ChoseTabsFragment.SelectedTabsAdapter.TabViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ChoseTabsFragment.SelectedTabsAdapter.TabViewHolder holder, int position) {
|
||||
holder.bind(position, holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return selectedTabs.size();
|
||||
}
|
||||
|
||||
class TabViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
TextView text;
|
||||
View view;
|
||||
CardView cardView;
|
||||
ImageView handle;
|
||||
|
||||
public TabViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
text = itemView.findViewById(R.id.tabName);
|
||||
cardView = itemView.findViewById(R.id.layoutCard);
|
||||
handle = itemView.findViewById(R.id.handle);
|
||||
view = itemView;
|
||||
}
|
||||
|
||||
void bind(int position, TabViewHolder holder) {
|
||||
handle.setImageResource(ThemeHelper.getIconByAttr(R.attr.drag_handle, getContext()));
|
||||
handle.setOnTouchListener(getOnTouchListener(holder));
|
||||
|
||||
view.setOnLongClickListener(getOnLongClickListener(holder));
|
||||
|
||||
if(selectedTabs.get(position).startsWith("6\t")) {
|
||||
String channelInfo[] = selectedTabs.get(position).split("\t");
|
||||
String channelName = "";
|
||||
if (channelInfo.length == 4) channelName = channelInfo[2];
|
||||
String textToSet = availableTabs[6] + ": " + channelName;
|
||||
text.setText(textToSet);
|
||||
} else if(selectedTabs.get(position).startsWith("1\t")) {
|
||||
String kioskInfo[] = selectedTabs.get(position).split("\t");
|
||||
String kioskName = "";
|
||||
if (kioskInfo.length == 3) kioskName = kioskInfo[1];
|
||||
String textToSet = availableTabs[1] + ": " + kioskName;
|
||||
text.setText(textToSet);
|
||||
} else {
|
||||
text.setText(availableTabs[Integer.parseInt(selectedTabs.get(position))]);
|
||||
}
|
||||
}
|
||||
|
||||
private View.OnTouchListener getOnTouchListener(final RecyclerView.ViewHolder item) {
|
||||
return (view, motionEvent) -> {
|
||||
view.performClick();
|
||||
if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||
if(itemTouchHelper != null) itemTouchHelper.startDrag(item);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private View.OnLongClickListener getOnLongClickListener(TabViewHolder holder) {
|
||||
return (view) -> {
|
||||
if(itemTouchHelper != null) itemTouchHelper.startSwipe(holder);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
|
||||
return new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
|
||||
ItemTouchHelper.START | ItemTouchHelper.END) {
|
||||
@Override
|
||||
public int interpolateOutOfBoundsScroll(RecyclerView recyclerView, int viewSize,
|
||||
int viewSizeOutOfBounds, int totalSize,
|
||||
long msSinceStartScroll) {
|
||||
final int standardSpeed = super.interpolateOutOfBoundsScroll(recyclerView, viewSize,
|
||||
viewSizeOutOfBounds, totalSize, msSinceStartScroll);
|
||||
final int minimumAbsVelocity = Math.max(12,
|
||||
Math.abs(standardSpeed));
|
||||
return minimumAbsVelocity * (int) Math.signum(viewSizeOutOfBounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source,
|
||||
RecyclerView.ViewHolder target) {
|
||||
if (source.getItemViewType() != target.getItemViewType() ||
|
||||
selectedTabsAdapter == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int sourceIndex = source.getAdapterPosition();
|
||||
final int targetIndex = target.getAdapterPosition();
|
||||
selectedTabsAdapter.swapItems(sourceIndex, targetIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLongPressDragEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemViewSwipeEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
|
||||
int position = viewHolder.getAdapterPosition();
|
||||
selectedTabs.remove(position);
|
||||
selectedTabsAdapter.notifyItemRemoved(position);
|
||||
saveChanges();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.preference.ListPreference;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.util.Log;
|
||||
@ -20,15 +21,12 @@ import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
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.FilePickerActivityHelper;
|
||||
import org.schabi.newpipe.util.KioskTranslator;
|
||||
import org.schabi.newpipe.util.ZipHelper;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@ -42,11 +40,8 @@ import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
public class ContentSettingsFragment extends BasePreferenceFragment {
|
||||
|
||||
private static final int REQUEST_IMPORT_PATH = 8945;
|
||||
@ -98,68 +93,6 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
||||
|
||||
addPreferencesFromResource(R.xml.content_settings);
|
||||
|
||||
final ListPreference mainPageContentPref = (ListPreference) findPreference(getString(R.string.main_page_content_key));
|
||||
mainPageContentPref.setOnPreferenceChangeListener((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((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().getName();
|
||||
} catch (ExtractionException e) {
|
||||
onError(e);
|
||||
}
|
||||
String kioskName = KioskTranslator.getTranslatedKioskName(kioskId,
|
||||
getContext());
|
||||
|
||||
String summary =
|
||||
String.format(getString(R.string.service_kiosk_string),
|
||||
serviceName,
|
||||
kioskName);
|
||||
|
||||
mainPageContentPref.setSummary(summary);
|
||||
});
|
||||
selectKioskFragment.setOnCancelListener(() -> {
|
||||
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((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(() -> {
|
||||
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;
|
||||
});
|
||||
|
||||
Preference importDataPreference = findPreference(getString(R.string.import_data));
|
||||
importDataPreference.setOnPreferenceClickListener((Preference p) -> {
|
||||
Intent i = new Intent(getActivity(), FilePickerActivityHelper.class)
|
||||
@ -349,66 +282,6 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
||||
}
|
||||
}
|
||||
|
||||
@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_kiosk_string),
|
||||
service.getServiceInfo().getName(),
|
||||
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
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
@ -71,7 +71,7 @@ public class NewPipeSettings {
|
||||
}
|
||||
|
||||
public static File getVideoDownloadFolder(Context context) {
|
||||
return getFolder(context, R.string.download_path_key, Environment.DIRECTORY_MOVIES);
|
||||
return getDir(context, R.string.download_path_key, Environment.DIRECTORY_MOVIES);
|
||||
}
|
||||
|
||||
public static String getVideoDownloadPath(Context context) {
|
||||
@ -81,7 +81,7 @@ public class NewPipeSettings {
|
||||
}
|
||||
|
||||
public static File getAudioDownloadFolder(Context context) {
|
||||
return getFolder(context, R.string.download_path_audio_key, Environment.DIRECTORY_MUSIC);
|
||||
return getDir(context, R.string.download_path_audio_key, Environment.DIRECTORY_MUSIC);
|
||||
}
|
||||
|
||||
public static String getAudioDownloadPath(Context context) {
|
||||
@ -90,21 +90,37 @@ public class NewPipeSettings {
|
||||
return prefs.getString(key, Environment.DIRECTORY_MUSIC);
|
||||
}
|
||||
|
||||
private static File getFolder(Context context, int keyID, String defaultDirectoryName) {
|
||||
private static File getDir(Context context, int keyID, String defaultDirectoryName) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
final String key = context.getString(keyID);
|
||||
String downloadPath = prefs.getString(key, null);
|
||||
if ((downloadPath != null) && (!downloadPath.isEmpty())) return new File(downloadPath.trim());
|
||||
|
||||
final File folder = getFolder(defaultDirectoryName);
|
||||
final File dir = getDir(defaultDirectoryName);
|
||||
SharedPreferences.Editor spEditor = prefs.edit();
|
||||
spEditor.putString(key, new File(folder, "NewPipe").getAbsolutePath());
|
||||
spEditor.putString(key, getNewPipeChildFolderPathForDir(dir));
|
||||
spEditor.apply();
|
||||
return folder;
|
||||
return dir;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static File getFolder(String defaultDirectoryName) {
|
||||
private static File getDir(String defaultDirectoryName) {
|
||||
return new File(Environment.getExternalStorageDirectory(), defaultDirectoryName);
|
||||
}
|
||||
|
||||
public static void resetDownloadFolders(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
resetDownloadFolder(prefs, context.getString(R.string.download_path_audio_key), Environment.DIRECTORY_MUSIC);
|
||||
resetDownloadFolder(prefs, context.getString(R.string.download_path_key), Environment.DIRECTORY_MOVIES);
|
||||
}
|
||||
|
||||
private static void resetDownloadFolder(SharedPreferences prefs, String key, String defaultDirectoryName) {
|
||||
SharedPreferences.Editor spEditor = prefs.edit();
|
||||
spEditor.putString(key, getNewPipeChildFolderPathForDir(getDir(defaultDirectoryName)));
|
||||
spEditor.apply();
|
||||
}
|
||||
|
||||
private static String getNewPipeChildFolderPathForDir(File dir) {
|
||||
return new File(dir, "NewPipe").getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ public final class ExtractorHelper {
|
||||
return Single.fromCallable(() ->
|
||||
SearchInfo.getInfo(NewPipe.getService(serviceId),
|
||||
NewPipe.getService(serviceId)
|
||||
.getSearchQIHFactory()
|
||||
.getSearchQHFactory()
|
||||
.fromQuery(searchString, contentFilter, sortFilter),
|
||||
contentCountry));
|
||||
}
|
||||
@ -88,7 +88,7 @@ public final class ExtractorHelper {
|
||||
return Single.fromCallable(() ->
|
||||
SearchInfo.getMoreItems(NewPipe.getService(serviceId),
|
||||
NewPipe.getService(serviceId)
|
||||
.getSearchQIHFactory()
|
||||
.getSearchQHFactory()
|
||||
.fromQuery(searchString, contentFilter, sortFilter),
|
||||
contentCountry,
|
||||
pageUrl));
|
||||
|
@ -35,4 +35,17 @@ public class KioskTranslator {
|
||||
return kioskId;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getKioskIcons(String kioskId, Context c) {
|
||||
switch(kioskId) {
|
||||
case "Trending":
|
||||
return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_hot);
|
||||
case "Top 50":
|
||||
return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_hot);
|
||||
case "New & hot":
|
||||
return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_hot);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,17 +31,17 @@ import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||
import org.schabi.newpipe.extractor.stream.Stream;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
||||
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandler;
|
||||
import org.schabi.newpipe.fragments.MainFragment;
|
||||
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
|
||||
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
|
||||
import org.schabi.newpipe.local.bookmark.BookmarkFragment;
|
||||
import org.schabi.newpipe.local.feed.FeedFragment;
|
||||
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
|
||||
import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment;
|
||||
import org.schabi.newpipe.fragments.list.search.SearchFragment;
|
||||
import org.schabi.newpipe.local.history.StatisticsPlaylistFragment;
|
||||
import org.schabi.newpipe.local.playlist.LocalPlaylistFragment;
|
||||
import org.schabi.newpipe.local.subscription.SubscriptionFragment;
|
||||
import org.schabi.newpipe.local.subscription.SubscriptionsImportFragment;
|
||||
import org.schabi.newpipe.player.BackgroundPlayer;
|
||||
import org.schabi.newpipe.player.BackgroundPlayerActivity;
|
||||
@ -349,6 +349,20 @@ public class NavigationHelper {
|
||||
.commit();
|
||||
}
|
||||
|
||||
public static void openBookmarksFragment(FragmentManager fragmentManager) {
|
||||
defaultTransaction(fragmentManager)
|
||||
.replace(R.id.fragment_holder, new BookmarkFragment())
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public static void openSubscriptionFragment(FragmentManager fragmentManager) {
|
||||
defaultTransaction(fragmentManager)
|
||||
.replace(R.id.fragment_holder, new SubscriptionFragment())
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public static void openKioskFragment(FragmentManager fragmentManager, int serviceId, String kioskId) throws ExtractionException {
|
||||
defaultTransaction(fragmentManager)
|
||||
.replace(R.id.fragment_holder, KioskFragment.getInstance(serviceId, kioskId))
|
||||
|
@ -1,10 +1,17 @@
|
||||
package us.shandian.giga.get;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.schabi.newpipe.download.ExtSDDownloadFailedActivity;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
@ -23,7 +30,9 @@ public class DownloadManagerImpl implements DownloadManager {
|
||||
private static final String TAG = DownloadManagerImpl.class.getSimpleName();
|
||||
private final DownloadDataSource mDownloadDataSource;
|
||||
|
||||
private final ArrayList<DownloadMission> mMissions = new ArrayList<DownloadMission>();
|
||||
private final ArrayList<DownloadMission> mMissions = new ArrayList<>();
|
||||
@NonNull
|
||||
private final Context context;
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
@ -33,6 +42,13 @@ public class DownloadManagerImpl implements DownloadManager {
|
||||
*/
|
||||
public DownloadManagerImpl(Collection<String> searchLocations, DownloadDataSource downloadDataSource) {
|
||||
mDownloadDataSource = downloadDataSource;
|
||||
this.context = null;
|
||||
loadMissions(searchLocations);
|
||||
}
|
||||
|
||||
public DownloadManagerImpl(Collection<String> searchLocations, DownloadDataSource downloadDataSource, Context context) {
|
||||
mDownloadDataSource = downloadDataSource;
|
||||
this.context = context;
|
||||
loadMissions(searchLocations);
|
||||
}
|
||||
|
||||
@ -277,10 +293,12 @@ public class DownloadManagerImpl implements DownloadManager {
|
||||
}
|
||||
|
||||
private class Initializer extends Thread {
|
||||
private DownloadMission mission;
|
||||
private final DownloadMission mission;
|
||||
private final Handler handler;
|
||||
|
||||
public Initializer(DownloadMission mission) {
|
||||
this.mission = mission;
|
||||
this.handler = new Handler();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -335,6 +353,13 @@ public class DownloadManagerImpl implements DownloadManager {
|
||||
af.close();
|
||||
|
||||
mission.start();
|
||||
} catch (IOException ie) {
|
||||
if(context == null) throw new RuntimeException(ie);
|
||||
|
||||
if(ie.getMessage().contains("Permission denied")) {
|
||||
handler.post(() ->
|
||||
context.startActivity(new Intent(context, ExtSDDownloadFailedActivity.class)));
|
||||
} else throw new RuntimeException(ie);
|
||||
} catch (Exception e) {
|
||||
// TODO Notify
|
||||
throw new RuntimeException(e);
|
||||
|
@ -81,7 +81,7 @@ public class DownloadManagerService extends Service {
|
||||
ArrayList<String> paths = new ArrayList<>(2);
|
||||
paths.add(NewPipeSettings.getVideoDownloadPath(this));
|
||||
paths.add(NewPipeSettings.getAudioDownloadPath(this));
|
||||
mManager = new DownloadManagerImpl(paths, mDataSource);
|
||||
mManager = new DownloadManagerImpl(paths, mDataSource, this);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "mManager == null");
|
||||
Log.d(TAG, "Download directory: " + paths);
|
||||
|
BIN
app/src/main/res/drawable-hdpi/ic_add.png
Normal file
After Width: | Height: | Size: 223 B |
BIN
app/src/main/res/drawable-hdpi/ic_arrow_down_white.png
Normal file
After Width: | Height: | Size: 267 B |
BIN
app/src/main/res/drawable-hdpi/ic_arrow_up_white.png
Normal file
After Width: | Height: | Size: 261 B |
BIN
app/src/main/res/drawable-hdpi/ic_remove.png
Normal file
After Width: | Height: | Size: 363 B |
BIN
app/src/main/res/drawable-mdpi/ic_add.png
Normal file
After Width: | Height: | Size: 152 B |
BIN
app/src/main/res/drawable-mdpi/ic_arrow_down_white.png
Normal file
After Width: | Height: | Size: 210 B |
BIN
app/src/main/res/drawable-mdpi/ic_arrow_up_white.png
Normal file
After Width: | Height: | Size: 201 B |
BIN
app/src/main/res/drawable-mdpi/ic_remove.png
Normal file
After Width: | Height: | Size: 230 B |
BIN
app/src/main/res/drawable-xhdpi/ic_add.png
Normal file
After Width: | Height: | Size: 197 B |
BIN
app/src/main/res/drawable-xhdpi/ic_arrow_down_white.png
Normal file
After Width: | Height: | Size: 425 B |
BIN
app/src/main/res/drawable-xhdpi/ic_arrow_up_white.png
Normal file
After Width: | Height: | Size: 415 B |
BIN
app/src/main/res/drawable-xhdpi/ic_remove.png
Normal file
After Width: | Height: | Size: 380 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_add.png
Normal file
After Width: | Height: | Size: 351 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_arrow_down_white.png
Normal file
After Width: | Height: | Size: 470 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_arrow_up_white.png
Normal file
After Width: | Height: | Size: 458 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_remove.png
Normal file
After Width: | Height: | Size: 611 B |
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="#64000000" />
|
||||
</shape>
|
9
app/src/main/res/drawable/ic_add_black_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_add_white_24dp.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_brightness_high_white_72dp.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20,8.69L20,4h-4.69L12,0.69 8.69,4L4,4v4.69L0.69,12 4,15.31L4,20h4.69L12,23.31 15.31,20L20,20v-4.69L23.31,12 20,8.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_brightness_low_white_72dp.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20,15.31L23.31,12 20,8.69V4h-4.69L12,0.69 8.69,4H4v4.69L0.69,12 4,15.31V20h4.69L12,23.31 15.31,20H20v-4.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6z" />
|
||||
</vector>
|
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20,15.31L23.31,12 20,8.69V4h-4.69L12,0.69 8.69,4H4v4.69L0.69,12 4,15.31V20h4.69L12,23.31 15.31,20H20v-4.69zM12,18V6c3.31,0 6,2.69 6,6s-2.69,6 -6,6z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_volume_down_white_72dp.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M18.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM5,9v6h4l5,5V4L9,9H5z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_volume_mute_white_72dp.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M7,9v6h4l5,5V4l-5,5H7z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_volume_off_white_72dp.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v2.21l2.45,2.45c0.03,-0.2 0.05,-0.41 0.05,-0.63zM19,12c0,0.94 -0.2,1.82 -0.54,2.64l1.51,1.51C20.63,14.91 21,13.5 21,12c0,-4.28 -2.99,-7.86 -7,-8.77v2.06c2.89,0.86 5,3.54 5,6.71zM4.27,3L3,4.27 7.73,9L3,9v6h4l5,5v-6.73l4.25,4.25c-0.67,0.52 -1.42,0.93 -2.25,1.18v2.06c1.38,-0.31 2.63,-0.95 3.69,-1.81L19.73,21 21,19.73l-9,-9L4.27,3zM12,4L9.91,6.09 12,8.18L12,4z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_volume_up_white_72dp.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z" />
|
||||
</vector>
|
12
app/src/main/res/drawable/progress_circular_white.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fromDegrees="-90"
|
||||
android:toDegrees="-90">
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:innerRadiusRatio="2.25"
|
||||
android:shape="ring"
|
||||
android:thicknessRatio="17.75"
|
||||
android:useLevel="true">
|
||||
<solid android:color="@android:color/white" />
|
||||
</shape>
|
||||
</rotate>
|
69
app/src/main/res/layout-v21/drawer_header.xml
Normal file
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="150dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<Button
|
||||
android:id="@+id/drawer_header_action_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:attr/selectableItemBackground" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/background_header" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/drawer_header_np_nude_view"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_marginLeft="30dp"
|
||||
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:src="@drawable/np_logo_nude_shadow" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawer_header_np_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_alignBottom="@id/drawer_header_np_nude_view"
|
||||
android:layout_alignTop="@id/drawer_header_np_nude_view"
|
||||
android:layout_toEndOf="@id/drawer_header_np_nude_view"
|
||||
android:layout_toRightOf="@id/drawer_header_np_nude_view"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="30dp"
|
||||
android:textStyle="bold|italic" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawer_header_service_view"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_alignLeft="@id/drawer_header_np_text_view"
|
||||
android:layout_alignStart="@id/drawer_header_np_text_view"
|
||||
android:layout_below="@id/drawer_header_np_text_view"
|
||||
android:text="YouTube"
|
||||
android:textSize="18dp"
|
||||
android:textStyle="italic" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/drawer_arrow"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="35dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:paddingBottom="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingRight="20dp"
|
||||
android:src="@drawable/ic_arrow_down_white" />
|
||||
|
||||
</RelativeLayout>
|
@ -4,7 +4,8 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
|
||||
<FrameLayout
|
||||
|
@ -471,9 +471,10 @@
|
||||
android:id="@+id/controlAnimationView"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:src="@drawable/ic_action_av_fast_rewind"
|
||||
android:background="@drawable/background_oval_black_transparent"
|
||||
android:visibility="gone"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:src="@drawable/ic_action_av_fast_rewind"
|
||||
tools:visibility="visible" />
|
||||
</LinearLayout>
|
||||
|
||||
@ -503,43 +504,57 @@
|
||||
android:layout_toRightOf="@+id/loading_panel"
|
||||
tools:ignore="RtlHardcoded">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/volumeTextView"
|
||||
<RelativeLayout
|
||||
android:id="@+id/volumeRelativeLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:background="#64000000"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingLeft="30dp"
|
||||
android:paddingRight="30dp"
|
||||
android:paddingTop="10dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="35sp"
|
||||
android:background="@drawable/background_oval_black_transparent"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="Volume 0"
|
||||
tools:visibility="visible" />
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/brightnessTextView"
|
||||
<ProgressBar
|
||||
android:id="@+id/volumeProgressBar"
|
||||
style="?android:progressBarStyleHorizontal"
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="128dp"
|
||||
android:indeterminate="false"
|
||||
android:progressDrawable="@drawable/progress_circular_white" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/volumeImageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginRight="20dp"
|
||||
android:background="#64000000"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingLeft="30dp"
|
||||
android:paddingRight="30dp"
|
||||
android:paddingTop="10dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="35sp"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:src="@drawable/ic_volume_up_white_72dp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/brightnessRelativeLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:background="@drawable/background_oval_black_transparent"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="Brightness 0"
|
||||
tools:visibility="visible" />
|
||||
tools:visibility="visible">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/brightnessProgressBar"
|
||||
style="?android:progressBarStyleHorizontal"
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="128dp"
|
||||
android:indeterminate="false"
|
||||
android:progressDrawable="@drawable/progress_circular_white" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/brightnessImageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:src="@drawable/ic_brightness_high_white_72dp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/currentDisplaySeek"
|
||||
|
69
app/src/main/res/layout/drawer_header.xml
Normal file
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="150dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<Button
|
||||
android:id="@+id/drawer_header_action_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:attr/selectableItemBackground"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:src="@drawable/background_header"
|
||||
android:scaleType="centerCrop"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/drawer_header_np_nude_view"
|
||||
android:layout_marginLeft="30dp"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginTop="20dp"
|
||||
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:src="@drawable/np_logo_nude_shadow"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawer_header_np_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:text="@string/app_name"
|
||||
android:layout_toRightOf="@id/drawer_header_np_nude_view"
|
||||
android:layout_toEndOf="@id/drawer_header_np_nude_view"
|
||||
android:layout_alignTop="@id/drawer_header_np_nude_view"
|
||||
android:layout_alignBottom="@id/drawer_header_np_nude_view"
|
||||
android:gravity="center"
|
||||
android:textSize="30dp"
|
||||
android:textStyle="bold|italic"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawer_header_service_view"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:text="YouTube"
|
||||
android:layout_below="@id/drawer_header_np_text_view"
|
||||
android:layout_alignLeft="@id/drawer_header_np_text_view"
|
||||
android:layout_alignStart="@id/drawer_header_np_text_view"
|
||||
android:textSize="18dp"
|
||||
android:textStyle="italic"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/drawer_arrow"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="35dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:paddingBottom="20dp"
|
||||
android:paddingRight="20dp"
|
||||
android:src="@drawable/ic_arrow_down_white"
|
||||
android:paddingEnd="20dp" />
|
||||
|
||||
</RelativeLayout>
|
@ -1,81 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout android:id="@+id/navigation_layout"
|
||||
<android.support.design.widget.NavigationView android:id="@+id/navigation_layout"
|
||||
android:orientation="vertical"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:background="?attr/android:windowBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/drawer_header"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_alignLeft="@id/navigation"
|
||||
android:layout_alignRight="@id/navigation"
|
||||
android:layout_alignStart="@id/navigation"
|
||||
android:layout_alignEnd="@id/navigation"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<Button
|
||||
android:id="@+id/drawer_header_action_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:attr/selectableItemBackground"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:src="@drawable/background_header"
|
||||
android:scaleType="centerCrop"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/drawer_header_np_nude_view"
|
||||
android:layout_marginLeft="30dp"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginTop="20dp"
|
||||
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:src="@drawable/np_logo_nude_shadow"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawer_header_np_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:text="@string/app_name"
|
||||
android:layout_toRightOf="@id/drawer_header_np_nude_view"
|
||||
android:layout_toEndOf="@id/drawer_header_np_nude_view"
|
||||
android:layout_alignTop="@id/drawer_header_np_nude_view"
|
||||
android:layout_alignBottom="@id/drawer_header_np_nude_view"
|
||||
android:gravity="center"
|
||||
android:textSize="30dp"
|
||||
android:textStyle="bold|italic"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawer_header_service_view"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:text="YouTube"
|
||||
android:layout_below="@id/drawer_header_np_text_view"
|
||||
android:layout_alignLeft="@id/drawer_header_np_text_view"
|
||||
android:layout_alignStart="@id/drawer_header_np_text_view"
|
||||
android:textSize="18dp"
|
||||
android:textStyle="italic"/>
|
||||
|
||||
</RelativeLayout>
|
||||
android:focusable="true"
|
||||
>
|
||||
|
||||
<android.support.design.widget.NavigationView
|
||||
android:id="@+id/navigation"
|
||||
android:layout_below="@id/drawer_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:elevation="0dp"/>
|
||||
app:elevation="0dp"
|
||||
android:background="?attr/android:windowBackground"
|
||||
app:headerLayout="@layout/drawer_header"/>
|
||||
<!-- app:menu="@menu/drawer_items" -->
|
||||
|
||||
<LinearLayout
|
||||
@ -89,29 +30,6 @@
|
||||
android:layout_alignEnd="@id/navigation"
|
||||
|
||||
android:layout_alignParentBottom="true">
|
||||
<ImageButton
|
||||
android:id="@+id/drawer_settings"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="?attr/settings"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/drawer_downloads"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="?attr/download" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/drawer_history"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="?attr/history"/>
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
</android.support.design.widget.NavigationView>
|
32
app/src/main/res/layout/fragment_chose_tabs.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/relLay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/usedTabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="0dp"
|
||||
android:paddingBottom="0dp"
|
||||
android:paddingTop="0dp" >
|
||||
|
||||
</android.support.v7.widget.RecyclerView>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/floatingActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:clickable="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="16dp"
|
||||
android:focusable="true" />
|
||||
|
||||
</RelativeLayout>
|
@ -9,7 +9,6 @@
|
||||
tools:layout_height="84dp"
|
||||
tools:layout_width="@dimen/popup_minimum_width">
|
||||
|
||||
|
||||
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
||||
android:id="@+id/aspectRatioLayout"
|
||||
android:layout_width="match_parent"
|
||||
@ -290,4 +289,11 @@
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:visibility="gone"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/closingOverlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#AAFF0000"
|
||||
android:visibility="gone"/>
|
||||
</FrameLayout>
|
18
app/src/main/res/layout/player_popup_close_overlay.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/closeButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:src="@drawable/ic_close_white_24dp"
|
||||
app:backgroundTint="@color/light_youtube_primary_color"
|
||||
app:borderWidth="0dp"
|
||||
app:fabSize="normal"/>
|
||||
</FrameLayout>
|
40
app/src/main/res/layout/viewholder_chose_tabs.xml
Normal file
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/layoutCard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="3dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingTop="4dp"
|
||||
app:cardCornerRadius="5dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/handle"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginRight="10dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tabName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:paddingBottom="9dp"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingRight="15dp"
|
||||
android:paddingStart="3dp"
|
||||
android:paddingTop="9dp"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</android.support.v7.widget.CardView>
|
@ -2,13 +2,11 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<group
|
||||
android:id="@+id/menu_services_group">
|
||||
<item
|
||||
android:id="@+id/menu_service_youtube"
|
||||
android:icon="@drawable/place_holder_youtube"
|
||||
android:title="@string/youtube"/>
|
||||
<item
|
||||
android:id="@+id/menu_service_soundcloud"
|
||||
android:icon="@drawable/place_holder_circle"
|
||||
android:title="@string/soundcloud"/>
|
||||
</group>
|
||||
<group
|
||||
android:id="@+id/menu_tabs_group">
|
||||
</group>
|
||||
<group
|
||||
android:id="@+id/menu_options_about_group">
|
||||
</group>
|
||||
</menu>
|
@ -19,9 +19,4 @@
|
||||
android:orderInCategory="990"
|
||||
android:title="@string/settings"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/action_about"
|
||||
android:orderInCategory="1000"
|
||||
android:title="@string/action_about"/>
|
||||
</menu>
|
34
app/src/main/res/values-v21/styles_services.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- YouTube -->
|
||||
<style name="LightTheme.YouTube" parent="LightTheme.Switchable">
|
||||
<item name="colorPrimaryDark">@color/light_youtube_statusbar_color</item>
|
||||
</style>
|
||||
|
||||
<style name="DarkTheme.YouTube" parent="DarkTheme.Switchable">
|
||||
<item name="colorPrimaryDark">@color/dark_youtube_statusbar_color</item>
|
||||
</style>
|
||||
|
||||
<style name="BlackTheme.YouTube" parent="BlackTheme.Switchable">
|
||||
<item name="colorPrimaryDark">@color/dark_youtube_statusbar_color</item>
|
||||
</style>
|
||||
<!-- SoundCloud -->
|
||||
<style name="LightTheme.SoundCloud" parent="LightTheme.Switchable">
|
||||
<item name="colorPrimary">@color/light_soundcloud_primary_color</item>
|
||||
<item name="colorPrimaryDark">@color/light_soundcloud_statusbar_color</item>
|
||||
<item name="colorAccent">@color/light_soundcloud_accent_color</item>
|
||||
</style>
|
||||
|
||||
<style name="DarkTheme.SoundCloud" parent="DarkTheme.Switchable">
|
||||
<item name="colorPrimary">@color/dark_soundcloud_primary_color</item>
|
||||
<item name="colorPrimaryDark">@color/dark_soundcloud_statusbar_color</item>
|
||||
<item name="colorAccent">@color/dark_soundcloud_accent_color</item>
|
||||
</style>
|
||||
|
||||
<style name="BlackTheme.SoundCloud" parent="BlackTheme.Switchable">
|
||||
<item name="colorPrimary">@color/dark_soundcloud_primary_color</item>
|
||||
<item name="colorPrimaryDark">@color/dark_soundcloud_statusbar_color</item>
|
||||
<item name="colorAccent">@color/dark_soundcloud_accent_color</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -35,6 +35,7 @@
|
||||
<attr name="ic_import_export" format="reference"/>
|
||||
<attr name="ic_save" format="reference"/>
|
||||
<attr name="ic_backup" format="reference"/>
|
||||
<attr name="ic_add" format="reference"/>
|
||||
|
||||
<!-- Can't refer to colors directly into drawable's xml-->
|
||||
<attr name="toolbar_shadow_drawable" format="reference"/>
|
||||
|
@ -29,13 +29,13 @@
|
||||
<color name="dark_queue_background_color">#af000000</color>
|
||||
|
||||
<!-- Black Theme -->
|
||||
<color name="black_background_color">#000</color>
|
||||
<color name="black_background_color">#000000</color>
|
||||
<color name="black_settings_accent_color">@color/dark_settings_accent_color</color>
|
||||
<color name="black_separator_color">#1effffff</color>
|
||||
<color name="black_contrast_background_color">#23454545</color>
|
||||
|
||||
<!-- Miscellaneous -->
|
||||
<color name="duration_background_color">#AA000000</color>
|
||||
<color name="duration_background_color">#aa000000</color>
|
||||
<color name="live_duration_background_color">#c8E53935</color>
|
||||
<color name="playlist_stream_count_background_color">#e6000000</color>
|
||||
<color name="duration_text_color">#EEFFFFFF</color>
|
||||
@ -70,5 +70,6 @@
|
||||
<color name="gray">#616161</color>
|
||||
|
||||
<color name="black">#000</color>
|
||||
<color name="gray_transparent">#be757575</color>
|
||||
|
||||
</resources>
|
||||
|
@ -2,20 +2,24 @@
|
||||
<resources>
|
||||
<!-- YouTube -->
|
||||
<color name="light_youtube_primary_color">#e53935</color>
|
||||
<color name="light_youtube_dark_color">#d32f2f</color>
|
||||
<color name="light_youtube_dark_color">#992722</color>
|
||||
<color name="light_youtube_accent_color">#000000</color>
|
||||
<color name="light_youtube_statusbar_color">#ff4336</color>
|
||||
|
||||
<color name="dark_youtube_primary_color">#CD322E</color>
|
||||
<color name="dark_youtube_dark_color">#BC211D</color>
|
||||
<color name="dark_youtube_dark_color">#992722</color>
|
||||
<color name="dark_youtube_accent_color">#FFFFFF</color>
|
||||
<color name="dark_youtube_statusbar_color">#ff4336</color>
|
||||
|
||||
<!-- SoundCloud -->
|
||||
<color name="light_soundcloud_primary_color">#f57c00</color>
|
||||
<color name="light_soundcloud_dark_color">#ef6c00</color>
|
||||
<color name="light_soundcloud_dark_color">#995700</color>
|
||||
<color name="light_soundcloud_accent_color">#000000</color>
|
||||
<color name="light_soundcloud_statusbar_color">#ff9100</color>
|
||||
|
||||
<color name="dark_soundcloud_primary_color">#f57c00</color>
|
||||
<color name="dark_soundcloud_dark_color">#ef6c00</color>
|
||||
<color name="dark_soundcloud_dark_color">#995700</color>
|
||||
<color name="dark_soundcloud_accent_color">#FFFFFF</color>
|
||||
<color name="dark_soundcloud_statusbar_color">#ff9100</color>
|
||||
|
||||
</resources>
|
@ -35,6 +35,8 @@
|
||||
<string name="tab_main">Main</string>
|
||||
<string name="tab_subscriptions">Subscriptions</string>
|
||||
<string name="tab_bookmarks">Bookmarks</string>
|
||||
<string name="tab_new">New Tab</string>
|
||||
<string name="tab_chose">Chose Tab</string>
|
||||
|
||||
<string name="fragment_whats_new">What\'s New</string>
|
||||
|
||||
@ -168,6 +170,8 @@
|
||||
<string name="search_history_deleted">Search history deleted.</string>
|
||||
<!-- error strings -->
|
||||
<string name="general_error">Error</string>
|
||||
<string name="download_to_sdcard_error_title">External storage not available.</string>
|
||||
<string name="download_to_sdcard_error_message">Download to external SD Card is not possible yet. Should the download place be reset?</string>
|
||||
<string name="network_error">Network error</string>
|
||||
<string name="could_not_load_thumbnails">Could not load all thumbnails</string>
|
||||
<string name="youtube_signature_decryption_error">Could not decrypt video URL signature</string>
|
||||
@ -357,6 +361,9 @@
|
||||
|
||||
<!-- Content -->
|
||||
<string name="main_page_content">Content of main page</string>
|
||||
<string name="main_page_content_summary">What tabs are shown on the main page</string>
|
||||
<string name="selection">Selection</string>
|
||||
<string name="chosenTabs">Your tabs</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>
|
||||
|
@ -51,6 +51,7 @@
|
||||
<item name="ic_import_export">@drawable/ic_import_export_black_24dp</item>
|
||||
<item name="ic_save">@drawable/ic_save_black_24dp</item>
|
||||
<item name="ic_backup">@drawable/ic_backup_black_24dp</item>
|
||||
<item name="ic_add">@drawable/ic_add_black_24dp</item>
|
||||
|
||||
<item name="separator_color">@color/light_separator_color</item>
|
||||
<item name="contrast_background_color">@color/light_contrast_background_color</item>
|
||||
@ -108,6 +109,7 @@
|
||||
<item name="ic_import_export">@drawable/ic_import_export_white_24dp</item>
|
||||
<item name="ic_save">@drawable/ic_save_white_24dp</item>
|
||||
<item name="ic_backup">@drawable/ic_backup_white_24dp</item>
|
||||
<item name="ic_add">@drawable/ic_add_white_24dp</item>
|
||||
|
||||
<item name="separator_color">@color/dark_separator_color</item>
|
||||
<item name="contrast_background_color">@color/dark_contrast_background_color</item>
|
||||
|
@ -1,12 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- YouTube -->
|
||||
<style name="LightTheme.YouTube" parent="LightTheme.Switchable"/>
|
||||
<style name="LightTheme.YouTube" parent="LightTheme.Switchable">
|
||||
</style>
|
||||
|
||||
<style name="DarkTheme.YouTube" parent="DarkTheme.Switchable"/>
|
||||
|
||||
<style name="BlackTheme.YouTube" parent="BlackTheme.Switchable"/>
|
||||
<style name="DarkTheme.YouTube" parent="DarkTheme.Switchable">
|
||||
</style>
|
||||
|
||||
<style name="BlackTheme.YouTube" parent="BlackTheme.Switchable">
|
||||
</style>
|
||||
<!-- SoundCloud -->
|
||||
<style name="LightTheme.SoundCloud" parent="LightTheme.Switchable">
|
||||
<item name="colorPrimary">@color/light_soundcloud_primary_color</item>
|
||||
|
@ -34,4 +34,11 @@
|
||||
android:key="@string/caption_settings_key"
|
||||
android:title="@string/caption_setting_title"
|
||||
android:summary="@string/caption_setting_description"/>
|
||||
|
||||
<PreferenceScreen
|
||||
android:fragment="org.schabi.newpipe.settings.ChoseTabsFragment"
|
||||
android:summary="@string/main_page_content_summary"
|
||||
android:key="@string/main_page_content_key"
|
||||
android:title="@string/main_page_content"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
@ -43,14 +43,6 @@
|
||||
android:title="@string/download_thumbnail_title"
|
||||
android:summary="@string/download_thumbnail_summary"/>
|
||||
|
||||
<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"/>
|
||||
|
||||
<Preference
|
||||
android:summary="@string/import_data_summary"
|
||||
android:key="@string/import_data"
|
||||
|
@ -6,7 +6,7 @@ buildscript {
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.1.3'
|
||||
classpath 'com.android.tools.build:gradle:3.1.4'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|