Compare commits
123 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
140cfaec90 | ||
![]() |
a0f20aac23 | ||
![]() |
93fafb362f | ||
![]() |
9152df5512 | ||
![]() |
415bcd9f7e | ||
![]() |
2224033a85 | ||
![]() |
ade0498684 | ||
![]() |
211b00fff4 | ||
![]() |
77c72d03a8 | ||
![]() |
f429d93351 | ||
![]() |
e428f8b116 | ||
![]() |
9482b9d638 | ||
![]() |
e019c9f720 | ||
![]() |
e2778366e9 | ||
![]() |
36d2f8339c | ||
![]() |
a4a0c3b9fd | ||
![]() |
1b1b6c8af8 | ||
![]() |
064fd2bc68 | ||
![]() |
13152ab6ea | ||
![]() |
1743d821eb | ||
![]() |
ff16e577ef | ||
![]() |
86062c6e94 | ||
![]() |
8ce2350563 | ||
![]() |
cb8989af7f | ||
![]() |
877fa45eb4 | ||
![]() |
e33942486d | ||
![]() |
9606e080ef | ||
![]() |
d5cd9c55be | ||
![]() |
9c197ced80 | ||
![]() |
f8424599e1 | ||
![]() |
ccee18057a | ||
![]() |
1ad0f342ad | ||
![]() |
7a16ac574b | ||
![]() |
f46738f750 | ||
![]() |
fb8ff3fece | ||
![]() |
7498dd3800 | ||
![]() |
957c31b9c5 | ||
![]() |
b260570e8c | ||
![]() |
46542747b7 | ||
![]() |
d64480fc9b | ||
![]() |
c00e694d40 | ||
![]() |
f0761cc95e | ||
![]() |
068554955c | ||
![]() |
a2f915f556 | ||
![]() |
cffd35c974 | ||
![]() |
2ef2aa98a4 | ||
![]() |
ba98b30aa4 | ||
![]() |
87c0f9c803 | ||
![]() |
ce620b9e28 | ||
![]() |
fcbb5536eb | ||
![]() |
72df6dbd80 | ||
![]() |
3a6b023dbf | ||
![]() |
8b67f1358d | ||
![]() |
2aebb3b8db | ||
![]() |
f2b38be2b0 | ||
![]() |
a43001f30d | ||
![]() |
17abe1ea5c | ||
![]() |
6aaefab618 | ||
![]() |
cd867fb4d1 | ||
![]() |
25988f61a6 | ||
![]() |
be421e580d | ||
![]() |
641ab25470 | ||
![]() |
a508539c2e | ||
![]() |
cac79d9a0d | ||
![]() |
9ede8118da | ||
![]() |
e47761750a | ||
![]() |
2f181ce7c9 | ||
![]() |
3a13d4a1de | ||
![]() |
719de00e0f | ||
![]() |
ddffe99f53 | ||
![]() |
9ade596f06 | ||
![]() |
46f413b7f2 | ||
![]() |
5fe2e7b8ad | ||
![]() |
3008cbb5f4 | ||
![]() |
f7983960e5 | ||
![]() |
bb8007bb7c | ||
![]() |
01751ba97a | ||
![]() |
f41475d11c | ||
![]() |
d8914d9b6d | ||
![]() |
94cc2ad365 | ||
![]() |
e07464b81c | ||
![]() |
9d231b55b5 | ||
![]() |
77d8dac3c1 | ||
![]() |
e160015283 | ||
![]() |
aeb0cac3ee | ||
![]() |
a539f94837 | ||
![]() |
df70751071 | ||
![]() |
e55f1dff78 | ||
![]() |
47646e1c62 | ||
![]() |
80e673f20c | ||
![]() |
9ca8c5480c | ||
![]() |
4d0d3c7ead | ||
![]() |
58137aadc9 | ||
![]() |
82a59ae479 | ||
![]() |
affd23b14e | ||
![]() |
9c7f249756 | ||
![]() |
e2a0502171 | ||
![]() |
3832a4b355 | ||
![]() |
84f059415c | ||
![]() |
bb292e3199 | ||
![]() |
70541bf561 | ||
![]() |
48dd8e88e3 | ||
![]() |
52c2e0899d | ||
![]() |
9955d5b62f | ||
![]() |
8e26247fa1 | ||
![]() |
72924e2692 | ||
![]() |
8c2c8d630f | ||
![]() |
5ccf0baa6b | ||
![]() |
8fff0ccdf2 | ||
![]() |
35264bfb97 | ||
![]() |
4c9b0dc8e9 | ||
![]() |
4deb7caa83 | ||
![]() |
45f1a512b4 | ||
![]() |
ab95fdc087 | ||
![]() |
df608b9ded | ||
![]() |
6a4c81d160 | ||
![]() |
040d658540 | ||
![]() |
cbc9913e9c | ||
![]() |
f007cbd5ee | ||
![]() |
7351591df7 | ||
![]() |
5222d4cbba | ||
![]() |
ef9966815e | ||
![]() |
ad73440ce9 |
16
README.md
@@ -19,11 +19,16 @@ Project status:
|
|||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
[<img src="screenshots/screenshot_1.png" width=150>](screenshots/screenshot_1.png)
|
[<img src="screenshots/screenshot_1.png" width=160>](screenshots/screenshot_1.png)
|
||||||
[<img src="screenshots/screenshot_2.png" width=150>](screenshots/screenshot_2.png)
|
[<img src="screenshots/screenshot_2.png" width=160>](screenshots/screenshot_2.png)
|
||||||
[<img src="screenshots/screenshot_3.png" width=150>](screenshots/screenshot_3.png)
|
[<img src="screenshots/screenshot_3.png" width=160>](screenshots/screenshot_3.png)
|
||||||
[<img src="screenshots/screenshot_4.png" width=150>](screenshots/screenshot_4.png)
|
[<img src="screenshots/screenshot_4.png" width=160>](screenshots/screenshot_4.png)
|
||||||
[<img src="screenshots/screenshot_5.png" width=150>](screenshots/screenshot_5.png)
|
[<img src="screenshots/screenshot_5.png" width=160>](screenshots/screenshot_5.png)
|
||||||
|
[<img src="screenshots/screenshot_6.png" width=160>](screenshots/screenshot_6.png)
|
||||||
|
[<img src="screenshots/screenshot_7.png" width=160>](screenshots/screenshot_7.png)
|
||||||
|
[<img src="screenshots/screenshot_8.png" width=160>](screenshots/screenshot_8.png)
|
||||||
|
[<img src="screenshots/screenshot_9.png" width=160>](screenshots/screenshot_9.png)
|
||||||
|
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
@@ -35,6 +40,7 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only
|
|||||||
* Display general information about a video
|
* Display general information about a video
|
||||||
* Watch YouTube videos
|
* Watch YouTube videos
|
||||||
* Listen to YouTube videos (experimental)
|
* Listen to YouTube videos (experimental)
|
||||||
|
* Popup mode (floating player)
|
||||||
* Select the streaming player to watch the video with
|
* Select the streaming player to watch the video with
|
||||||
* Download videos
|
* Download videos
|
||||||
* Download audio only
|
* Download audio only
|
||||||
|
@@ -8,8 +8,8 @@ android {
|
|||||||
applicationId "org.schabi.newpipe"
|
applicationId "org.schabi.newpipe"
|
||||||
minSdkVersion 15
|
minSdkVersion 15
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 31
|
versionCode 34
|
||||||
versionName "0.9.4"
|
versionName "0.9.7"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
|
@@ -1,28 +0,0 @@
|
|||||||
package org.schabi.newpipe;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
|
|
||||||
public class ThemableActivity extends AppCompatActivity {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
.getString("theme", getResources().getString(R.string.light_theme_title)).
|
|
||||||
equals(getResources().getString(R.string.dark_theme_title))) {
|
|
||||||
setTheme(R.style.DarkTheme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
.getString("theme", getResources().getString(R.string.light_theme_title)).
|
|
||||||
equals(getResources().getString(R.string.dark_theme_title))) {
|
|
||||||
setTheme(R.style.DarkTheme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,165 +0,0 @@
|
|||||||
package org.schabi.newpipe.download;
|
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.support.v4.app.NotificationCompat;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
|
|
||||||
import info.guardianproject.netcipher.NetCipher;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Christian Schabesberger on 14.08.15.
|
|
||||||
*
|
|
||||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
|
||||||
* FileDownloader.java is part of NewPipe.
|
|
||||||
*
|
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* NewPipe is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: FOR HEAVEN SAKE !!! DO NOT SIMPLY USE ASYNCTASK. MAKE THIS A PROPER SERVICE !!!
|
|
||||||
public class FileDownloader extends AsyncTask<Void, Integer, Void> {
|
|
||||||
public static final String TAG = "FileDownloader";
|
|
||||||
|
|
||||||
|
|
||||||
private NotificationManager nm;
|
|
||||||
private NotificationCompat.Builder builder;
|
|
||||||
private int notifyId = 0x1234;
|
|
||||||
private int fileSize = 0xffffffff;
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
private final String fileURL;
|
|
||||||
private final File saveFilePath;
|
|
||||||
private final String title;
|
|
||||||
|
|
||||||
private final String debugContext;
|
|
||||||
|
|
||||||
public FileDownloader(Context context, String fileURL, File saveFilePath, String title) {
|
|
||||||
this.context = context;
|
|
||||||
this.fileURL = fileURL;
|
|
||||||
this.saveFilePath = saveFilePath;
|
|
||||||
this.title = title;
|
|
||||||
|
|
||||||
this.debugContext = "'" + fileURL +
|
|
||||||
"' => '" + saveFilePath + "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads a file from a URL in the background using an {@link AsyncTask}.
|
|
||||||
*
|
|
||||||
* @param fileURL HTTP URL of the file to be downloaded
|
|
||||||
* @param saveFilePath path of the directory to save the file
|
|
||||||
* @param title
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static void downloadFile(final Context context, final String fileURL, final File saveFilePath, String title) {
|
|
||||||
new FileDownloader(context, fileURL, saveFilePath, title).execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** AsyncTask impl: executed in gui thread */
|
|
||||||
@Override
|
|
||||||
protected void onPreExecute() {
|
|
||||||
super.onPreExecute();
|
|
||||||
nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
||||||
Drawable icon = context.getResources().getDrawable(R.mipmap.ic_launcher);
|
|
||||||
builder = new NotificationCompat.Builder(context)
|
|
||||||
.setSmallIcon(android.R.drawable.stat_sys_download)
|
|
||||||
.setLargeIcon(((BitmapDrawable) icon).getBitmap())
|
|
||||||
.setContentTitle(saveFilePath.getName())
|
|
||||||
.setContentText(saveFilePath.getAbsolutePath())
|
|
||||||
.setProgress(fileSize, 0, false);
|
|
||||||
nm.notify(notifyId, builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** AsyncTask impl: executed in background thread does the download */
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... voids) {
|
|
||||||
HttpsURLConnection con = null;
|
|
||||||
InputStream inputStream = null;
|
|
||||||
FileOutputStream outputStream = null;
|
|
||||||
try {
|
|
||||||
con = NetCipher.getHttpsURLConnection(fileURL);
|
|
||||||
int responseCode = con.getResponseCode();
|
|
||||||
|
|
||||||
// always check HTTP response code first
|
|
||||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
|
||||||
fileSize = con.getContentLength();
|
|
||||||
inputStream = new BufferedInputStream(con.getInputStream());
|
|
||||||
outputStream = new FileOutputStream(saveFilePath);
|
|
||||||
|
|
||||||
int bufferSize = 8192;
|
|
||||||
int downloaded = 0;
|
|
||||||
|
|
||||||
int bytesRead = -1;
|
|
||||||
byte[] buffer = new byte[bufferSize];
|
|
||||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
|
||||||
outputStream.write(buffer, 0, bytesRead);
|
|
||||||
downloaded += bytesRead;
|
|
||||||
if (downloaded % 50000 < bufferSize) {
|
|
||||||
publishProgress(downloaded);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
publishProgress(bufferSize);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "No file to download. Server replied HTTP code: " + responseCode);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "No file to download. Server replied HTTP code: ", e);
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (outputStream != null) {
|
|
||||||
outputStream.close();
|
|
||||||
}
|
|
||||||
if (inputStream != null) {
|
|
||||||
inputStream.close();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
if (con != null) {
|
|
||||||
con.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onProgressUpdate(Integer... progress) {
|
|
||||||
builder.setProgress(fileSize, progress[0], false);
|
|
||||||
nm.notify(notifyId, builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Void aVoid) {
|
|
||||||
super.onPostExecute(aVoid);
|
|
||||||
nm.cancel(notifyId);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,7 +1,5 @@
|
|||||||
package org.schabi.newpipe.fragments;
|
package org.schabi.newpipe.fragments;
|
||||||
|
|
||||||
import android.animation.Animator;
|
|
||||||
import android.animation.AnimatorListenerAdapter;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
@@ -28,6 +26,8 @@ import org.schabi.newpipe.R;
|
|||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
public abstract class BaseFragment extends Fragment {
|
public abstract class BaseFragment extends Fragment {
|
||||||
protected final String TAG = "BaseFragment@" + Integer.toHexString(hashCode());
|
protected final String TAG = "BaseFragment@" + Integer.toHexString(hashCode());
|
||||||
protected static final boolean DEBUG = MainActivity.DEBUG;
|
protected static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
@@ -130,70 +130,6 @@ public abstract class BaseFragment extends Fragment {
|
|||||||
// Utils
|
// Utils
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public void animateView(final View view, final boolean enterOrExit, long duration) {
|
|
||||||
animateView(view, enterOrExit, duration, 0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void animateView(final View view, final boolean enterOrExit, long duration, final Runnable execOnEnd) {
|
|
||||||
animateView(view, enterOrExit, duration, 0, execOnEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void animateView(final View view, final boolean enterOrExit, long duration, long delay) {
|
|
||||||
animateView(view, enterOrExit, duration, delay, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Animate the view
|
|
||||||
*
|
|
||||||
* @param view view that will be animated
|
|
||||||
* @param enterOrExit true to enter, false to exit
|
|
||||||
* @param duration how long the animation will take, in milliseconds
|
|
||||||
* @param delay how long the animation will take to start, in milliseconds
|
|
||||||
* @param execOnEnd runnable that will be executed when the animation ends
|
|
||||||
*/
|
|
||||||
public void animateView(final View view, final boolean enterOrExit, long duration, long delay, final Runnable execOnEnd) {
|
|
||||||
if (DEBUG) Log.d(TAG, "animateView() called with: view = [" + view + "], enterOrExit = [" + enterOrExit + "], duration = [" + duration + "], execOnEnd = [" + execOnEnd + "]");
|
|
||||||
if (view == null) return;
|
|
||||||
|
|
||||||
if (view.getVisibility() == View.VISIBLE && enterOrExit) {
|
|
||||||
view.animate().setListener(null).cancel();
|
|
||||||
view.setVisibility(View.VISIBLE);
|
|
||||||
view.setAlpha(1f);
|
|
||||||
if (execOnEnd != null) execOnEnd.run();
|
|
||||||
return;
|
|
||||||
} else if ((view.getVisibility() == View.GONE || view.getVisibility() == View.INVISIBLE) && !enterOrExit) {
|
|
||||||
view.animate().setListener(null).cancel();
|
|
||||||
view.setVisibility(View.GONE);
|
|
||||||
view.setAlpha(0f);
|
|
||||||
if (execOnEnd != null) execOnEnd.run();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
view.animate().setListener(null).cancel();
|
|
||||||
view.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
if (enterOrExit) {
|
|
||||||
view.animate().alpha(1f).setDuration(duration).setStartDelay(delay)
|
|
||||||
.setListener(new AnimatorListenerAdapter() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation) {
|
|
||||||
if (execOnEnd != null) execOnEnd.run();
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
} else {
|
|
||||||
view.animate().alpha(0f)
|
|
||||||
.setDuration(duration).setStartDelay(delay)
|
|
||||||
.setListener(new AnimatorListenerAdapter() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation) {
|
|
||||||
view.setVisibility(View.GONE);
|
|
||||||
if (execOnEnd != null) execOnEnd.run();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setErrorMessage(String message, boolean showRetryButton) {
|
protected void setErrorMessage(String message, boolean showRetryButton) {
|
||||||
if (errorTextView == null || activity == null) return;
|
if (errorTextView == null || activity == null) return;
|
||||||
|
|
||||||
|
@@ -36,6 +36,8 @@ import java.io.Serializable;
|
|||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
public class ChannelFragment extends BaseFragment implements ChannelExtractorWorker.OnChannelInfoReceive {
|
public class ChannelFragment extends BaseFragment implements ChannelExtractorWorker.OnChannelInfoReceive {
|
||||||
private final String TAG = "ChannelFragment@" + Integer.toHexString(hashCode());
|
private final String TAG = "ChannelFragment@" + Integer.toHexString(hashCode());
|
||||||
|
|
||||||
|
@@ -9,11 +9,9 @@ import android.view.MenuInflater;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.MediaFormat;
|
|
||||||
import org.schabi.newpipe.extractor.stream_info.VideoStream;
|
import org.schabi.newpipe.extractor.stream_info.VideoStream;
|
||||||
import org.schabi.newpipe.util.Utils;
|
import org.schabi.newpipe.util.Utils;
|
||||||
|
|
||||||
@@ -40,6 +38,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
class ActionBarHandler {
|
class ActionBarHandler {
|
||||||
private static final String TAG = "ActionBarHandler";
|
private static final String TAG = "ActionBarHandler";
|
||||||
|
|
||||||
@@ -70,16 +69,9 @@ class ActionBarHandler {
|
|||||||
if (activity == null) return;
|
if (activity == null) return;
|
||||||
selectedVideoStream = 0;
|
selectedVideoStream = 0;
|
||||||
|
|
||||||
// this array will be shown in the dropdown menu for selecting the stream/resolution.
|
|
||||||
String[] itemArray = new String[videoStreams.size()];
|
|
||||||
for (int i = 0; i < videoStreams.size(); i++) {
|
|
||||||
VideoStream item = videoStreams.get(i);
|
|
||||||
itemArray[i] = MediaFormat.getNameById(item.format) + " " + item.resolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
int defaultResolutionIndex = Utils.getDefaultResolution(activity, videoStreams);
|
int defaultResolutionIndex = Utils.getDefaultResolution(activity, videoStreams);
|
||||||
ArrayAdapter<String> itemAdapter = new ArrayAdapter<>(activity.getBaseContext(), android.R.layout.simple_spinner_dropdown_item, itemArray);
|
boolean isExternalPlayerEnabled = PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(activity.getString(R.string.use_external_video_player_key), false);
|
||||||
toolbarSpinner.setAdapter(itemAdapter);
|
toolbarSpinner.setAdapter(new SpinnerToolbarAdapter(activity, videoStreams, isExternalPlayerEnabled));
|
||||||
toolbarSpinner.setSelection(defaultResolutionIndex);
|
toolbarSpinner.setSelection(defaultResolutionIndex);
|
||||||
toolbarSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
toolbarSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -103,6 +95,10 @@ class ActionBarHandler {
|
|||||||
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||||
inflater.inflate(R.menu.video_detail_menu, menu);
|
inflater.inflate(R.menu.video_detail_menu, menu);
|
||||||
|
|
||||||
|
updateItemsVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateItemsVisibility(){
|
||||||
showPlayWithKodiAction(defaultPreferences.getBoolean(activity.getString(R.string.show_play_with_kodi_key), false));
|
showPlayWithKodiAction(defaultPreferences.getBoolean(activity.getString(R.string.show_play_with_kodi_key), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,74 @@
|
|||||||
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.extractor.MediaFormat;
|
||||||
|
import org.schabi.newpipe.extractor.stream_info.VideoStream;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SpinnerToolbarAdapter extends BaseAdapter {
|
||||||
|
private final List<VideoStream> videoStreams;
|
||||||
|
private final boolean showIconNoAudio;
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public SpinnerToolbarAdapter(Context context, List<VideoStream> videoStreams, boolean showIconNoAudio) {
|
||||||
|
this.context = context;
|
||||||
|
this.videoStreams = videoStreams;
|
||||||
|
this.showIconNoAudio = showIconNoAudio;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return videoStreams.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int position) {
|
||||||
|
return videoStreams.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getDropDownView(int position, View convertView, ViewGroup parent) {
|
||||||
|
return getCustomView(position, convertView, parent, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
return getCustomView(((Spinner) parent).getSelectedItemPosition(), convertView, parent, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private View getCustomView(int position, View convertView, ViewGroup parent, boolean isDropdownItem) {
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = LayoutInflater.from(context).inflate(R.layout.resolutions_spinner_item, parent, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageView woSoundIcon = (ImageView) convertView.findViewById(R.id.wo_sound_icon);
|
||||||
|
TextView text = (TextView) convertView.findViewById(android.R.id.text1);
|
||||||
|
VideoStream item = (VideoStream) getItem(position);
|
||||||
|
text.setText(MediaFormat.getNameById(item.format) + " " + item.resolution);
|
||||||
|
|
||||||
|
int visibility = !showIconNoAudio ? View.GONE
|
||||||
|
: item.isVideoOnly ? View.VISIBLE
|
||||||
|
: isDropdownItem ? View.INVISIBLE
|
||||||
|
: View.GONE;
|
||||||
|
woSoundIcon.setVisibility(visibility);
|
||||||
|
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -19,6 +19,7 @@ import android.text.TextUtils;
|
|||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
@@ -39,7 +40,6 @@ import com.nostra13.universalimageloader.core.assist.FailReason;
|
|||||||
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
|
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
|
||||||
|
|
||||||
import org.schabi.newpipe.ImageErrorLoadingListener;
|
import org.schabi.newpipe.ImageErrorLoadingListener;
|
||||||
import org.schabi.newpipe.Localization;
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.ReCaptchaActivity;
|
import org.schabi.newpipe.ReCaptchaActivity;
|
||||||
import org.schabi.newpipe.download.DownloadDialog;
|
import org.schabi.newpipe.download.DownloadDialog;
|
||||||
@@ -55,6 +55,8 @@ import org.schabi.newpipe.player.MainVideoPlayer;
|
|||||||
import org.schabi.newpipe.player.PlayVideoActivity;
|
import org.schabi.newpipe.player.PlayVideoActivity;
|
||||||
import org.schabi.newpipe.player.PopupVideoPlayer;
|
import org.schabi.newpipe.player.PopupVideoPlayer;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
|
import org.schabi.newpipe.util.Constants;
|
||||||
|
import org.schabi.newpipe.util.Localization;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
import org.schabi.newpipe.util.PermissionHelper;
|
||||||
import org.schabi.newpipe.util.Utils;
|
import org.schabi.newpipe.util.Utils;
|
||||||
@@ -64,6 +66,8 @@ import java.io.Serializable;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
public class VideoDetailFragment extends BaseFragment implements StreamExtractorWorker.OnStreamInfoReceivedListener, SharedPreferences.OnSharedPreferenceChangeListener, View.OnClickListener {
|
public class VideoDetailFragment extends BaseFragment implements StreamExtractorWorker.OnStreamInfoReceivedListener, SharedPreferences.OnSharedPreferenceChangeListener, View.OnClickListener {
|
||||||
private final String TAG = "VideoDetailFragment@" + Integer.toHexString(hashCode());
|
private final String TAG = "VideoDetailFragment@" + Integer.toHexString(hashCode());
|
||||||
|
|
||||||
@@ -71,9 +75,6 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor
|
|||||||
private static final int INITIAL_RELATED_VIDEOS = 8;
|
private static final int INITIAL_RELATED_VIDEOS = 8;
|
||||||
|
|
||||||
private static final String KORE_PACKET = "org.xbmc.kore";
|
private static final String KORE_PACKET = "org.xbmc.kore";
|
||||||
private static final String SERVICE_ID_KEY = "service_id_key";
|
|
||||||
private static final String VIDEO_URL_KEY = "video_url_key";
|
|
||||||
private static final String VIDEO_TITLE_KEY = "video_title_key";
|
|
||||||
private static final String STACK_KEY = "stack_key";
|
private static final String STACK_KEY = "stack_key";
|
||||||
private static final String INFO_KEY = "info_key";
|
private static final String INFO_KEY = "info_key";
|
||||||
private static final String WAS_RELATED_EXPANDED_KEY = "was_related_expanded_key";
|
private static final String WAS_RELATED_EXPANDED_KEY = "was_related_expanded_key";
|
||||||
@@ -97,6 +98,7 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor
|
|||||||
|
|
||||||
private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1;
|
private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1;
|
||||||
private static final int RESOLUTIONS_MENU_UPDATE_FLAG = 0x2;
|
private static final int RESOLUTIONS_MENU_UPDATE_FLAG = 0x2;
|
||||||
|
private static final int TOOLBAR_ITEMS_UPDATE_FLAG = 0x4;
|
||||||
private int updateFlags = 0;
|
private int updateFlags = 0;
|
||||||
|
|
||||||
private boolean autoPlayEnabled;
|
private boolean autoPlayEnabled;
|
||||||
@@ -170,9 +172,9 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor
|
|||||||
if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
|
if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
videoTitle = savedInstanceState.getString(VIDEO_TITLE_KEY);
|
videoTitle = savedInstanceState.getString(Constants.KEY_TITLE);
|
||||||
videoUrl = savedInstanceState.getString(VIDEO_URL_KEY);
|
videoUrl = savedInstanceState.getString(Constants.KEY_URL);
|
||||||
serviceId = savedInstanceState.getInt(SERVICE_ID_KEY, 0);
|
serviceId = savedInstanceState.getInt(Constants.KEY_SERVICE_ID, 0);
|
||||||
wasRelatedStreamsExpanded = savedInstanceState.getBoolean(WAS_RELATED_EXPANDED_KEY, false);
|
wasRelatedStreamsExpanded = savedInstanceState.getBoolean(WAS_RELATED_EXPANDED_KEY, false);
|
||||||
Serializable serializable = savedInstanceState.getSerializable(STACK_KEY);
|
Serializable serializable = savedInstanceState.getSerializable(STACK_KEY);
|
||||||
if (serializable instanceof Stack) {
|
if (serializable instanceof Stack) {
|
||||||
@@ -218,6 +220,8 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor
|
|||||||
if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) initRelatedVideos(currentStreamInfo);
|
if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) initRelatedVideos(currentStreamInfo);
|
||||||
if ((updateFlags & RESOLUTIONS_MENU_UPDATE_FLAG) != 0) setupActionBarHandler(currentStreamInfo);
|
if ((updateFlags & RESOLUTIONS_MENU_UPDATE_FLAG) != 0) setupActionBarHandler(currentStreamInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((updateFlags & TOOLBAR_ITEMS_UPDATE_FLAG) != 0 && actionBarHandler != null) actionBarHandler.updateItemsVisibility();
|
||||||
updateFlags = 0;
|
updateFlags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,9 +293,9 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor
|
|||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
if (DEBUG) Log.d(TAG, "onSaveInstanceState() called with: outState = [" + outState + "]");
|
if (DEBUG) Log.d(TAG, "onSaveInstanceState() called with: outState = [" + outState + "]");
|
||||||
outState.putString(VIDEO_URL_KEY, videoUrl);
|
outState.putString(Constants.KEY_URL, videoUrl);
|
||||||
outState.putString(VIDEO_TITLE_KEY, videoTitle);
|
outState.putString(Constants.KEY_TITLE, videoTitle);
|
||||||
outState.putInt(SERVICE_ID_KEY, serviceId);
|
outState.putInt(Constants.KEY_SERVICE_ID, serviceId);
|
||||||
outState.putSerializable(STACK_KEY, stack);
|
outState.putSerializable(STACK_KEY, stack);
|
||||||
|
|
||||||
int nextCount = currentStreamInfo != null && currentStreamInfo.next_video != null ? 2 : 0;
|
int nextCount = currentStreamInfo != null && currentStreamInfo.next_video != null ? 2 : 0;
|
||||||
@@ -326,8 +330,11 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor
|
|||||||
updateFlags |= RELATED_STREAMS_UPDATE_FLAG;
|
updateFlags |= RELATED_STREAMS_UPDATE_FLAG;
|
||||||
} else if (key.equals(getString(R.string.preferred_video_format_key))
|
} else if (key.equals(getString(R.string.preferred_video_format_key))
|
||||||
|| key.equals(getString(R.string.default_resolution_key))
|
|| key.equals(getString(R.string.default_resolution_key))
|
||||||
|| key.equals(getString(R.string.show_higher_resolutions_key))) {
|
|| key.equals(getString(R.string.show_higher_resolutions_key))
|
||||||
|
|| key.equals(getString(R.string.use_external_video_player_key))) {
|
||||||
updateFlags |= RESOLUTIONS_MENU_UPDATE_FLAG;
|
updateFlags |= RESOLUTIONS_MENU_UPDATE_FLAG;
|
||||||
|
} else if (key.equals(getString(R.string.show_play_with_kodi_key))) {
|
||||||
|
updateFlags |= TOOLBAR_ITEMS_UPDATE_FLAG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,7 +427,10 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor
|
|||||||
if (isLoading.get()) return;
|
if (isLoading.get()) return;
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(activity)) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(activity)) {
|
||||||
Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG).show();
|
Toast toast = Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG);
|
||||||
|
TextView messageView = (TextView) toast.getView().findViewById(android.R.id.message);
|
||||||
|
if (messageView != null) messageView.setGravity(Gravity.CENTER);
|
||||||
|
toast.show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -673,33 +683,10 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Bundle args = new Bundle();
|
DownloadDialog downloadDialog = DownloadDialog.newInstance(info, sortedStreamVideosList, selectedStreamId);
|
||||||
|
|
||||||
// Sometimes it may be that some information is not available due to changes fo the
|
|
||||||
// website which was crawled. Then the ui has to understand this and act right.
|
|
||||||
|
|
||||||
if (info.audio_streams != null) {
|
|
||||||
AudioStream audioStream =
|
|
||||||
info.audio_streams.get(Utils.getPreferredAudioFormat(activity, info.audio_streams));
|
|
||||||
|
|
||||||
String audioSuffix = "." + MediaFormat.getSuffixById(audioStream.format);
|
|
||||||
args.putString(DownloadDialog.AUDIO_URL, audioStream.url);
|
|
||||||
args.putString(DownloadDialog.FILE_SUFFIX_AUDIO, audioSuffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sortedStreamVideosList != null) {
|
|
||||||
VideoStream selectedStreamItem = sortedStreamVideosList.get(selectedStreamId);
|
|
||||||
String videoSuffix = "." + MediaFormat.getSuffixById(selectedStreamItem.format);
|
|
||||||
args.putString(DownloadDialog.FILE_SUFFIX_VIDEO, videoSuffix);
|
|
||||||
args.putString(DownloadDialog.VIDEO_URL, selectedStreamItem.url);
|
|
||||||
}
|
|
||||||
|
|
||||||
args.putString(DownloadDialog.TITLE, info.title);
|
|
||||||
DownloadDialog downloadDialog = DownloadDialog.newInstance(args);
|
|
||||||
downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
|
downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Toast.makeText(activity,
|
Toast.makeText(activity, R.string.could_not_setup_download_menu, Toast.LENGTH_LONG).show();
|
||||||
R.string.could_not_setup_download_menu, Toast.LENGTH_LONG).show();
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -800,7 +787,7 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor
|
|||||||
* If it is, check if the cache contains the info already.</br>
|
* If it is, check if the cache contains the info already.</br>
|
||||||
* If the cache doesn't have the info, load from the network.
|
* If the cache doesn't have the info, load from the network.
|
||||||
*
|
*
|
||||||
* @param info info to prepare and load, can be null
|
* @param info info to prepare and load, can be null
|
||||||
* @param scrollToTop whether or not scroll the scrollView to y = 0
|
* @param scrollToTop whether or not scroll the scrollView to y = 0
|
||||||
*/
|
*/
|
||||||
public void prepareAndLoad(StreamInfo info, boolean scrollToTop) {
|
public void prepareAndLoad(StreamInfo info, boolean scrollToTop) {
|
||||||
@@ -844,7 +831,7 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor
|
|||||||
else parallaxScrollRootView.scrollTo(0, 0);
|
else parallaxScrollRootView.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
animateView(contentRootLayoutHiding, false, greaterThanThreshold ? 250 : 0, new Runnable() {
|
animateView(contentRootLayoutHiding, false, greaterThanThreshold ? 250 : 0, 0, new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
handleStreamInfo(infoFinal, false);
|
handleStreamInfo(infoFinal, false);
|
||||||
@@ -1052,7 +1039,7 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor
|
|||||||
private void setErrorImage(final int imageResource) {
|
private void setErrorImage(final int imageResource) {
|
||||||
if (thumbnailImageView == null || activity == null) return;
|
if (thumbnailImageView == null || activity == null) return;
|
||||||
thumbnailImageView.setImageDrawable(ContextCompat.getDrawable(activity, imageResource));
|
thumbnailImageView.setImageDrawable(ContextCompat.getDrawable(activity, imageResource));
|
||||||
animateView(thumbnailImageView, false, 0, new Runnable() {
|
animateView(thumbnailImageView, false, 0, 0, new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
animateView(thumbnailImageView, true, 500);
|
animateView(thumbnailImageView, true, 500);
|
||||||
|
@@ -5,6 +5,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
@@ -37,6 +38,7 @@ import org.schabi.newpipe.extractor.search.SearchResult;
|
|||||||
import org.schabi.newpipe.fragments.BaseFragment;
|
import org.schabi.newpipe.fragments.BaseFragment;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
import org.schabi.newpipe.info_list.InfoListAdapter;
|
import org.schabi.newpipe.info_list.InfoListAdapter;
|
||||||
|
import org.schabi.newpipe.util.Constants;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.workers.SearchWorker;
|
import org.schabi.newpipe.workers.SearchWorker;
|
||||||
import org.schabi.newpipe.workers.SuggestionWorker;
|
import org.schabi.newpipe.workers.SuggestionWorker;
|
||||||
@@ -45,12 +47,13 @@ import java.util.ArrayList;
|
|||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
public class SearchFragment extends BaseFragment implements SuggestionWorker.OnSuggestionResult, SearchWorker.OnSearchResult {
|
public class SearchFragment extends BaseFragment implements SuggestionWorker.OnSuggestionResult, SearchWorker.OnSearchResult {
|
||||||
private final String TAG = "SearchFragment@" + Integer.toHexString(hashCode());
|
private final String TAG = "SearchFragment@" + Integer.toHexString(hashCode());
|
||||||
// savedInstanceBundle arguments
|
// savedInstanceBundle arguments
|
||||||
private static final String QUERY_KEY = "query_key";
|
private static final String QUERY_KEY = "query_key";
|
||||||
private static final String PAGE_NUMBER_KEY = "page_number_key";
|
private static final String PAGE_NUMBER_KEY = "page_number_key";
|
||||||
private static final String SERVICE_KEY = "service_key";
|
|
||||||
private static final String INFO_LIST_KEY = "info_list_key";
|
private static final String INFO_LIST_KEY = "info_list_key";
|
||||||
private static final String WAS_LOADING_KEY = "was_loading_key";
|
private static final String WAS_LOADING_KEY = "was_loading_key";
|
||||||
private static final String ERROR_KEY = "error_key";
|
private static final String ERROR_KEY = "error_key";
|
||||||
@@ -66,6 +69,7 @@ public class SearchFragment extends BaseFragment implements SuggestionWorker.OnS
|
|||||||
private int serviceId = -1;
|
private int serviceId = -1;
|
||||||
private String searchQuery = "";
|
private String searchQuery = "";
|
||||||
private int pageNumber = 0;
|
private int pageNumber = 0;
|
||||||
|
private boolean showSuggestions = true;
|
||||||
|
|
||||||
private SearchWorker curSearchWorker;
|
private SearchWorker curSearchWorker;
|
||||||
private SuggestionWorker curSuggestionWorker;
|
private SuggestionWorker curSuggestionWorker;
|
||||||
@@ -101,7 +105,7 @@ public class SearchFragment extends BaseFragment implements SuggestionWorker.OnS
|
|||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
searchQuery = savedInstanceState.getString(QUERY_KEY);
|
searchQuery = savedInstanceState.getString(QUERY_KEY);
|
||||||
serviceId = savedInstanceState.getInt(SERVICE_KEY, 0);
|
serviceId = savedInstanceState.getInt(Constants.KEY_SERVICE_ID, 0);
|
||||||
pageNumber = savedInstanceState.getInt(PAGE_NUMBER_KEY, 0);
|
pageNumber = savedInstanceState.getInt(PAGE_NUMBER_KEY, 0);
|
||||||
wasLoading.set(savedInstanceState.getBoolean(WAS_LOADING_KEY, false));
|
wasLoading.set(savedInstanceState.getBoolean(WAS_LOADING_KEY, false));
|
||||||
filterItemCheckedId = savedInstanceState.getInt(FILTER_CHECKED_ID_KEY, 0);
|
filterItemCheckedId = savedInstanceState.getInt(FILTER_CHECKED_ID_KEY, 0);
|
||||||
@@ -133,6 +137,8 @@ public class SearchFragment extends BaseFragment implements SuggestionWorker.OnS
|
|||||||
if (pageNumber > 0) search(searchQuery, pageNumber);
|
if (pageNumber > 0) search(searchQuery, pageNumber);
|
||||||
else search(searchQuery, 0, true);
|
else search(searchQuery, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showSuggestions = PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(getString(R.string.show_search_suggestions_key), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -171,7 +177,7 @@ public class SearchFragment extends BaseFragment implements SuggestionWorker.OnS
|
|||||||
String query = searchEditText != null && !TextUtils.isEmpty(searchEditText.getText().toString())
|
String query = searchEditText != null && !TextUtils.isEmpty(searchEditText.getText().toString())
|
||||||
? searchEditText.getText().toString() : searchQuery;
|
? searchEditText.getText().toString() : searchQuery;
|
||||||
outState.putString(QUERY_KEY, query);
|
outState.putString(QUERY_KEY, query);
|
||||||
outState.putInt(SERVICE_KEY, serviceId);
|
outState.putInt(Constants.KEY_SERVICE_ID, serviceId);
|
||||||
outState.putInt(PAGE_NUMBER_KEY, pageNumber);
|
outState.putInt(PAGE_NUMBER_KEY, pageNumber);
|
||||||
outState.putSerializable(INFO_LIST_KEY, ((ArrayList<InfoItem>) infoListAdapter.getItemsList()));
|
outState.putSerializable(INFO_LIST_KEY, ((ArrayList<InfoItem>) infoListAdapter.getItemsList()));
|
||||||
outState.putBoolean(WAS_LOADING_KEY, curSearchWorker != null && curSearchWorker.isRunning());
|
outState.putBoolean(WAS_LOADING_KEY, curSearchWorker != null && curSearchWorker.isRunning());
|
||||||
@@ -521,6 +527,11 @@ public class SearchFragment extends BaseFragment implements SuggestionWorker.OnS
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void searchSuggestions(String query) {
|
private void searchSuggestions(String query) {
|
||||||
|
if (!showSuggestions) {
|
||||||
|
if (DEBUG) Log.d(TAG, "searchSuggestions() showSuggestions is disabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "searchSuggestions() called with: query = [" + query + "]");
|
if (DEBUG) Log.d(TAG, "searchSuggestions() called with: query = [" + query + "]");
|
||||||
if (curSuggestionWorker != null && curSuggestionWorker.isRunning()) curSuggestionWorker.cancel();
|
if (curSuggestionWorker != null && curSuggestionWorker.isRunning()) curSuggestionWorker.cancel();
|
||||||
curSuggestionWorker = SuggestionWorker.startForQuery(activity, serviceId, query, this);
|
curSuggestionWorker = SuggestionWorker.startForQuery(activity, serviceId, query, this);
|
||||||
|
@@ -1,49 +0,0 @@
|
|||||||
package org.schabi.newpipe.fragments.search;
|
|
||||||
|
|
||||||
import android.support.v7.widget.SearchView;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Christian Schabesberger on 02.08.16.
|
|
||||||
*
|
|
||||||
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
|
||||||
* SearchSuggestionListener.java is part of NewPipe.
|
|
||||||
*
|
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* NewPipe is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
public class SearchSuggestionListener implements SearchView.OnSuggestionListener{
|
|
||||||
|
|
||||||
private final SearchView searchView;
|
|
||||||
private final SuggestionListAdapter adapter;
|
|
||||||
|
|
||||||
public SearchSuggestionListener(SearchView searchView, SuggestionListAdapter adapter) {
|
|
||||||
this.searchView = searchView;
|
|
||||||
this.adapter = adapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onSuggestionSelect(int position) {
|
|
||||||
String suggestion = adapter.getSuggestion(position);
|
|
||||||
searchView.setQuery(suggestion,true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onSuggestionClick(int position) {
|
|
||||||
String suggestion = adapter.getSuggestion(position);
|
|
||||||
searchView.setQuery(suggestion,true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -189,6 +189,7 @@ public abstract class BasePlayer implements ExoPlayer.EventListener, AudioManage
|
|||||||
ImageLoader.getInstance().loadImage(videoThumbnailUrl, new SimpleImageLoadingListener() {
|
ImageLoader.getInstance().loadImage(videoThumbnailUrl, new SimpleImageLoadingListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
||||||
|
if (simpleExoPlayer == null) return;
|
||||||
if (DEBUG) Log.d(TAG, "onLoadingComplete() called with: imageUri = [" + imageUri + "], view = [" + view + "], loadedImage = [" + loadedImage + "]");
|
if (DEBUG) Log.d(TAG, "onLoadingComplete() called with: imageUri = [" + imageUri + "], view = [" + view + "], loadedImage = [" + loadedImage + "]");
|
||||||
videoThumbnail = loadedImage;
|
videoThumbnail = loadedImage;
|
||||||
onThumbnailReceived(loadedImage);
|
onThumbnailReceived(loadedImage);
|
||||||
@@ -319,7 +320,6 @@ public abstract class BasePlayer implements ExoPlayer.EventListener, AudioManage
|
|||||||
if (DEBUG) Log.d(TAG, "onAudioFocusGain() called");
|
if (DEBUG) Log.d(TAG, "onAudioFocusGain() called");
|
||||||
if (simpleExoPlayer != null) simpleExoPlayer.setVolume(DUCK_AUDIO_TO);
|
if (simpleExoPlayer != null) simpleExoPlayer.setVolume(DUCK_AUDIO_TO);
|
||||||
animateAudio(DUCK_AUDIO_TO, 1f, DUCK_DURATION);
|
animateAudio(DUCK_AUDIO_TO, 1f, DUCK_DURATION);
|
||||||
simpleExoPlayer.setPlayWhenReady(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onAudioFocusLoss() {
|
protected void onAudioFocusLoss() {
|
||||||
|
@@ -21,10 +21,13 @@ import android.widget.TextView;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.util.AnimationUtils;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
import org.schabi.newpipe.util.PermissionHelper;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity Player implementing VideoPlayer
|
* Activity Player implementing VideoPlayer
|
||||||
*
|
*
|
||||||
@@ -37,14 +40,7 @@ public class MainVideoPlayer extends Activity {
|
|||||||
private AudioManager audioManager;
|
private AudioManager audioManager;
|
||||||
private GestureDetector gestureDetector;
|
private GestureDetector gestureDetector;
|
||||||
|
|
||||||
private final Runnable hideUiRunnable = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
hideSystemUi();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private boolean activityPaused;
|
private boolean activityPaused;
|
||||||
|
|
||||||
private VideoPlayerImpl playerImpl;
|
private VideoPlayerImpl playerImpl;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
@@ -188,6 +184,7 @@ public class MainVideoPlayer extends Activity {
|
|||||||
repeatButton.setAlpha(77);
|
repeatButton.setAlpha(77);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRootView().setKeepScreenOn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -265,14 +262,15 @@ public class MainVideoPlayer extends Activity {
|
|||||||
else if (v.getId() == screenRotationButton.getId()) onScreenRotationClicked();
|
else if (v.getId() == screenRotationButton.getId()) onScreenRotationClicked();
|
||||||
|
|
||||||
if (getCurrentState() != STATE_COMPLETED) {
|
if (getCurrentState() != STATE_COMPLETED) {
|
||||||
|
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
|
||||||
animateView(playerImpl.getControlsRoot(), true, 300, 0, new Runnable() {
|
animateView(playerImpl.getControlsRoot(), true, 300, 0, new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (getCurrentState() == STATE_PLAYING && !playerImpl.isQualityMenuVisible()) {
|
if (getCurrentState() == STATE_PLAYING && !playerImpl.isQualityMenuVisible()) {
|
||||||
animateView(playerImpl.getControlsRoot(), false, 300, DEFAULT_CONTROLS_HIDE_TIME, true);
|
hideControls(300, DEFAULT_CONTROLS_HIDE_TIME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, false);
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,14 +283,14 @@ public class MainVideoPlayer extends Activity {
|
|||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
super.onStopTrackingTouch(seekBar);
|
super.onStopTrackingTouch(seekBar);
|
||||||
if (playerImpl.wasPlaying()) {
|
if (playerImpl.wasPlaying()) {
|
||||||
animateView(playerImpl.getControlsRoot(), false, 100, 0);
|
hideControls(100, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDismiss(PopupMenu menu) {
|
public void onDismiss(PopupMenu menu) {
|
||||||
super.onDismiss(menu);
|
super.onDismiss(menu);
|
||||||
if (isPlaying()) animateView(getControlsRoot(), false, 500, 0);
|
if (isPlaying()) hideControls(300, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -310,53 +308,51 @@ public class MainVideoPlayer extends Activity {
|
|||||||
public void onLoading() {
|
public void onLoading() {
|
||||||
super.onLoading();
|
super.onLoading();
|
||||||
playPauseButton.setImageResource(R.drawable.ic_pause_white);
|
playPauseButton.setImageResource(R.drawable.ic_pause_white);
|
||||||
animateView(playPauseButton, false, 100, 0);
|
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 100);
|
||||||
|
getRootView().setKeepScreenOn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBuffering() {
|
public void onBuffering() {
|
||||||
super.onBuffering();
|
super.onBuffering();
|
||||||
animateView(playPauseButton, false, 100, 0);
|
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 100);
|
||||||
|
getRootView().setKeepScreenOn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlaying() {
|
public void onPlaying() {
|
||||||
super.onPlaying();
|
super.onPlaying();
|
||||||
//playPauseButton.setImageResource(R.drawable.ic_pause_white);
|
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, new Runnable() {
|
||||||
//animateView(playPauseButton, true, 500, 0);
|
|
||||||
|
|
||||||
animateView(playPauseButton, false, 80, 0, new Runnable() {
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
playPauseButton.setImageResource(R.drawable.ic_pause_white);
|
playPauseButton.setImageResource(R.drawable.ic_pause_white);
|
||||||
animateView(playPauseButton, true, 200, 0);
|
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, true, 200);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
showSystemUi();
|
showSystemUi();
|
||||||
|
getRootView().setKeepScreenOn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPaused() {
|
public void onPaused() {
|
||||||
super.onPaused();
|
super.onPaused();
|
||||||
//playPauseButton.setImageResource(R.drawable.ic_play_arrow_white);
|
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, new Runnable() {
|
||||||
//animateView(playPauseButton, true, 100, 0);
|
|
||||||
|
|
||||||
animateView(playPauseButton, false, 80, 0, new Runnable() {
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white);
|
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white);
|
||||||
animateView(playPauseButton, true, 200, 0);
|
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, true, 200);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
showSystemUi();
|
showSystemUi();
|
||||||
|
getRootView().setKeepScreenOn(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPausedSeek() {
|
public void onPausedSeek() {
|
||||||
super.onPausedSeek();
|
super.onPausedSeek();
|
||||||
animateView(playPauseButton, false, 100, 0);
|
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 100);
|
||||||
|
getRootView().setKeepScreenOn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -366,14 +362,15 @@ public class MainVideoPlayer extends Activity {
|
|||||||
playPauseButton.setImageResource(R.drawable.ic_pause_white);
|
playPauseButton.setImageResource(R.drawable.ic_pause_white);
|
||||||
} else {
|
} else {
|
||||||
showSystemUi();
|
showSystemUi();
|
||||||
animateView(playPauseButton, false, 0, 0, new Runnable() {
|
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
playPauseButton.setImageResource(R.drawable.ic_replay_white);
|
playPauseButton.setImageResource(R.drawable.ic_replay_white);
|
||||||
animateView(playPauseButton, true, 300, 0);
|
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, true, 300);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
getRootView().setKeepScreenOn(false);
|
||||||
super.onCompleted();
|
super.onCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,19 +379,20 @@ public class MainVideoPlayer extends Activity {
|
|||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void animateView(View view, boolean enterOrExit, long duration, long delay, final Runnable execOnEnd, boolean hideUi) {
|
public void hideControls(final long duration, long delay) {
|
||||||
//if (execOnEnd == null) playerImpl.setDefaultAnimationEnd(hideUiRunnable);
|
if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
|
||||||
|
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
|
||||||
if (hideUi && execOnEnd != null) {
|
getControlsVisibilityHandler().postDelayed(new Runnable() {
|
||||||
Runnable combinedRunnable = new Runnable() {
|
@Override
|
||||||
@Override
|
public void run() {
|
||||||
public void run() {
|
animateView(getControlsRoot(), false, duration, 0, new Runnable() {
|
||||||
execOnEnd.run();
|
@Override
|
||||||
hideUiRunnable.run();
|
public void run() {
|
||||||
}
|
hideSystemUi();
|
||||||
};
|
}
|
||||||
super.animateView(view, enterOrExit, duration, delay, combinedRunnable, true);
|
});
|
||||||
} else super.animateView(view, enterOrExit, duration, delay, hideUi ? hideUiRunnable : execOnEnd, hideUi);
|
}
|
||||||
|
}, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@@ -443,19 +441,16 @@ public class MainVideoPlayer extends Activity {
|
|||||||
if (DEBUG) Log.d(TAG, "onSingleTapConfirmed() called with: e = [" + e + "]");
|
if (DEBUG) Log.d(TAG, "onSingleTapConfirmed() called with: e = [" + e + "]");
|
||||||
if (playerImpl.getCurrentState() != BasePlayer.STATE_PLAYING) return true;
|
if (playerImpl.getCurrentState() != BasePlayer.STATE_PLAYING) return true;
|
||||||
|
|
||||||
if (playerImpl.isControlsVisible()) playerImpl.animateView(playerImpl.getControlsRoot(), false, 150, 0, true);
|
if (playerImpl.isControlsVisible()) playerImpl.hideControls(150, 0);
|
||||||
else {
|
else {
|
||||||
playerImpl.animateView(playerImpl.getControlsRoot(), true, 500, 0, new Runnable() {
|
playerImpl.showControlsThenHide();
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
playerImpl.animateView(playerImpl.getControlsRoot(), false, 300, VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
showSystemUi();
|
showSystemUi();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final boolean isGestureControlsEnabled = playerImpl.getSharedPreferences().getBoolean(getString(R.string.player_gesture_controls_key), true);
|
||||||
|
|
||||||
private final float stepsBrightness = 15, stepBrightness = (1f / stepsBrightness), minBrightness = .01f;
|
private final float stepsBrightness = 15, stepBrightness = (1f / stepsBrightness), minBrightness = .01f;
|
||||||
private float currentBrightness = .5f;
|
private float currentBrightness = .5f;
|
||||||
|
|
||||||
@@ -473,6 +468,8 @@ public class MainVideoPlayer extends Activity {
|
|||||||
// TODO: Improve video gesture controls
|
// TODO: Improve video gesture controls
|
||||||
@Override
|
@Override
|
||||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||||
|
if (!isGestureControlsEnabled) return false;
|
||||||
|
|
||||||
//noinspection PointlessBooleanExpression
|
//noinspection PointlessBooleanExpression
|
||||||
if (DEBUG && false) Log.d(TAG, "MainVideoPlayer.onScroll = " +
|
if (DEBUG && false) Log.d(TAG, "MainVideoPlayer.onScroll = " +
|
||||||
", e1.getRaw = [" + e1.getRawX() + ", " + e1.getRawY() + "]" +
|
", e1.getRaw = [" + e1.getRawX() + ", " + e1.getRawY() + "]" +
|
||||||
@@ -500,7 +497,7 @@ public class MainVideoPlayer extends Activity {
|
|||||||
if (DEBUG) Log.d(TAG, "onScroll().volumeControl, currentVolume = " + currentVolume);
|
if (DEBUG) Log.d(TAG, "onScroll().volumeControl, currentVolume = " + currentVolume);
|
||||||
playerImpl.getVolumeTextView().setText(volumeUnicode + " " + Math.round((((float) currentVolume) / maxVolume) * 100) + "%");
|
playerImpl.getVolumeTextView().setText(volumeUnicode + " " + Math.round((((float) currentVolume) / maxVolume) * 100) + "%");
|
||||||
|
|
||||||
if (playerImpl.getVolumeTextView().getVisibility() != View.VISIBLE) playerImpl.animateView(playerImpl.getVolumeTextView(), true, 200, 0);
|
if (playerImpl.getVolumeTextView().getVisibility() != View.VISIBLE) animateView(playerImpl.getVolumeTextView(), true, 200);
|
||||||
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) playerImpl.getBrightnessTextView().setVisibility(View.GONE);
|
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) playerImpl.getBrightnessTextView().setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
WindowManager.LayoutParams lp = getWindow().getAttributes();
|
WindowManager.LayoutParams lp = getWindow().getAttributes();
|
||||||
@@ -515,7 +512,7 @@ public class MainVideoPlayer extends Activity {
|
|||||||
|
|
||||||
playerImpl.getBrightnessTextView().setText(brightnessUnicode + " " + (brightnessNormalized == 1 ? 0 : brightnessNormalized) + "%");
|
playerImpl.getBrightnessTextView().setText(brightnessUnicode + " " + (brightnessNormalized == 1 ? 0 : brightnessNormalized) + "%");
|
||||||
|
|
||||||
if (playerImpl.getBrightnessTextView().getVisibility() != View.VISIBLE) playerImpl.animateView(playerImpl.getBrightnessTextView(), true, 200, 0);
|
if (playerImpl.getBrightnessTextView().getVisibility() != View.VISIBLE) animateView(playerImpl.getBrightnessTextView(), true, 200);
|
||||||
if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) playerImpl.getVolumeTextView().setVisibility(View.GONE);
|
if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) playerImpl.getVolumeTextView().setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -527,11 +524,11 @@ public class MainVideoPlayer extends Activity {
|
|||||||
eventsNum = 0;
|
eventsNum = 0;
|
||||||
/* if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) playerImpl.getVolumeTextView().setVisibility(View.GONE);
|
/* if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) playerImpl.getVolumeTextView().setVisibility(View.GONE);
|
||||||
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) playerImpl.getBrightnessTextView().setVisibility(View.GONE);*/
|
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) playerImpl.getBrightnessTextView().setVisibility(View.GONE);*/
|
||||||
if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) playerImpl.animateView(playerImpl.getVolumeTextView(), false, 200, 200);
|
if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) animateView(playerImpl.getVolumeTextView(), false, 200, 200);
|
||||||
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) playerImpl.animateView(playerImpl.getBrightnessTextView(), false, 200, 200);
|
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) animateView(playerImpl.getBrightnessTextView(), false, 200, 200);
|
||||||
|
|
||||||
if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == BasePlayer.STATE_PLAYING) {
|
if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == BasePlayer.STATE_PLAYING) {
|
||||||
playerImpl.animateView(playerImpl.getControlsRoot(), false, 300, VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME, true);
|
playerImpl.hideControls(300, VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -53,15 +53,17 @@ public class SettingsActivity extends AppCompatActivity {
|
|||||||
actionBar.setDisplayShowTitleEnabled(true);
|
actionBar.setDisplayShowTitleEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFragmentManager().beginTransaction()
|
if (savedInstanceBundle == null) {
|
||||||
.replace(R.id.fragment_holder, new SettingsFragment())
|
getFragmentManager().beginTransaction()
|
||||||
.commit();
|
.replace(R.id.fragment_holder, new SettingsFragment())
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
int id = item.getItemId();
|
int id = item.getItemId();
|
||||||
if(id == android.R.id.home) {
|
if (id == android.R.id.home) {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
126
app/src/main/java/org/schabi/newpipe/util/AnimationUtils.java
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
package org.schabi.newpipe.util;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.player.BasePlayer;
|
||||||
|
|
||||||
|
public class AnimationUtils {
|
||||||
|
private static final String TAG = "AnimationUtils";
|
||||||
|
private static final boolean DEBUG = BasePlayer.DEBUG;
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
ALPHA, SCALE_AND_ALPHA
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void animateView(View view, boolean enterOrExit, long duration) {
|
||||||
|
animateView(view, Type.ALPHA, enterOrExit, duration, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void animateView(View view, boolean enterOrExit, long duration, long delay) {
|
||||||
|
animateView(view, Type.ALPHA, enterOrExit, duration, delay, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void animateView(View view, boolean enterOrExit, long duration, long delay, Runnable execOnEnd) {
|
||||||
|
animateView(view, Type.ALPHA, enterOrExit, duration, delay, execOnEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void animateView(View view, Type animationType, boolean enterOrExit, long duration) {
|
||||||
|
animateView(view, animationType, enterOrExit, duration, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void animateView(View view, Type animationType, boolean enterOrExit, long duration, long delay) {
|
||||||
|
animateView(view, animationType, enterOrExit, duration, delay, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animate the view
|
||||||
|
*
|
||||||
|
* @param view view that will be animated
|
||||||
|
* @param animationType {@link Type} of the animation
|
||||||
|
* @param enterOrExit true to enter, false to exit
|
||||||
|
* @param duration how long the animation will take, in milliseconds
|
||||||
|
* @param delay how long the animation will wait to start, in milliseconds
|
||||||
|
* @param execOnEnd runnable that will be executed when the animation ends
|
||||||
|
*/
|
||||||
|
public static void animateView(final View view, Type animationType, boolean enterOrExit, long duration, long delay, Runnable execOnEnd) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "animateView() called with: view = [" + view + "], animationType = [" + animationType + "], enterOrExit = [" + enterOrExit + "], duration = [" + duration + "], delay = [" + delay + "], execOnEnd = [" + execOnEnd + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view.getVisibility() == View.VISIBLE && enterOrExit) {
|
||||||
|
if (DEBUG) Log.d(TAG, "animateView() view was already visible > view = [" + view + "]");
|
||||||
|
view.animate().setListener(null).cancel();
|
||||||
|
view.setVisibility(View.VISIBLE);
|
||||||
|
view.setAlpha(1f);
|
||||||
|
if (execOnEnd != null) execOnEnd.run();
|
||||||
|
return;
|
||||||
|
} else if ((view.getVisibility() == View.GONE || view.getVisibility() == View.INVISIBLE) && !enterOrExit) {
|
||||||
|
if (DEBUG) Log.d(TAG, "animateView() view was already gone > view = [" + view + "]");
|
||||||
|
view.animate().setListener(null).cancel();
|
||||||
|
view.setVisibility(View.GONE);
|
||||||
|
view.setAlpha(0f);
|
||||||
|
if (execOnEnd != null) execOnEnd.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
view.animate().setListener(null).cancel();
|
||||||
|
view.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
switch (animationType) {
|
||||||
|
case ALPHA:
|
||||||
|
animateAlpha(view, enterOrExit, duration, delay, execOnEnd);
|
||||||
|
break;
|
||||||
|
case SCALE_AND_ALPHA:
|
||||||
|
animateScaleAndAlpha(view, enterOrExit, duration, delay, execOnEnd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void animateScaleAndAlpha(final View view, boolean enterOrExit, long duration, long delay, final Runnable execOnEnd) {
|
||||||
|
if (enterOrExit) {
|
||||||
|
view.setAlpha(0f);
|
||||||
|
view.setScaleX(.8f);
|
||||||
|
view.setScaleY(.8f);
|
||||||
|
view.animate().alpha(1f).scaleX(1f).scaleY(1f).setDuration(duration).setStartDelay(delay).setListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
if (execOnEnd != null) execOnEnd.run();
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
} else {
|
||||||
|
view.setAlpha(1f);
|
||||||
|
view.setScaleX(1f);
|
||||||
|
view.setScaleY(1f);
|
||||||
|
view.animate().alpha(0f).scaleX(.8f).scaleY(.8f).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 animateAlpha(final View view, boolean enterOrExit, long duration, long delay, final Runnable execOnEnd) {
|
||||||
|
if (enterOrExit) {
|
||||||
|
view.animate().alpha(1f).setDuration(duration).setStartDelay(delay).setListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
if (execOnEnd != null) execOnEnd.run();
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
} else {
|
||||||
|
view.animate().alpha(0f).setDuration(duration).setStartDelay(delay).setListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
view.setVisibility(View.GONE);
|
||||||
|
if (execOnEnd != null) execOnEnd.run();
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,10 +1,12 @@
|
|||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe.util;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
BIN
app/src/main/res/drawable-hdpi/ic_volume_off_black_24dp.png
Normal file
After Width: | Height: | Size: 407 B |
BIN
app/src/main/res/drawable-hdpi/ic_volume_off_white_24dp.png
Normal file
After Width: | Height: | Size: 433 B |
BIN
app/src/main/res/drawable-mdpi/ic_volume_off_black_24dp.png
Normal file
After Width: | Height: | Size: 279 B |
BIN
app/src/main/res/drawable-mdpi/ic_volume_off_white_24dp.png
Normal file
After Width: | Height: | Size: 301 B |
BIN
app/src/main/res/drawable-xhdpi/ic_volume_off_black_24dp.png
Normal file
After Width: | Height: | Size: 493 B |
BIN
app/src/main/res/drawable-xhdpi/ic_volume_off_white_24dp.png
Normal file
After Width: | Height: | Size: 532 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_volume_off_black_24dp.png
Normal file
After Width: | Height: | Size: 704 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_volume_off_white_24dp.png
Normal file
After Width: | Height: | Size: 753 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_volume_off_black_24dp.png
Normal file
After Width: | Height: | Size: 924 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_volume_off_white_24dp.png
Normal file
After Width: | Height: | Size: 1005 B |
@@ -5,8 +5,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@android:color/black"
|
android:background="@android:color/black"
|
||||||
android:gravity="center"
|
android:gravity="center">
|
||||||
android:keepScreenOn="true">
|
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
||||||
android:id="@+id/aspectRatioLayout"
|
android:id="@+id/aspectRatioLayout"
|
||||||
|
@@ -32,12 +32,11 @@
|
|||||||
|
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
android:id="@+id/video_audio_group"
|
android:id="@+id/video_audio_group"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/file_name"
|
android:layout_below="@+id/file_name"
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:layout_marginLeft="20dp"
|
android:layout_marginLeft="20dp"
|
||||||
android:layout_marginRight="20dp"
|
android:layout_marginBottom="6dp"
|
||||||
android:gravity="left"
|
android:gravity="left"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
tools:ignore="RtlHardcoded">
|
tools:ignore="RtlHardcoded">
|
||||||
@@ -56,11 +55,22 @@
|
|||||||
android:text="@string/audio"/>
|
android:text="@string/audio"/>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/quality_spinner"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minWidth="150dp"
|
||||||
|
android:layout_below="@+id/video_audio_group"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:layout_marginLeft="20dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
tools:listitem="@layout/resolutions_spinner_item"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/threads_text_view"
|
android:id="@+id/threads_text_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/video_audio_group"
|
android:layout_below="@+id/quality_spinner"
|
||||||
android:layout_marginBottom="6dp"
|
android:layout_marginBottom="6dp"
|
||||||
android:layout_marginLeft="24dp"
|
android:layout_marginLeft="24dp"
|
||||||
android:layout_marginRight="24dp"
|
android:layout_marginRight="24dp"
|
||||||
|
@@ -5,7 +5,9 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@android:color/black"
|
android:background="@android:color/black"
|
||||||
android:gravity="center">
|
android:gravity="center"
|
||||||
|
tools:layout_width="@dimen/popup_default_width"
|
||||||
|
tools:layout_height="101.25dp">
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
||||||
@@ -189,4 +191,21 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:indeterminate="true"/>
|
android:indeterminate="true"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/resizing_indicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="left|top"
|
||||||
|
android:background="#6e000000"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:text="@string/popup_resizing_indicator_title"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:visibility="visible"/>
|
||||||
</FrameLayout>
|
</FrameLayout>
|