+ * StreamInfoItemHolder.java is part of NewPipe.
+ *
+ * NewPipe is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NewPipe is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NewPipe. If not, see .
+ */
+
+public class PlayQueueItemHolder extends RecyclerView.ViewHolder {
+
+ public final TextView itemVideoTitleView, itemDurationView, itemAdditionalDetailsView;
+ public final ImageView itemSelected, itemThumbnailView, itemHandle;
+
+ public final View itemRoot;
+
+ public PlayQueueItemHolder(View v) {
+ super(v);
+ itemRoot = v.findViewById(R.id.itemRoot);
+ itemVideoTitleView = v.findViewById(R.id.itemVideoTitleView);
+ itemDurationView = v.findViewById(R.id.itemDurationView);
+ itemAdditionalDetailsView = v.findViewById(R.id.itemAdditionalDetails);
+ itemSelected = v.findViewById(R.id.itemSelected);
+ itemThumbnailView = v.findViewById(R.id.itemThumbnailView);
+ itemHandle = v.findViewById(R.id.itemHandle);
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/playlist/SinglePlayQueue.java b/app/src/main/java/org/schabi/newpipe/playlist/SinglePlayQueue.java
new file mode 100644
index 000000000..fc68e931a
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/playlist/SinglePlayQueue.java
@@ -0,0 +1,19 @@
+package org.schabi.newpipe.playlist;
+
+import org.schabi.newpipe.extractor.stream.StreamInfo;
+
+import java.util.Collections;
+
+public final class SinglePlayQueue extends PlayQueue {
+ public SinglePlayQueue(final StreamInfo info) {
+ super(0, Collections.singletonList(new PlayQueueItem(info)));
+ }
+
+ @Override
+ public boolean isComplete() {
+ return true;
+ }
+
+ @Override
+ public void fetch() {}
+}
diff --git a/app/src/main/java/org/schabi/newpipe/playlist/events/AppendEvent.java b/app/src/main/java/org/schabi/newpipe/playlist/events/AppendEvent.java
new file mode 100644
index 000000000..b3ba8835a
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/playlist/events/AppendEvent.java
@@ -0,0 +1,19 @@
+package org.schabi.newpipe.playlist.events;
+
+
+public class AppendEvent implements PlayQueueEvent {
+ final private int amount;
+
+ @Override
+ public PlayQueueEventType type() {
+ return PlayQueueEventType.APPEND;
+ }
+
+ public AppendEvent(final int amount) {
+ this.amount = amount;
+ }
+
+ public int getAmount() {
+ return amount;
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/playlist/events/ErrorEvent.java b/app/src/main/java/org/schabi/newpipe/playlist/events/ErrorEvent.java
new file mode 100644
index 000000000..45629feb6
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/playlist/events/ErrorEvent.java
@@ -0,0 +1,31 @@
+package org.schabi.newpipe.playlist.events;
+
+
+public class ErrorEvent implements PlayQueueEvent {
+ final private int errorIndex;
+ final private int queueIndex;
+ final private boolean skippable;
+
+ @Override
+ public PlayQueueEventType type() {
+ return PlayQueueEventType.ERROR;
+ }
+
+ public ErrorEvent(final int errorIndex, final int queueIndex, final boolean skippable) {
+ this.errorIndex = errorIndex;
+ this.queueIndex = queueIndex;
+ this.skippable = skippable;
+ }
+
+ public int getErrorIndex() {
+ return errorIndex;
+ }
+
+ public int getQueueIndex() {
+ return queueIndex;
+ }
+
+ public boolean isSkippable() {
+ return skippable;
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/playlist/events/InitEvent.java b/app/src/main/java/org/schabi/newpipe/playlist/events/InitEvent.java
new file mode 100644
index 000000000..1c1d01508
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/playlist/events/InitEvent.java
@@ -0,0 +1,8 @@
+package org.schabi.newpipe.playlist.events;
+
+public class InitEvent implements PlayQueueEvent {
+ @Override
+ public PlayQueueEventType type() {
+ return PlayQueueEventType.INIT;
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/playlist/events/MoveEvent.java b/app/src/main/java/org/schabi/newpipe/playlist/events/MoveEvent.java
new file mode 100644
index 000000000..4370fe328
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/playlist/events/MoveEvent.java
@@ -0,0 +1,24 @@
+package org.schabi.newpipe.playlist.events;
+
+public class MoveEvent implements PlayQueueEvent {
+ final private int fromIndex;
+ final private int toIndex;
+
+ @Override
+ public PlayQueueEventType type() {
+ return PlayQueueEventType.MOVE;
+ }
+
+ public MoveEvent(final int oldIndex, final int newIndex) {
+ this.fromIndex = oldIndex;
+ this.toIndex = newIndex;
+ }
+
+ public int getFromIndex() {
+ return fromIndex;
+ }
+
+ public int getToIndex() {
+ return toIndex;
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/playlist/events/PlayQueueEvent.java b/app/src/main/java/org/schabi/newpipe/playlist/events/PlayQueueEvent.java
new file mode 100644
index 000000000..c56c3fbc0
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/playlist/events/PlayQueueEvent.java
@@ -0,0 +1,7 @@
+package org.schabi.newpipe.playlist.events;
+
+import java.io.Serializable;
+
+public interface PlayQueueEvent extends Serializable {
+ PlayQueueEventType type();
+}
diff --git a/app/src/main/java/org/schabi/newpipe/playlist/events/PlayQueueEventType.java b/app/src/main/java/org/schabi/newpipe/playlist/events/PlayQueueEventType.java
new file mode 100644
index 000000000..0fc40c098
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/playlist/events/PlayQueueEventType.java
@@ -0,0 +1,27 @@
+package org.schabi.newpipe.playlist.events;
+
+public enum PlayQueueEventType {
+ INIT,
+
+ // sent when the index is changed
+ SELECT,
+
+ // sent when more streams are added to the play queue
+ APPEND,
+
+ // sent when a pending stream is removed from the play queue
+ REMOVE,
+
+ // sent when two streams swap place in the play queue
+ MOVE,
+
+ // sent when queue is shuffled
+ REORDER,
+
+ // sent when recovery record is set on a stream
+ RECOVERY,
+
+ // sent when the item at index has caused an exception
+ ERROR
+}
+
diff --git a/app/src/main/java/org/schabi/newpipe/playlist/events/RecoveryEvent.java b/app/src/main/java/org/schabi/newpipe/playlist/events/RecoveryEvent.java
new file mode 100644
index 000000000..715cf88c4
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/playlist/events/RecoveryEvent.java
@@ -0,0 +1,25 @@
+package org.schabi.newpipe.playlist.events;
+
+
+public class RecoveryEvent implements PlayQueueEvent {
+ final private int index;
+ final private long position;
+
+ @Override
+ public PlayQueueEventType type() {
+ return PlayQueueEventType.RECOVERY;
+ }
+
+ public RecoveryEvent(final int index, final long position) {
+ this.index = index;
+ this.position = position;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public long getPosition() {
+ return position;
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/playlist/events/RemoveEvent.java b/app/src/main/java/org/schabi/newpipe/playlist/events/RemoveEvent.java
new file mode 100644
index 000000000..464dbfa49
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/playlist/events/RemoveEvent.java
@@ -0,0 +1,25 @@
+package org.schabi.newpipe.playlist.events;
+
+
+public class RemoveEvent implements PlayQueueEvent {
+ final private int removeIndex;
+ final private int queueIndex;
+
+ @Override
+ public PlayQueueEventType type() {
+ return PlayQueueEventType.REMOVE;
+ }
+
+ public RemoveEvent(final int removeIndex, final int queueIndex) {
+ this.removeIndex = removeIndex;
+ this.queueIndex = queueIndex;
+ }
+
+ public int getQueueIndex() {
+ return queueIndex;
+ }
+
+ public int getRemoveIndex() {
+ return removeIndex;
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/playlist/events/ReorderEvent.java b/app/src/main/java/org/schabi/newpipe/playlist/events/ReorderEvent.java
new file mode 100644
index 000000000..f1d09d457
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/playlist/events/ReorderEvent.java
@@ -0,0 +1,12 @@
+package org.schabi.newpipe.playlist.events;
+
+public class ReorderEvent implements PlayQueueEvent {
+ @Override
+ public PlayQueueEventType type() {
+ return PlayQueueEventType.REORDER;
+ }
+
+ public ReorderEvent() {
+
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/playlist/events/SelectEvent.java b/app/src/main/java/org/schabi/newpipe/playlist/events/SelectEvent.java
new file mode 100644
index 000000000..d1d0b1137
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/playlist/events/SelectEvent.java
@@ -0,0 +1,25 @@
+package org.schabi.newpipe.playlist.events;
+
+
+public class SelectEvent implements PlayQueueEvent {
+ final private int oldIndex;
+ final private int newIndex;
+
+ @Override
+ public PlayQueueEventType type() {
+ return PlayQueueEventType.SELECT;
+ }
+
+ public SelectEvent(final int oldIndex, final int newIndex) {
+ this.oldIndex = oldIndex;
+ this.newIndex = newIndex;
+ }
+
+ public int getOldIndex() {
+ return oldIndex;
+ }
+
+ public int getNewIndex() {
+ return newIndex;
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java
index b62b63510..43e240fbb 100644
--- a/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java
@@ -160,7 +160,7 @@ public class ErrorActivity extends AppCompatActivity {
key = k;
}
}
- String[] el = new String[]{report.get(key)};
+ String[] el = new String[]{report.get(key).toString()};
Intent intent = new Intent(context, ErrorActivity.class);
intent.putExtra(ERROR_INFO, errorInfo);
diff --git a/app/src/main/java/org/schabi/newpipe/settings/BasePreferenceFragment.java b/app/src/main/java/org/schabi/newpipe/settings/BasePreferenceFragment.java
index a16f7dd79..e3c52cdad 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/BasePreferenceFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/BasePreferenceFragment.java
@@ -19,8 +19,8 @@ public abstract class BasePreferenceFragment extends PreferenceFragmentCompat {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ super.onCreate(savedInstanceState);
}
@Override
diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
index 6021b40fd..2cda95987 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
@@ -1,12 +1,175 @@
package org.schabi.newpipe.settings;
+import android.app.Activity;
import android.os.Bundle;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
import org.schabi.newpipe.R;
+import org.schabi.newpipe.extractor.NewPipe;
+import org.schabi.newpipe.extractor.StreamingService;
+import org.schabi.newpipe.extractor.exceptions.ExtractionException;
+import org.schabi.newpipe.report.ErrorActivity;
+import org.schabi.newpipe.report.UserAction;
+import org.schabi.newpipe.util.Constants;
+import org.schabi.newpipe.util.KioskTranslator;
public class ContentSettingsFragment extends BasePreferenceFragment {
+
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+
addPreferencesFromResource(R.xml.content_settings);
+
+ final ListPreference mainPageContentPref = (ListPreference) findPreference(getString(R.string.main_page_content_key));
+ mainPageContentPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValueO) {
+ final String newValue = newValueO.toString();
+
+ final String mainPrefOldValue =
+ defaultPreferences.getString(getString(R.string.main_page_content_key), "blank_page");
+ final String mainPrefOldSummary = getMainPagePrefSummery(mainPrefOldValue, mainPageContentPref);
+
+ if(newValue.equals(getString(R.string.kiosk_page_key))) {
+ SelectKioskFragment selectKioskFragment = new SelectKioskFragment();
+ selectKioskFragment.setOnSelectedLisener(new SelectKioskFragment.OnSelectedLisener() {
+ @Override
+ public void onKioskSelected(String kioskId, int service_id) {
+ defaultPreferences.edit()
+ .putInt(getString(R.string.main_page_selected_service), service_id).apply();
+ defaultPreferences.edit()
+ .putString(getString(R.string.main_page_selectd_kiosk_id), kioskId).apply();
+ String serviceName = "";
+ try {
+ serviceName = NewPipe.getService(service_id).getServiceInfo().name;
+ } catch (ExtractionException e) {
+ onError(e);
+ }
+ String kioskName = KioskTranslator.getTranslatedKioskName(kioskId,
+ getContext());
+
+ String summary =
+ String.format(getString(R.string.service_kiosk_string),
+ serviceName,
+ kioskName);
+
+ mainPageContentPref.setSummary(summary);
+ }
+ });
+ selectKioskFragment.setOnCancelListener(new SelectKioskFragment.OnCancelListener() {
+ @Override
+ public void onCancel() {
+ mainPageContentPref.setSummary(mainPrefOldSummary);
+ mainPageContentPref.setValue(mainPrefOldValue);
+ }
+ });
+ selectKioskFragment.show(getFragmentManager(), "select_kiosk");
+ } else if(newValue.equals(getString(R.string.channel_page_key))) {
+ SelectChannelFragment selectChannelFragment = new SelectChannelFragment();
+ selectChannelFragment.setOnSelectedLisener(new SelectChannelFragment.OnSelectedLisener() {
+ @Override
+ public void onChannelSelected(String url, String name, int service) {
+ defaultPreferences.edit()
+ .putInt(getString(R.string.main_page_selected_service), service).apply();
+ defaultPreferences.edit()
+ .putString(getString(R.string.main_page_selected_channel_url), url).apply();
+ defaultPreferences.edit()
+ .putString(getString(R.string.main_page_selected_channel_name), name).apply();
+
+ mainPageContentPref.setSummary(name);
+ }
+ });
+ selectChannelFragment.setOnCancelListener(new SelectChannelFragment.OnCancelListener() {
+ @Override
+ public void onCancel() {
+ mainPageContentPref.setSummary(mainPrefOldSummary);
+ mainPageContentPref.setValue(mainPrefOldValue);
+ }
+ });
+ selectChannelFragment.show(getFragmentManager(), "select_channel");
+ } else {
+ mainPageContentPref.setSummary(getMainPageSummeryByKey(newValue));
+ }
+
+ defaultPreferences.edit().putBoolean(Constants.KEY_MAIN_PAGE_CHANGE, true).apply();
+
+ return true;
+ }
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ final String mainPageContentKey = getString(R.string.main_page_content_key);
+ final Preference mainPagePref = findPreference(getString(R.string.main_page_content_key));
+ final String bpk = getString(R.string.blank_page_key);
+ if(defaultPreferences.getString(mainPageContentKey, bpk)
+ .equals(getString(R.string.channel_page_key))) {
+ mainPagePref.setSummary(defaultPreferences.getString(getString(R.string.main_page_selected_channel_name), "error"));
+ } else if(defaultPreferences.getString(mainPageContentKey, bpk)
+ .equals(getString(R.string.kiosk_page_key))) {
+ try {
+ StreamingService service = NewPipe.getService(
+ defaultPreferences.getInt(
+ getString(R.string.main_page_selected_service), 0));
+
+ String kioskName = KioskTranslator.getTranslatedKioskName(
+ defaultPreferences.getString(
+ getString(R.string.main_page_selectd_kiosk_id), "Trending"),
+ getContext());
+
+ String summary =
+ String.format(getString(R.string.service_kiosk_string),
+ service.getServiceInfo().name,
+ kioskName);
+
+ mainPagePref.setSummary(summary);
+ } catch (Exception e) {
+ onError(e);
+ }
+ }
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Utils
+ //////////////////////////////////////////////////////////////////////////*/
+ private String getMainPagePrefSummery(final String mainPrefOldValue, final ListPreference mainPageContentPref) {
+ if(mainPrefOldValue.equals(getString(R.string.channel_page_key))) {
+ return defaultPreferences.getString(getString(R.string.main_page_selected_channel_name), "error");
+ } else {
+ return mainPageContentPref.getSummary().toString();
+ }
+ }
+
+ private int getMainPageSummeryByKey(final String key) {
+ if(key.equals(getString(R.string.blank_page_key))) {
+ return R.string.blank_page_summary;
+ } else if(key.equals(getString(R.string.kiosk_page_key))) {
+ return R.string.kiosk_page_summary;
+ } else if(key.equals(getString(R.string.feed_page_key))) {
+ return R.string.feed_page_summary;
+ } else if(key.equals(getString(R.string.subscription_page_key))) {
+ return R.string.subscription_page_summary;
+ } else if(key.equals(getString(R.string.channel_page_key))) {
+ return R.string.channel_page_summary;
+ }
+ return R.string.blank_page_summary;
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Error
+ //////////////////////////////////////////////////////////////////////////*/
+
+ protected boolean onError(Throwable e) {
+ final Activity activity = getActivity();
+ ErrorActivity.reportError(activity, e,
+ activity.getClass(),
+ null,
+ ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
+ "none", "", R.string.app_ui_crash));
+ return true;
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java
index f93134a5d..9a43374a5 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java
@@ -7,9 +7,8 @@ import android.support.annotation.Nullable;
import android.support.v7.preference.Preference;
import android.util.Log;
-import com.nononsenseapps.filepicker.FilePickerActivity;
-
import org.schabi.newpipe.R;
+import org.schabi.newpipe.util.FilePickerActivityHelper;
public class DownloadSettingsFragment extends BasePreferenceFragment {
private static final int REQUEST_DOWNLOAD_PATH = 0x1235;
@@ -48,10 +47,10 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
}
if (preference.getKey().equals(DOWNLOAD_PATH_PREFERENCE) || preference.getKey().equals(DOWNLOAD_PATH_AUDIO_PREFERENCE)) {
- Intent i = new Intent(getActivity(), FilePickerActivity.class)
- .putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
- .putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
- .putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR);
+ Intent i = new Intent(getActivity(), FilePickerActivityHelper.class)
+ .putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
+ .putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, true)
+ .putExtra(FilePickerActivityHelper.EXTRA_MODE, FilePickerActivityHelper.MODE_DIR);
if (preference.getKey().equals(DOWNLOAD_PATH_PREFERENCE)) {
startActivityForResult(i, REQUEST_DOWNLOAD_PATH);
} else if (preference.getKey().equals(DOWNLOAD_PATH_AUDIO_PREFERENCE)) {
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java
new file mode 100644
index 000000000..97af11f1b
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java
@@ -0,0 +1,238 @@
+package org.schabi.newpipe.settings;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.nostra13.universalimageloader.core.DisplayImageOptions;
+import com.nostra13.universalimageloader.core.ImageLoader;
+
+import org.schabi.newpipe.R;
+import org.schabi.newpipe.database.subscription.SubscriptionEntity;
+import org.schabi.newpipe.fragments.subscription.SubscriptionService;
+import org.schabi.newpipe.report.ErrorActivity;
+import org.schabi.newpipe.report.UserAction;
+
+import java.util.List;
+import java.util.Vector;
+
+import de.hdodenhof.circleimageview.CircleImageView;
+import io.reactivex.Observer;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+
+/**
+ * Created by Christian Schabesberger on 26.09.17.
+ * SelectChannelFragment.java is part of NewPipe.
+ *
+ * NewPipe is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NewPipe is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NewPipe. If not, see .
+ */
+
+public class SelectChannelFragment extends DialogFragment {
+ private SelectChannelAdapter channelAdapter;
+ private SubscriptionService subscriptionService;
+ private ImageLoader imageLoader = ImageLoader.getInstance();
+
+ private ProgressBar progressBar;
+ private TextView emptyView;
+ private RecyclerView recyclerView;
+
+ private List subscriptions = new Vector<>();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Interfaces
+ //////////////////////////////////////////////////////////////////////////*/
+
+ public interface OnSelectedLisener {
+ void onChannelSelected(String url, String name, int service);
+ }
+ OnSelectedLisener onSelectedLisener = null;
+ public void setOnSelectedLisener(OnSelectedLisener listener) {
+ onSelectedLisener = listener;
+ }
+
+ public interface OnCancelListener {
+ void onCancel();
+ }
+ OnCancelListener onCancelListener = null;
+ public void setOnCancelListener(OnCancelListener listener) {
+ onCancelListener = listener;
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Init
+ //////////////////////////////////////////////////////////////////////////*/
+
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.select_channel_fragment, container, false);
+ recyclerView = (RecyclerView) v.findViewById(R.id.items_list);
+ recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+ channelAdapter = new SelectChannelAdapter();
+ recyclerView.setAdapter(channelAdapter);
+
+ progressBar = v.findViewById(R.id.progressBar);
+ emptyView = v.findViewById(R.id.empty_state_view);
+ progressBar.setVisibility(View.VISIBLE);
+ recyclerView.setVisibility(View.GONE);
+ emptyView.setVisibility(View.GONE);
+
+
+ subscriptionService = SubscriptionService.getInstance();
+ subscriptionService.getSubscription().toObservable()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(getSubscriptionObserver());
+
+ return v;
+ }
+
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Handle actions
+ //////////////////////////////////////////////////////////////////////////*/
+
+ @Override
+ public void onCancel(final DialogInterface dialogInterface) {
+ super.onCancel(dialogInterface);
+ if(onCancelListener != null) {
+ onCancelListener.onCancel();
+ }
+ }
+
+ private void clickedItem(int position) {
+ if(onSelectedLisener != null) {
+ SubscriptionEntity entry = subscriptions.get(position);
+ onSelectedLisener.onChannelSelected(entry.getUrl(), entry.getName(), entry.getServiceId());
+ }
+ dismiss();
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Item handling
+ //////////////////////////////////////////////////////////////////////////*/
+
+ private void displayChannels(List subscriptions) {
+ this.subscriptions = subscriptions;
+ progressBar.setVisibility(View.GONE);
+ if(subscriptions.isEmpty()) {
+ emptyView.setVisibility(View.VISIBLE);
+ return;
+ }
+ recyclerView.setVisibility(View.VISIBLE);
+
+ }
+
+ private Observer> getSubscriptionObserver() {
+ return new Observer>() {
+ @Override
+ public void onSubscribe(Disposable d) {
+ }
+
+ @Override
+ public void onNext(List subscriptions) {
+ displayChannels(subscriptions);
+ }
+
+ @Override
+ public void onError(Throwable exception) {
+ onError(exception);
+ }
+
+ @Override
+ public void onComplete() {
+ }
+ };
+ }
+
+ private class SelectChannelAdapter extends
+ RecyclerView.Adapter {
+
+ @Override
+ public SelectChannelItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View item = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.select_channel_item, parent, false);
+ return new SelectChannelItemHolder(item);
+ }
+
+ @Override
+ public void onBindViewHolder(SelectChannelItemHolder holder, final int position) {
+ SubscriptionEntity entry = subscriptions.get(position);
+ holder.titleView.setText(entry.getName());
+ holder.view.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ clickedItem(position);
+ }
+ });
+ imageLoader.displayImage(entry.getAvatarUrl(), holder.thumbnailView, DISPLAY_IMAGE_OPTIONS);
+ }
+
+ @Override
+ public int getItemCount() {
+ return subscriptions.size();
+ }
+
+ public class SelectChannelItemHolder extends RecyclerView.ViewHolder {
+ public SelectChannelItemHolder(View v) {
+ super(v);
+ this.view = v;
+ thumbnailView = v.findViewById(R.id.itemThumbnailView);
+ titleView = v.findViewById(R.id.itemTitleView);
+ }
+ public View view;
+ public CircleImageView thumbnailView;
+ public TextView titleView;
+ }
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Error
+ //////////////////////////////////////////////////////////////////////////*/
+
+ protected boolean onError(Throwable e) {
+ final Activity activity = getActivity();
+ ErrorActivity.reportError(activity, e,
+ activity.getClass(),
+ null,
+ ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
+ "none", "", R.string.app_ui_crash));
+ return true;
+ }
+
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // ImageLoaderOptions
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /**
+ * Base display options
+ */
+ public static final DisplayImageOptions DISPLAY_IMAGE_OPTIONS =
+ new DisplayImageOptions.Builder()
+ .cacheInMemory(true)
+ .build();
+}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java
new file mode 100644
index 000000000..9e5420b6e
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java
@@ -0,0 +1,192 @@
+package org.schabi.newpipe.settings;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.schabi.newpipe.R;
+import org.schabi.newpipe.database.subscription.SubscriptionEntity;
+import org.schabi.newpipe.extractor.NewPipe;
+import org.schabi.newpipe.extractor.StreamingService;
+import org.schabi.newpipe.fragments.subscription.SubscriptionService;
+import org.schabi.newpipe.report.ErrorActivity;
+import org.schabi.newpipe.report.UserAction;
+import org.schabi.newpipe.util.KioskTranslator;
+import org.schabi.newpipe.util.ServiceIconMapper;
+
+import java.util.List;
+import java.util.Vector;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * Created by Christian Schabesberger on 09.10.17.
+ * SelectKioskFragment.java is part of NewPipe.
+ *
+ * NewPipe is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NewPipe is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NewPipe. If not, see .
+ */
+
+public class SelectKioskFragment extends DialogFragment {
+
+ RecyclerView recyclerView = null;
+ SelectKioskAdapter selectKioskAdapter = null;
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Interfaces
+ //////////////////////////////////////////////////////////////////////////*/
+
+ public interface OnSelectedLisener {
+ void onKioskSelected(String kioskId, int service_id);
+ }
+
+ OnSelectedLisener onSelectedLisener = null;
+ public void setOnSelectedLisener(OnSelectedLisener listener) {
+ onSelectedLisener = listener;
+ }
+
+ public interface OnCancelListener {
+ void onCancel();
+ }
+ OnCancelListener onCancelListener = null;
+ public void setOnCancelListener(OnCancelListener listener) {
+ onCancelListener = listener;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.select_kiosk_fragment, container, false);
+ recyclerView = (RecyclerView) v.findViewById(R.id.items_list);
+ recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+ try {
+ selectKioskAdapter = new SelectKioskAdapter();
+ } catch (Exception e) {
+ onError(e);
+ }
+ recyclerView.setAdapter(selectKioskAdapter);
+
+ return v;
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Handle actions
+ //////////////////////////////////////////////////////////////////////////*/
+
+ @Override
+ public void onCancel(final DialogInterface dialogInterface) {
+ super.onCancel(dialogInterface);
+ if(onCancelListener != null) {
+ onCancelListener.onCancel();
+ }
+ }
+
+ private void clickedItem(SelectKioskAdapter.Entry entry) {
+ if(onSelectedLisener != null) {
+ onSelectedLisener.onKioskSelected(entry.kioskId, entry.serviceId);
+ }
+ dismiss();
+ }
+
+ private class SelectKioskAdapter
+ extends RecyclerView.Adapter {
+ public class Entry {
+ public Entry (int i, int si, String ki, String kn){
+ icon = i; serviceId=si; kioskId=ki; kioskName = kn;
+ }
+ int icon;
+ int serviceId;
+ String kioskId;
+ String kioskName;
+ }
+
+ private List kioskList = new Vector<>();
+
+ public SelectKioskAdapter()
+ throws Exception {
+
+ for(StreamingService service : NewPipe.getServices()) {
+ for(String kioskId : service.getKioskList().getAvailableKiosks()) {
+ String name = String.format(getString(R.string.service_kiosk_string),
+ service.getServiceInfo().name,
+ KioskTranslator.getTranslatedKioskName(kioskId, getContext()));
+ kioskList.add(new Entry(
+ //ServiceIconMapper.getIconResource(service.getServiceId()),
+ ServiceIconMapper.getIconResource(-1),
+ service.getServiceId(),
+ kioskId,
+ name));
+ }
+ }
+ }
+
+ public int getItemCount() {
+ //todo: uncommend this line on multyservice support
+ //return kioskList.size();
+ return 1;
+ }
+
+ public SelectKioskItemHolder onCreateViewHolder(ViewGroup parent, int type) {
+ View item = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.select_kiosk_item, parent, false);
+ return new SelectKioskItemHolder(item);
+ }
+
+ public class SelectKioskItemHolder extends RecyclerView.ViewHolder {
+ public SelectKioskItemHolder(View v) {
+ super(v);
+ this.view = v;
+ thumbnailView = v.findViewById(R.id.itemThumbnailView);
+ titleView = v.findViewById(R.id.itemTitleView);
+ }
+ public View view;
+ public ImageView thumbnailView;
+ public TextView titleView;
+ }
+
+ public void onBindViewHolder(SelectKioskItemHolder holder, final int position) {
+ final Entry entry = kioskList.get(position);
+ holder.titleView.setText(entry.kioskName);
+ holder.thumbnailView.setImageDrawable(ContextCompat.getDrawable(getContext(), entry.icon));
+ holder.view.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ clickedItem(entry);
+ }
+ });
+ }
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Error
+ //////////////////////////////////////////////////////////////////////////*/
+
+ protected boolean onError(Throwable e) {
+ final Activity activity = getActivity();
+ ErrorActivity.reportError(activity, e,
+ activity.getClass(),
+ null,
+ ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
+ "none", "", R.string.app_ui_crash));
+ return true;
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/util/AnimationUtils.java b/app/src/main/java/org/schabi/newpipe/util/AnimationUtils.java
index ac70bd05f..c954211fa 100644
--- a/app/src/main/java/org/schabi/newpipe/util/AnimationUtils.java
+++ b/app/src/main/java/org/schabi/newpipe/util/AnimationUtils.java
@@ -19,7 +19,7 @@ public class AnimationUtils {
private static final boolean DEBUG = MainActivity.DEBUG;
public enum Type {
- ALPHA, SCALE_AND_ALPHA, LIGHT_SCALE_AND_ALPHA
+ ALPHA, SCALE_AND_ALPHA, LIGHT_SCALE_AND_ALPHA, SLIDE_AND_ALPHA, LIGHT_SLIDE_AND_ALPHA
}
public static void animateView(View view, boolean enterOrExit, long duration) {
@@ -95,9 +95,16 @@ public class AnimationUtils {
case LIGHT_SCALE_AND_ALPHA:
animateLightScaleAndAlpha(view, enterOrExit, duration, delay, execOnEnd);
break;
+ case SLIDE_AND_ALPHA:
+ animateSlideAndAlpha(view, enterOrExit, duration, delay, execOnEnd);
+ break;
+ case LIGHT_SLIDE_AND_ALPHA:
+ animateLightSlideAndAlpha(view, enterOrExit, duration, delay, execOnEnd);
+ break;
}
}
+
/**
* Animate the background color of a view
*/
@@ -237,4 +244,50 @@ public class AnimationUtils {
}).start();
}
}
+
+ private static void animateSlideAndAlpha(final View view, boolean enterOrExit, long duration, long delay, final Runnable execOnEnd) {
+ if (enterOrExit) {
+ view.setTranslationY(-view.getHeight());
+ view.setAlpha(0f);
+ view.animate().setInterpolator(new FastOutSlowInInterpolator()).alpha(1f).translationY(0)
+ .setDuration(duration).setStartDelay(delay).setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (execOnEnd != null) execOnEnd.run();
+ }
+ }).start();
+ } else {
+ view.animate().setInterpolator(new FastOutSlowInInterpolator()).alpha(0f).translationY(-view.getHeight())
+ .setDuration(duration).setStartDelay(delay).setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setVisibility(View.GONE);
+ if (execOnEnd != null) execOnEnd.run();
+ }
+ }).start();
+ }
+ }
+
+ private static void animateLightSlideAndAlpha(final View view, boolean enterOrExit, long duration, long delay, final Runnable execOnEnd) {
+ if (enterOrExit) {
+ view.setTranslationY(-view.getHeight() / 2);
+ view.setAlpha(0f);
+ view.animate().setInterpolator(new FastOutSlowInInterpolator()).alpha(1f).translationY(0)
+ .setDuration(duration).setStartDelay(delay).setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (execOnEnd != null) execOnEnd.run();
+ }
+ }).start();
+ } else {
+ view.animate().setInterpolator(new FastOutSlowInInterpolator()).alpha(0f).translationY(-view.getHeight() / 2)
+ .setDuration(duration).setStartDelay(delay).setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setVisibility(View.GONE);
+ if (execOnEnd != null) execOnEnd.run();
+ }
+ }).start();
+ }
+ }
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/Constants.java b/app/src/main/java/org/schabi/newpipe/util/Constants.java
index f9329b0be..a6aec96e2 100644
--- a/app/src/main/java/org/schabi/newpipe/util/Constants.java
+++ b/app/src/main/java/org/schabi/newpipe/util/Constants.java
@@ -9,4 +9,7 @@ public class Constants {
public static final String KEY_QUERY = "key_query";
public static final String KEY_THEME_CHANGE = "key_theme_change";
+ public static final String KEY_MAIN_PAGE_CHANGE = "key_main_page_change";
+
+ public static final int NO_SERVICE_ID = -1;
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java
index 5cf9f057e..4763b6a02 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java
@@ -26,6 +26,7 @@ import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.extractor.ListExtractor.NextItemsResult;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
+import org.schabi.newpipe.extractor.kiosk.KioskInfo;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.search.SearchEngine;
import org.schabi.newpipe.extractor.search.SearchResult;
@@ -50,7 +51,14 @@ public final class ExtractorHelper {
//no instance
}
+ private static void checkServiceId(int serviceId) {
+ if(serviceId == Constants.NO_SERVICE_ID) {
+ throw new IllegalArgumentException("serviceId is NO_SERVICE_ID");
+ }
+ }
+
public static Single searchFor(final int serviceId, final String query, final int pageNumber, final String searchLanguage, final SearchEngine.Filter filter) {
+ checkServiceId(serviceId);
return Single.fromCallable(new Callable() {
@Override
public SearchResult call() throws Exception {
@@ -61,6 +69,7 @@ public final class ExtractorHelper {
}
public static Single getMoreSearchItems(final int serviceId, final String query, final int nextPageNumber, final String searchLanguage, final SearchEngine.Filter filter) {
+ checkServiceId(serviceId);
return searchFor(serviceId, query, nextPageNumber, searchLanguage, filter)
.map(new Function() {
@Override
@@ -71,6 +80,7 @@ public final class ExtractorHelper {
}
public static Single> suggestionsFor(final int serviceId, final String query, final String searchLanguage) {
+ checkServiceId(serviceId);
return Single.fromCallable(new Callable>() {
@Override
public List call() throws Exception {
@@ -80,6 +90,7 @@ public final class ExtractorHelper {
}
public static Single getStreamInfo(final int serviceId, final String url, boolean forceLoad) {
+ checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable() {
@Override
public StreamInfo call() throws Exception {
@@ -89,6 +100,7 @@ public final class ExtractorHelper {
}
public static Single getChannelInfo(final int serviceId, final String url, boolean forceLoad) {
+ checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable() {
@Override
public ChannelInfo call() throws Exception {
@@ -98,6 +110,7 @@ public final class ExtractorHelper {
}
public static Single getMoreChannelItems(final int serviceId, final String url, final String nextStreamsUrl) {
+ checkServiceId(serviceId);
return Single.fromCallable(new Callable() {
@Override
public NextItemsResult call() throws Exception {
@@ -107,6 +120,7 @@ public final class ExtractorHelper {
}
public static Single getPlaylistInfo(final int serviceId, final String url, boolean forceLoad) {
+ checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable() {
@Override
public PlaylistInfo call() throws Exception {
@@ -116,6 +130,7 @@ public final class ExtractorHelper {
}
public static Single getMorePlaylistItems(final int serviceId, final String url, final String nextStreamsUrl) {
+ checkServiceId(serviceId);
return Single.fromCallable(new Callable() {
@Override
public NextItemsResult call() throws Exception {
@@ -124,6 +139,24 @@ public final class ExtractorHelper {
});
}
+ public static Single getKioskInfo(final int serviceId, final String url, final String contentCountry, boolean forceLoad) {
+ return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable() {
+ @Override
+ public KioskInfo call() throws Exception {
+ return KioskInfo.getInfo(NewPipe.getService(serviceId), url, contentCountry);
+ }
+ }));
+ }
+
+ public static Single getMoreKioskItems(final int serviceId, final String url, final String nextStreamsUrl) {
+ return Single.fromCallable(new Callable() {
+ @Override
+ public NextItemsResult call() throws Exception {
+ return KioskInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl);
+ }
+ });
+ }
+
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
@@ -133,6 +166,7 @@ public final class ExtractorHelper {
* and put the results in the cache.
*/
private static Single checkCache(boolean forceLoad, int serviceId, String url, Single loadFromNetwork) {
+ checkServiceId(serviceId);
loadFromNetwork = loadFromNetwork.doOnSuccess(new Consumer() {
@Override
public void accept(@NonNull I i) throws Exception {
@@ -157,6 +191,7 @@ public final class ExtractorHelper {
* Default implementation uses the {@link InfoCache} to get cached results
*/
public static Maybe loadFromCache(final int serviceId, final String url) {
+ checkServiceId(serviceId);
return Maybe.defer(new Callable>() {
@Override
public MaybeSource extends I> call() throws Exception {
diff --git a/app/src/main/java/org/schabi/newpipe/util/FilePickerActivityHelper.java b/app/src/main/java/org/schabi/newpipe/util/FilePickerActivityHelper.java
new file mode 100644
index 000000000..5f588c5ca
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/util/FilePickerActivityHelper.java
@@ -0,0 +1,17 @@
+package org.schabi.newpipe.util;
+
+import android.os.Bundle;
+import org.schabi.newpipe.R;
+
+public class FilePickerActivityHelper extends com.nononsenseapps.filepicker.FilePickerActivity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ if(ThemeHelper.isLightThemeSelected(this)) {
+ this.setTheme(R.style.FilePickerThemeLight);
+ } else {
+ this.setTheme(R.style.FilePickerThemeDark);
+ }
+ super.onCreate(savedInstanceState);
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java
new file mode 100644
index 000000000..4740b82e0
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java
@@ -0,0 +1,38 @@
+package org.schabi.newpipe.util;
+
+import android.content.Context;
+
+import org.schabi.newpipe.R;
+
+/**
+ * Created by Chrsitian Schabesberger on 28.09.17.
+ * KioskTranslator.java is part of NewPipe.
+ *
+ * NewPipe is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NewPipe is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NewPipe. If not, see .
+ */
+
+public class KioskTranslator {
+ public static String getTranslatedKioskName(String kioskId, Context c) {
+ switch(kioskId) {
+ case "Trending":
+ return c.getString(R.string.trending);
+ case "Top 50":
+ return c.getString(R.string.top_50);
+ case "New & hot":
+ return c.getString(R.string.new_and_hot);
+ default:
+ return kioskId;
+ }
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/util/LayoutManagerSmoothScroller.java b/app/src/main/java/org/schabi/newpipe/util/LayoutManagerSmoothScroller.java
new file mode 100644
index 000000000..9eca2d610
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/util/LayoutManagerSmoothScroller.java
@@ -0,0 +1,43 @@
+package org.schabi.newpipe.util;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.LinearSmoothScroller;
+import android.support.v7.widget.RecyclerView;
+
+public class LayoutManagerSmoothScroller extends LinearLayoutManager {
+
+ public LayoutManagerSmoothScroller(Context context) {
+ super(context, VERTICAL, false);
+ }
+
+ public LayoutManagerSmoothScroller(Context context, int orientation, boolean reverseLayout) {
+ super(context, orientation, reverseLayout);
+ }
+
+ @Override
+ public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
+ RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext());
+ smoothScroller.setTargetPosition(position);
+ startSmoothScroll(smoothScroller);
+ }
+
+ private class TopSnappedSmoothScroller extends LinearSmoothScroller {
+ public TopSnappedSmoothScroller(Context context) {
+ super(context);
+
+ }
+
+ @Override
+ public PointF computeScrollVectorForPosition(int targetPosition) {
+ return LayoutManagerSmoothScroller.this
+ .computeScrollVectorForPosition(targetPosition);
+ }
+
+ @Override
+ protected int getVerticalSnapPreference() {
+ return SNAP_TO_START;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
index 3fda47438..697a0c7c1 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
@@ -56,6 +56,13 @@ public final class ListHelper {
if (defaultPreferences == null) return 0;
String defaultResolution = defaultPreferences.getString(context.getString(R.string.default_resolution_key), context.getString(R.string.default_resolution_value));
+ return getDefaultResolutionIndex(context, videoStreams, defaultResolution);
+ }
+
+ /**
+ * @see #getDefaultResolutionIndex(String, String, MediaFormat, List)
+ */
+ public static int getDefaultResolutionIndex(Context context, List videoStreams, String defaultResolution) {
return getDefaultResolutionWithDefaultFormat(context, defaultResolution, videoStreams);
}
@@ -67,6 +74,13 @@ public final class ListHelper {
if (defaultPreferences == null) return 0;
String defaultResolution = defaultPreferences.getString(context.getString(R.string.default_popup_resolution_key), context.getString(R.string.default_popup_resolution_value));
+ return getPopupDefaultResolutionIndex(context, videoStreams, defaultResolution);
+ }
+
+ /**
+ * @see #getDefaultResolutionIndex(String, String, MediaFormat, List)
+ */
+ public static int getPopupDefaultResolutionIndex(Context context, List videoStreams, String defaultResolution) {
return getDefaultResolutionWithDefaultFormat(context, defaultResolution, videoStreams);
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/Localization.java b/app/src/main/java/org/schabi/newpipe/util/Localization.java
index b6ec3cd3a..43ebc1677 100644
--- a/app/src/main/java/org/schabi/newpipe/util/Localization.java
+++ b/app/src/main/java/org/schabi/newpipe/util/Localization.java
@@ -6,6 +6,7 @@ import android.content.res.Resources;
import android.preference.PreferenceManager;
import android.support.annotation.PluralsRes;
import android.support.annotation.StringRes;
+import android.text.TextUtils;
import org.schabi.newpipe.R;
diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
index 0a529ab4e..a68494706 100644
--- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
@@ -1,11 +1,14 @@
package org.schabi.newpipe.util;
import android.app.Activity;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.net.Uri;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
+import android.support.v7.app.AppCompatActivity;
import com.nostra13.universalimageloader.core.ImageLoader;
@@ -14,23 +17,22 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.about.AboutActivity;
import org.schabi.newpipe.download.DownloadActivity;
import org.schabi.newpipe.extractor.NewPipe;
+import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamingService;
-import org.schabi.newpipe.extractor.stream.AudioStream;
-import org.schabi.newpipe.extractor.stream.StreamInfo;
+import org.schabi.newpipe.extractor.exceptions.ExtractionException;
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.fragments.list.feed.FeedFragment;
+import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment;
import org.schabi.newpipe.fragments.list.search.SearchFragment;
import org.schabi.newpipe.history.HistoryActivity;
-import org.schabi.newpipe.player.BackgroundPlayer;
import org.schabi.newpipe.player.BasePlayer;
import org.schabi.newpipe.player.VideoPlayer;
+import org.schabi.newpipe.playlist.PlayQueue;
import org.schabi.newpipe.settings.SettingsActivity;
-import java.util.ArrayList;
-
@SuppressWarnings({"unused", "WeakerAccess"})
public class NavigationHelper {
public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag";
@@ -38,46 +40,41 @@ public class NavigationHelper {
/*//////////////////////////////////////////////////////////////////////////
// Players
//////////////////////////////////////////////////////////////////////////*/
+ public static Intent getPlayerIntent(final Context context,
+ final Class targetClazz,
+ final PlayQueue playQueue,
+ final String quality) {
+ Intent intent = new Intent(context, targetClazz)
+ .putExtra(VideoPlayer.PLAY_QUEUE, playQueue);
+ if (quality != null) intent.putExtra(VideoPlayer.PLAYBACK_QUALITY, quality);
- public static Intent getOpenVideoPlayerIntent(Context context, Class targetClazz, StreamInfo info, int selectedStreamIndex) {
- Intent mIntent = new Intent(context, targetClazz)
- .putExtra(BasePlayer.VIDEO_TITLE, info.name)
- .putExtra(BasePlayer.VIDEO_URL, info.url)
- .putExtra(BasePlayer.VIDEO_THUMBNAIL_URL, info.thumbnail_url)
- .putExtra(BasePlayer.CHANNEL_NAME, info.uploader_name)
- .putExtra(VideoPlayer.INDEX_SEL_VIDEO_STREAM, selectedStreamIndex)
- .putExtra(VideoPlayer.VIDEO_STREAMS_LIST, new ArrayList<>(ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false)))
- .putExtra(VideoPlayer.VIDEO_ONLY_AUDIO_STREAM, ListHelper.getHighestQualityAudio(info.audio_streams));
- if (info.start_position > 0) mIntent.putExtra(BasePlayer.START_POSITION, info.start_position * 1000L);
- return mIntent;
+ return intent;
}
- public static Intent getOpenVideoPlayerIntent(Context context, Class targetClazz, VideoPlayer instance) {
- return new Intent(context, targetClazz)
- .putExtra(BasePlayer.VIDEO_TITLE, instance.getVideoTitle())
- .putExtra(BasePlayer.VIDEO_URL, instance.getVideoUrl())
- .putExtra(BasePlayer.VIDEO_THUMBNAIL_URL, instance.getVideoThumbnailUrl())
- .putExtra(BasePlayer.CHANNEL_NAME, instance.getUploaderName())
- .putExtra(VideoPlayer.INDEX_SEL_VIDEO_STREAM, instance.getSelectedStreamIndex())
- .putExtra(VideoPlayer.VIDEO_STREAMS_LIST, instance.getVideoStreamsList())
- .putExtra(VideoPlayer.VIDEO_ONLY_AUDIO_STREAM, instance.getAudioStream())
- .putExtra(BasePlayer.START_POSITION, instance.getPlayer().getCurrentPosition())
- .putExtra(BasePlayer.PLAYBACK_SPEED, instance.getPlaybackSpeed());
+ public static Intent getPlayerIntent(final Context context,
+ final Class targetClazz,
+ final PlayQueue playQueue) {
+ return getPlayerIntent(context, targetClazz, playQueue, null);
}
- public static Intent getOpenBackgroundPlayerIntent(Context context, StreamInfo info) {
- return getOpenBackgroundPlayerIntent(context, info, info.audio_streams.get(ListHelper.getDefaultAudioFormat(context, info.audio_streams)));
+ public static Intent getPlayerEnqueueIntent(final Context context,
+ final Class targetClazz,
+ final PlayQueue playQueue) {
+ return getPlayerIntent(context, targetClazz, playQueue)
+ .putExtra(BasePlayer.APPEND_ONLY, true);
}
- public static Intent getOpenBackgroundPlayerIntent(Context context, StreamInfo info, AudioStream audioStream) {
- Intent mIntent = new Intent(context, BackgroundPlayer.class)
- .putExtra(BasePlayer.VIDEO_TITLE, info.name)
- .putExtra(BasePlayer.VIDEO_URL, info.url)
- .putExtra(BasePlayer.VIDEO_THUMBNAIL_URL, info.thumbnail_url)
- .putExtra(BasePlayer.CHANNEL_NAME, info.uploader_name)
- .putExtra(BackgroundPlayer.AUDIO_STREAM, audioStream);
- if (info.start_position > 0) mIntent.putExtra(BasePlayer.START_POSITION, info.start_position * 1000L);
- return mIntent;
+ public static Intent getPlayerIntent(final Context context,
+ final Class targetClazz,
+ final PlayQueue playQueue,
+ final int repeatMode,
+ final float playbackSpeed,
+ final float playbackPitch,
+ final String playbackQuality) {
+ return getPlayerIntent(context, targetClazz, playQueue, playbackQuality)
+ .putExtra(BasePlayer.REPEAT_MODE, repeatMode)
+ .putExtra(BasePlayer.PLAYBACK_SPEED, playbackSpeed)
+ .putExtra(BasePlayer.PLAYBACK_PITCH, playbackPitch);
}
/*//////////////////////////////////////////////////////////////////////////
@@ -91,7 +88,7 @@ public class NavigationHelper {
if (!popped) openMainFragment(fragmentManager);
}
- private static void openMainFragment(FragmentManager fragmentManager) {
+ public static void openMainFragment(FragmentManager fragmentManager) {
InfoCache.getInstance().trimCache();
fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
@@ -161,6 +158,15 @@ public class NavigationHelper {
.commit();
}
+ public static void openKioskFragment(FragmentManager fragmentManager, int serviceId, String kioskId)
+ throws ExtractionException {
+ fragmentManager.beginTransaction()
+ .setCustomAnimations(R.animator.custom_fade_in, R.animator.custom_fade_out, R.animator.custom_fade_in, R.animator.custom_fade_out)
+ .replace(R.id.fragment_holder, KioskFragment.getInstance(serviceId, kioskId))
+ .addToBackStack(null)
+ .commit();
+ }
+
/*//////////////////////////////////////////////////////////////////////////
// Through Intents
//////////////////////////////////////////////////////////////////////////*/
@@ -228,13 +234,17 @@ public class NavigationHelper {
// Link handling
//////////////////////////////////////////////////////////////////////////*/
- public static void openByLink(Context context, String url) throws Exception {
- Intent intentByLink = getIntentByLink(context, url);
- if (intentByLink == null)
- throw new NullPointerException("getIntentByLink(context = [" + context + "], url = [" + url + "]) returned null");
+ public static boolean openByLink(Context context, String url) {
+ Intent intentByLink;
+ try {
+ intentByLink = getIntentByLink(context, url);
+ } catch (ExtractionException e) {
+ return false;
+ }
intentByLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intentByLink.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intentByLink);
+ return true;
}
private static Intent getOpenIntent(Context context, String url, int serviceId, StreamingService.LinkType type) {
@@ -245,14 +255,20 @@ public class NavigationHelper {
return mIntent;
}
- private static Intent getIntentByLink(Context context, String url) throws Exception {
- StreamingService service = NewPipe.getServiceByUrl(url);
+ public static Intent getIntentByLink(Context context, String url) throws ExtractionException {
+ return getIntentByLink(context, NewPipe.getServiceByUrl(url), url);
+ }
+
+ public static Intent getIntentByLink(Context context, StreamingService service, String url) throws ExtractionException {
+ if (service != ServiceList.YouTube.getService()) {
+ throw new ExtractionException("Service not supported at the moment");
+ }
int serviceId = service.getServiceId();
StreamingService.LinkType linkType = service.getLinkTypeByUrl(url);
if (linkType == StreamingService.LinkType.NONE) {
- throw new Exception("Url not known to service. service=" + serviceId + " url=" + url);
+ throw new ExtractionException("Url not known to service. service=" + serviceId + " url=" + url);
}
url = getCleanUrl(service, url, linkType);
@@ -268,7 +284,7 @@ public class NavigationHelper {
return rIntent;
}
- private static String getCleanUrl(StreamingService service, String dirtyUrl, StreamingService.LinkType linkType) throws Exception {
+ private static String getCleanUrl(StreamingService service, String dirtyUrl, StreamingService.LinkType linkType) throws ExtractionException {
switch (linkType) {
case STREAM:
return service.getStreamUrlIdHandler().cleanUrl(dirtyUrl);
@@ -281,4 +297,55 @@ public class NavigationHelper {
}
return null;
}
+
+
+ private static Uri openMarketUrl(String packageName) {
+ return Uri.parse("market://details")
+ .buildUpon()
+ .appendQueryParameter("id", packageName)
+ .build();
+ }
+
+ private static Uri getGooglePlayUrl(String packageName) {
+ return Uri.parse("https://play.google.com/store/apps/details")
+ .buildUpon()
+ .appendQueryParameter("id", packageName)
+ .build();
+ }
+
+ private static void installApp(Context context, String packageName) {
+ try {
+ // Try market:// scheme
+ context.startActivity(new Intent(Intent.ACTION_VIEW, openMarketUrl(packageName)));
+ } catch (ActivityNotFoundException e) {
+ // Fall back to google play URL (don't worry F-Droid can handle it :)
+ context.startActivity(new Intent(Intent.ACTION_VIEW, getGooglePlayUrl(packageName)));
+ }
+ }
+
+ /**
+ * Start an activity to install Kore
+ * @param context the context
+ */
+ public static void installKore(Context context) {
+ installApp(context, context.getString(R.string.kore_package));
+ }
+
+ /**
+ * Start Kore app to show a video on Kodi
+ *
+ * For a list of supported urls see the
+ *
+ * Kore source code
+ * .
+ *
+ * @param context the context to use
+ * @param videoURL the url to the video
+ */
+ public static void playWithKore(Context context, Uri videoURL) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setPackage(context.getString(R.string.kore_package));
+ intent.setData(videoURL);
+ context.startActivity(intent);
+ }
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/ServiceIconMapper.java b/app/src/main/java/org/schabi/newpipe/util/ServiceIconMapper.java
new file mode 100644
index 000000000..060013dd2
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/util/ServiceIconMapper.java
@@ -0,0 +1,35 @@
+package org.schabi.newpipe.util;
+
+import org.schabi.newpipe.R;
+import org.schabi.newpipe.extractor.NewPipe;
+
+/**
+ * Created by Chrsitian Schabesberger on 09.10.17.
+ * ServiceIconMapper.java is part of NewPipe.
+ *
+ * NewPipe is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NewPipe is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NewPipe. If not, see .
+ */
+
+public class ServiceIconMapper {
+ public static int getIconResource(int service_id) {
+ switch(service_id) {
+ case 0:
+ return R.drawable.youtube;
+ case 1:
+ return R.drawable.soud_cloud;
+ default:
+ return R.drawable.service;
+ }
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/util/StateSaver.java b/app/src/main/java/org/schabi/newpipe/util/StateSaver.java
index bd268abf7..51dceddf3 100644
--- a/app/src/main/java/org/schabi/newpipe/util/StateSaver.java
+++ b/app/src/main/java/org/schabi/newpipe/util/StateSaver.java
@@ -21,6 +21,7 @@ package org.schabi.newpipe.util;
import android.content.Context;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -29,6 +30,7 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
+import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.MainActivity;
import java.io.File;
@@ -110,6 +112,7 @@ public class StateSaver {
/**
* Try to restore the state from memory and disk, using the {@link StateSaver.WriteRead#readFrom(Queue)} from the writeRead.
*/
+ @Nullable
private static SavedState tryToRestore(@NonNull SavedState savedState, @NonNull WriteRead writeRead) {
if (MainActivity.DEBUG) {
Log.d(TAG, "tryToRestore() called with: savedState = [" + savedState + "], writeRead = [" + writeRead + "]");
@@ -117,7 +120,7 @@ public class StateSaver {
FileInputStream fileInputStream = null;
try {
- Queue savedObjects = stateObjectsHolder.remove(savedState.prefixFileSaved);
+ Queue savedObjects = stateObjectsHolder.remove(savedState.getPrefixFileSaved());
if (savedObjects != null) {
writeRead.readFrom(savedObjects);
if (MainActivity.DEBUG) {
@@ -126,8 +129,13 @@ public class StateSaver {
return savedState;
}
- File file = new File(savedState.pathFileSaved);
- if (!file.exists()) return null;
+ File file = new File(savedState.getPathFileSaved());
+ if (!file.exists()) {
+ if(MainActivity.DEBUG) {
+ Log.d(TAG, "Cache file doesn't exist: " + file.getAbsolutePath());
+ }
+ return null;
+ }
fileInputStream = new FileInputStream(file);
ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
@@ -139,7 +147,7 @@ public class StateSaver {
return savedState;
} catch (Exception e) {
- e.printStackTrace();
+ Log.e(TAG, "Failed to restore state", e);
} finally {
if (fileInputStream != null) {
try {
@@ -154,10 +162,17 @@ public class StateSaver {
/**
* @see #tryToSave(boolean, String, String, WriteRead)
*/
+ @Nullable
public static SavedState tryToSave(boolean isChangingConfig, @Nullable SavedState savedState, Bundle outState, WriteRead writeRead) {
- String currentSavedPrefix = savedState == null || TextUtils.isEmpty(savedState.prefixFileSaved)
- ? System.nanoTime() - writeRead.hashCode() + ""
- : savedState.prefixFileSaved;
+ @NonNull
+ String currentSavedPrefix;
+ if (savedState == null || TextUtils.isEmpty(savedState.getPrefixFileSaved())) {
+ // Generate unique prefix
+ currentSavedPrefix = System.nanoTime() - writeRead.hashCode() + "";
+ } else {
+ // Reuse prefix
+ currentSavedPrefix = savedState.getPrefixFileSaved();
+ }
savedState = tryToSave(isChangingConfig, currentSavedPrefix, writeRead.generateSuffix(), writeRead);
if (savedState != null) {
@@ -173,22 +188,33 @@ public class StateSaver {
* to the file with the name of prefixFileName + suffixFileName, in a cache folder got from the {@link #init(Context)}.
*
* It checks if the file already exists and if it does, just return the path, so a good way to save is:
- *
A fixed prefix for the file
- * A changing suffix
+ *
+ * A fixed prefix for the file
+ * A changing suffix
+ *
+ *
+ * @param isChangingConfig
+ * @param prefixFileName
+ * @param suffixFileName
+ * @param writeRead
*/
+ @Nullable
private static SavedState tryToSave(boolean isChangingConfig, final String prefixFileName, String suffixFileName, WriteRead writeRead) {
if (MainActivity.DEBUG) {
Log.d(TAG, "tryToSave() called with: isChangingConfig = [" + isChangingConfig + "], prefixFileName = [" + prefixFileName + "], suffixFileName = [" + suffixFileName + "], writeRead = [" + writeRead + "]");
}
- Queue savedObjects = new LinkedList<>();
+ LinkedList savedObjects = new LinkedList<>();
writeRead.writeTo(savedObjects);
if (isChangingConfig) {
if (savedObjects.size() > 0) {
stateObjectsHolder.put(prefixFileName, savedObjects);
return new SavedState(prefixFileName, "");
- } else return null;
+ } else {
+ if(MainActivity.DEBUG) Log.d(TAG, "Nothing to save");
+ return null;
+ }
}
FileOutputStream fileOutputStream = null;
@@ -197,8 +223,12 @@ public class StateSaver {
if (!cacheDir.exists()) throw new RuntimeException("Cache dir does not exist > " + cacheDirPath);
cacheDir = new File(cacheDir, CACHE_DIR_NAME);
if (!cacheDir.exists()) {
- boolean mkdirResult = cacheDir.mkdir();
- if (!mkdirResult) return null;
+ if(!cacheDir.mkdir()) {
+ if(BuildConfig.DEBUG) {
+ Log.e(TAG, "Failed to create cache directory " + cacheDir.getAbsolutePath());
+ }
+ return null;
+ }
}
if (TextUtils.isEmpty(suffixFileName)) suffixFileName = ".cache";
@@ -214,7 +244,9 @@ public class StateSaver {
return name.contains(prefixFileName);
}
});
- for (File file1 : files) file1.delete();
+ for (File fileToDelete : files) {
+ fileToDelete.delete();
+ }
}
fileOutputStream = new FileOutputStream(file);
@@ -223,7 +255,7 @@ public class StateSaver {
return new SavedState(prefixFileName, file.getAbsolutePath());
} catch (Exception e) {
- e.printStackTrace();
+ Log.e(TAG, "Failed to save state", e);
} finally {
if (fileOutputStream != null) {
try {
@@ -241,11 +273,11 @@ public class StateSaver {
public static void onDestroy(SavedState savedState) {
if (MainActivity.DEBUG) Log.d(TAG, "onDestroy() called with: savedState = [" + savedState + "]");
- if (savedState != null && !TextUtils.isEmpty(savedState.pathFileSaved)) {
- stateObjectsHolder.remove(savedState.prefixFileSaved);
+ if (savedState != null && !TextUtils.isEmpty(savedState.getPathFileSaved())) {
+ stateObjectsHolder.remove(savedState.getPrefixFileSaved());
try {
//noinspection ResultOfMethodCallIgnored
- new File(savedState.pathFileSaved).delete();
+ new File(savedState.getPathFileSaved()).delete();
} catch (Exception ignored) {
}
}
@@ -271,9 +303,12 @@ public class StateSaver {
// Inner
//////////////////////////////////////////////////////////////////////////*/
+ /**
+ * Information about the saved state on the disk
+ */
public static class SavedState implements Parcelable {
- public String prefixFileSaved;
- public String pathFileSaved;
+ private final String prefixFileSaved;
+ private final String pathFileSaved;
public SavedState(String prefixFileSaved, String pathFileSaved) {
this.prefixFileSaved = prefixFileSaved;
@@ -287,7 +322,7 @@ public class StateSaver {
@Override
public String toString() {
- return prefixFileSaved + " > " + pathFileSaved;
+ return getPrefixFileSaved() + " > " + getPathFileSaved();
}
@Override
@@ -313,6 +348,22 @@ public class StateSaver {
return new SavedState[size];
}
};
+
+ /**
+ * Get the prefix of the saved file
+ * @return the file prefix
+ */
+ public String getPrefixFileSaved() {
+ return prefixFileSaved;
+ }
+
+ /**
+ * Get the path to the saved file
+ * @return the path to the saved file
+ */
+ public String getPathFileSaved() {
+ return pathFileSaved;
+ }
}
diff --git a/app/src/main/java/us/shandian/giga/get/DownloadManagerImpl.java b/app/src/main/java/us/shandian/giga/get/DownloadManagerImpl.java
index 479a5cee3..acbd41680 100755
--- a/app/src/main/java/us/shandian/giga/get/DownloadManagerImpl.java
+++ b/app/src/main/java/us/shandian/giga/get/DownloadManagerImpl.java
@@ -101,6 +101,18 @@ public class DownloadManagerImpl implements DownloadManager {
}
+ /**
+ * Sort a list of mission by its timestamp. Oldest first
+ * @param missions the missions to sort
+ */
+ static void sortByTimestamp(List missions) {
+ Collections.sort(missions, new Comparator() {
+ @Override
+ public int compare(DownloadMission o1, DownloadMission o2) {
+ return Long.valueOf(o1.timestamp).compareTo(o2.timestamp);
+ }
+ });
+ }
/**
* Loads finished missions from the data source
@@ -111,12 +123,8 @@ public class DownloadManagerImpl implements DownloadManager {
finishedMissions = new ArrayList<>();
}
// Ensure its sorted
- Collections.sort(finishedMissions, new Comparator() {
- @Override
- public int compare(DownloadMission o1, DownloadMission o2) {
- return (int) (o1.timestamp - o2.timestamp);
- }
- });
+ sortByTimestamp(finishedMissions);
+
mMissions.ensureCapacity(mMissions.size() + finishedMissions.size());
for (DownloadMission mission : finishedMissions) {
File downloadedFile = mission.getDownloadedFile();
diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java
index d60ae86ab..50975728f 100755
--- a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java
+++ b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java
@@ -6,8 +6,8 @@ import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
@@ -15,7 +15,6 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.support.v4.app.NotificationCompat.Builder;
-import android.support.v4.content.ContextCompat;
import android.support.v4.content.PermissionChecker;
import android.util.Log;
import android.widget.Toast;
@@ -96,12 +95,12 @@ public class DownloadManagerService extends Service {
openDownloadListIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
- Drawable icon = ContextCompat.getDrawable(this, R.mipmap.ic_launcher);
+ Bitmap iconBitmap = BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher);
Builder builder = new Builder(this, getString(R.string.notification_channel_id))
.setContentIntent(pendingIntent)
.setSmallIcon(android.R.drawable.stat_sys_download)
- .setLargeIcon(((BitmapDrawable) icon).getBitmap())
+ .setLargeIcon(iconBitmap)
.setContentTitle(getString(R.string.msg_running))
.setContentText(getString(R.string.msg_running_detail));
diff --git a/app/src/main/res/drawable-hdpi/ic_channel_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_channel_black_24dp.png
new file mode 100644
index 000000000..ac66a3b86
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_channel_black_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_channel_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_channel_white_24dp.png
new file mode 100644
index 000000000..e0ef2a1a8
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_channel_white_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_drag_handle_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_drag_handle_black_24dp.png
new file mode 100644
index 000000000..7ebc39358
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_drag_handle_black_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_drag_handle_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_drag_handle_white_24dp.png
new file mode 100644
index 000000000..8747b9ecb
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_drag_handle_white_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_fiber_manual_record_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_fiber_manual_record_black_24dp.png
new file mode 100644
index 000000000..459eec3fe
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_fiber_manual_record_black_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_fiber_manual_record_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_fiber_manual_record_white_24dp.png
new file mode 100644
index 000000000..2c476010b
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_fiber_manual_record_white_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_shuffle_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_shuffle_white_24dp.png
new file mode 100644
index 000000000..ab55a83f4
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_shuffle_white_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_whatshot_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_whatshot_black_24dp.png
new file mode 100644
index 000000000..b2db5994c
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_whatshot_black_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_whatshot_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_whatshot_white_24dp.png
new file mode 100644
index 000000000..46ed1f8b6
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_whatshot_white_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_channel_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_channel_black_24dp.png
new file mode 100644
index 000000000..984ff498e
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_channel_black_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_channel_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_channel_white_24dp.png
new file mode 100644
index 000000000..68f6ffd7f
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_channel_white_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_drag_handle_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_drag_handle_black_24dp.png
new file mode 100644
index 000000000..e09d492fc
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_drag_handle_black_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_drag_handle_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_drag_handle_white_24dp.png
new file mode 100644
index 000000000..e509264d3
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_drag_handle_white_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_fiber_manual_record_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_fiber_manual_record_black_24dp.png
new file mode 100644
index 000000000..cfc8b4e60
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_fiber_manual_record_black_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_fiber_manual_record_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_fiber_manual_record_white_24dp.png
new file mode 100644
index 000000000..f6f53a154
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_fiber_manual_record_white_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_shuffle_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_shuffle_white_24dp.png
new file mode 100644
index 000000000..d13a258a3
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_shuffle_white_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_whatshot_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_whatshot_black_24dp.png
new file mode 100644
index 000000000..31b1981f0
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_whatshot_black_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_whatshot_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_whatshot_white_24dp.png
new file mode 100644
index 000000000..4cf6f85f8
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_whatshot_white_24dp.png differ
diff --git a/app/src/main/res/drawable-nodpi/service.png b/app/src/main/res/drawable-nodpi/service.png
new file mode 100644
index 000000000..cfaff19e2
Binary files /dev/null and b/app/src/main/res/drawable-nodpi/service.png differ
diff --git a/app/src/main/res/drawable-nodpi/soud_cloud.png b/app/src/main/res/drawable-nodpi/soud_cloud.png
new file mode 100644
index 000000000..0fa6045d5
Binary files /dev/null and b/app/src/main/res/drawable-nodpi/soud_cloud.png differ
diff --git a/app/src/main/res/drawable-nodpi/youtube.png b/app/src/main/res/drawable-nodpi/youtube.png
new file mode 100644
index 000000000..82aa58ff1
Binary files /dev/null and b/app/src/main/res/drawable-nodpi/youtube.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_channel_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_channel_black_24dp.png
new file mode 100644
index 000000000..0851f1738
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_channel_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_channel_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_channel_white_24dp.png
new file mode 100644
index 000000000..2f0f6c5fd
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_channel_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_drag_handle_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_drag_handle_black_24dp.png
new file mode 100644
index 000000000..906f5eee0
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_drag_handle_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_drag_handle_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_drag_handle_white_24dp.png
new file mode 100644
index 000000000..aa1547b04
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_drag_handle_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_fiber_manual_record_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_fiber_manual_record_black_24dp.png
new file mode 100644
index 000000000..3eb79e4c1
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_fiber_manual_record_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_fiber_manual_record_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_fiber_manual_record_white_24dp.png
new file mode 100644
index 000000000..0fa16b016
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_fiber_manual_record_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_shuffle_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_shuffle_white_24dp.png
new file mode 100644
index 000000000..66c15ce62
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_shuffle_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_whatshot_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_whatshot_black_24dp.png
new file mode 100644
index 000000000..e9ae82670
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_whatshot_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_whatshot_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_whatshot_white_24dp.png
new file mode 100644
index 000000000..3651d061a
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_whatshot_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_channel_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_channel_black_24dp.png
new file mode 100644
index 000000000..4861728c4
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_channel_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_channel_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_channel_white_24dp.png
new file mode 100644
index 000000000..2fd740ee8
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_channel_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_drag_handle_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_drag_handle_black_24dp.png
new file mode 100644
index 000000000..71da19a59
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_drag_handle_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_drag_handle_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_drag_handle_white_24dp.png
new file mode 100644
index 000000000..e91ef07e9
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_drag_handle_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_fiber_manual_record_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_fiber_manual_record_black_24dp.png
new file mode 100644
index 000000000..b53beb106
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_fiber_manual_record_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_fiber_manual_record_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_fiber_manual_record_white_24dp.png
new file mode 100644
index 000000000..422487473
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_fiber_manual_record_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_shuffle_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_shuffle_white_24dp.png
new file mode 100644
index 000000000..dc8e5341b
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_shuffle_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_whatshot_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_whatshot_black_24dp.png
new file mode 100644
index 000000000..a14dcd695
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_whatshot_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_whatshot_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_whatshot_white_24dp.png
new file mode 100644
index 000000000..8eaf3755d
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_whatshot_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_channel_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_channel_black_24dp.png
new file mode 100644
index 000000000..2ff64b449
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_channel_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_channel_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_channel_white_24dp.png
new file mode 100644
index 000000000..9384592d6
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_channel_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_drag_handle_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_drag_handle_black_24dp.png
new file mode 100644
index 000000000..d102adeb2
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_drag_handle_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_drag_handle_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_drag_handle_white_24dp.png
new file mode 100644
index 000000000..122690738
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_drag_handle_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_fiber_manual_record_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_fiber_manual_record_black_24dp.png
new file mode 100644
index 000000000..eff1e3594
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_fiber_manual_record_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_fiber_manual_record_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_fiber_manual_record_white_24dp.png
new file mode 100644
index 000000000..591b54a57
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_fiber_manual_record_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_shuffle_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_shuffle_white_24dp.png
new file mode 100644
index 000000000..e24dfa3b0
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_shuffle_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_whatshot_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_whatshot_black_24dp.png
new file mode 100644
index 000000000..8f03a95c7
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_whatshot_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_whatshot_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_whatshot_white_24dp.png
new file mode 100644
index 000000000..5c5d86873
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_whatshot_white_24dp.png differ
diff --git a/app/src/main/res/drawable/dark_selector.xml b/app/src/main/res/drawable/dark_selector.xml
new file mode 100644
index 000000000..eb658e16d
--- /dev/null
+++ b/app/src/main/res/drawable/dark_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/light_selector.xml b/app/src/main/res/drawable/light_selector.xml
new file mode 100644
index 000000000..63f2ccaf3
--- /dev/null
+++ b/app/src/main/res/drawable/light_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/activity_player_queue_control.xml b/app/src/main/res/layout-land/activity_player_queue_control.xml
new file mode 100644
index 000000000..a577b7fe0
--- /dev/null
+++ b/app/src/main/res/layout-land/activity_player_queue_control.xml
@@ -0,0 +1,300 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_history.xml b/app/src/main/res/layout/activity_history.xml
index 7076eb34f..e53b9bff9 100644
--- a/app/src/main/res/layout/activity_history.xml
+++ b/app/src/main/res/layout/activity_history.xml
@@ -13,7 +13,6 @@
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="@dimen/appbar_padding_top"
android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.ActionBar">
diff --git a/app/src/main/res/layout/activity_main_player.xml b/app/src/main/res/layout/activity_main_player.xml
index e3ef022f9..5c6349c35 100644
--- a/app/src/main/res/layout/activity_main_player.xml
+++ b/app/src/main/res/layout/activity_main_player.xml
@@ -1,9 +1,10 @@
-
@@ -11,6 +12,7 @@
android:id="@+id/aspectRatioLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_centerInParent="true"
android:layout_gravity="center">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -94,10 +178,15 @@
android:id="@+id/channelTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:ellipsize="end"
- android:maxLines="1"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:scrollHorizontally="true"
+ android:singleLine="true"
android:textColor="@android:color/white"
android:textSize="12sp"
+ android:clickable="true"
+ android:focusable="true"
tools:text="The Video Artist LONG very LONG very Long"/>
@@ -135,26 +224,28 @@
android:layout_height="35dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
- android:layout_toLeftOf="@+id/repeatButton"
+ android:layout_toLeftOf="@+id/queueButton"
android:background="#00ffffff"
android:clickable="true"
+ android:focusable="true"
android:padding="8dp"
android:scaleType="fitXY"
android:src="@drawable/ic_screen_rotation_white"
tools:ignore="ContentDescription,RtlHardcoded"/>
@@ -223,11 +315,45 @@
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
- android:background="#00000000"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitXY"
android:src="@drawable/ic_pause_white"
tools:ignore="ContentDescription"/>
+
+
+
+
@@ -328,4 +454,4 @@
tools:visibility="visible"/>
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_player_queue_control.xml b/app/src/main/res/layout/activity_player_queue_control.xml
new file mode 100644
index 000000000..a59e5ba2e
--- /dev/null
+++ b/app/src/main/res/layout/activity_player_queue_control.xml
@@ -0,0 +1,289 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_blank.xml b/app/src/main/res/layout/fragment_blank.xml
index ad91b1d1d..d1167d722 100644
--- a/app/src/main/res/layout/fragment_blank.xml
+++ b/app/src/main/res/layout/fragment_blank.xml
@@ -16,4 +16,10 @@
android:layout_marginTop="50dp"
android:visibility="gone" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_channel.xml b/app/src/main/res/layout/fragment_channel.xml
index 460f95a7a..67691fc81 100644
--- a/app/src/main/res/layout/fragment_channel.xml
+++ b/app/src/main/res/layout/fragment_channel.xml
@@ -62,4 +62,10 @@
android:visibility="gone"
tools:visibility="visible"/>
+
+
diff --git a/app/src/main/res/layout/fragment_feed.xml b/app/src/main/res/layout/fragment_feed.xml
index 0f2d0b675..0868d8233 100644
--- a/app/src/main/res/layout/fragment_feed.xml
+++ b/app/src/main/res/layout/fragment_feed.xml
@@ -34,4 +34,10 @@
android:visibility="gone"
tools:visibility="visible"/>
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_kiosk.xml b/app/src/main/res/layout/fragment_kiosk.xml
new file mode 100644
index 000000000..4730e66c8
--- /dev/null
+++ b/app/src/main/res/layout/fragment_kiosk.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml
index dac5478ff..b1dd3e20b 100644
--- a/app/src/main/res/layout/fragment_main.xml
+++ b/app/src/main/res/layout/fragment_main.xml
@@ -10,13 +10,14 @@
android:id="@+id/main_tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
+ android:layout_alignParentTop="true"
+ android:background="@color/dark_youtube_primary_color"
app:tabGravity="fill"/>
+ android:layout_below="@id/main_tab_layout"/>
diff --git a/app/src/main/res/layout/fragment_playlist.xml b/app/src/main/res/layout/fragment_playlist.xml
index d5ef26a63..37c609fa4 100644
--- a/app/src/main/res/layout/fragment_playlist.xml
+++ b/app/src/main/res/layout/fragment_playlist.xml
@@ -62,4 +62,10 @@
android:visibility="gone"
tools:visibility="visible"/>
+
+
diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml
index 9ba44e76f..d49d23175 100644
--- a/app/src/main/res/layout/fragment_search.xml
+++ b/app/src/main/res/layout/fragment_search.xml
@@ -51,6 +51,25 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_subscription.xml b/app/src/main/res/layout/fragment_subscription.xml
index 35cfbfeb7..e0d0348dc 100644
--- a/app/src/main/res/layout/fragment_subscription.xml
+++ b/app/src/main/res/layout/fragment_subscription.xml
@@ -35,4 +35,10 @@
android:visibility="gone"
tools:visibility="visible"/>
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml
index 4cafbcf9a..8c445adcd 100644
--- a/app/src/main/res/layout/fragment_video_detail.xml
+++ b/app/src/main/res/layout/fragment_video_detail.xml
@@ -28,6 +28,7 @@
android:layout_height="wrap_content"
android:background="@android:color/black"
android:clickable="true"
+ android:focusable="true"
android:foreground="?attr/selectableItemBackground">
+
@@ -68,6 +86,7 @@
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
+ android:focusable="true"
android:paddingLeft="12dp"
android:paddingRight="12dp">
@@ -223,10 +242,12 @@
android:layout_width="80dp"
android:layout_height="55dp"
android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_gravity="center_vertical"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
+ android:focusable="true"
android:contentDescription="@string/open_in_popup_mode"
android:drawableTop="?attr/popup"
android:gravity="center"
@@ -242,8 +263,10 @@
android:layout_alignParentTop="true"
android:layout_gravity="center_vertical"
android:layout_toLeftOf="@id/detail_controls_popup"
+ android:layout_toStartOf="@id/detail_controls_popup"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
+ android:focusable="true"
android:contentDescription="@string/play_audio"
android:drawableTop="?attr/audio"
android:gravity="center"
diff --git a/app/src/main/res/layout/item_search_suggestion.xml b/app/src/main/res/layout/item_search_suggestion.xml
new file mode 100644
index 000000000..b230f6da0
--- /dev/null
+++ b/app/src/main/res/layout/item_search_suggestion.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/play_queue_item.xml b/app/src/main/res/layout/play_queue_item.xml
new file mode 100644
index 000000000..4d5a6fbd4
--- /dev/null
+++ b/app/src/main/res/layout/play_queue_item.xml
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/player_notification.xml b/app/src/main/res/layout/player_notification.xml
index 958b9bf3d..157615bb7 100644
--- a/app/src/main/res/layout/player_notification.xml
+++ b/app/src/main/res/layout/player_notification.xml
@@ -12,6 +12,7 @@
android:layout_height="64dp"
android:background="@color/background_notification_color"
android:clickable="true"
+ android:focusable="true"
android:gravity="center_vertical"
android:orientation="horizontal">
@@ -58,6 +59,7 @@
android:layout_height="match_parent"
android:background="#00000000"
android:clickable="true"
+ android:focusable="true"
android:padding="5dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_repeat_white"
@@ -69,9 +71,10 @@
android:layout_height="match_parent"
android:background="#00000000"
android:clickable="true"
+ android:focusable="true"
android:padding="5dp"
android:scaleType="fitCenter"
- android:src="@drawable/ic_action_av_fast_rewind"
+ android:src="@drawable/exo_controls_previous"
tools:ignore="ContentDescription"/>
@@ -89,9 +93,10 @@
android:layout_height="match_parent"
android:background="#00000000"
android:clickable="true"
+ android:focusable="true"
android:padding="5dp"
android:scaleType="fitCenter"
- android:src="@drawable/ic_action_av_fast_forward"
+ android:src="@drawable/exo_controls_next"
tools:ignore="ContentDescription"/>
@@ -26,6 +27,7 @@
android:layout_alignParentRight="true"
android:background="#00000000"
android:clickable="true"
+ android:focusable="true"
android:padding="8dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_close_white_24dp"
@@ -82,9 +84,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
android:layout_marginTop="2dp"
android:layout_alignTop="@+id/notificationProgressBar"
android:layout_toRightOf="@+id/notificationCover"
+ android:layout_toEndOf="@+id/notificationCover"
android:ellipsize="end"
android:maxLines="1"
android:textSize="12sp"
@@ -109,6 +113,7 @@
android:layout_centerVertical="true"
android:background="#00000000"
android:clickable="true"
+ android:focusable="true"
android:scaleType="fitXY"
android:src="@drawable/ic_repeat_white"
tools:ignore="ContentDescription"/>
@@ -122,9 +127,10 @@
android:layout_toLeftOf="@+id/notificationPlayPause"
android:background="#00000000"
android:clickable="true"
+ android:focusable="true"
android:padding="2dp"
android:scaleType="fitCenter"
- android:src="@drawable/ic_action_av_fast_rewind"
+ android:src="@drawable/exo_controls_previous"
tools:ignore="ContentDescription"/>
@@ -150,107 +157,10 @@
android:layout_marginRight="8dp"
android:background="#00000000"
android:clickable="true"
+ android:focusable="true"
android:padding="2dp"
android:scaleType="fitCenter"
- android:src="@drawable/ic_action_av_fast_forward"
+ android:src="@drawable/exo_controls_next"
tools:ignore="ContentDescription"/>
-
-
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/player_popup_notification.xml b/app/src/main/res/layout/player_popup_notification.xml
index 4010064d9..ab436a1fa 100644
--- a/app/src/main/res/layout/player_popup_notification.xml
+++ b/app/src/main/res/layout/player_popup_notification.xml
@@ -7,6 +7,7 @@
android:layout_height="64dp"
android:background="@color/background_notification_color"
android:clickable="true"
+ android:focusable="true"
android:gravity="center_vertical"
android:orientation="horizontal">
@@ -54,6 +55,7 @@
android:layout_height="match_parent"
android:background="#00000000"
android:clickable="true"
+ android:focusable="true"
android:padding="5dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_repeat_white"
@@ -65,6 +67,7 @@
android:layout_height="match_parent"
android:background="#00000000"
android:clickable="true"
+ android:focusable="true"
android:src="@drawable/ic_pause_white"
tools:ignore="ContentDescription"/>
@@ -75,6 +78,7 @@
android:layout_marginLeft="5dp"
android:background="#00000000"
android:clickable="true"
+ android:focusable="true"
android:padding="5dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_close_white_24dp"
diff --git a/app/src/main/res/layout/playlist_header.xml b/app/src/main/res/layout/playlist_header.xml
index 192363359..0f129672d 100644
--- a/app/src/main/res/layout/playlist_header.xml
+++ b/app/src/main/res/layout/playlist_header.xml
@@ -20,62 +20,125 @@
android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="@dimen/playlist_detail_title_text_size"
- tools:text="Mix musics #23 title Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blanditLorem ipsumLorem ipsumLorem ipsumLorem ipsumLorem ipsumLorem ipsumLorem ipsum"/>
+ tools:text="Mix musics #23 title Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blanditLorem ipsumLorem ipsumLorem ipsumLorem ipsumLorem ipsumLorem ipsumLorem ipsum" />
+ android:id="@+id/playlist_meta">
+
-
+
+
+
+
+ tools:text="234 videos"/>
+
-
+ android:id="@+id/play_control"
+ android:paddingLeft="5dp"
+ android:paddingRight="5dp"
+ android:layout_below="@+id/playlist_meta">
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/select_channel_fragment.xml b/app/src/main/res/layout/select_channel_fragment.xml
new file mode 100644
index 000000000..11c723b4b
--- /dev/null
+++ b/app/src/main/res/layout/select_channel_fragment.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/select_channel_item.xml b/app/src/main/res/layout/select_channel_item.xml
new file mode 100644
index 000000000..09602a371
--- /dev/null
+++ b/app/src/main/res/layout/select_channel_item.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/select_kiosk_fragment.xml b/app/src/main/res/layout/select_kiosk_fragment.xml
new file mode 100644
index 000000000..8e376742b
--- /dev/null
+++ b/app/src/main/res/layout/select_kiosk_fragment.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/select_kiosk_item.xml b/app/src/main/res/layout/select_kiosk_item.xml
new file mode 100644
index 000000000..2efadca79
--- /dev/null
+++ b/app/src/main/res/layout/select_kiosk_item.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/toolbar_layout.xml b/app/src/main/res/layout/toolbar_layout.xml
index 36ab6454e..096974c03 100644
--- a/app/src/main/res/layout/toolbar_layout.xml
+++ b/app/src/main/res/layout/toolbar_layout.xml
@@ -36,9 +36,4 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/toolbar_search_layout.xml b/app/src/main/res/layout/toolbar_search_layout.xml
index 7780a0226..797eea48e 100644
--- a/app/src/main/res/layout/toolbar_search_layout.xml
+++ b/app/src/main/res/layout/toolbar_search_layout.xml
@@ -4,16 +4,9 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary"
- android:focusable="true"
- android:focusableInTouchMode="true">
+ android:background="?attr/colorPrimary">
-
-
-
+ android:title="@string/action_about"/>
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_play_queue.xml b/app/src/main/res/menu/menu_play_queue.xml
new file mode 100644
index 000000000..8fd0c9b6b
--- /dev/null
+++ b/app/src/main/res/menu/menu_play_queue.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 000000000..80b730f36
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 000000000..a95153a1f
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 000000000..bccfaff0e
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 000000000..65ced7a8b
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 000000000..b7b42cbff
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 000000000..4ce448946
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index fc3706bba..004fe64ec 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -1,63 +1,112 @@
-
-
- جاري التشغيل في الخلفية
- إلغاء
- إختر متصفح
- مظلم
- صيغة الصوت الإفتراضية
- الدقة الإفتراضية
- عدم الإعجاب
- الإعجابات
- صور معاينة الفيديو
- "Uploader's userpic thumbnail"
- هل تقصد:
- تنزيل
- تنزيل
- أدخل مسار التنزيل للملفات الصوتية.
- مسار حفظ التنزيلات الصوتية في.
- مسار الصوتيات المحفوظة
- أدخل مسار التنزيل لملفات الفيديو
- مسار حفظ تنزيلات الفيديو في.
- مسار الفيديوهات المحفوظة
- "لا يمكن إنشاء مجلد للتنزيلات في '%1$s'"
- "تم إنشاء مجلد تنزيلات في '%1$s'"
- تثبيت
- تطبيق Kore غير موجود. هل تريد تثبيته؟
- مضيء
- صور معاينة الفيديو
- m4a — جودة أفضل
- خطأ في الشبكة
- الفيديو التالي
- لا يوجد مشغل فيديو. هل تريد تثبيت VLC ؟
- فتح في المتصفح
- صوت
- تشغيل
- تشغيل بواسطة Kodi
- تدوير
- بحث
- لغة المحتوى المفضل
- الإعدادات
- المظهر
- تعريب JetSub مدونة درويديات
- الفيديو والصوتيات
- مشاركة
- مشاركة بواسطة
- عرض التالي والفيديوهات المشابهة
- عرض خيار لتشغيل الفيديو بواسطة Kodi Media Center.
- عرض خيار التشغيل بواسطة Kodi.
- الثيم
- تم الرفع في %1$s
- الرابط غير مدعوم
- استخدام مشغل صوتيات خارجي
- استخدام مشغل فيديو خارجي
- إجراء التنزيلات من خلال استخدام بروكسي Tor لزيادة الخصوصية ( تشغيل الفيديو المباشر غير مدعوم حتى الأن )
- استخدام Tor
- %1$s المشاهدات
- WebM
- Blocked by GEMA.
- المحتوى غير متاح.
- لم يتمكن من تحميل كل صور المعاينة
- خطأ
- لا يمكن تحليل الموقع.
- لا يمكن فك تشفير توقيع رابط الفيديو.
-
+
+
+ جاري التشغيل في الخلفية
+ إلغاء
+ إختر متصفح
+ مظلم
+ صيغة الصوت الإفتراضية
+ الدقة الإفتراضية
+ عدم الإعجاب
+ الإعجابات
+ صور معاينة الفيديو
+ "Uploader's userpic thumbnail"
+ هل تقصد : %1$s ؟
+ تنزيل
+ تنزيل
+ أدخل مسار لتنزيل الملفات الصوتية.
+ مسار حفظ التنزيلات الصوتية
+ مسار الصوتيات المحفوظة
+ أدخل مسار التنزيل لملفات الفيديو
+ مسار حفظ تنزيلات الفيديو في
+ مسار تحميل الفيديو
+ "لا يمكن إنشاء مجلد للتنزيلات في '%1$s'"
+ "تم إنشاء مجلد تنزيلات في '%1$s'"
+ تثبيت
+ تطبيق Kore غير موجود. هل تريد تثبيته؟
+ مضيء
+ صور معاينة الفيديو
+ m4a — جودة أفضل
+ خطأ في الشبكة
+ الفيديو التالي
+ لا يوجد مشغل فيديو. هل تريد تثبيت VLC ؟
+ فتح في المتصفح
+ صوت
+ تشغيل
+ تشغيل بواسطة Kodi
+ تدوير
+ بحث
+ لغة المحتوى المفضل
+ الإعدادات
+ المظهر
+ تعريب JetSub مدونة درويديات
+ الفيديو والصوتيات
+ مشاركة
+ مشاركة بواسطة
+ عرض التالي والفيديوهات المشابهة
+ عرض خيار لتشغيل الفيديو بواسطة Kodi Media Center.
+ عرض خيار التشغيل بواسطة Kodi.
+ السمة
+ تم نشرها في %1$s
+ الرابط غير مدعوم
+ استخدام مشغل صوتيات خارجي
+ استخدام مشغل فيديو خارجي
+ إجراء التنزيلات من خلال استخدام بروكسي Tor لزيادة الخصوصية ( تشغيل الفيديو المباشر غير مدعوم حتى الأن )
+ استخدام Tor
+ %1$s المشاهدات
+ WebM
+ Blocked by GEMA.
+ المحتوى غير متاح.
+ لم يتمكن من تحميل كل صور المعاينة
+ خطأ
+ لا يمكن تحليل الموقع.
+ لا يمكن فك تشفير توقيع رابط الفيديو.
+إضغط على البحث للمواصلة
+ إشترك
+ مشترك
+ الرئيسية
+ الإشتراكات
+
+ ما الجديد
+
+ الخلفية
+ التشغيل التلقائي
+ أسود
+ التأريخ
+ التأريخ
+ المحتوى
+ التنزيلات
+ التنزيلات
+ الكل
+ قناة
+ فيديو
+ التنزيل
+ عن التطبيق
+ عن التطبيق
+ التأريخ
+ التأريخ
+ فتح في نوافذ
+ بعض خيارات الجودة لن يكون الصوت عند تمكين هذا الخيار
+ NewPipe وضع النافذة
+ تم إلغاء اشتراك القناة
+ تعذر تغيير في الاشتراك
+ تعذر تحديث الاشتراك
+
+ نافذة
+
+ تشغيل الفيديو تلقائيا عند استدعاء نيوبيب من تطبيق آخر
+ جودة النوافذ الافتراضية
+ إظهار جودة أعلى
+ فقط بعض الأجهزة تدعم تشغيل فيديوهات 2K / 4K
+ تنسيق الفيديو الافتراضي
+ تذكر حجم النافذة و وضعها
+ تذكر آخر حجم ومكان النافذة
+ ضوابط إشارة المشغل
+ استخدم الإشارات للتحكم في سطوع وحجم المشغل
+ اقتراحات البحث
+ عرض الاقتراحات عند البحث
+ سجل البحث
+ تخزين طلبات البحث محليا
+ تتبع مقاطع الفيديو التي تمت مشاهدتها
+ استئناف عند اكساب التركيز
+ متابعة اللعب بعد المقاطعات (مثل المكالمات الهاتفية)
+
diff --git a/app/src/main/res/values-b+ast/strings.xml b/app/src/main/res/values-b+ast/strings.xml
index 58a13dd09..08d209448 100644
--- a/app/src/main/res/values-b+ast/strings.xml
+++ b/app/src/main/res/values-b+ast/strings.xml
@@ -2,7 +2,7 @@
Calca na gueta pa entamar
%1$s visiones
- Espublizáu\'l %1$s
+ Espublizóse\'l %1$s
Nun s\'alcontró un reproductor de fluxos. ¿Quies instalar VLC?
Instalar
Encaboxar
@@ -14,15 +14,15 @@
¿Quixesti dicir %1$s?
Compartir con
Escoyer restolador
- rotación
- Usar reproductor de videu esternu
- Usar reproductor d\'audiu esternu
+ voltéu
+ Usar reproductor esternu de videu
+ Usar reproductor esternu d\'audiu
Camín de descarga de vídeos
- Camín nel qu\'atroxar los vídeos baxaos.
+ Camín nel qu\'atroxar los vídeos baxaos
Introducir camín de descarga pa vídeos
- Camín de descarga d\'audiu
+ Camín de descarga p\'audios
Camín nel qu\'atroxar los audios baxaos.
Introducir camín de descarga pa ficheros d\'audiu
@@ -30,11 +30,11 @@
Reproducir con Kodi
Nun s\'alcontró Kore. ¿Instalalu?
Amosar opción «Reproducir con Kodi»
- Amuesa una opción pa reproducir un videu per Kodi.
+ Amuesa una opción pa reproducir un videu per Kodi
Audiu
- Formatu d\'audiu por defeutu
+ Formatu por defeutu d\'audiu
WebM — formatu llibre
- m4a — calidá meyor
+ M4A — calidá meyor
Tema
Escuru
Claru
@@ -43,15 +43,15 @@
Videu siguiente
Amosar vídeos siguientes y asemeyaos
URL non sofitada
- Llingua de conteníu preferíu
+ Llingua por defeutu del conteníu
Videu y audiu
Aspeutu
Otru
Reproduciendo de fondu
Reproducir
Conteníu
- Amosar conteníu restrinxíu pola edá
- El videu ta restrinxíu pola edá. Deshabilita esto diendo primero a axustes.
+ Amosar conteníu torgáu pola edá
+ El videu ta torgáu pola edá. Desactiva esto diendo primero a axustes.
en direuto
Descargues
Descargues
@@ -60,16 +60,16 @@
Fallu
Fallu de rede
Nun pudieron cargase toles miniatures
- Nun pudo descargase la robla de la url del videu.
- Nun pudo analizase\'l sitiu web.
- Nun pudo analizase dafechu\'l sitiu web.
- Conteníu non disponible.
- Bloquiáu por GEMA.
- Nun pudo configurase\'l menú de descarga.
- Esto ye una tresmisión de direuto pero entá nun ta sofitao.
- Nun pudo consiguise tresmisión dala.
+ Nun pudo descifrase la robla de la URL
+ Nun pudo analizase\'l sitiu web
+ Nun pudo analizase dafechu\'l sitiu web
+ Conteníu non disponible
+ Bloquiáu por GEMA
+ Nun pudo configurase\'l menú de descarga
+ Esto ye una tresmisión de direuto qu\'entá nun se sofita.
+ Nun pudo consiguise tresmisión dala
Perdón, eso nun debió asoceder.
- Fallu d\'informe per corréu
+ Informar per corréu del fallu
Perdón, asocedieron dellos fallos.
INFORMAR
Información:
@@ -78,11 +78,11 @@
Detalles:
- Miniatura de previsualización de videu
- Miniatura de previsualización de videu
+ Miniatura de previsualización del videu
+ Miniatura de previsualización del videu
Préstames
Usar Tor
- (Esperimental) Forcia\'l tráficu de descargues pente Tor pa más privacidá (la tresmisión de vídeos entá nun ta sofitao).
+ (Esperimental) Forcia\'l tráficu de descargues pente Tor pa más privacidá (la tresmisión de vídeos entá nun se sofita).
Informa d\'un fallu
Informe d\'usuariu
@@ -92,11 +92,11 @@
Videu
Audiu
Retentar
- Ñegóse l\'accesu al almacenamientu
+ Ñegóse\'l permisu d\'accesu al almacenamientu
Aniciar
Posar
- Ver
+ Reproducir
Desaniciar
Suma de comprobación
@@ -110,23 +110,23 @@
URL malformada o internet non disponible
Calca pa detallles
Espera, por favor…
- Copióse al cartafueyu.
- Esbilla un direutoriu de descarga disponible, por favor.
+ Copióse al cartafueyu
+ Esbilla una carpeta disponible de descarga, por favor
- Auto-reproduz un videu al llamar a NewPipe dende otra aplicación.
- Auto-reproducir al llamar dende otra aplicación
- Miniatura del xubidor
+ Auto-reproduz un videu al llamar a NewPipe dende otra aplicación
+ Auto-reproducción
+ Miniatura del avatar del xubidor
Despréstames
NewPipe baxando
Nun pudo cargase la imaxe
Cascó l\'aplicación/IU
-
+ Lo qu\'asocedió:\\nSolicitú:\\nLlingua del conteníu:\\nServiciu:\\nHora GMT:\\nPaquete:\\nVersión:\\nVersión del SO:\\nRangu global d\'IP:
Abrir en ventanu emerxente
Mou de ventanu emerxente de NewPipe
- Formatu preferíu de videu
+ Formatu por defeutu de videu
Prietu
Reproduciendo en ventanu emerxente
@@ -134,7 +134,7 @@
Canal
Sí
Más sero
- Deshabilitóse
+ Desactivóse
Usar reproductor vieyu
@@ -142,26 +142,26 @@
M
Mill
MMill
- Precísase esti permisu pa
-abrir en ventanu emerxente
+ Precísase esti permisu p\'abrir
+\nen ventanu emerxente
reCAPTCHA
Prueba reCAPTCHA
- Prueba reCAPTCHA solicitada
+ Solicitóse la prueba reCAPTCHA
Fondu
Ventanu emerxente
- Resolución por defeutu de ventanu emerxente
+ Resolución por defeutu del ventanu emerxente
Amosar resoluciones más altes
- Namái dellos preseos sofiten vídeos en 2k/4k
+ Namái dellos preseos sofiten vídeos en 2K/4K
Peñera
Refrescar
Llimpiar
- Delles resoluciones NUN tendrán audiu al habilitar esta opción
- Tamañu y posición del ventanu emerxente
- Recuerda la cabera posición y resolución afitada nel ventanu emerxente
+ Delles resoluciones NUN tendrán audiu al activar esta opción
+ Recuerdar tamañu y posición del ventanu emerxente
+ Recuerda la cabera posición y resolución afitaes nel ventanu emerxente
Controles per xestos del reproductor
Usa xestos pa controlar el brilléu y volume del reproductor
Suxerencies de gueta
@@ -170,5 +170,109 @@ abrir en ventanu emerxente
Ventanu emerxente
Redimensionáu
- Compilación vieya del reproductor Mediaframework.
-
+ Reproductor vieyu integráu de Mediaframework
+Soscribise
+ Soscribiéstite
+ Desoscribiéstite de la canal
+ Nun pue camudase la resolución
+ Nun pue anovase la soscripción
+
+ Principal
+ Soscripciones
+
+ Qué hai nuevo
+
+ Historial de gueta
+ Atroxa de mou llocal les solicitúes de gueta
+ Historial
+ Fai un siguimientu de los vídeos vistos
+ Siguir al ganar el focu
+ Sigue reproduciendo tres les interrupciones (por exemplu, llamaes de teléfonu)
+ Reproductor
+ Comportamientu
+ Historial
+ Llistáu de reproducción
+ La meyor resolución
+ Desfacer
+
+ Avisu de NewPipe
+ Avisos pa los reproductores de fondu y en ventanu emerxente de NewPipe
+
+ Ensin resultaos
+ Equí nun hai más que grillos
+
+ Ensin soscriptores
+
+ - %s soscriptor
+ - %s soscriptores
+
+
+ Ensin visionaos
+
+ - %s visionáu
+ - %s visionaos
+
+
+ Nun hai vídeos
+
+ - %s videu
+ - %s vídeos
+
+
+ Descargues
+ Caráuteres permitíos nos nomes de ficheros
+ Los caráuteres non válidos tróquense por esti valor
+ Troquéu de caráuteres
+
+ Lletres y díxitos
+ La mayoría de caráuteres especiales
+
+ Tocante a NewPipe
+ Axustes
+ Tocante a
+ Llicencies de terceros
+ © %1$s por %2$s so la %3$s
+ Nun pudo cargase la llicencia
+ Abrir sitiu web
+ Tocante a
+ Collaboradores
+ Llicencies
+ Un frontal llixeru de YouTube p\'Android.
+ Ver en GitHub
+ Llicencia de NewPipe
+ Si tienes idees, quies traducir, facer cambeos, llimpiar el códigu u otres coses, l\'ayuda siempres s\'agradez. ¡Cuánto más se faiga, más s\'ameyora!
+ Lleer llicencia
+ Collaboración
+
+ Historial
+ Guetao
+ Visto
+ L\'historial ta desactiváu
+ Historial
+ L\'historial ta baleru
+ Llimpióse l\'historial
+ Desanicióse l\'elementu
+ ¿Quies desaniciar esti elementu del historial de gueta?
+Reproducir too
+
+ Nun pudo reproducise esta tresmisión
+ Asocedió un error irrecuperable del reproductor
+ Recuperándose del error del reproductor
+
+ Conteníu de la páxina principal
+ Páxina en blancu
+ Páxina del quioscu
+ Páxina de suscripción
+ Páxina de fluxu
+ Páxina de canal
+ Seleiciona un canal
+ Entá nun hai canales soscritos
+ Seleiciona un quioscu
+
+ Quioscu
+ Tendencies
+ 50 meyores
+ Reproductor de fondu
+ Desaniciar
+ Detalles
+
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 94f030dfa..085f06ffa 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -17,83 +17,83 @@
Použít externí audio přehrávač
Cesta, kam se uloží stažené audio
- Zadejte umístění pro stažené audio soubory.
+ Zadejte umístění pro stažené audio soubory
Umístění pro stažené audio
Výchozí rozlišení
Přehrát pomocí Kodi
- Aplikace Kore nenalezena. Nainstalovat Kore?
+ Aplikace Kore nenalezena. Chcete ji nainstalovat?
%1$s zhlédnutí
Umístění pro stažené video
- Cesta, kam se uloží stažené video.
+ Cesta, kam se uloží stažené video
Zadejte umístění pro stažená videa
Zobrazit možnost \"Přehrát pomocí Kodi\"
- Zobrazit možnost přehrání videa pomocí multimediálního centra Kodi.
- Audio
- Výchozí audio formát
+ Zobrazit možnost přehrání videa pomocí multimediálního centra Kodi
+ Zvuk
+ Výchozí formát zvuku
WebM — svobodný formát
- m4a — lepší kvalita
+ M4A — lepší kvalita
Téma
Tmavé
Světlé
Stáhnout
- Následující video
- Zobrazit následující a podobná videa
+ Další video
+ Zobrazovat další a podobná videa
URL není podporováno
Preferovaný jazyk obsahu
- Video a audio
+ Video a zvuk
Vzhled
Ostatní
- Přehrávám na pozadí
+ Přehrávání na pozadí
Přehrát
Chyba
Chyba sítě
Nebylo možné nahrát všechny náhledy
- Nebylo možné dekódovat URL videa.
- Nebylo možné analyzovat webovou stránku.
- Obsah není k dispozici.
- Obsah blokuje GEMA.
+ Nebylo možné dekódovat URL videa
+ Nebylo možné analyzovat stránku
+ Obsah není k dispozici
+ Obsah blokuje GEMA
Náhled videa
Náhled videa
- Náhled obrázku uploadera
+ Náhled avataru uploadera
To se mi líbí
To se mi nelíbí
Použít Tor
- (Experimentální) Vynutit stahování skrz Tor pro zvýšené soukromí (streaming zatím není podporován).
+ (Experimentální) Vynutit stahování skrz Tor pro zvýšené soukromí (streamovaná videa zatím nepodporována).
Nebylo možné vytvořit složku pro stažené soubory \'%1$s\'
Vytvořena složka pro stažené soubory \'%1$s\'
- Automaticky přehrávat při otevření z jiné aplikace
- Automaticky přehrát video, když je NewPipe otevřen z jiné aplikace.
+ Automaticky přehrávat
+ Automaticky přehrát video, když je NewPipe otevřen z jiné aplikace
Obsah
Zobrazovat věkově omezený obsah
Toto video je věkově omezeno. Povolte věkově omezená videa v nastavení.
živě
- Nebylo možné kompletně analyzovat stránku.
- Pro začátek stiskni hledat
- Zkopírováno do schránky.
+ Nebylo možné kompletně analyzovat stránku
+ Začni stiskem hledat
+ Zkopírováno do schránky
Počkejte prosím…
- NewPipe se stahuje
- Stiskněte pro detaily
+ NewPipe stahuje
+ Stiskni pro detaily
Server není podporován
Soubor již existuje
- Špatné URL nebo připojení k Internetu není k disposici
+ Špatné URL nebo bez připojení k internetu
Chyba
Jméno souboru
Vlákna
Zastavit
Smazat
- Začít
+ Start
Zkusit znovu
Video
- Audio
+ Zvuk
Nahlásit chybu
- Detaily:
+ Podrobnosti:
Co se stalo:
@@ -104,18 +104,18 @@
Nepodařilo se nahrát obrázek
Aplikace/UI spadlo
Tento stream je vysílán živě, funkce ještě není podporována.
- Nepodařilo se dostat žádný stream.
- Nepodařilo se nastavit menu stahování.
+ Nepodařilo se dostat žádný stream
+ Nepodařilo se nastavit menu stahování
Nahlásit chybu
Stažené soubory
Stažené soubory
Info:
- Vaše poznámky (Anglicky):
- Oprávnění přístupu do Úložiště bylo zamítnuto
- Shlédnout
+ Vaše poznámky (anglicky):
+ Oprávnění přístupu do úložiště bylo zamítnuto
+ Přehrát
Nová mise
- Hotovo
+ OK
reCAPTCHA
Výzva reCAPTCHA
@@ -123,9 +123,9 @@
Černé
- Checksum
+ Kontrolní součet
- Prosím vyberte dostupnou složku pro stažení souborů.
+ Prosím vyberte dostupnou složku pro stažení souborů
Hlášení uživatele
@@ -136,18 +136,154 @@
Později
- k
+ tis.
Otevřít ve vyskakovacím okně
- M
+ mil.
Toto oprávnění je vyžadováno pro
otevření ve vyskakovacím okně
Použít starý přehrávač
Některé formáty rozlišení NEBUDOU obsahovat zvukovou stopu po zapnutí této funkce
- Zobrazit vyšší rozlišení
- Pouze některá zařízení podporují přehrávání videí ve 2K/4K
- Preferovaný video formát
- Zapamatovat si velikost a pozici vyskakovacího okna
- Zapamatovat si poslední nastavení velikosti a pozice vyskakovacího okna
-
+ Zobrazovat vyšší rozlišení
+ Pouze některá zařízení podporují přehrávání 2K/4K videí
+ Výchozí formát videa
+ Pamatovat si velikost a pozici vyskakovacího okna
+ Pamatovat si poslední velikost a pozici vyskakovacího okna
+ NewPipe režim vyskakovacího okna
+ Odebírat
+ Odebíráno
+ Odběr zrušen
+ Nelze změnit odběr
+ Nelze aktualizovat odběr
+
+ Hlavní
+ Odběry
+
+ Co je nového
+
+ Na pozadí
+ V okně
+
+ Výchozí rozlišení vyskakovacího okna
+ Ovládání přehrávače gesty
+ Používat gesta pro nastavení jasu a hlasitosti přehrávače
+ Návrhy vyhledávání
+ Zobrazovat návrhy při vyhledávání
+ Historie vyhledávání
+ Hledané výrazy lokálně uchovávat
+ Historie
+ Evidovat zhlédnutá videa
+ Přehrávat po přechodu do popředí
+ Pokračovat v přehrávání po přerušení (např. hovor)
+ Přehrávač
+ Chování
+ Historie
+ V okně
+ Přehrávání v okně
+ Playlist
+ Vypnuto
+ Filtr
+ Obnovit
+ Vyčistit
+ Změna velikosti
+ Nejlepší rozlišení
+ Vrátit
+
+ NewPipe notifikace
+ Notifikace pro NewPipe v pozadí a v okně
+
+ Žádné výsledky
+ Je tu sranda jak v márnici
+
+ Starý zabudovaný Mediaframework přehrávač
+
+ mld.
+
+ Žádní odběratelé
+
+ - %s odběratel
+ - %s odběratelů
+ - %s odběratelé
+
+
+ Žádná zhlédnutí
+
+ - %s zhlédnutí
+ - %s zhlédnutí
+ - %s zhlédnutí
+
+
+ Žádná videa
+
+ - %s video
+ - %s videí
+ - %s videa
+
+
+ Stahování
+ Povolené znaky v názvech souborů
+ Neplatné znaky budou nahrazeny těmito
+ Náhradní znak
+
+ Písmena a číslice
+ Většina speciálních znaků
+
+ O NewPipe
+ Nastavení
+ O aplikaci
+ Licence třetích stran
+ © %1$s od %2$s pod %3$s
+ Nepodařilo se nahrát licenci
+ Otevřít webstránku
+ O aplikaci
+ Přispěvatelé
+ Licence
+ Bezplatná a nenáročná YouTube aplikace pro Android.
+ Zobraz na GitHubu
+ Licence NewPipe
+ Pokud máte nápady na zlepšení jako; překlad, změny designu, vylepšování kódu nebo opravdu velké změny kódu - pomoc je vždy vítána. Čím více se udělá, tím lepší to bude!
+ Přečíst licenci
+ Příspěvek
+
+ Historie
+ Vyhledáváno
+ Zhlédnuto
+ Historie je vypnutá
+ Historie
+ Historie je prázdná
+ Historie smazána
+ Položka byla odstraněna
+Zobrazovat tip \"Podrž pro přidání\"
+ Zobrazí se po stisku tlačítek přehrát na pozadí nebo v okně na stránce videa
+ Ve frontě přehrávače na pozadí
+ Ve frontě přehrávače v okně
+ Přehrát vše
+
+ Přehrávání streamu selhalo
+ Došlo k neobnovitelné chybě přehrávače
+ Obnovování z chyby přehrávače
+
+ Odstranit tuto položku z historie vyhledávání?
+
+ Obsah úvodní obrazovky
+ Prázdná stránka
+ Kiosek
+ Odběry
+ Novinky
+ Kanál
+ Zvolte kanál
+ Žádný kanál dosud neodebírán
+ Zvolte kiosek
+
+ Kiosek
+ Trendy
+ Top 50
+ Nové & hot
+ Přehrávač na pozadí
+ Přehrávač v okně
+ Odebrat
+ Podrobnosti
+ Nastavení zvuku
+ Podrž pro zařazení do fronty
+
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index e25dc099e..c412ea1d3 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -5,7 +5,7 @@
Keinen Streamplayer gefunden. Möchtest du VLC installieren?
Installieren
Abbrechen
- In Browser öffnen
+ Im Browser öffnen
Teilen
Download
Suchen
@@ -15,7 +15,7 @@
Browser
Rotation
Downloadverzeichnis für Videos
- Verzeichnis in dem heruntergeladene Videos gespeichert werden
+ Verzeichnis für heruntergeladene Videos
Downloadverzeichnis für Videos eingeben
Standardauflösung
Mit Kodi abspielen
@@ -119,7 +119,7 @@
Starten
Pause
- Ansehen
+ Abspielen
Neue Mission
OK
Server nicht unterstützt
@@ -203,7 +203,7 @@
Abo beenden
Abos
- Änderungen
+ Neuigkeiten
Suchverlauf
Speichere den Suchverlauf lokal
@@ -218,7 +218,7 @@
Verlauf bereinigt
Fehler beim Ändern des Abos
- Fehler beim Updaten des Abos
+ Fehler beim Aktualisieren des Abos
Nach Unterbrechungen (z.B. Telefonaten) Wiedergabe fortsetzen
@@ -254,4 +254,38 @@
Die meisten Sonderzeichen
Element gelöscht
+ Fortsetzen bei erneutem Fokussieren
+ Player
+ Nichts hier außer Grillen
+
+ Möchten Sie dieses Element aus dem Suchverlauf löschen?
+Leere Seite
+ Wähle einen Kanal aus
+ Noch kein Kanal abonniert
+ Trends
+ Angereiht an Popup Player
+ Alles abspielen
+
+ Entfernen
+ Audio Einstellungen
+ Abspielen des Streams fehlgeschlagen
+ Inhalt der Hauptseite
+ Abonnement-Seite
+ Feed-Seite
+ Kanal-Seite
+ Hintergrund-Player
+ Popup-Player
+ Details
+ Top 50
+ Nicht behebbarer Wiedergabefehler aufgetreten
+ Player-Fehler gelöst
+
+ Kiosk-Seite
+ Kiosk auswählen
+
+ Kiosk
+ Tipp anzeigen, wenn der Hintergrundwiedergabe-Button oder der Popup-Button auf der Videodetailseite gedrückt und gehalten wird
+ In der Warteschlange bei der Hintergrundwiedergabe
+ Neu und brandheiß
+ Halten, um in die Warteschlange einzureihen
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index f257a61d3..11931b05f 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -1,7 +1,7 @@
%1$s visualizaciones
- Publicado en %1$s
+ Publicado el %1$s
No se encontró ningún reproductor de vídeo. ¿Desea instalar VLC?
Instalar
Cancelar
@@ -12,7 +12,7 @@
Ajustes
¿Quiso decir: %1$s?
Compartir con
- Seleccionar navegador
+ Elegir navegador
rotación
Ruta de descarga de vídeo
Ruta para almacenar los vídeos descargados
@@ -72,7 +72,7 @@
Mostrar contenido restringido por edad
Vídeo restringido por edad. Permitir este tipo de material es posible desde Ajustes.
- Toque buscar para empezar
+ Toque en buscar para empezar
Autoreproducir
Reproducir automáticamente un vídeo cuando NewPipe es llamado desde otra aplicación
en vivo
@@ -170,7 +170,7 @@ abrir en modo popup