Merge branch 'master' of github.com:theScrabi/NewPipe
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -7,3 +7,4 @@
 | 
			
		||||
/app/app.iml
 | 
			
		||||
/.idea
 | 
			
		||||
/*.iml
 | 
			
		||||
gradle.properties
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,8 @@ android {
 | 
			
		||||
        applicationId "org.schabi.newpipe"
 | 
			
		||||
        minSdkVersion 15
 | 
			
		||||
        targetSdkVersion 23
 | 
			
		||||
        versionCode 9
 | 
			
		||||
        versionName "0.7.0"
 | 
			
		||||
        versionCode 10
 | 
			
		||||
        versionName "0.7.1"
 | 
			
		||||
    }
 | 
			
		||||
    buildTypes {
 | 
			
		||||
        release {
 | 
			
		||||
@@ -35,4 +35,5 @@ dependencies {
 | 
			
		||||
    compile 'com.android.support:recyclerview-v7:23.1.1'
 | 
			
		||||
    compile 'org.jsoup:jsoup:1.8.3'
 | 
			
		||||
    compile 'org.mozilla:rhino:1.7.7'
 | 
			
		||||
    compile 'info.guardianproject.netcipher:netcipher:1.2'
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 | 
			
		||||
    <application
 | 
			
		||||
        android:name=".App"
 | 
			
		||||
        android:allowBackup="true"
 | 
			
		||||
        android:icon="@mipmap/ic_launcher"
 | 
			
		||||
        android:logo="@mipmap/ic_launcher"
 | 
			
		||||
@@ -29,43 +30,46 @@
 | 
			
		||||
            <meta-data
 | 
			
		||||
                android:name="android.support.PARENT_ACTIVITY"
 | 
			
		||||
                android:value=".VideoItemListActivity" />
 | 
			
		||||
 | 
			
		||||
            <intent-filter>
 | 
			
		||||
                <action android:name="android.intent.action.VIEW"/>
 | 
			
		||||
                <action android:name="android.intent.action.VIEW" />
 | 
			
		||||
                <action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
 | 
			
		||||
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
 | 
			
		||||
 | 
			
		||||
                <category android:name="android.intent.category.DEFAULT" />
 | 
			
		||||
                <category android:name="android.intent.category.BROWSABLE" />
 | 
			
		||||
 | 
			
		||||
                <data
 | 
			
		||||
                    android:host="youtube.com"
 | 
			
		||||
                    android:scheme="http"
 | 
			
		||||
                    android:pathPattern="/?*#*/*watch"/>
 | 
			
		||||
                <data
 | 
			
		||||
                    android:host="youtube.com"
 | 
			
		||||
                    android:scheme="https"
 | 
			
		||||
                    android:pathPattern="/?*#*/*watch"/>
 | 
			
		||||
                <data
 | 
			
		||||
                    android:host="www.youtube.com"
 | 
			
		||||
                    android:scheme="http"
 | 
			
		||||
                    android:pathPattern="/?*#*/*watch"/>
 | 
			
		||||
                <data
 | 
			
		||||
                    android:host="www.youtube.com"
 | 
			
		||||
                    android:scheme="https"
 | 
			
		||||
                    android:pathPattern="/?*#*/*watch"/>
 | 
			
		||||
                <data
 | 
			
		||||
                    android:host="m.youtube.com"
 | 
			
		||||
                    android:scheme="http"
 | 
			
		||||
                    android:pathPattern="/?*#*/*watch"/>
 | 
			
		||||
                <data
 | 
			
		||||
                    android:host="m.youtube.com"
 | 
			
		||||
                    android:scheme="https"
 | 
			
		||||
                    android:pathPattern="/?*#*/*watch"/>
 | 
			
		||||
                <data
 | 
			
		||||
                    android:host="youtu.be"
 | 
			
		||||
                    android:scheme="https"
 | 
			
		||||
                    android:pathPrefix="/"/>
 | 
			
		||||
                <data
 | 
			
		||||
                    android:host="youtu.be"
 | 
			
		||||
                    android:scheme="http"
 | 
			
		||||
                    android:pathPrefix="/"/>
 | 
			
		||||
                <data android:scheme="http" />
 | 
			
		||||
                <data android:scheme="https" />
 | 
			
		||||
                <data android:host="youtube.com" />
 | 
			
		||||
                <data android:host="m.youtube.com" />
 | 
			
		||||
                <data android:host="www.youtube.com" />
 | 
			
		||||
                <data android:pathPrefix="/v/" />
 | 
			
		||||
                <data android:pathPrefix="/watch" />
 | 
			
		||||
            </intent-filter>
 | 
			
		||||
            <intent-filter>
 | 
			
		||||
                <action android:name="android.intent.action.VIEW" />
 | 
			
		||||
                <action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
 | 
			
		||||
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
 | 
			
		||||
 | 
			
		||||
                <category android:name="android.intent.category.DEFAULT" />
 | 
			
		||||
                <category android:name="android.intent.category.BROWSABLE" />
 | 
			
		||||
 | 
			
		||||
                <data android:scheme="http" />
 | 
			
		||||
                <data android:scheme="https" />
 | 
			
		||||
                <data android:host="youtu.be" />
 | 
			
		||||
                <data android:pathPrefix="/" />
 | 
			
		||||
            </intent-filter>
 | 
			
		||||
            <intent-filter>
 | 
			
		||||
                <action android:name="android.intent.action.VIEW" />
 | 
			
		||||
                <action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
 | 
			
		||||
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
 | 
			
		||||
 | 
			
		||||
                <category android:name="android.intent.category.DEFAULT" />
 | 
			
		||||
                <category android:name="android.intent.category.BROWSABLE" />
 | 
			
		||||
 | 
			
		||||
                <data android:scheme="vnd.youtube" />
 | 
			
		||||
                <data android:scheme="vnd.youtube.launch" />
 | 
			
		||||
            </intent-filter>
 | 
			
		||||
        </activity>
 | 
			
		||||
        <activity android:name=".PlayVideoActivity"
 | 
			
		||||
@@ -74,15 +78,26 @@
 | 
			
		||||
            android:parentActivityName=".VideoItemDetailActivity"
 | 
			
		||||
            tools:ignore="UnusedAttribute">
 | 
			
		||||
        </activity>
 | 
			
		||||
        <!--TODO: make label a translatable string -->
 | 
			
		||||
        <service
 | 
			
		||||
            android:name=".BackgroundPlayer"
 | 
			
		||||
            android:label="NewPipe Background Player"
 | 
			
		||||
            android:exported="false" >
 | 
			
		||||
        </service>
 | 
			
		||||
            android:label="@string/background_player_name"
 | 
			
		||||
            android:exported="false" />
 | 
			
		||||
        <activity
 | 
			
		||||
            android:name=".SettingsActivity"
 | 
			
		||||
            android:label="@string/title_activity_settings" >
 | 
			
		||||
        </activity>
 | 
			
		||||
        <activity
 | 
			
		||||
            android:name=".PanicResponderActivity"
 | 
			
		||||
            android:launchMode="singleInstance"
 | 
			
		||||
            android:noHistory="true"
 | 
			
		||||
            android:theme="@android:style/Theme.NoDisplay">
 | 
			
		||||
            <intent-filter>
 | 
			
		||||
                <action android:name="info.guardianproject.panic.action.TRIGGER" />
 | 
			
		||||
                <category android:name="android.intent.category.DEFAULT" />
 | 
			
		||||
            </intent-filter>
 | 
			
		||||
        </activity>
 | 
			
		||||
        <activity
 | 
			
		||||
            android:name=".ExitActivity"
 | 
			
		||||
            android:theme="@android:style/Theme.NoDisplay" />
 | 
			
		||||
    </application>
 | 
			
		||||
</manifest>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								app/src/main/java/org/schabi/newpipe/App.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,46 @@
 | 
			
		||||
package org.schabi.newpipe;
 | 
			
		||||
 | 
			
		||||
import android.app.Application;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.SharedPreferences;
 | 
			
		||||
import android.preference.PreferenceManager;
 | 
			
		||||
 | 
			
		||||
import info.guardianproject.netcipher.NetCipher;
 | 
			
		||||
import info.guardianproject.netcipher.proxy.OrbotHelper;
 | 
			
		||||
 | 
			
		||||
public class App extends Application {
 | 
			
		||||
 | 
			
		||||
    private static boolean useTor;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onCreate() {
 | 
			
		||||
        super.onCreate();
 | 
			
		||||
        // if Orbot is installed, then default to using Tor, the user can still override
 | 
			
		||||
        if (OrbotHelper.requestStartTor(this)) {
 | 
			
		||||
            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
 | 
			
		||||
            configureTor(prefs.getBoolean(getString(R.string.useTor), true));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the proxy settings based on whether Tor should be enabled or not.
 | 
			
		||||
     */
 | 
			
		||||
    static void configureTor(boolean enabled) {
 | 
			
		||||
        useTor = enabled;
 | 
			
		||||
        if (useTor) {
 | 
			
		||||
            NetCipher.useTor();
 | 
			
		||||
        } else {
 | 
			
		||||
            NetCipher.setProxy(null);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void checkStartTor(Context context) {
 | 
			
		||||
        if (useTor) {
 | 
			
		||||
            OrbotHelper.requestStartTor(context);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static boolean isUsingTor() {
 | 
			
		||||
        return useTor;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -17,6 +17,7 @@ import android.os.IBinder;
 | 
			
		||||
import android.os.PowerManager;
 | 
			
		||||
import android.support.v7.app.NotificationCompat;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.widget.RemoteViews;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
@@ -113,9 +114,9 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare
 | 
			
		||||
        private int noteID = TAG.hashCode();
 | 
			
		||||
        private BackgroundPlayer owner;
 | 
			
		||||
        private NotificationManager noteMgr;
 | 
			
		||||
        private NotificationCompat.Builder noteBuilder;
 | 
			
		||||
        private WifiManager.WifiLock wifiLock;
 | 
			
		||||
        private Bitmap videoThumbnail = null;
 | 
			
		||||
        private NotificationCompat.Builder noteBuilder;
 | 
			
		||||
 | 
			
		||||
        public PlayerThread(String src, String title, BackgroundPlayer owner) {
 | 
			
		||||
            this.source = src;
 | 
			
		||||
@@ -124,10 +125,9 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare
 | 
			
		||||
            mediaPlayer = new MediaPlayer();
 | 
			
		||||
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void run() {
 | 
			
		||||
            Resources res = getApplicationContext().getResources();
 | 
			
		||||
 | 
			
		||||
            mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);//cpu lock
 | 
			
		||||
            try {
 | 
			
		||||
                mediaPlayer.setDataSource(source);
 | 
			
		||||
@@ -174,54 +174,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare
 | 
			
		||||
            filter.addAction(ACTION_STOP);
 | 
			
		||||
            registerReceiver(broadcastReceiver, filter);
 | 
			
		||||
 | 
			
		||||
            PendingIntent playPI = PendingIntent.getBroadcast(owner, noteID,
 | 
			
		||||
                    new Intent(ACTION_PLAYPAUSE), PendingIntent.FLAG_UPDATE_CURRENT);
 | 
			
		||||
 | 
			
		||||
            NotificationCompat.Action playButton = new NotificationCompat.Action.Builder
 | 
			
		||||
                    (R.drawable.ic_play_arrow_white_48dp, "Play", playPI).build();
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
            NotificationCompat.Action pauseButton = new NotificationCompat.Action.Builder
 | 
			
		||||
                    (R.drawable.ic_pause_white_24dp, "Pause", playPI).build();
 | 
			
		||||
            */
 | 
			
		||||
 | 
			
		||||
            PendingIntent stopPI = PendingIntent.getBroadcast(owner, noteID,
 | 
			
		||||
                    new Intent(ACTION_STOP), PendingIntent.FLAG_UPDATE_CURRENT);
 | 
			
		||||
 | 
			
		||||
            noteBuilder = new NotificationCompat.Builder(owner);
 | 
			
		||||
            noteBuilder
 | 
			
		||||
                    .setContentTitle(title)
 | 
			
		||||
                    //really? Id like to put something more helpful here.
 | 
			
		||||
                    //.setContentText("NewPipe is playing in the background")
 | 
			
		||||
                    .setContentText(channelName)
 | 
			
		||||
                    //.setAutoCancel(!mediaPlayer.isPlaying())
 | 
			
		||||
                    .setOngoing(true)
 | 
			
		||||
                    .setDeleteIntent(stopPI)
 | 
			
		||||
                    //doesn't fit with Notification.MediaStyle
 | 
			
		||||
                    //.setProgress(vidLength, 0, false)
 | 
			
		||||
                    .setSmallIcon(R.drawable.ic_play_circle_filled_white_24dp)
 | 
			
		||||
                    .setLargeIcon(videoThumbnail)
 | 
			
		||||
                    .setTicker(
 | 
			
		||||
                            String.format(res.getString(
 | 
			
		||||
                                    R.string.backgroundPlayerTickerText), title))
 | 
			
		||||
                    .addAction(playButton);
 | 
			
		||||
                    //.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
 | 
			
		||||
                    //.setLargeIcon(cover)
 | 
			
		||||
            if(android.os.Build.VERSION.SDK_INT >= 16)
 | 
			
		||||
                noteBuilder.setPriority(Notification.PRIORITY_LOW);
 | 
			
		||||
            if(android.os.Build.VERSION.SDK_INT >= 21)
 | 
			
		||||
                noteBuilder.setCategory(Notification.CATEGORY_TRANSPORT);
 | 
			
		||||
 | 
			
		||||
                noteBuilder.setStyle(new NotificationCompat.MediaStyle()
 | 
			
		||||
                                //.setMediaSession(mMediaSession.getSessionToken())
 | 
			
		||||
                                .setShowActionsInCompactView(new int[]{0})
 | 
			
		||||
                                .setShowCancelButton(true)
 | 
			
		||||
                                .setCancelButtonIntent(stopPI));
 | 
			
		||||
            if(videoThumbnail != null) {
 | 
			
		||||
                noteBuilder.setLargeIcon(videoThumbnail);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Notification note = noteBuilder.build();
 | 
			
		||||
            Notification note = buildNotification();
 | 
			
		||||
 | 
			
		||||
            Intent openDetailView = new Intent(getApplicationContext(),
 | 
			
		||||
                    VideoItemDetailActivity.class);
 | 
			
		||||
@@ -249,7 +202,6 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare
 | 
			
		||||
                    Log.d(TAG, "sleep failure");
 | 
			
		||||
                }
 | 
			
		||||
            }*/
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
 | 
			
		||||
@@ -303,5 +255,93 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare
 | 
			
		||||
                afterPlayCleanup();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Notification buildNotification() {
 | 
			
		||||
            Notification note;
 | 
			
		||||
            Resources res = getApplicationContext().getResources();
 | 
			
		||||
            noteBuilder = new NotificationCompat.Builder(owner);
 | 
			
		||||
 | 
			
		||||
            PendingIntent playPI = PendingIntent.getBroadcast(owner, noteID,
 | 
			
		||||
                    new Intent(ACTION_PLAYPAUSE), PendingIntent.FLAG_UPDATE_CURRENT);
 | 
			
		||||
            PendingIntent stopPI = PendingIntent.getBroadcast(owner, noteID,
 | 
			
		||||
                    new Intent(ACTION_STOP), PendingIntent.FLAG_UPDATE_CURRENT);
 | 
			
		||||
            /*
 | 
			
		||||
            NotificationCompat.Action pauseButton = new NotificationCompat.Action.Builder
 | 
			
		||||
                    (R.drawable.ic_pause_white_24dp, "Pause", playPI).build();
 | 
			
		||||
            */
 | 
			
		||||
 | 
			
		||||
            noteBuilder
 | 
			
		||||
                    .setOngoing(true)
 | 
			
		||||
                    .setDeleteIntent(stopPI)
 | 
			
		||||
                            //doesn't fit with Notification.MediaStyle
 | 
			
		||||
                            //.setProgress(vidLength, 0, false)
 | 
			
		||||
                    .setSmallIcon(R.drawable.ic_play_circle_filled_white_24dp)
 | 
			
		||||
                    .setTicker(
 | 
			
		||||
                            String.format(res.getString(
 | 
			
		||||
                                    R.string.backgroundPlayerTickerText), title));
 | 
			
		||||
 | 
			
		||||
            if (android.os.Build.VERSION.SDK_INT < 21) {
 | 
			
		||||
 | 
			
		||||
                NotificationCompat.Action playButton = new NotificationCompat.Action.Builder
 | 
			
		||||
                        (R.drawable.ic_play_arrow_white_48dp,
 | 
			
		||||
                                res.getString(R.string.play), playPI).build();
 | 
			
		||||
 | 
			
		||||
                noteBuilder
 | 
			
		||||
                        .setContentTitle(title)
 | 
			
		||||
                                //really? Id like to put something more helpful here.
 | 
			
		||||
                                //.setContentText("NewPipe is playing in the background")
 | 
			
		||||
                        .setContentText(channelName)
 | 
			
		||||
                                //.setAutoCancel(!mediaPlayer.isPlaying())
 | 
			
		||||
                        .setDeleteIntent(stopPI)
 | 
			
		||||
                                //doesn't fit with Notification.MediaStyle
 | 
			
		||||
                                //.setProgress(vidLength, 0, false)
 | 
			
		||||
                        .setLargeIcon(videoThumbnail)
 | 
			
		||||
                        .addAction(playButton);
 | 
			
		||||
                        //.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
 | 
			
		||||
                        //.setLargeIcon(cover)
 | 
			
		||||
 | 
			
		||||
                if (android.os.Build.VERSION.SDK_INT >= 16)
 | 
			
		||||
                    noteBuilder.setPriority(Notification.PRIORITY_LOW);
 | 
			
		||||
 | 
			
		||||
                noteBuilder.setStyle(new NotificationCompat.MediaStyle()
 | 
			
		||||
                        //.setMediaSession(mMediaSession.getSessionToken())
 | 
			
		||||
                        .setShowActionsInCompactView(new int[]{0})
 | 
			
		||||
                        .setShowCancelButton(true)
 | 
			
		||||
                        .setCancelButtonIntent(stopPI));
 | 
			
		||||
                if (videoThumbnail != null) {
 | 
			
		||||
                    noteBuilder.setLargeIcon(videoThumbnail);
 | 
			
		||||
                }
 | 
			
		||||
                note = noteBuilder.build();
 | 
			
		||||
            } else {
 | 
			
		||||
                RemoteViews view =
 | 
			
		||||
                        new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_notification);
 | 
			
		||||
                view.setImageViewBitmap(R.id.backgroundCover, videoThumbnail);
 | 
			
		||||
                view.setTextViewText(R.id.backgroundSongName, title);
 | 
			
		||||
                view.setTextViewText(R.id.backgroundArtist, channelName);
 | 
			
		||||
                view.setOnClickPendingIntent(R.id.backgroundStop, stopPI);
 | 
			
		||||
                view.setOnClickPendingIntent(R.id.backgroundPlayPause, playPI);
 | 
			
		||||
 | 
			
		||||
                RemoteViews expandedView =
 | 
			
		||||
                        new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_notification);
 | 
			
		||||
                expandedView.setImageViewBitmap(R.id.backgroundCover, videoThumbnail);
 | 
			
		||||
                expandedView.setTextViewText(R.id.backgroundSongName, title);
 | 
			
		||||
                expandedView.setTextViewText(R.id.backgroundArtist, channelName);
 | 
			
		||||
                expandedView.setOnClickPendingIntent(R.id.backgroundStop, stopPI);
 | 
			
		||||
                expandedView.setOnClickPendingIntent(R.id.backgroundPlayPause, playPI);
 | 
			
		||||
 | 
			
		||||
                noteBuilder.setCategory(Notification.CATEGORY_TRANSPORT);
 | 
			
		||||
 | 
			
		||||
                //Make notification appear on lockscreen
 | 
			
		||||
                noteBuilder.setVisibility(Notification.VISIBILITY_PUBLIC);
 | 
			
		||||
 | 
			
		||||
                note = noteBuilder.build();
 | 
			
		||||
                note.contentView = view;
 | 
			
		||||
 | 
			
		||||
                //todo: This never shows up. I was not able to figure out why:
 | 
			
		||||
                note.bigContentView = expandedView;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return note;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -57,26 +57,29 @@ public class DownloadDialog extends DialogFragment {
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void onClick(DialogInterface dialog, int which) {
 | 
			
		||||
                        Context context = getActivity();
 | 
			
		||||
                        SharedPreferences defaultPreferences = PreferenceManager.getDefaultSharedPreferences(context);
 | 
			
		||||
                        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
 | 
			
		||||
                        String suffix = "";
 | 
			
		||||
                        String title = arguments.getString(TITLE);
 | 
			
		||||
                        String url = "";
 | 
			
		||||
                        String downloadFolder = Environment.DIRECTORY_DOWNLOADS;
 | 
			
		||||
                        switch(which) {
 | 
			
		||||
                            case 0:     // Video
 | 
			
		||||
                                suffix = arguments.getString(FILE_SUFFIX_VIDEO);
 | 
			
		||||
                                url = arguments.getString(VIDEO_URL);
 | 
			
		||||
                                downloadFolder = Environment.DIRECTORY_MOVIES;
 | 
			
		||||
                                break;
 | 
			
		||||
                            case 1:
 | 
			
		||||
                                suffix = arguments.getString(FILE_SUFFIX_AUDIO);
 | 
			
		||||
                                url = arguments.getString(AUDIO_URL);
 | 
			
		||||
                                downloadFolder = Environment.DIRECTORY_MUSIC;
 | 
			
		||||
                                break;
 | 
			
		||||
                            default:
 | 
			
		||||
                                Log.d(TAG, "lolz");
 | 
			
		||||
                        }
 | 
			
		||||
                        //to avoid hard-coded string like "/storage/emulated/0/NewPipe"
 | 
			
		||||
                        final File dir = new File(defaultPreferences.getString(
 | 
			
		||||
                                "download_path_preference",
 | 
			
		||||
                                Environment.getExternalStorageDirectory().getAbsolutePath() + "/NewPipe"));
 | 
			
		||||
                        //to avoid hard-coded string like "/storage/emulated/0/Movies"
 | 
			
		||||
                        String downloadPath = prefs.getString(getString(R.string.downloadPathPreference),
 | 
			
		||||
                                Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + downloadFolder);
 | 
			
		||||
                        final File dir = new File(downloadPath);
 | 
			
		||||
                        if(!dir.exists()) {
 | 
			
		||||
                            boolean mkdir = dir.mkdir(); //attempt to create directory
 | 
			
		||||
                            if(!mkdir && !dir.isDirectory()) {
 | 
			
		||||
@@ -84,12 +87,15 @@ public class DownloadDialog extends DialogFragment {
 | 
			
		||||
                                //TODO notify user "download directory should be changed" ?
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        String saveFilePath = dir + "/" + title + suffix;
 | 
			
		||||
                        if (App.isUsingTor()) {
 | 
			
		||||
                            // if using Tor, do not use DownloadManager because the proxy cannot be set
 | 
			
		||||
                            Downloader.downloadFile(getContext(), url, saveFilePath);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
 | 
			
		||||
                            DownloadManager.Request request = new DownloadManager.Request(
 | 
			
		||||
                                    Uri.parse(url));
 | 
			
		||||
                        request.setDestinationUri(Uri.fromFile(new File(
 | 
			
		||||
                                defaultPreferences.getString("download_path_preference", "/storage/emulated/0/NewPipe")
 | 
			
		||||
                                        + "/" + title + suffix)));
 | 
			
		||||
                            request.setDestinationUri(Uri.fromFile(new File(saveFilePath)));
 | 
			
		||||
                            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
 | 
			
		||||
                            try {
 | 
			
		||||
                                dm.enqueue(request);
 | 
			
		||||
@@ -97,6 +103,7 @@ public class DownloadDialog extends DialogFragment {
 | 
			
		||||
                                e.printStackTrace();
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
        return builder.create();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,30 @@
 | 
			
		||||
package org.schabi.newpipe;
 | 
			
		||||
 | 
			
		||||
import android.app.Notification;
 | 
			
		||||
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 java.io.BufferedInputStream;
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.InputStreamReader;
 | 
			
		||||
import java.net.HttpURLConnection;
 | 
			
		||||
import java.net.MalformedURLException;
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import java.net.UnknownHostException;
 | 
			
		||||
 | 
			
		||||
import javax.net.ssl.HttpsURLConnection;
 | 
			
		||||
 | 
			
		||||
import info.guardianproject.netcipher.NetCipher;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by Christian Schabesberger on 14.08.15.
 | 
			
		||||
 *
 | 
			
		||||
@@ -28,6 +46,7 @@ import java.net.UnknownHostException;
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
public class Downloader {
 | 
			
		||||
    public static final String TAG = "Downloader";
 | 
			
		||||
 | 
			
		||||
    private static final String USER_AGENT = "Mozilla/5.0";
 | 
			
		||||
 | 
			
		||||
@@ -40,7 +59,7 @@ public class Downloader {
 | 
			
		||||
        String ret = "";
 | 
			
		||||
        try {
 | 
			
		||||
            URL url = new URL(siteUrl);
 | 
			
		||||
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
 | 
			
		||||
            HttpsURLConnection con = NetCipher.getHttpsURLConnection(url);
 | 
			
		||||
            con.setRequestProperty("Accept-Language", language);
 | 
			
		||||
            ret = dl(con);
 | 
			
		||||
        }
 | 
			
		||||
@@ -84,7 +103,7 @@ public class Downloader {
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            URL url = new URL(siteUrl);
 | 
			
		||||
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
 | 
			
		||||
            HttpsURLConnection con = NetCipher.getHttpsURLConnection(url);
 | 
			
		||||
            ret = dl(con);
 | 
			
		||||
        }
 | 
			
		||||
        catch(Exception e) {
 | 
			
		||||
@@ -93,4 +112,92 @@ public class Downloader {
 | 
			
		||||
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
     * @throws IOException
 | 
			
		||||
     */
 | 
			
		||||
    public static void downloadFile(final Context context, final String fileURL, final String saveFilePath) {
 | 
			
		||||
        new AsyncTask<Void, Integer, Void>() {
 | 
			
		||||
 | 
			
		||||
            private NotificationManager nm;
 | 
			
		||||
            private NotificationCompat.Builder builder;
 | 
			
		||||
            private int notifyId = 0x1234;
 | 
			
		||||
            private int fileSize = 0xffffffff;
 | 
			
		||||
 | 
			
		||||
            @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.substring(saveFilePath.lastIndexOf('/') + 1))
 | 
			
		||||
                        .setContentText(saveFilePath)
 | 
			
		||||
                        .setProgress(fileSize, 0, false);
 | 
			
		||||
                nm.notify(notifyId, builder.build());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            protected Void doInBackground(Void... voids) {
 | 
			
		||||
                HttpsURLConnection con = 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 inputStream = new BufferedInputStream(con.getInputStream());
 | 
			
		||||
                        FileOutputStream 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);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        outputStream.close();
 | 
			
		||||
                        inputStream.close();
 | 
			
		||||
                        publishProgress(bufferSize);
 | 
			
		||||
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Log.i(TAG, "No file to download. Server replied HTTP code: " + responseCode);
 | 
			
		||||
                    }
 | 
			
		||||
                } catch (IOException e) {
 | 
			
		||||
                    e.printStackTrace();
 | 
			
		||||
                } finally {
 | 
			
		||||
                    if (con != null) {
 | 
			
		||||
                        con.disconnect();
 | 
			
		||||
                        con = null;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                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);
 | 
			
		||||
            }
 | 
			
		||||
        }.execute();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										36
									
								
								app/src/main/java/org/schabi/newpipe/ExitActivity.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,36 @@
 | 
			
		||||
 | 
			
		||||
package org.schabi.newpipe;
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint;
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.os.Build;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
 | 
			
		||||
public class ExitActivity extends Activity {
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("NewApi")
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
 | 
			
		||||
        if (Build.VERSION.SDK_INT >= 21) {
 | 
			
		||||
            finishAndRemoveTask();
 | 
			
		||||
        } else {
 | 
			
		||||
            finish();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        System.exit(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void exitAndRemoveFromRecentApps(Activity activity) {
 | 
			
		||||
        Intent intent = new Intent(activity, ExitActivity.class);
 | 
			
		||||
 | 
			
		||||
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
 | 
			
		||||
                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
 | 
			
		||||
                | Intent.FLAG_ACTIVITY_CLEAR_TASK
 | 
			
		||||
                | Intent.FLAG_ACTIVITY_NO_ANIMATION);
 | 
			
		||||
 | 
			
		||||
        activity.startActivity(intent);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								app/src/main/java/org/schabi/newpipe/Localization.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,77 @@
 | 
			
		||||
package org.schabi.newpipe;
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.SharedPreferences;
 | 
			
		||||
import android.content.res.Resources;
 | 
			
		||||
import android.preference.PreferenceManager;
 | 
			
		||||
 | 
			
		||||
import java.text.DateFormat;
 | 
			
		||||
import java.text.NumberFormat;
 | 
			
		||||
import java.text.ParseException;
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.Locale;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by chschtsch on 12/29/15.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
public class Localization {
 | 
			
		||||
 | 
			
		||||
    public static Locale getPreferredLocale(Context context) {
 | 
			
		||||
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
 | 
			
		||||
 | 
			
		||||
        String languageCode = sp.getString(String.valueOf(R.string.searchLanguage), "en");
 | 
			
		||||
 | 
			
		||||
        if(languageCode.length() == 2) {
 | 
			
		||||
            return new Locale(languageCode);
 | 
			
		||||
        }
 | 
			
		||||
        else if(languageCode.contains("_")) {
 | 
			
		||||
            String country = languageCode
 | 
			
		||||
                    .substring(languageCode.indexOf("_"), languageCode.length());
 | 
			
		||||
            return new Locale(languageCode.substring(0, 2), country);
 | 
			
		||||
        }
 | 
			
		||||
        return Locale.getDefault();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String localizeViewCount(long viewCount, Context context) {
 | 
			
		||||
        Locale locale = getPreferredLocale(context);
 | 
			
		||||
 | 
			
		||||
        Resources res = context.getResources();
 | 
			
		||||
        String viewsString = res.getString(R.string.viewCountText);
 | 
			
		||||
 | 
			
		||||
        NumberFormat nf = NumberFormat.getInstance(locale);
 | 
			
		||||
        String formattedViewCount = nf.format(viewCount);
 | 
			
		||||
        return String.format(viewsString, formattedViewCount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String localizeNumber(long number, Context context) {
 | 
			
		||||
        Locale locale = getPreferredLocale(context);
 | 
			
		||||
        NumberFormat nf = NumberFormat.getInstance(locale);
 | 
			
		||||
        return nf.format(number);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String formatDate(String date, Context context) {
 | 
			
		||||
        Locale locale = getPreferredLocale(context);
 | 
			
		||||
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
 | 
			
		||||
        Date datum = null;
 | 
			
		||||
        try {
 | 
			
		||||
            datum = formatter.parse(date);
 | 
			
		||||
        } catch (ParseException e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
 | 
			
		||||
 | 
			
		||||
        return df.format(datum);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String localizeDate(String date, Context context) {
 | 
			
		||||
        Resources res = context.getResources();
 | 
			
		||||
        String dateString = res.getString(R.string.uploadDateText);
 | 
			
		||||
 | 
			
		||||
        String formattedDate = formatDate(date, context);
 | 
			
		||||
        return String.format(dateString, formattedDate);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
 | 
			
		||||
package org.schabi.newpipe;
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint;
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.os.Build;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
 | 
			
		||||
public class PanicResponderActivity extends Activity {
 | 
			
		||||
 | 
			
		||||
    public static final String PANIC_TRIGGER_ACTION = "info.guardianproject.panic.action.TRIGGER";
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("NewApi")
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
 | 
			
		||||
        Intent intent = getIntent();
 | 
			
		||||
        if (intent != null && PANIC_TRIGGER_ACTION.equals(intent.getAction())) {
 | 
			
		||||
            // TODO explicitly clear the search results once they are restored when the app restarts
 | 
			
		||||
            // or if the app reloads the current video after being killed, that should be cleared also
 | 
			
		||||
            ExitActivity.exitAndRemoveFromRecentApps(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (Build.VERSION.SDK_INT >= 21) {
 | 
			
		||||
            finishAndRemoveTask();
 | 
			
		||||
        } else {
 | 
			
		||||
            finish();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -187,6 +187,18 @@ public class PlayVideoActivity extends AppCompatActivity {
 | 
			
		||||
        videoView.pause();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onResume() {
 | 
			
		||||
        super.onResume();
 | 
			
		||||
        App.checkStartTor(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onDestroy() {
 | 
			
		||||
        super.onDestroy();
 | 
			
		||||
        prefs = getPreferences(Context.MODE_PRIVATE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onOptionsItemSelected(MenuItem item) {
 | 
			
		||||
        int id = item.getItemId();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,14 @@
 | 
			
		||||
package org.schabi.newpipe;
 | 
			
		||||
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.SharedPreferences;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.content.res.Configuration;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.os.Environment;
 | 
			
		||||
import android.preference.CheckBoxPreference;
 | 
			
		||||
import android.preference.Preference;
 | 
			
		||||
import android.preference.PreferenceActivity;
 | 
			
		||||
import android.preference.PreferenceFragment;
 | 
			
		||||
import android.preference.PreferenceManager;
 | 
			
		||||
import android.support.annotation.LayoutRes;
 | 
			
		||||
import android.support.annotation.NonNull;
 | 
			
		||||
import android.support.v7.app.ActionBar;
 | 
			
		||||
@@ -17,6 +18,8 @@ import android.view.MenuItem;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
 | 
			
		||||
import info.guardianproject.netcipher.proxy.OrbotHelper;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by Christian Schabesberger on 31.08.15.
 | 
			
		||||
 *
 | 
			
		||||
@@ -39,6 +42,7 @@ import android.view.ViewGroup;
 | 
			
		||||
 | 
			
		||||
public class SettingsActivity extends PreferenceActivity {
 | 
			
		||||
 | 
			
		||||
    private static final int REQUEST_INSTALL_ORBOT = 0x1234;
 | 
			
		||||
    private AppCompatDelegate mDelegate = null;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -56,11 +60,46 @@ public class SettingsActivity extends PreferenceActivity {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class SettingsFragment extends PreferenceFragment {
 | 
			
		||||
        private CheckBoxPreference useTorCheckBox;
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
            super.onCreate(savedInstanceState);
 | 
			
		||||
            addPreferencesFromResource(R.xml.settings_screen);
 | 
			
		||||
 | 
			
		||||
            // if Orbot is installed, then default to using Tor, the user can still override
 | 
			
		||||
            useTorCheckBox = (CheckBoxPreference) findPreference(getString(R.string.useTor));
 | 
			
		||||
            final Activity activity = getActivity();
 | 
			
		||||
            final boolean useTor = OrbotHelper.isOrbotInstalled(activity);
 | 
			
		||||
            useTorCheckBox.setDefaultValue(useTor);
 | 
			
		||||
            useTorCheckBox.setChecked(useTor);
 | 
			
		||||
            useTorCheckBox.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
 | 
			
		||||
                @Override
 | 
			
		||||
                public boolean onPreferenceChange(Preference preference, Object o) {
 | 
			
		||||
                    boolean useTor = (Boolean) o;
 | 
			
		||||
                    if (useTor) {
 | 
			
		||||
                        if (OrbotHelper.isOrbotInstalled(activity)) {
 | 
			
		||||
                            App.configureTor(true);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            Intent intent = OrbotHelper.getOrbotInstallIntent(activity);
 | 
			
		||||
                            activity.startActivityForResult(intent, REQUEST_INSTALL_ORBOT);
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        App.configureTor(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 | 
			
		||||
        super.onActivityResult(requestCode, resultCode, data);
 | 
			
		||||
        // try to start tor regardless of resultCode since clicking back after
 | 
			
		||||
        // installing the app does not necessarily return RESULT_OK
 | 
			
		||||
        App.configureTor(requestCode == REQUEST_INSTALL_ORBOT
 | 
			
		||||
                && OrbotHelper.requestStartTor(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -148,17 +187,4 @@ public class SettingsActivity extends PreferenceActivity {
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void initSettings(Context context) {
 | 
			
		||||
        PreferenceManager.setDefaultValues(context, R.xml.settings_screen, false);
 | 
			
		||||
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
 | 
			
		||||
        if(sp.getString(context.getString(R.string.downloadPathPreference), "").isEmpty()){
 | 
			
		||||
            SharedPreferences.Editor spEditor = sp.edit();
 | 
			
		||||
            String newPipeDownloadStorage =
 | 
			
		||||
                    Environment.getExternalStorageDirectory().getAbsolutePath() + "/NewPipe";
 | 
			
		||||
            spEditor.putString(context.getString(R.string.downloadPathPreference)
 | 
			
		||||
                    , newPipeDownloadStorage);
 | 
			
		||||
            spEditor.apply();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package org.schabi.newpipe;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
@@ -33,7 +34,7 @@ class VideoInfoItemViewCreator {
 | 
			
		||||
        this.inflater = inflater;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public View getViewFromVideoInfoItem(View convertView, ViewGroup parent, VideoPreviewInfo info) {
 | 
			
		||||
    public View getViewFromVideoInfoItem(View convertView, ViewGroup parent, VideoPreviewInfo info, Context context) {
 | 
			
		||||
        ViewHolder holder;
 | 
			
		||||
        if(convertView == null) {
 | 
			
		||||
            convertView = inflater.inflate(R.layout.video_item, parent, false);
 | 
			
		||||
@@ -59,8 +60,7 @@ class VideoInfoItemViewCreator {
 | 
			
		||||
        if(!info.upload_date.isEmpty()) {
 | 
			
		||||
            holder.itemUploadDateView.setText(info.upload_date);
 | 
			
		||||
        } else {
 | 
			
		||||
            //tweak if necessary: This is a hack to prevent having white space in the layout :P
 | 
			
		||||
            holder.itemUploadDateView.setText(String.format("%d", info.view_count));
 | 
			
		||||
            holder.itemUploadDateView.setText(Localization.localizeViewCount(info.view_count, context));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return convertView;
 | 
			
		||||
 
 | 
			
		||||
@@ -113,6 +113,12 @@ public class VideoItemDetailActivity extends AppCompatActivity {
 | 
			
		||||
                .commit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onResume() {
 | 
			
		||||
        super.onResume();
 | 
			
		||||
        App.checkStartTor(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onSaveInstanceState(Bundle outState) {
 | 
			
		||||
        outState.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,7 @@
 | 
			
		||||
package org.schabi.newpipe;
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint;
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.content.SharedPreferences;
 | 
			
		||||
import android.content.res.Resources;
 | 
			
		||||
import android.graphics.Bitmap;
 | 
			
		||||
import android.graphics.BitmapFactory;
 | 
			
		||||
@@ -35,13 +33,7 @@ import android.view.MenuItem;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import java.text.DateFormat;
 | 
			
		||||
import java.text.NumberFormat;
 | 
			
		||||
import java.text.ParseException;
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.Locale;
 | 
			
		||||
import java.util.Vector;
 | 
			
		||||
 | 
			
		||||
import org.schabi.newpipe.services.VideoExtractor;
 | 
			
		||||
@@ -235,7 +227,7 @@ public class VideoItemDetailFragment extends Fragment {
 | 
			
		||||
            switch (info.errorCode) {
 | 
			
		||||
                case VideoInfo.NO_ERROR: {
 | 
			
		||||
                    View nextVideoView = videoItemViewCreator
 | 
			
		||||
                            .getViewFromVideoInfoItem(null, nextVideoFrame, info.nextVideo);
 | 
			
		||||
                            .getViewFromVideoInfoItem(null, nextVideoFrame, info.nextVideo, getContext());
 | 
			
		||||
                    nextVideoFrame.addView(nextVideoView);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -253,31 +245,20 @@ public class VideoItemDetailFragment extends Fragment {
 | 
			
		||||
                    uploaderView.setText(info.uploader);
 | 
			
		||||
                    actionBarHandler.setChannelName(info.uploader);
 | 
			
		||||
 | 
			
		||||
                    Locale locale = getPreferredLocale();
 | 
			
		||||
                    NumberFormat nf = NumberFormat.getInstance(locale);
 | 
			
		||||
                    String localisedViewCount = nf.format(info.view_count);
 | 
			
		||||
                    viewCountView.setText(
 | 
			
		||||
                            String.format(
 | 
			
		||||
                                    res.getString(R.string.viewCountText), localisedViewCount));
 | 
			
		||||
                    String localizedViewCount = Localization.localizeViewCount(info.view_count, getContext());
 | 
			
		||||
                    viewCountView.setText(localizedViewCount);
 | 
			
		||||
 | 
			
		||||
                    thumbsUpView.setText(nf.format(info.like_count));
 | 
			
		||||
                    thumbsDownView.setText(nf.format(info.dislike_count));
 | 
			
		||||
                    String localizedLikeCount = Localization.localizeNumber(info.like_count, getContext());
 | 
			
		||||
                    thumbsUpView.setText(localizedLikeCount);
 | 
			
		||||
 | 
			
		||||
                    @SuppressLint("SimpleDateFormat")
 | 
			
		||||
                    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
 | 
			
		||||
                    Date datum = null;
 | 
			
		||||
                    try {
 | 
			
		||||
                        datum = formatter.parse(info.upload_date);
 | 
			
		||||
                    } catch (ParseException e) {
 | 
			
		||||
                        e.printStackTrace();
 | 
			
		||||
                    }
 | 
			
		||||
                    String localizedDislikeCount = Localization.localizeNumber(info.dislike_count, getContext());
 | 
			
		||||
                    thumbsDownView.setText(localizedDislikeCount);
 | 
			
		||||
 | 
			
		||||
                    DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
 | 
			
		||||
                    String localizedDate = Localization.localizeDate(info.upload_date, getContext());
 | 
			
		||||
                    uploadDateView.setText(localizedDate);
 | 
			
		||||
 | 
			
		||||
                    String localisedDate = df.format(datum);
 | 
			
		||||
                    uploadDateView.setText(
 | 
			
		||||
                            String.format(res.getString(R.string.uploadDateText), localisedDate));
 | 
			
		||||
                    descriptionView.setText(Html.fromHtml(info.description));
 | 
			
		||||
 | 
			
		||||
                    descriptionView.setMovementMethod(LinkMovementMethod.getInstance());
 | 
			
		||||
 | 
			
		||||
                    actionBarHandler.setServiceId(streamingServiceId);
 | 
			
		||||
@@ -306,7 +287,7 @@ public class VideoItemDetailFragment extends Fragment {
 | 
			
		||||
                                VideoItemDetailFragment.ARG_ITEM_ID, currentVideoInfo.nextVideo.id); */
 | 
			
		||||
                            detailIntent.putExtra(
 | 
			
		||||
                                    VideoItemDetailFragment.VIDEO_URL, currentVideoInfo.nextVideo.webpage_url);
 | 
			
		||||
                            //todo: make id dynamic the following line is crap
 | 
			
		||||
 | 
			
		||||
                            detailIntent.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, streamingServiceId);
 | 
			
		||||
                            startActivity(detailIntent);
 | 
			
		||||
                        }
 | 
			
		||||
@@ -315,7 +296,7 @@ public class VideoItemDetailFragment extends Fragment {
 | 
			
		||||
                break;
 | 
			
		||||
                case VideoInfo.ERROR_BLOCKED_BY_GEMA:
 | 
			
		||||
                    thumbnailView.setImageBitmap(BitmapFactory.decodeResource(
 | 
			
		||||
                            getResources(), R.drawable.gruese_die_gema_unangebracht));
 | 
			
		||||
                            getResources(), R.drawable.gruese_die_gema));
 | 
			
		||||
                    backgroundButton.setOnClickListener(new View.OnClickListener() {
 | 
			
		||||
                        @Override
 | 
			
		||||
                        public void onClick(View v) {
 | 
			
		||||
@@ -458,30 +439,6 @@ public class VideoItemDetailFragment extends Fragment {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**Returns the java.util.Locale object which corresponds to the locale set in NewPipe's preferences.
 | 
			
		||||
     * Currently not affected by the device's locale.*/
 | 
			
		||||
    private Locale getPreferredLocale() {
 | 
			
		||||
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
 | 
			
		||||
        String languageKey = getContext().getString(R.string.searchLanguage);
 | 
			
		||||
        //i know the following line defaults languageCode to "en", but java is picky about uninitialised values
 | 
			
		||||
        // Schabi: well lint tels me the value is redundant. I'll suppress it for now.
 | 
			
		||||
        @SuppressWarnings("UnusedAssignment")
 | 
			
		||||
        String languageCode = "en";
 | 
			
		||||
        languageCode = sp.getString(languageKey, "en");
 | 
			
		||||
 | 
			
		||||
        if(languageCode.length() == 2) {
 | 
			
		||||
            return new Locale(languageCode);
 | 
			
		||||
        }
 | 
			
		||||
        else if(languageCode.contains("_")) {
 | 
			
		||||
            String country = languageCode
 | 
			
		||||
                    .substring(languageCode.indexOf("_"), languageCode.length());
 | 
			
		||||
            return new Locale(languageCode.substring(0, 2), country);
 | 
			
		||||
        }
 | 
			
		||||
        return Locale.getDefault();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean checkIfLandscape() {
 | 
			
		||||
        DisplayMetrics displayMetrics = new DisplayMetrics();
 | 
			
		||||
        getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ package org.schabi.newpipe;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.preference.PreferenceManager;
 | 
			
		||||
import android.support.v4.app.NavUtils;
 | 
			
		||||
import android.support.v7.app.AppCompatActivity;
 | 
			
		||||
import android.support.v7.widget.SearchView;
 | 
			
		||||
@@ -171,7 +172,13 @@ public class VideoItemListActivity extends AppCompatActivity
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SettingsActivity.initSettings(this);
 | 
			
		||||
        PreferenceManager.setDefaultValues(this, R.xml.settings_screen, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onResume() {
 | 
			
		||||
        super.onResume();
 | 
			
		||||
        App.checkStartTor(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -96,7 +96,7 @@ class VideoListAdapter extends BaseAdapter {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public View getView(int position, View convertView, ViewGroup parent) {
 | 
			
		||||
        convertView = viewCreator.getViewFromVideoInfoItem(convertView, parent, videoList.get(position));
 | 
			
		||||
        convertView = viewCreator.getViewFromVideoInfoItem(convertView, parent, videoList.get(position), context);
 | 
			
		||||
 | 
			
		||||
        if(listView.isItemChecked(position)) {
 | 
			
		||||
            convertView.setBackgroundColor(ContextCompat.getColor(context,R.color.primaryColorYoutube));
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-hdpi/ic_close_white_24dp.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 221 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-mdpi/ic_close_white_24dp.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 175 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-nodpi/gruese_die_gema.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 89 KiB  | 
| 
		 Before Width: | Height: | Size: 16 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xhdpi/ic_close_white_24dp.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 257 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 347 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 436 B  | 
@@ -8,7 +8,7 @@
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:text="Loading"
 | 
			
		||||
        android:text="@string/loading"
 | 
			
		||||
        android:textAppearance="?android:attr/textAppearanceMedium" />
 | 
			
		||||
 | 
			
		||||
    <ProgressBar
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										66
									
								
								app/src/main/res/layout/player_notification.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,66 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
    android:id="@+id/content"
 | 
			
		||||
    android:layout_width="fill_parent"
 | 
			
		||||
    android:layout_height="wrap_content"
 | 
			
		||||
    android:clickable="true"
 | 
			
		||||
    android:gravity="center_vertical"
 | 
			
		||||
    android:orientation="horizontal"
 | 
			
		||||
    android:background="@color/background_notification_color"
 | 
			
		||||
    tools:targetApi="jelly_bean">
 | 
			
		||||
 | 
			
		||||
    <ImageView
 | 
			
		||||
        android:id="@+id/backgroundCover"
 | 
			
		||||
        android:layout_width="64dp"
 | 
			
		||||
        android:layout_height="64dp"
 | 
			
		||||
        android:src="@drawable/dummy_thumbnail"
 | 
			
		||||
        android:scaleType="centerCrop"/>
 | 
			
		||||
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
        android:layout_width="0dp"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_marginLeft="8dp"
 | 
			
		||||
        android:layout_weight="1"
 | 
			
		||||
        android:orientation="vertical" >
 | 
			
		||||
 | 
			
		||||
        <TextView
 | 
			
		||||
            android:id="@+id/backgroundSongName"
 | 
			
		||||
            style="@android:style/TextAppearance.StatusBar.EventContent.Title"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:ellipsize="marquee"
 | 
			
		||||
            android:singleLine="true"
 | 
			
		||||
            android:text="title" />
 | 
			
		||||
 | 
			
		||||
        <TextView
 | 
			
		||||
            android:id="@+id/backgroundArtist"
 | 
			
		||||
            style="@android:style/TextAppearance.StatusBar.EventContent"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:ellipsize="marquee"
 | 
			
		||||
            android:singleLine="true"
 | 
			
		||||
            android:text="artist" />
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
    <ImageButton
 | 
			
		||||
        android:id="@+id/backgroundPlayPause"
 | 
			
		||||
        android:layout_width="40dp"
 | 
			
		||||
        android:layout_height="40dp"
 | 
			
		||||
        android:layout_margin="5dp"
 | 
			
		||||
        android:background="#00ffffff"
 | 
			
		||||
        android:clickable="true"
 | 
			
		||||
        android:scaleType="fitXY"
 | 
			
		||||
        android:src="@drawable/ic_play_arrow_white_48dp" />
 | 
			
		||||
 | 
			
		||||
    <ImageButton
 | 
			
		||||
        android:id="@+id/backgroundStop"
 | 
			
		||||
        android:layout_width="40dp"
 | 
			
		||||
        android:layout_height="40dp"
 | 
			
		||||
        android:layout_margin="5dp"
 | 
			
		||||
        android:background="#00ffffff"
 | 
			
		||||
        android:clickable="true"
 | 
			
		||||
        android:scaleType="fitXY"
 | 
			
		||||
        android:src="@drawable/ic_close_white_24dp" />
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
							
								
								
									
										80
									
								
								app/src/main/res/layout/player_notification_expanded.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,80 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
    android:id="@+id/content"
 | 
			
		||||
    android:layout_width="fill_parent"
 | 
			
		||||
    android:layout_height="wrap_content"
 | 
			
		||||
    android:clickable="true"
 | 
			
		||||
    android:background="@color/background_notification_color"
 | 
			
		||||
    tools:targetApi="jelly_bean" >
 | 
			
		||||
 | 
			
		||||
    <ImageView
 | 
			
		||||
        android:id="@+id/backgroundCover"
 | 
			
		||||
        android:layout_width="128dp"
 | 
			
		||||
        android:layout_height="128dp"
 | 
			
		||||
        android:layout_marginRight="8dp"
 | 
			
		||||
        android:src="@drawable/dummy_thumbnail"
 | 
			
		||||
        android:scaleType="centerCrop"/>
 | 
			
		||||
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
        android:layout_width="fill_parent"
 | 
			
		||||
        android:layout_height="fill_parent"
 | 
			
		||||
        android:layout_above="@+id/backgroundButtons"
 | 
			
		||||
        android:layout_toRightOf="@+id/backgroundCover"
 | 
			
		||||
        android:gravity="center_vertical"
 | 
			
		||||
        android:orientation="vertical" >
 | 
			
		||||
 | 
			
		||||
        <TextView
 | 
			
		||||
            android:id="@+id/backgroundSongName"
 | 
			
		||||
            style="@android:style/TextAppearance.StatusBar.EventContent.Title"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_marginRight="40dp"
 | 
			
		||||
            android:ellipsize="marquee"
 | 
			
		||||
            android:singleLine="true"
 | 
			
		||||
            android:text="title" />
 | 
			
		||||
 | 
			
		||||
        <TextView
 | 
			
		||||
            android:id="@+id/backgroundArtist"
 | 
			
		||||
            style="@android:style/TextAppearance.StatusBar.EventContent"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:ellipsize="marquee"
 | 
			
		||||
            android:singleLine="true"
 | 
			
		||||
            android:text="artist" />
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
    <ImageButton
 | 
			
		||||
        android:id="@+id/backgroundStop"
 | 
			
		||||
        android:layout_width="30dp"
 | 
			
		||||
        android:layout_height="30dp"
 | 
			
		||||
        android:layout_alignParentRight="true"
 | 
			
		||||
        android:layout_margin="5dp"
 | 
			
		||||
        android:background="#00ffffff"
 | 
			
		||||
        android:clickable="true"
 | 
			
		||||
        android:scaleType="fitXY"
 | 
			
		||||
        android:src="@drawable/ic_close_white_24dp" />
 | 
			
		||||
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
        android:id="@+id/backgroundButtons"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="40dp"
 | 
			
		||||
        android:layout_alignBottom="@id/backgroundCover"
 | 
			
		||||
        android:layout_alignParentRight="true"
 | 
			
		||||
        android:layout_toRightOf="@+id/backgroundCover"
 | 
			
		||||
        android:orientation="horizontal" >
 | 
			
		||||
 | 
			
		||||
        <ImageButton
 | 
			
		||||
            android:id="@+id/backgroundPlayPause"
 | 
			
		||||
            android:layout_width="0dp"
 | 
			
		||||
            android:layout_height="fill_parent"
 | 
			
		||||
            android:layout_marginLeft="30dp"
 | 
			
		||||
            android:layout_marginRight="30dp"
 | 
			
		||||
            android:layout_weight="1"
 | 
			
		||||
            android:background="#00ffffff"
 | 
			
		||||
            android:clickable="true"
 | 
			
		||||
            android:scaleType="centerInside"
 | 
			
		||||
            android:src="@drawable/ic_play_arrow_white_48dp" />
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
</RelativeLayout>
 | 
			
		||||
@@ -49,4 +49,9 @@
 | 
			
		||||
    <string name="detailUploaderThumbnailViewDescription">Avatar de l\'utilisateur</string>
 | 
			
		||||
    <string name="useExternalVideoPlayerTitle">Utiliser un lecteur vidéo externe</string>
 | 
			
		||||
    <string name="useExternalAudioPlayerTitle">Utiliser un lecteur audio externe</string>
 | 
			
		||||
    <string name="backgroundPlayerStartPlayingToast">Lecture en arrière-plan</string>
 | 
			
		||||
    <string name="background_player_name">Lecteur en arrière-plan NewPipe</string>
 | 
			
		||||
    <string name="loading">Chargement</string>
 | 
			
		||||
    <string name="play">Lecture</string>
 | 
			
		||||
 | 
			
		||||
    </resources>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								app/src/main/res/values-he/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,10 @@
 | 
			
		||||
<?xml version='1.0' encoding='utf-8'?>
 | 
			
		||||
<resources><string name="viewCountText">%1$s צפיות</string>
 | 
			
		||||
    <string name="uploadDateText">הועלה בתאריך %1$s</string>
 | 
			
		||||
    <string name="share">שתף</string>
 | 
			
		||||
    <string name="search">חפש</string>
 | 
			
		||||
    <string name="nextVideoTitle">הבא</string>
 | 
			
		||||
    <string name="download">הורדה</string>
 | 
			
		||||
    <string name="settings">הגדרות</string>
 | 
			
		||||
    <string name="title_activity_settings">הגדרות</string>
 | 
			
		||||
    </resources>
 | 
			
		||||
							
								
								
									
										1
									
								
								app/src/main/res/values-id
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
values-in
 | 
			
		||||
							
								
								
									
										3
									
								
								app/src/main/res/values-in/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,3 @@
 | 
			
		||||
<?xml version='1.0' encoding='utf-8'?>
 | 
			
		||||
<resources>
 | 
			
		||||
</resources>
 | 
			
		||||
							
								
								
									
										1
									
								
								app/src/main/res/values-iw
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
values-he
 | 
			
		||||
@@ -50,4 +50,8 @@
 | 
			
		||||
    <string name="useExternalAudioPlayerTitle">外部オーディオ プレイヤーを使用する</string>
 | 
			
		||||
    <string name="backgroundPlayerStartPlayingToast">バックグラウンドで再生しています</string>
 | 
			
		||||
 | 
			
		||||
    <string name="background_player_name">NewPipe バックグラウンド プレーヤー</string>
 | 
			
		||||
    <string name="loading">読み込み中</string>
 | 
			
		||||
    <string name="play">再生</string>
 | 
			
		||||
 | 
			
		||||
    </resources>
 | 
			
		||||
 
 | 
			
		||||
@@ -51,4 +51,7 @@
 | 
			
		||||
    <string name="detailUploaderThumbnailViewDescription">Миниатюра аватара пользователся</string>
 | 
			
		||||
    <string name="detailThumbsDownImgViewDescription">Дислайки</string>
 | 
			
		||||
    <string name="detailThumbsUpImgViewDescription">Лайки</string>
 | 
			
		||||
</resources>
 | 
			
		||||
<string name="useExternalVideoPlayerTitle">Использовать внешний проигрыватель для видео</string>
 | 
			
		||||
    <string name="useExternalAudioPlayerTitle">Использовать внешний проигрыватель для аудио</string>
 | 
			
		||||
    <string name="backgroundPlayerStartPlayingToast">Проигрывание в фоновом режиме</string>
 | 
			
		||||
    </resources>
 | 
			
		||||
 
 | 
			
		||||
@@ -47,4 +47,9 @@
 | 
			
		||||
 | 
			
		||||
    <string name="detailThumbsUpImgViewDescription">Všeč mi je</string>
 | 
			
		||||
<string name="detailThumbsDownImgViewDescription">Ni mi všeč</string>
 | 
			
		||||
    <string name="background_player_name">Ozadnji predvajalnik NewPipe</string>
 | 
			
		||||
    <string name="loading">Nalaganje ...</string>
 | 
			
		||||
    <string name="backgroundPlayerStartPlayingToast">Predvajanje v ozadju</string>
 | 
			
		||||
    <string name="play">Predvajaj</string>
 | 
			
		||||
 | 
			
		||||
    </resources>
 | 
			
		||||
 
 | 
			
		||||
@@ -54,4 +54,10 @@
 | 
			
		||||
    <string name="useExternalAudioPlayerTitle">Користи спољашњи аудио плејер</string>
 | 
			
		||||
    <string name="backgroundPlayerStartPlayingToast">Пуштам у позадини</string>
 | 
			
		||||
 | 
			
		||||
    </resources>
 | 
			
		||||
    <string name="background_player_name">Позадински плејер за Јутјуб цев</string>
 | 
			
		||||
    <string name="loading">Учитавам</string>
 | 
			
		||||
    <string name="play">Пусти</string>
 | 
			
		||||
 | 
			
		||||
    <string name="useTor">Користи Тор</string>
 | 
			
		||||
    <string name="useTorSummary">Принудно преусмерење саобраћаја кроз Тор за доданту приватност (токови још нису подржани)</string>
 | 
			
		||||
</resources>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,4 +7,5 @@
 | 
			
		||||
    <color name="durationText">#efff</color>
 | 
			
		||||
    <color name="dark_overlay">#6000</color>
 | 
			
		||||
    <color name="background_gray">#EEEEEE</color>
 | 
			
		||||
    <color name="background_notification_color">#323232</color>
 | 
			
		||||
</resources>
 | 
			
		||||
@@ -71,6 +71,7 @@
 | 
			
		||||
        <item>sl</item>
 | 
			
		||||
        <item>fi</item>
 | 
			
		||||
        <item>sv</item>
 | 
			
		||||
        <item>bo</item>
 | 
			
		||||
        <item>vi</item>
 | 
			
		||||
        <item>tr</item>
 | 
			
		||||
        <item>bg</item>
 | 
			
		||||
@@ -149,6 +150,7 @@
 | 
			
		||||
        <item>Slovenščina</item>
 | 
			
		||||
        <item>Suomi</item>
 | 
			
		||||
        <item>Svenska</item>
 | 
			
		||||
        <item>Tibetan བོད་སྐད།</item>
 | 
			
		||||
        <item>Tiếng Việt</item>
 | 
			
		||||
        <item>Türkçe</item>
 | 
			
		||||
        <item>Български</item>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
<?xml version='1.0' encoding='utf-8'?>
 | 
			
		||||
<resources>
 | 
			
		||||
    <string name="app_name" translatable="false">NewPipe</string>
 | 
			
		||||
    <string name="background_player_name">NewPipe Background Player</string>
 | 
			
		||||
    <string name="title_videoitem_detail" translatable="false">NewPipe</string>
 | 
			
		||||
    <string name="viewCountText">%1$s views</string>
 | 
			
		||||
    <string name="uploadDateText">Uploaded on %1$s</string>
 | 
			
		||||
@@ -10,6 +11,7 @@
 | 
			
		||||
    <string name="fdroidVLCurl" translatable="false">https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc</string>
 | 
			
		||||
    <string name="open_in_browser">Open in browser</string>
 | 
			
		||||
    <string name="share">Share</string>
 | 
			
		||||
    <string name="loading">Loading</string>
 | 
			
		||||
    <string name="download">Download</string>
 | 
			
		||||
    <string name="search">Search</string>
 | 
			
		||||
    <string name="settings">Settings</string>
 | 
			
		||||
@@ -53,6 +55,7 @@
 | 
			
		||||
    <string name="backgroundPlayerTickerText" translatable="false">%1$s - NewPipe</string>
 | 
			
		||||
    <string name="backgroundPlayerStartPlayingToast">Playing in background</string>
 | 
			
		||||
    <string name="c3sUrl" translatable="false">https://www.c3s.cc/</string>
 | 
			
		||||
    <string name="play">Play</string>
 | 
			
		||||
 | 
			
		||||
    <!-- Content descriptions (for better accessibility) -->
 | 
			
		||||
    <string name="itemThumbnailViewDescription">Video preview thumbnail</string>
 | 
			
		||||
@@ -60,4 +63,6 @@
 | 
			
		||||
    <string name="detailUploaderThumbnailViewDescription">Uploader thumbnail</string>
 | 
			
		||||
    <string name="detailThumbsDownImgViewDescription">Dislikes</string>
 | 
			
		||||
    <string name="detailThumbsUpImgViewDescription">Likes</string>
 | 
			
		||||
    <string name="useTor">Use Tor</string>
 | 
			
		||||
    <string name="useTorSummary">Force download traffic through Tor for increased privacy (streaming videos not yet supported)</string>
 | 
			
		||||
</resources>
 | 
			
		||||
 
 | 
			
		||||
@@ -64,8 +64,7 @@
 | 
			
		||||
            android:key="@string/downloadPathPreference"
 | 
			
		||||
            android:title="@string/downloadLocation"
 | 
			
		||||
            android:summary="@string/downloadLocationSummary"
 | 
			
		||||
            android:dialogTitle="@string/downloadLocationDialogTitle"
 | 
			
		||||
            android:defaultValue=""/>
 | 
			
		||||
            android:dialogTitle="@string/downloadLocationDialogTitle" />
 | 
			
		||||
 | 
			
		||||
        <CheckBoxPreference
 | 
			
		||||
            android:key="@string/autoPlayThroughIntent"
 | 
			
		||||
@@ -73,5 +72,10 @@
 | 
			
		||||
            android:summary="@string/autoPlayThroughIntentSummary"
 | 
			
		||||
            android:defaultValue="false" />
 | 
			
		||||
 | 
			
		||||
        <CheckBoxPreference
 | 
			
		||||
            android:key="@string/useTor"
 | 
			
		||||
            android:title="@string/useTor"
 | 
			
		||||
            android:summary="@string/useTorSummary" />
 | 
			
		||||
 | 
			
		||||
    </PreferenceCategory>
 | 
			
		||||
</PreferenceScreen>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 62 KiB  | 
@@ -1,18 +0,0 @@
 | 
			
		||||
# Project-wide Gradle settings.
 | 
			
		||||
 | 
			
		||||
# IDE (e.g. Android Studio) users:
 | 
			
		||||
# Gradle settings configured through the IDE *will override*
 | 
			
		||||
# any settings specified in this file.
 | 
			
		||||
 | 
			
		||||
# For more details on how to configure your build environment visit
 | 
			
		||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
 | 
			
		||||
 | 
			
		||||
# Specifies the JVM arguments used for the daemon process.
 | 
			
		||||
# The setting is particularly useful for tweaking memory settings.
 | 
			
		||||
# Default value: -Xmx10248m -XX:MaxPermSize=256m
 | 
			
		||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
 | 
			
		||||
 | 
			
		||||
# When configured, Gradle will run in incubating parallel mode.
 | 
			
		||||
# This option should only be used with decoupled projects. More details, visit
 | 
			
		||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
 | 
			
		||||
# org.gradle.parallel=true
 | 
			
		||||