Merge pull request #209 from sschueller/develop

Release v1.0.44
This commit is contained in:
Stefan Schüller 2020-07-05 20:15:17 +02:00 committed by GitHub
commit cab4220cda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 707 additions and 712 deletions

View File

@ -1,3 +1,9 @@
### Version 1.0.44 Tag: v1.0.44 (2020-07-05)
* Completed implementation of Likes & Dislikes (@Poslovitch)
* Added preview of the current playback speed and video quality in the VideoOptionsFragment (@Poslovitch)
* Lots of code cleanup
* Various translations
### Version 1.0.43 Tag: v1.0.43 (2020-07-04)
* Fix back button issue

19
Dockerfile Normal file
View File

@ -0,0 +1,19 @@
FROM gradle:5.6.4-jdk8
ENV ANDROID_SDK_URL https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
ENV ANDROID_BUILD_TOOLS_VERSION 29.0.3
ENV ANDROID_HOME /usr/local/android-sdk-linux
ENV ANDROID_VERSION 29
ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools
RUN mkdir "$ANDROID_HOME" .android && \
cd "$ANDROID_HOME" && \
curl -o sdk.zip $ANDROID_SDK_URL && \
unzip sdk.zip && \
rm sdk.zip
RUN yes | ${ANDROID_HOME}/tools/bin/sdkmanager --licenses
RUN $ANDROID_HOME/tools/bin/sdkmanager --update
RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \
"platforms;android-${ANDROID_VERSION}" \
"platform-tools"

61
REPRODUCIBLE_BUILDS.md Normal file
View File

@ -0,0 +1,61 @@
# Reproducible Builds
Note: reproducible builds work starting version 1.0.44
## Install Docker
Download and install [Docker](https://www.docker.com/).
## Check your Thorium app version and build timestamp
1. Open the Thorium app
2. Go to Settings
3. Check the app version listed under About 'Version' (e.g., 1.0.44), and record its value to be used later
4. Check the build timestamp under About 'Build Time' (e.g., 1593942384524), and record its value to be used later
## Download the App open-source code
1. Make sure you have `git` installed
2. Clone the Github repository
3. Checkout the Tag that corresponds to the version of your Thorium app (e.g., 1.0.44)
```shell
git clone https://github.com/sschueller/peertube-android ~/peertube-android
cd ~/peertube-android
git checkout v1.0.44
```
## Build the project using Docker
1. Build a Docker Image with the required Android Tools
2. Build the App in the Docker Container while specifying the build timestamp that was recorded earlier (e.g., 1593942384524)
3. Copy the freshly-built APK
```shell
cd ~/peertube-android
docker build -t thorium-builder .
docker run --rm -v ~/peertube-android:/home/peertube-android -w /home/peertube-android thorium-builder gradle assembleProdRelease -PkeystorePassword=securePassword -PkeyAliasPassword=securePassword -PkeystoreFile=build.keystore -PbuildTimestamp=1593942384524
cp app/build/outputs/apk/prod/release/app-prod-release.apk thorium-built.apk
```
## Extract the Play Store APK from your phone
1. Make sure you have `adb` installed
2. Connect your phone to your computer
3. Extract the APK from the phone
```shell
cd ~/peertube-android
adb pull `adb shell pm path net.schueller.peertube | cut -d':' -f2` thorium-store.apk
```
## Compare the two files
1. Make sure you have `python` installed
2. Use the `apkdiff` script to compare the APKs
```shell
cd ~/peertube-android
python apkdiff.py thorium-built.apk thorium-store.apk
```

View File

@ -1,13 +1,33 @@
apply plugin: 'com.android.application'
ext.readProperty = { paramName -> readPropertyWithDefault(paramName, null) }
ext.readPropertyWithDefault = { paramName, defaultValue ->
if (project.hasProperty(paramName)) {
return project.getProperties().get(paramName)
} else {
Properties properties = new Properties()
if (project.rootProject.file('local.properties').exists()) {
properties.load(project.rootProject.file('local.properties').newDataInputStream())
}
if (properties.getProperty(paramName) != null) {
return properties.getProperty(paramName)
} else {
return defaultValue
}
}
}
android {
compileSdkVersion 29
defaultConfig {
applicationId "net.schueller.peertube"
minSdkVersion 21
targetSdkVersion 29
versionCode 1043
versionName "1.0.43"
versionCode 1044
versionName "1.0.44"
//buildTime readPropertyWithDefault('buildTimestamp', System.currentTimeMillis()) + 'L'
//buildConfigField "long", "BUILD_TIME", readPropertyWithDefault('buildTimestamp', System.currentTimeMillis()) + 'L'
//resValue "string", "BUILD_TIME", readPropertyWithDefault('buildTimestamp', System.currentTimeMillis()) + 'L'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ext {
libVersions = [
@ -87,6 +107,7 @@ android {
applicationVariants.all { variant ->
variant.resValue "string", "versionName", variant.versionName
variant.resValue "string", "buildTime", readPropertyWithDefault('buildTimestamp', System.currentTimeMillis()) + ''
}
}

View File

@ -49,7 +49,7 @@
android:label="@string/title_activity_settings"
android:theme="@style/AppTheme.NoActionBar" /> <!-- Server Selection -->
<activity
android:name=".activity.SelectServerActivity"
android:name=".activity.SearchServerActivity"
android:label="@string/title_activity_select_server"
android:theme="@style/AppTheme.NoActionBar" /> <!-- Me -->
<activity

View File

@ -1,145 +0,0 @@
/*
* Copyright 2018 Stefan Schüller <sschueller@techdroid.com>
*
* License: GPL-3.0+
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.schueller.peertube.activity;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import androidx.annotation.LayoutRes;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatDelegate;
import android.preference.PreferenceManager;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import static net.schueller.peertube.helper.Constants.DEFAULT_THEME;
import static net.schueller.peertube.helper.Constants.THEME_PREF_KEY;
/**
* A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
* to be used with AppCompat.
*/
public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
private AppCompatDelegate mDelegate;
@Override
protected void onCreate(Bundle savedInstanceState) {
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
// TODO: cleanup this duplication
// Set Night Mode
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
AppCompatDelegate.setDefaultNightMode(sharedPref.getBoolean("pref_dark_mode", false) ?
AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
// Set theme
setTheme(getResources().getIdentifier(
sharedPref.getString(THEME_PREF_KEY, DEFAULT_THEME),
"style",
getPackageName())
);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getDelegate().onPostCreate(savedInstanceState);
}
public ActionBar getSupportActionBar() {
return getDelegate().getSupportActionBar();
}
// public void setSupportActionBar(@Nullable Toolbar toolbar) {
// getDelegate().setSupportActionBar(toolbar);
// }
@Override
public MenuInflater getMenuInflater() {
return getDelegate().getMenuInflater();
}
@Override
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
@Override
public void setContentView(View view) {
getDelegate().setContentView(view);
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().setContentView(view, params);
}
@Override
public void addContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().addContentView(view, params);
}
@Override
protected void onPostResume() {
super.onPostResume();
getDelegate().onPostResume();
}
@Override
protected void onTitleChanged(CharSequence title, int color) {
super.onTitleChanged(title, color);
getDelegate().setTitle(title);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getDelegate().onConfigurationChanged(newConfig);
}
@Override
protected void onStop() {
super.onStop();
getDelegate().onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
getDelegate().onDestroy();
}
public void invalidateOptionsMenu() {
getDelegate().invalidateOptionsMenu();
}
private AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, null);
}
return mDelegate;
}
}

View File

@ -26,10 +26,9 @@ import android.preference.PreferenceManager;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import java.util.Locale;
import net.schueller.peertube.R;
import static net.schueller.peertube.helper.Constants.DEFAULT_THEME;
import static net.schueller.peertube.helper.Constants.THEME_PREF_KEY;
import java.util.Locale;
public class CommonActivity extends AppCompatActivity {
@ -39,23 +38,28 @@ public class CommonActivity extends AppCompatActivity {
// Set Night Mode
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
AppCompatDelegate.setDefaultNightMode(sharedPref.getBoolean("pref_dark_mode", false) ?
AppCompatDelegate.setDefaultNightMode(sharedPref.getBoolean(getString(R.string.pref_dark_mode_key), false) ?
AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
// Set theme
setTheme(getResources().getIdentifier(
sharedPref.getString(THEME_PREF_KEY, DEFAULT_THEME),
sharedPref.getString(
getString(R.string.pref_theme_key),
getString(R.string.app_default_theme)
),
"style",
getPackageName())
);
// Set language
String countryCode=sharedPref.getString("pref_language_app","en");
Locale locale=new Locale(countryCode);;
String countryCode = sharedPref.getString(getString(R.string.pref_language_app_key), "en");
assert countryCode != null;
Locale locale = new Locale(countryCode);
//Neither Chinese language choice was working, found this fix on stack overflow
if(countryCode.equals("zh-rCN"))
if (countryCode.equals("zh-rCN"))
locale = Locale.SIMPLIFIED_CHINESE;
if(countryCode.equals("zh-rTW"))
if (countryCode.equals("zh-rTW"))
locale = Locale.TRADITIONAL_CHINESE;
Locale.setDefault(locale);

View File

@ -18,7 +18,6 @@
package net.schueller.peertube.activity;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -27,36 +26,25 @@ import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.util.Patterns;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import net.schueller.peertube.R;
import net.schueller.peertube.adapter.ServerAdapter;
import net.schueller.peertube.adapter.VideoAdapter;
import net.schueller.peertube.adapter.ServerSearchAdapter;
import net.schueller.peertube.helper.APIUrlHelper;
import net.schueller.peertube.model.ServerList;
import net.schueller.peertube.model.VideoList;
import net.schueller.peertube.network.GetServerListDataService;
import net.schueller.peertube.network.GetVideoDataService;
import net.schueller.peertube.network.RetrofitInstance;
import java.util.ArrayList;
import java.util.Objects;
import static net.schueller.peertube.helper.Constants.DEFAULT_THEME;
import static net.schueller.peertube.helper.Constants.THEME_PREF_KEY;
public class SearchServerActivity extends CommonActivity {
public class SelectServerActivity extends CommonActivity {
private ServerAdapter serverAdapter;
private ServerSearchAdapter serverAdapter;
private SwipeRefreshLayout swipeRefreshLayout;
private int currentStart = 0;
@ -76,7 +64,7 @@ public class SelectServerActivity extends CommonActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_server_selection);
setContentView(R.layout.activity_search_server);
// Attaching the layout to the toolbar object
Toolbar toolbar = findViewById(R.id.tool_bar_server_selection);
@ -97,10 +85,10 @@ public class SelectServerActivity extends CommonActivity {
emptyView = findViewById(R.id.empty_server_selection_view);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(SelectServerActivity.this);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(SearchServerActivity.this);
recyclerView.setLayoutManager(layoutManager);
serverAdapter = new ServerAdapter(new ArrayList<>(), this);
serverAdapter = new ServerSearchAdapter(new ArrayList<>(), this);
recyclerView.setAdapter(serverAdapter);
loadServers(currentStart, count);
@ -144,7 +132,7 @@ public class SelectServerActivity extends CommonActivity {
isLoading = true;
GetServerListDataService service = RetrofitInstance.getRetrofitInstance(
APIUrlHelper.getServerIndexUrl(SelectServerActivity.this)
APIUrlHelper.getServerIndexUrl(SearchServerActivity.this)
).create(GetServerListDataService.class);
@ -183,7 +171,7 @@ public class SelectServerActivity extends CommonActivity {
@Override
public void onFailure(@NonNull Call<ServerList> call, @NonNull Throwable t) {
Log.wtf("err", t.fillInStackTrace());
Toast.makeText(SelectServerActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show();
Toast.makeText(SearchServerActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show();
isLoading = false;
swipeRefreshLayout.setRefreshing(false);
}

View File

@ -25,8 +25,6 @@ import androidx.preference.PreferenceFragmentCompat;
import net.schueller.peertube.R;
import java.util.Objects;
public class SettingsActivity extends CommonActivity {
@Override

View File

@ -50,7 +50,6 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
@ -320,8 +319,8 @@ public class VideoListActivity extends CommonActivity {
isLoading = true;
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String nsfw = sharedPref.getBoolean("pref_show_nsfw", false) ? "both" : "false";
Set<String> languages = sharedPref.getStringSet("pref_language", null);
String nsfw = sharedPref.getBoolean(getString(R.string.pref_show_nsfw_key), false) ? "both" : "false";
Set<String> languages = sharedPref.getStringSet(getString(R.string.pref_video_language_key), null);
String apiBaseURL = APIUrlHelper.getUrlWithVersion(this);
GetVideoDataService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetVideoDataService.class);
@ -383,7 +382,7 @@ public class VideoListActivity extends CommonActivity {
// only check when we actually need the permission
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED &&
sharedPref.getBoolean("pref_torrent_player", false)) {
sharedPref.getBoolean(getString(R.string.pref_torrent_player_key), false)) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
}
}

View File

@ -36,6 +36,7 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
@ -56,26 +57,25 @@ import net.schueller.peertube.service.VideoPlayerService;
import java.util.ArrayList;
import java.util.Objects;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
//import static net.schueller.peertube.helper.Constants.BACKGROUND_PLAY_PREF_KEY;
import static com.google.android.exoplayer2.ui.PlayerNotificationManager.ACTION_PAUSE;
import static com.google.android.exoplayer2.ui.PlayerNotificationManager.ACTION_PLAY;
import static com.google.android.exoplayer2.ui.PlayerNotificationManager.ACTION_STOP;
import static net.schueller.peertube.helper.Constants.BACKGROUND_AUDIO;
import static net.schueller.peertube.helper.Constants.DEFAULT_THEME;
import static net.schueller.peertube.helper.Constants.THEME_PREF_KEY;
import static net.schueller.peertube.helper.VideoHelper.canEnterPipMode;
public class VideoPlayActivity extends AppCompatActivity {
private static final String TAG = "VideoPlayActivity";
private static boolean floatMode = false;
static boolean floatMode = false;
private static final int REQUEST_CODE = 101;
private BroadcastReceiver receiver;
//This can only be called when in entering pip mode which can't happen if the device doesn't support pip mode.
@SuppressLint("NewApi")
public void makePipControls() {
@ -84,7 +84,7 @@ public class VideoPlayActivity extends AppCompatActivity {
ArrayList<RemoteAction> actions = new ArrayList<>();
Intent actionIntent = new Intent(BACKGROUND_AUDIO);
Intent actionIntent = new Intent(getString(R.string.app_background_audio));
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE, actionIntent, 0);
@SuppressLint({"NewApi", "LocalSuppress"}) Icon icon = Icon.createWithResource(getApplicationContext(), android.R.drawable.stat_sys_speakerphone);
@SuppressLint({"NewApi", "LocalSuppress"}) RemoteAction remoteAction = new RemoteAction(icon, "close pip", "from pip window custom command", pendingIntent);
@ -96,21 +96,21 @@ public class VideoPlayActivity extends AppCompatActivity {
remoteAction = new RemoteAction(icon, "play", "stop the media", pendingIntent);
actions.add(remoteAction);
if (videoPlayerFragment.isPaused()){
Log.e(TAG,"setting actions with play button");
assert videoPlayerFragment != null;
if (videoPlayerFragment.isPaused()) {
Log.e(TAG, "setting actions with play button");
actionIntent = new Intent(ACTION_PLAY);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE, actionIntent, 0);
icon = Icon.createWithResource(getApplicationContext(), com.google.android.exoplayer2.ui.R.drawable.exo_notification_play);
remoteAction = new RemoteAction(icon, "play", "play the media", pendingIntent);
actions.add(remoteAction);
} else {
Log.e(TAG,"setting actions with pause button");
Log.e(TAG, "setting actions with pause button");
actionIntent = new Intent(ACTION_PAUSE);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE, actionIntent, 0);
icon = Icon.createWithResource(getApplicationContext(), com.google.android.exoplayer2.ui.R.drawable.exo_notification_pause);
remoteAction = new RemoteAction(icon, "pause", "pause the media", pendingIntent);
actions.add(remoteAction);
}
actions.add(remoteAction);
//add custom actions to pip window
@ -119,12 +119,13 @@ public class VideoPlayActivity extends AppCompatActivity {
.setActions(actions)
.build();
setPictureInPictureParams(params);
}
public void changedToPipMode() {
FragmentManager fragmentManager = getSupportFragmentManager();
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
assert videoPlayerFragment != null;
videoPlayerFragment.showControls(false);
//create custom actions
makePipControls();
@ -134,11 +135,12 @@ public class VideoPlayActivity extends AppCompatActivity {
filter.addAction(ACTION_STOP);
filter.addAction(ACTION_PAUSE);
filter.addAction(ACTION_PLAY);
filter.addAction((BACKGROUND_AUDIO));
filter.addAction((getString(R.string.app_background_audio)));
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
assert action != null;
if (action.equals(ACTION_PAUSE)) {
videoPlayerFragment.pauseVideo();
makePipControls();
@ -148,7 +150,7 @@ public class VideoPlayActivity extends AppCompatActivity {
makePipControls();
}
if (action.equals(BACKGROUND_AUDIO)) {
if (action.equals(getString(R.string.app_background_audio))) {
unregisterReceiver(receiver);
finish();
}
@ -161,20 +163,23 @@ public class VideoPlayActivity extends AppCompatActivity {
registerReceiver(receiver, filter);
Log.v(TAG, "switched to pip ");
floatMode=true;
floatMode = true;
videoPlayerFragment.showControls(false);
}
public void changedToNormalMode(){
public void changedToNormalMode() {
FragmentManager fragmentManager = getSupportFragmentManager();
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
assert videoPlayerFragment != null;
videoPlayerFragment.showControls(true);
if (receiver != null) {
unregisterReceiver(receiver);
}
Log.v(TAG,"switched to normal");
floatMode=false;
Log.v(TAG, "switched to normal");
floatMode = false;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -182,7 +187,10 @@ public class VideoPlayActivity extends AppCompatActivity {
// Set theme
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
setTheme(getResources().getIdentifier(
sharedPref.getString(THEME_PREF_KEY, DEFAULT_THEME),
sharedPref.getString(
getString(R.string.pref_theme_key),
getString(R.string.app_default_theme)
),
"style",
getPackageName())
);
@ -197,17 +205,17 @@ public class VideoPlayActivity extends AppCompatActivity {
assert videoPlayerFragment != null;
String playingVideo = videoPlayerFragment.getVideoUuid();
Log.v(TAG, "oncreate click: " + videoUuid +" is trying to replace: "+playingVideo);
Log.v(TAG, "oncreate click: " + videoUuid + " is trying to replace: " + playingVideo);
if (TextUtils.isEmpty(playingVideo)){
Log.v(TAG,"oncreate no video currently playing");
if (TextUtils.isEmpty(playingVideo)) {
Log.v(TAG, "oncreate no video currently playing");
videoPlayerFragment.start(videoUuid);
} else if(!playingVideo.equals(videoUuid)){
Log.v(TAG,"oncreate different video playing currently");
} else if (!playingVideo.equals(videoUuid)) {
Log.v(TAG, "oncreate different video playing currently");
videoPlayerFragment.stopVideo();
videoPlayerFragment.start(videoUuid);
} else {
Log.v(TAG,"oncreate same video playing currently");
Log.v(TAG, "oncreate same video playing currently");
}
// if we are in landscape set the video to fullscreen
@ -225,19 +233,18 @@ public class VideoPlayActivity extends AppCompatActivity {
getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);
assert videoPlayerFragment != null;
String videoUuid = intent.getStringExtra(VideoListActivity.EXTRA_VIDEOID);
Log.v(TAG, "new intent click: " + videoUuid +" is trying to replace: "+videoPlayerFragment.getVideoUuid());
assert videoPlayerFragment != null;
Log.v(TAG, "new intent click: " + videoUuid + " is trying to replace: " + videoPlayerFragment.getVideoUuid());
String playingVideo = videoPlayerFragment.getVideoUuid();
if (TextUtils.isEmpty(playingVideo)){
Log.v(TAG,"new intent no video currently playing");
if (TextUtils.isEmpty(playingVideo)) {
Log.v(TAG, "new intent no video currently playing");
videoPlayerFragment.start(videoUuid);
} else if(!playingVideo.equals(videoUuid)){
Log.v(TAG,"new intent different video playing currently");
} else if (!playingVideo.equals(videoUuid)) {
Log.v(TAG, "new intent different video playing currently");
videoPlayerFragment.stopVideo();
videoPlayerFragment.start(videoUuid);
} else {
Log.v(TAG,"new intent same video playing currently");
Log.v(TAG, "new intent same video playing currently");
}
// if we are in landscape set the video to fullscreen
@ -245,12 +252,10 @@ public class VideoPlayActivity extends AppCompatActivity {
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
setOrientation(true);
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
public void onConfigurationChanged(@NonNull Configuration newConfig) {
Log.v(TAG, "onConfigurationChanged()...");
super.onConfigurationChanged(newConfig);
@ -263,58 +268,44 @@ public class VideoPlayActivity extends AppCompatActivity {
}
}
private void setOrientation(Boolean isLandscape) {
FragmentManager fragmentManager = getSupportFragmentManager();
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
VideoMetaDataFragment videoMetaFragment = (VideoMetaDataFragment) fragmentManager.findFragmentById(R.id.video_meta_data_fragment);
assert videoPlayerFragment != null;
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) videoPlayerFragment.requireView().getLayoutParams();
params.width = FrameLayout.LayoutParams.MATCH_PARENT;
params.height = isLandscape ? FrameLayout.LayoutParams.MATCH_PARENT : (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 250, getResources().getDisplayMetrics());
videoPlayerFragment.requireView().setLayoutParams(params);
if (videoMetaFragment != null) {
FragmentTransaction transaction = fragmentManager.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
if (isLandscape) {
assert videoPlayerFragment != null;
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) Objects.requireNonNull(videoPlayerFragment.getView()).getLayoutParams();
params.width = FrameLayout.LayoutParams.MATCH_PARENT;
params.height = FrameLayout.LayoutParams.MATCH_PARENT;
videoPlayerFragment.getView().setLayoutParams(params);
if (videoMetaFragment != null) {
fragmentManager.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
.hide(videoMetaFragment)
.commit();
}
videoPlayerFragment.setIsFullscreen(true);
transaction.hide(videoMetaFragment);
} else {
assert videoPlayerFragment != null;
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) Objects.requireNonNull(videoPlayerFragment.getView()).getLayoutParams();
params.width = FrameLayout.LayoutParams.MATCH_PARENT;
params.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 250, getResources().getDisplayMetrics());
videoPlayerFragment.getView().setLayoutParams(params);
transaction.show(videoMetaFragment);
}
if (videoMetaFragment != null) {
fragmentManager.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
.show(videoMetaFragment)
.commit();
}
videoPlayerFragment.setIsFullscreen(false);
transaction.commit();
}
videoPlayerFragment.setIsFullscreen(isLandscape);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
@Override
protected void onDestroy() {
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);
assert videoPlayerFragment != null;
videoPlayerFragment.destroyVideo();
super.onDestroy();
Log.v(TAG, "onDestroy...");
}
@ -335,15 +326,6 @@ public class VideoPlayActivity extends AppCompatActivity {
protected void onStop() {
super.onStop();
// SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
//
// Log.v(TAG, "" + sharedPref.getBoolean(BACKGROUND_PLAY_PREF_KEY, false));
//
// if (!sharedPref.getBoolean(BACKGROUND_PLAY_PREF_KEY, false)) {
// Log.v(TAG, "BACKGROUND_PLAY_PREF_KEY...");
// stopService(new Intent(this, VideoPlayerService.class));
// }
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);
@ -362,26 +344,32 @@ public class VideoPlayActivity extends AppCompatActivity {
@SuppressLint("NewApi")
@Override
public void onUserLeaveHint () {
public void onUserLeaveHint() {
Log.v(TAG, "onUserLeaveHint()...");
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
FragmentManager fragmentManager = getSupportFragmentManager();
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
VideoMetaDataFragment videoMetaFragment = (VideoMetaDataFragment) fragmentManager.findFragmentById(R.id.video_meta_data_fragment);
String backgroundBehavior = sharedPref.getString("pref_background_behavior","backgroundStop");
switch(backgroundBehavior){
case "backgroundStop":
Log.v(TAG,"stop the video");
String backgroundBehavior = sharedPref.getString(getString(R.string.pref_background_behavior_key), getString(R.string.pref_background_stop_key));
assert videoPlayerFragment != null;
assert backgroundBehavior != null;
if (backgroundBehavior.equals(getString(R.string.pref_background_stop_key))) {
Log.v(TAG, "stop the video");
videoPlayerFragment.pauseVideo();
stopService(new Intent(this, VideoPlayerService.class));
super.onBackPressed();
break;
case "backgroundAudio":
Log.v(TAG,"play the Audio");
} else if (backgroundBehavior.equals(getString(R.string.pref_background_audio_key))) {
Log.v(TAG, "play the Audio");
super.onBackPressed();
break;
case "backgroundFloat":
Log.v(TAG,"play in floating video");
} else if (backgroundBehavior.equals(getString(R.string.pref_background_float_key))) {
Log.v(TAG, "play in floating video");
//canEnterPIPMode makes sure API level is high enough
if (canEnterPipMode(this)) {
Log.v(TAG, "enabling pip");
@ -389,49 +377,56 @@ public class VideoPlayActivity extends AppCompatActivity {
} else {
Log.v(TAG, "unable to use pip");
}
break;
} else {
// Deal with bad entries from older version
Log.v(TAG, "No setting, fallback");
super.onBackPressed();
}
Log.v(TAG, "onUserLeaveHint()...");
}
// @RequiresApi(api = Build.VERSION_CODES.O)
@SuppressLint("NewApi")
public void onBackPressed() {
Log.v(TAG, "onBackPressed()...");
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);
//copying Youtube behavior to have back button exit full screen.
if (videoPlayerFragment.getIsFullscreen()){
Log.v(TAG,"exiting full screen");
assert videoPlayerFragment != null;
// copying Youtube behavior to have back button exit full screen.
if (videoPlayerFragment.getIsFullscreen()) {
Log.v(TAG, "exiting full screen");
videoPlayerFragment.fullScreenToggle();
return;
}
if (sharedPref.getBoolean("pref_back_pause", true)) {
assert videoPlayerFragment != null;
// pause video if pref is enabled
if (sharedPref.getBoolean(getString(R.string.pref_back_pause_key), true)) {
videoPlayerFragment.pauseVideo();
}
String backgroundBehavior = sharedPref.getString("pref_background_behavior","backgroundStop");
String backgroundBehavior = sharedPref.getString(getString(R.string.pref_background_behavior_key), getString(R.string.pref_background_stop_key));
assert backgroundBehavior != null;
// Log.v(TAG,"backgroundBehavior: " + backgroundBehavior);
switch (backgroundBehavior){
case "backgroundStop":
Log.v(TAG,"stop the video");
if (backgroundBehavior.equals(getString(R.string.pref_background_stop_key))) {
Log.v(TAG, "stop the video");
videoPlayerFragment.pauseVideo();
stopService(new Intent(this, VideoPlayerService.class));
super.onBackPressed();
break;
case "backgroundAudio":
Log.v(TAG,"play the Audio");
} else if (backgroundBehavior.equals(getString(R.string.pref_background_audio_key))) {
Log.v(TAG, "play the Audio");
super.onBackPressed();
break;
case "backgroundFloat":
Log.v(TAG,"play in floating video");
} else if (backgroundBehavior.equals(getString(R.string.pref_background_float_key))) {
Log.v(TAG, "play in floating video");
//canEnterPIPMode makes sure API level is high enough
if (canEnterPipMode(this)) {
Log.v(TAG, "enabling pip");
@ -440,30 +435,24 @@ public class VideoPlayActivity extends AppCompatActivity {
Intent intentSettings = new Intent(this, VideoListActivity.class);
this.startActivity(intentSettings);
} else {
Log.v(TAG,"Unable to enter PIP mode");
Log.v(TAG, "Unable to enter PIP mode");
super.onBackPressed();
}
break;
default:
} else {
// Deal with bad entries from older version
Log.v(TAG,"No setting, fallback");
Log.v(TAG, "No setting, fallback");
super.onBackPressed();
break;
}
Log.v(TAG, "onBackPressed()...");
}
public boolean canEnterPipMode(Context context) {
Log.v(TAG,"api version "+Build.VERSION.SDK_INT);
if (Build.VERSION.SDK_INT<28){
return false;
}
AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
return (AppOpsManager.MODE_ALLOWED== appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_PICTURE_IN_PICTURE, android.os.Process.myUid(), context.getPackageName()));
}
@RequiresApi(api = Build.VERSION_CODES.O)
public void enterPipMode() {
Rational rational = new Rational(239, 100);
Log.v(TAG,rational.toString());
Log.v(TAG, rational.toString());
PictureInPictureParams mParams =
new PictureInPictureParams.Builder()
.setAspectRatio(rational)
@ -472,20 +461,27 @@ public class VideoPlayActivity extends AppCompatActivity {
enterPictureInPictureMode(mParams);
}
@Override
public void onPictureInPictureModeChanged (boolean isInPictureInPictureMode, Configuration newConfig) {
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
FragmentManager fragmentManager = getSupportFragmentManager();
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
if (videoPlayerFragment != null) {
if (isInPictureInPictureMode) {
changedToPipMode();
Log.v(TAG,"switched to pip ");
Log.v(TAG, "switched to pip ");
videoPlayerFragment.useController(false);
} else {
changedToNormalMode();
Log.v(TAG,"switched to normal");
Log.v(TAG, "switched to normal");
videoPlayerFragment.useController(true);
}
} else {
Log.e(TAG, "videoPlayerFragment is NULL");
}
}
}

View File

@ -18,15 +18,11 @@
package net.schueller.peertube.adapter;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.provider.SearchRecentSuggestions;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -39,12 +35,8 @@ import androidx.recyclerview.widget.RecyclerView;
import net.schueller.peertube.R;
import net.schueller.peertube.activity.SelectServerActivity;
import net.schueller.peertube.activity.ServerAddressBookActivity;
import net.schueller.peertube.activity.VideoListActivity;
import net.schueller.peertube.database.Server;
import net.schueller.peertube.helper.APIUrlHelper;
import net.schueller.peertube.provider.SearchSuggestionsProvider;
import net.schueller.peertube.service.LoginService;
@ -65,7 +57,7 @@ public class ServerListAdapter extends RecyclerView.Adapter<ServerListAdapter.Se
@NonNull
@Override
public ServerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = mInflater.inflate(R.layout.row_serverbook, parent, false);
View itemView = mInflater.inflate(R.layout.row_server_address_book, parent, false);
return new ServerViewHolder(itemView);
}
@ -94,7 +86,7 @@ public class ServerListAdapter extends RecyclerView.Adapter<ServerListAdapter.Se
String serverUrl = APIUrlHelper.cleanServerUrl(getServerAtPosition(position).getServerHost());
editor.putString("pref_api_base", serverUrl);
editor.putString(mInflater.getContext().getString(R.string.pref_api_base_key), serverUrl);
editor.apply();
// attempt authentication if we have a username

View File

@ -27,7 +27,7 @@ import android.widget.Toast;
import net.schueller.peertube.R;
import net.schueller.peertube.activity.SelectServerActivity;
import net.schueller.peertube.activity.SearchServerActivity;
import net.schueller.peertube.helper.APIUrlHelper;
import net.schueller.peertube.model.Server;
@ -41,14 +41,14 @@ import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import static android.app.Activity.RESULT_OK;
public class ServerAdapter extends RecyclerView.Adapter<ServerAdapter.AccountViewHolder> {
public class ServerSearchAdapter extends RecyclerView.Adapter<ServerSearchAdapter.AccountViewHolder> {
private ArrayList<Server> serverList;
private SelectServerActivity activity;
private SearchServerActivity activity;
private String baseUrl;
public ServerAdapter(ArrayList<Server> serverList, SelectServerActivity activity) {
public ServerSearchAdapter(ArrayList<Server> serverList, SearchServerActivity activity) {
this.serverList = serverList;
this.activity = activity;
}
@ -57,7 +57,7 @@ public class ServerAdapter extends RecyclerView.Adapter<ServerAdapter.AccountVie
@Override
public AccountViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.row_server, parent, false);
View view = layoutInflater.inflate(R.layout.row_search_server, parent, false);
baseUrl = APIUrlHelper.getUrl(activity);

View File

@ -63,7 +63,7 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoViewHol
@Override
public VideoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.row_video, parent, false);
View view = layoutInflater.inflate(R.layout.row_video_list, parent, false);
baseUrl = APIUrlHelper.getUrl(context);

View File

@ -38,10 +38,12 @@ import android.widget.EditText;
import android.widget.Toast;
import net.schueller.peertube.R;
import net.schueller.peertube.activity.SelectServerActivity;
import net.schueller.peertube.activity.SearchServerActivity;
import net.schueller.peertube.activity.ServerAddressBookActivity;
import net.schueller.peertube.helper.APIUrlHelper;
import java.util.Objects;
import static android.app.Activity.RESULT_OK;
@ -78,14 +80,15 @@ public class AddServerFragment extends Fragment {
Activity act = getActivity();
Boolean formValid = true;
boolean formValid = true;
// close keyboard
try {
assert act != null;
InputMethodManager inputManager = (InputMethodManager)
act.getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(act.getCurrentFocus().getWindowToken(),
inputManager.hideSoftInputFromWindow(Objects.requireNonNull(act.getCurrentFocus()).getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
} catch (Exception e) {
@ -128,7 +131,7 @@ public class AddServerFragment extends Fragment {
Button pickServerUrl = mView.findViewById(R.id.pickServerUrl);
pickServerUrl.setOnClickListener(view -> {
Intent intentServer = new Intent(getActivity(), SelectServerActivity.class);
Intent intentServer = new Intent(getActivity(), SearchServerActivity.class);
this.startActivityForResult(intentServer, PICK_SERVER);
});

View File

@ -17,6 +17,7 @@
*/
package net.schueller.peertube.fragment;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
@ -44,7 +45,7 @@ public class VideoMenuQualityFragment extends BottomSheetDialogFragment {
public static final String TAG = "VideoMenuQuality";
private static File autoQualityFile;
public static VideoMenuQualityFragment newInstance(ArrayList<File> files) {
public static VideoMenuQualityFragment newInstance(Context context, ArrayList<File> files) {
mFiles = files;
@ -53,7 +54,7 @@ public class VideoMenuQualityFragment extends BottomSheetDialogFragment {
autoQualityFile = new File();
Resolution autoQualityResolution = new Resolution();
autoQualityResolution.setId(0);
autoQualityResolution.setLabel("Auto");
autoQualityResolution.setLabel(context.getString(R.string.menu_video_options_quality_automated));
autoQualityFile.setId(0);
autoQualityFile.setResolution(autoQualityResolution);
}
@ -74,11 +75,11 @@ public class VideoMenuQualityFragment extends BottomSheetDialogFragment {
false);
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
Integer videoQuality = sharedPref.getInt("pref_quality", 0);
Integer videoQuality = sharedPref.getInt(getString(R.string.pref_quality_key), 0);
for (File file : mFiles) {
LinearLayout menuRow = (LinearLayout) inflater.inflate(R.layout.row_popup_menu, null);
LinearLayout menuRow = (LinearLayout) inflater.inflate(R.layout.row_popup_menu, container);
TextView iconView = menuRow.findViewById(R.id.video_quality_icon);
iconView.setId(file.getResolution().getId());
@ -90,7 +91,7 @@ public class VideoMenuQualityFragment extends BottomSheetDialogFragment {
textView.setOnClickListener(view1 -> {
// Log.v(TAG, file.getResolution().getLabel());
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt("pref_quality", file.getResolution().getId());
editor.putInt(getString(R.string.pref_quality_key), file.getResolution().getId());
editor.apply();
for (File fileV : mFiles) {

View File

@ -65,6 +65,10 @@ public class VideoMetaDataFragment extends Fragment {
private static final String TAG = "VideoMetaDataFragment";
private static final String RATING_NONE = "none";
private static final String RATING_LIKE = "like";
private static final String RATING_DISLIKE = "dislike";
private Rating videoRating;
private ColorStateList defaultTextColor;
@ -72,13 +76,11 @@ public class VideoMetaDataFragment extends Fragment {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_video_meta, container, false);
}
public void updateVideoMeta(Video video, VideoPlayerService mService) {
Context context = getContext();
Activity activity = getActivity();
@ -91,26 +93,23 @@ public class VideoMetaDataFragment extends Fragment {
thumbsUpButton.setText(R.string.video_thumbs_up_icon);
new Iconics.IconicsBuilder().ctx(context).on(thumbsUpButton).build();
thumbsUpButton.setOnClickListener(v -> {
rateVideo(true, video.getId());
rateVideo(true, video);
});
TextView thumbsUpButtonTotal = activity.findViewById(R.id.video_thumbs_up_total);
thumbsUpButtonTotal.setText(video.getLikes().toString());
// Thumbs Down
Button thumbsDownButton = activity.findViewById(R.id.video_thumbs_down);
thumbsDownButton.setText(R.string.video_thumbs_down_icon);
new Iconics.IconicsBuilder().ctx(context).on(thumbsDownButton).build();
thumbsDownButton.setOnClickListener(v -> {
rateVideo(false, video.getId());
rateVideo(false, video);
});
// video rating
videoRating = new Rating();
videoRating.setRating("none"); // default
updateVideoRating();
videoRating.setRating(RATING_NONE); // default
updateVideoRating(video);
// Retrieve which rating the user gave to this video
if (Session.getInstance().isLoggedIn()) {
Call<Rating> call = videoDataService.getVideoRating(video.getId());
call.enqueue(new Callback<Rating>() {
@ -118,20 +117,16 @@ public class VideoMetaDataFragment extends Fragment {
@Override
public void onResponse(Call<Rating> call, Response<Rating> response) {
videoRating = response.body();
updateVideoRating();
updateVideoRating(video);
}
@Override
public void onFailure(Call<Rating> call, Throwable t) {
// Toast.makeText(context, "Rating Failed", Toast.LENGTH_SHORT).show();
// Do nothing.
}
});
}
TextView thumbsDownButtonTotal = activity.findViewById(R.id.video_thumbs_down_total);
thumbsDownButtonTotal.setText(video.getDislikes().toString());
// Share
Button videoShareButton = activity.findViewById(R.id.video_share);
videoShareButton.setText(R.string.video_share_icon);
@ -156,7 +151,6 @@ public class VideoMetaDataFragment extends Fragment {
}
});
Account account = video.getAccount();
// owner / creator Avatar
@ -198,7 +192,6 @@ public class VideoMetaDataFragment extends Fragment {
TextView videoDescription = activity.findViewById(R.id.description);
videoDescription.setText(video.getDescription());
// video privacy
TextView videoPrivacy = activity.findViewById(R.id.video_privacy);
videoPrivacy.setText(video.getPrivacy().getLabel());
@ -211,7 +204,7 @@ public class VideoMetaDataFragment extends Fragment {
TextView videoLicense = activity.findViewById(R.id.video_license);
videoLicense.setText(video.getLicence().getLabel());
// video langauge
// video language
TextView videoLanguage = activity.findViewById(R.id.video_language);
videoLanguage.setText(video.getLanguage().getLabel());
@ -219,7 +212,6 @@ public class VideoMetaDataFragment extends Fragment {
TextView videoTags = activity.findViewById(R.id.video_tags);
videoTags.setText(android.text.TextUtils.join(", ", video.getTags()));
// more button
TextView moreButton = activity.findViewById(R.id.moreButton);
moreButton.setText(R.string.video_more_icon);
@ -259,8 +251,7 @@ public class VideoMetaDataFragment extends Fragment {
}
void updateVideoRating() {
void updateVideoRating(Video video) {
Button thumbsUpButton = getActivity().findViewById(R.id.video_thumbs_up);
Button thumbsDownButton = getActivity().findViewById(R.id.video_thumbs_down);
@ -269,44 +260,46 @@ public class VideoMetaDataFragment extends Fragment {
TypedArray a = getContext().obtainStyledAttributes(typedValue.data, new int[]{R.attr.colorPrimary});
int accentColor = a.getColor(0, 0);
if (videoRating.getRating().equals(getString(R.string.video_rating_none))) {
// Change the color of the thumbs
switch (videoRating.getRating()) {
case RATING_NONE:
thumbsUpButton.setTextColor(defaultTextColor);
thumbsDownButton.setTextColor(defaultTextColor);
//Log.v(TAG, getString(R.string.video_rating_none));
} else if (videoRating.getRating().equals(getString(R.string.video_rating_like))) {
break;
case RATING_LIKE:
thumbsUpButton.setTextColor(accentColor);
thumbsDownButton.setTextColor(defaultTextColor);
//Log.v(TAG, getString(R.string.video_rating_like));
} else if (videoRating.getRating().equals(getString(R.string.video_rating_dislike))) {
break;
case RATING_DISLIKE:
thumbsUpButton.setTextColor(defaultTextColor);
thumbsDownButton.setTextColor(accentColor);
//Log.v(TAG, getString(R.string.video_rating_dislike));
break;
}
// Update the texts
TextView thumbsDownTotal = getActivity().findViewById(R.id.video_thumbs_down_total);
TextView thumbsUpTotal = getActivity().findViewById(R.id.video_thumbs_up_total);
thumbsUpTotal.setText(String.valueOf(video.getLikes()));
thumbsDownTotal.setText(String.valueOf(video.getDislikes()));
a.recycle();
}
void rateVideo(Boolean rate, Integer videoId) {
// TODO cleanup
void rateVideo(Boolean like, Video video) {
if (Session.getInstance().isLoggedIn()) {
final String ratePayload;
String ratePayload = getString(R.string.video_rating_none);
if (rate) {
// thumbsup
if (videoRating.getRating().equals(getString(R.string.video_rating_none))) {
ratePayload = getString(R.string.video_rating_like);
}
} else {
// thumbsdown
if (videoRating.getRating().equals(getString(R.string.video_rating_none))) {
ratePayload = getString(R.string.video_rating_dislike);
}
switch (videoRating.getRating()) {
case RATING_LIKE:
ratePayload = like ? RATING_NONE : RATING_DISLIKE;
break;
case RATING_DISLIKE:
ratePayload = like ? RATING_LIKE : RATING_NONE;
break;
case RATING_NONE:
default:
ratePayload = like ? RATING_LIKE : RATING_DISLIKE;
break;
}
RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json"), "{\"rating\":\"" + ratePayload + "\"}");
@ -314,23 +307,47 @@ public class VideoMetaDataFragment extends Fragment {
String apiBaseURL = APIUrlHelper.getUrlWithVersion(getContext());
GetVideoDataService videoDataService = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetVideoDataService.class);
Call<ResponseBody> call = videoDataService.rateVideo(videoId, body);
final String newRating = ratePayload;
Call<ResponseBody> call = videoDataService.rateVideo(video.getId(), body);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
//Log.v(TAG, response.toString());
// if 20x update likes
// if 20x, update likes/dislikes
if (response.isSuccessful()) {
videoRating.setRating(newRating);
updateVideoRating();
String previousRating = videoRating.getRating();
// TODO: update count under thumb
// Update the likes/dislikes count of the video, if needed.
// This is only a visual trick, as the actual like/dislike count has
// already been modified on the PeerTube instance.
if (!previousRating.equals(ratePayload)) {
switch (previousRating) {
case RATING_NONE:
if (ratePayload.equals(RATING_LIKE)) {
video.setLikes(video.getLikes() + 1);
} else {
video.setDislikes(video.getDislikes() + 1);
}
break;
case RATING_LIKE:
video.setLikes(video.getLikes() - 1);
if (ratePayload.equals(RATING_DISLIKE)) {
video.setDislikes(video.getDislikes() + 1);
}
break;
case RATING_DISLIKE:
video.setDislikes(video.getDislikes() - 1);
if (ratePayload.equals(RATING_LIKE)) {
video.setLikes(video.getLikes() + 1);
}
break;
}
}
videoRating.setRating(ratePayload);
updateVideoRating(video);
}
}
@ -341,9 +358,7 @@ public class VideoMetaDataFragment extends Fragment {
});
} else {
Toast.makeText(getContext(), getString(R.string.video_login_required_for_service), Toast.LENGTH_SHORT).show();
}
}
}

View File

@ -17,9 +17,9 @@
*/
package net.schueller.peertube.fragment;
import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -28,6 +28,7 @@ import android.widget.TextView;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.mikepenz.iconics.Iconics;
import net.schueller.peertube.R;
import net.schueller.peertube.model.File;
import net.schueller.peertube.service.VideoPlayerService;
@ -35,6 +36,7 @@ import net.schueller.peertube.service.VideoPlayerService;
import java.util.ArrayList;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
public class VideoOptionsFragment extends BottomSheetDialogFragment {
@ -62,32 +64,41 @@ public class VideoOptionsFragment extends BottomSheetDialogFragment {
LinearLayout menuHolder = view.findViewById(R.id.video_options_popup);
// Video Speed
LinearLayout menuRow = (LinearLayout) inflater.inflate(R.layout.row_popup_menu, null);
LinearLayout menuRow = (LinearLayout) inflater.inflate(R.layout.row_popup_menu, container);
TextView iconView = menuRow.findViewById(R.id.video_quality_icon);
TextView textView = menuRow.findViewById(R.id.video_quality_text);
textView.setText(getString(R.string.menu_video_options_playback_speed));
textView.setText(
getString(
R.string.menu_video_options_playback_speed,
getCurrentVideoPlaybackSpeedString(videoPlayerService.getPlayBackSpeed()
)
)
);
iconView.setText(R.string.video_option_speed_icon);
new Iconics.IconicsBuilder().ctx(getContext()).on(iconView).build();
textView.setOnClickListener(view1 -> {
VideoMenuSpeedFragment videoMenuSpeedFragment =
VideoMenuSpeedFragment.newInstance(videoPlayerService);
videoMenuSpeedFragment.show(getActivity().getSupportFragmentManager(),
videoMenuSpeedFragment.show(requireActivity().getSupportFragmentManager(),
VideoMenuSpeedFragment.TAG);
});
menuHolder.addView(menuRow);
// Video Quality
LinearLayout menuRow2 = (LinearLayout) inflater.inflate(R.layout.row_popup_menu, null);
LinearLayout menuRow2 = (LinearLayout) inflater.inflate(R.layout.row_popup_menu, container);
TextView iconView2 = menuRow2.findViewById(R.id.video_quality_icon);
TextView textView2 = menuRow2.findViewById(R.id.video_quality_text);
textView2.setText(getString(R.string.menu_video_options_quality));
textView2.setText(String.format(getString(R.string.menu_video_options_quality), getCurrentVideoQuality(files)));
iconView2.setText(R.string.video_option_quality_icon);
new Iconics.IconicsBuilder().ctx(getContext()).on(iconView2).build();
textView2.setOnClickListener(view1 -> {
VideoMenuQualityFragment videoMenuQualityFragment =
VideoMenuQualityFragment.newInstance(files);
videoMenuQualityFragment.show(getActivity().getSupportFragmentManager(),
videoMenuQualityFragment.TAG);
VideoMenuQualityFragment.newInstance(getContext(), files);
videoMenuQualityFragment.show(requireActivity().getSupportFragmentManager(),
VideoMenuQualityFragment.TAG);
});
menuHolder.addView(menuRow2);
@ -95,4 +106,26 @@ public class VideoOptionsFragment extends BottomSheetDialogFragment {
}
private String getCurrentVideoQuality(ArrayList<File> files) {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
Integer videoQuality = sharedPref.getInt(getString(R.string.pref_quality_key), 0);
for (File file : files) {
if (videoQuality.equals(file.getResolution().getId())) {
return file.getResolution().getLabel();
}
}
// Returning Automated as a placeholder
return getString(R.string.menu_video_options_quality_automated);
}
private String getCurrentVideoPlaybackSpeedString(float playbackSpeed) {
String speed = String.valueOf(playbackSpeed);
// Remove all non-digit characters from the string
speed = speed.replaceAll("[^0-9]", "");
// Dynamically get the localized string corresponding to the speed
@StringRes int stringId = getResources().getIdentifier("video_speed_" + speed, "string", videoPlayerService.getPackageName());
return getString(stringId);
}
}

View File

@ -18,7 +18,6 @@
package net.schueller.peertube.fragment;
import android.app.Activity;
import android.app.AppOpsManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@ -66,15 +65,16 @@ import net.schueller.peertube.network.GetVideoDataService;
import net.schueller.peertube.network.RetrofitInstance;
import net.schueller.peertube.service.VideoPlayerService;
import java.util.Objects;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.fragment.app.Fragment;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static net.schueller.peertube.helper.VideoHelper.canEnterPipMode;
public class VideoPlayerFragment extends Fragment implements VideoRendererEventListener {
private String mVideoUuid;
@ -134,6 +134,7 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
progressBar = activity.findViewById(R.id.torrent_progress);
progressBar.setMax(100);
assert context != null;
simpleExoPlayerView = new PlayerView(context);
simpleExoPlayerView = activity.findViewById(R.id.video_view);
@ -195,30 +196,31 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
@Override
public void onFailure(@NonNull Call<Video> call, @NonNull Throwable t) {
Log.wtf(TAG, t.fillInStackTrace());
Toast.makeText(context, "Something went wrong: "+t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
Toast.makeText(context, "Something went wrong: " + t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
}
});
}
public void useController(boolean value){
if (mBound){
public void useController(boolean value) {
if (mBound) {
simpleExoPlayerView.setUseController(value);
}
}
private void playVideo(Video video) {
Context context = getContext();
// video Meta fragment
assert getFragmentManager() != null;
VideoMetaDataFragment videoMetaDataFragment = (VideoMetaDataFragment)
getFragmentManager().findFragmentById(R.id.video_meta_data_fragment);
requireActivity().getSupportFragmentManager().findFragmentById(R.id.video_meta_data_fragment);
assert videoMetaDataFragment != null;
videoMetaDataFragment.updateVideoMeta(video, mService);
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
if (sharedPref.getBoolean("pref_torrent_player", false)) {
if (sharedPref.getBoolean(getString(R.string.pref_torrent_player_key), false)) {
torrentStatus.setVisibility(View.VISIBLE);
String stream = video.getFiles().get(0).getTorrentUrl();
Log.v(TAG, "getTorrentUrl : " + video.getFiles().get(0).getTorrentUrl());
@ -226,11 +228,11 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
torrentStream.startStream(stream);
} else {
Integer videoQuality = sharedPref.getInt("pref_quality", 0);
Integer videoQuality = sharedPref.getInt(getString(R.string.pref_quality_key), 0);
//get video qualities
String urlToPlay = video.getFiles().get(0).getFileUrl();
for (File file :video.getFiles()) {
for (File file : video.getFiles()) {
// Set quality if it matches
if (file.getResolution().getId().equals(videoQuality)) {
urlToPlay = file.getFileUrl();
@ -247,7 +249,7 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
}
private void startPlayer() {
Util.startForegroundService(Objects.requireNonNull(getContext()), videoPlayerIntent);
Util.startForegroundService(requireContext(), videoPlayerIntent);
}
@ -259,30 +261,35 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
}
public void pauseVideo() {
if (mBound){
if (mBound) {
mService.player.setPlayWhenReady(false);
}
}
public void pauseToggle() {
if (mBound) {
mService.player.setPlayWhenReady(!mService.player.getPlayWhenReady());
}
}
public void unPauseVideo() {
if (mBound) {
mService.player.setPlayWhenReady(true);
}
}
public boolean isPaused(){
public boolean isPaused() {
return !mService.player.getPlayWhenReady();
}
public void showControls(boolean value){
public void showControls(boolean value) {
simpleExoPlayerView.setUseController(value);
}
public void stopVideo() {
if (mBound) {
Objects.requireNonNull(getContext()).unbindService(mConnection);
requireContext().unbindService(mConnection);
mBound = false;
}
}
@ -290,7 +297,7 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
public void setIsFullscreen(Boolean fullscreen) {
isFullscreen = fullscreen;
TextView fullscreenButton = getActivity().findViewById(R.id.exo_fullscreen);
TextView fullscreenButton = requireActivity().findViewById(R.id.exo_fullscreen);
if (fullscreen) {
fullscreenButton.setText(R.string.video_compress_icon);
} else {
@ -302,15 +309,17 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
public Boolean getIsFullscreen() {
return isFullscreen;
}
public void fullScreenToggle() {
if (!isFullscreen) {
setIsFullscreen(true);
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
setIsFullscreen(false);
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
/**
* Torrent Playback
*
@ -404,18 +413,6 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
Log.v(TAG, "onVideoDisabled()...");
}
public static boolean canEnterPipMode(Context context) {
Log.v(TAG,"api version "+Build.VERSION.SDK_INT);
if (Build.VERSION.SDK_INT<28){
return false;
}
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
if (!"BackgroundFloat".equals(sharedPref.getString("pref_background_behavior","backgroundStop"))){
return false;
}
AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
return (AppOpsManager.MODE_ALLOWED== appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_PICTURE_IN_PICTURE, android.os.Process.myUid(), context.getPackageName()));
}
View.OnTouchListener touchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
@ -423,11 +420,13 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
}
};
public String getVideoUuid(){
public String getVideoUuid() {
return mVideoUuid;
}
class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
/*
/*
@Override
public boolean onDown(MotionEvent event) {
Log.d("TAG","onDown: ");
@ -458,27 +457,27 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
Log.i("TAG", "onScroll: ");
return true;
}
*/
*/
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public boolean onFling(MotionEvent event1, MotionEvent event2,
float velocityX, float velocityY) {
Log.d(TAG ,event1.toString());
Log.d(TAG,event2.toString());
Log.d(TAG, event1.toString());
Log.d(TAG, event2.toString());
Log.d(TAG, String.valueOf(velocityX));
Log.d(TAG , String.valueOf(velocityY));
Log.d(TAG, String.valueOf(velocityY));
//arbitrarily velocity speeds that seem to work to differentiate events.
if (velocityY>4000){
Log.d(TAG,"we have a drag down event");
if (velocityY > 4000) {
Log.d(TAG, "we have a drag down event");
if (canEnterPipMode(getContext())) {
getActivity().enterPictureInPictureMode();
requireActivity().enterPictureInPictureMode();
}
}
if ((velocityX>2000) && (Math.abs(velocityY) <2000)){
Log.d(TAG,"swipe right "+velocityY);
if ((velocityX > 2000) && (Math.abs(velocityY) < 2000)) {
Log.d(TAG, "swipe right " + velocityY);
}
if ((velocityX<2000) && (Math.abs(velocityY)<2000)){
Log.d(TAG,"swipe left "+velocityY);
if ((velocityX < 2000) && (Math.abs(velocityY) < 2000)) {
Log.d(TAG, "swipe left " + velocityY);
}
return true;
}

View File

@ -32,7 +32,7 @@ public class APIUrlHelper{
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
// validate URL is valid
String URL = sharedPref.getString("pref_api_base", context.getResources().getString(R.string.pref_default_api_base_url));
String URL = sharedPref.getString(context.getString(R.string.pref_api_base_key), context.getResources().getString(R.string.pref_default_api_base_url));
if (!URLUtil.isValidUrl(URL)) {
return "http://invalid";
}

View File

@ -1,25 +0,0 @@
/*
* Copyright 2018 Stefan Schüller <sschueller@techdroid.com>
*
* License: GPL-3.0+
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.schueller.peertube.helper;
public class Constants {
public static final String THEME_PREF_KEY = "pref_theme";
public static final String DEFAULT_THEME = "AppTheme.BLUE";
public static final String BACKGROUND_PLAY_PREF_KEY = "pref_background_play";
public static final String BACKGROUND_AUDIO = "BACKGROUND_AUDIO";
}

View File

@ -0,0 +1,40 @@
package net.schueller.peertube.helper;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.preference.PreferenceManager;
import android.util.Log;
import net.schueller.peertube.R;
public class VideoHelper {
private static final String TAG = "VideoHelper";
public static boolean canEnterPipMode(Context context) {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
context.getString(R.string.pref_background_float_key);
// pref is disabled
if (!context.getString(R.string.pref_background_float_key).equals(
sharedPref.getString(
context.getString(R.string.pref_background_behavior_key),
context.getString(R.string.pref_background_float_key))
)
) {
return false;
}
// api does not support it
Log.v(TAG, "api version " + Build.VERSION.SDK_INT);
if (Build.VERSION.SDK_INT > 27) {
AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
return (AppOpsManager.MODE_ALLOWED == appOpsManager.checkOp(AppOpsManager.OPSTR_PICTURE_IN_PICTURE, android.os.Process.myUid(), context.getPackageName()));
}
return false;
}
}

View File

@ -178,11 +178,18 @@ public class VideoPlayerService extends Service {
//Playback speed control
public void setPlayBackSpeed(float speed) {
Log.v(TAG, "setPlayBackSpeed...");
player.setPlaybackParameters(new PlaybackParameters(speed));
}
/**
* Returns the current playback speed of the player.
* @return the current playback speed of the player.
*/
public float getPlayBackSpeed() {
return player.getPlaybackParameters().speed;
}
public void playVideo() {
Context context = this;

View File

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.SelectServerActivity">
tools:context=".activity.SearchServerActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_server_selection"

View File

@ -14,7 +14,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/darker_gray"
tools:listitem="@layout/row_serverbook" />
tools:listitem="@layout/row_server_address_book" />

View File

@ -143,8 +143,8 @@
<string name="video_meta_button_license">الرخصة</string>
<string name="video_meta_button_language">اللغة</string>
<string name="video_meta_button_tags">العلامات</string>
<string name="menu_video_options_playback_speed">سرعة التشغيل</string>
<string name="menu_video_options_quality">الجودة</string>
<string name="menu_video_options_playback_speed" formatted="true">سرعة التشغيل (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">(%1$s) الجودة</string>
<string name="account_bottom_menu_videos">الفيديو</string>
<string name="account_bottom_menu_channels">القنوات</string>
<string name="account_bottom_menu_about">حول</string>

View File

@ -285,8 +285,8 @@
<string name="deeppurple">গাঢ় বেগুনি</string>
<string name="action_bar_title_account">অ্যাকাউন্ট</string>
<string name="bottom_nav_title_recent">সাম্প্রতিক</string>
<string name="menu_video_options_playback_speed">প্লেব্যাক এর গতি</string>
<string name="menu_video_options_quality">কোয়ালিটি</string>
<string name="menu_video_options_playback_speed" formatted="true">প্লেব্যাক এর গতি (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">কোয়ালিটি (%1$s)</string>
<string name="account_bottom_menu_videos">ভিডিও</string>
<string name="account_bottom_menu_channels">চ্যানেলগুলি</string>
<string name="account_bottom_menu_about">সম্পর্কিত</string>

View File

@ -276,8 +276,8 @@
<string name="video_meta_button_license">Lizenz</string>
<string name="video_meta_button_language">Sprache</string>
<string name="video_meta_button_tags">Tags</string>
<string name="menu_video_options_playback_speed">Wiedergabegeschwindigkeit</string>
<string name="menu_video_options_quality">Qualität</string>
<string name="menu_video_options_playback_speed" formatted="true">Wiedergabegeschwindigkeit (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">Qualität (%1$s)</string>
<string name="account_bottom_menu_videos">Videos</string>
<string name="account_bottom_menu_channels">Kanäle</string>
<string name="account_bottom_menu_about">Über</string>
@ -314,4 +314,8 @@
<string name="clear_search_history">Suchverlauf löschen</string>
<string name="pref_description_language_app">Wählen Sie die Sprache für die Anwendungsschnittstelle aus. Starten Sie die Anwendung neu, damit die Änderung wirksam wird.</string>
<string name="pref_language_app">Sprache der Anwendung</string>
<string name="settings_activity_about_category_title">Über</string>
<string name="settings_activity_video_playback_category_title">Videowiedergabe</string>
<string name="settings_activity_video_list_category_title">Videoliste</string>
<string name="server_selection_video_totals">Videos: %s, Lokale Videos: %s</string>
</resources>

View File

@ -96,8 +96,8 @@
<string name="video_meta_button_license">Licencia</string>
<string name="video_meta_button_language">Idioma</string>
<string name="video_meta_button_tags">Etiquetas</string>
<string name="menu_video_options_playback_speed">Velocidad de reproducción</string>
<string name="menu_video_options_quality">Calidad</string>
<string name="menu_video_options_playback_speed" formatted="true">Velocidad de reproducción (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">Calidad (%1$s)</string>
<string name="account_bottom_menu_videos">Vídeos</string>
<string name="account_bottom_menu_channels">Canales</string>
<string name="account_bottom_menu_about">Acerca de</string>

View File

@ -103,7 +103,7 @@
<string name="mi">maori</string>
<string name="or">oriya (makrokieli)</string>
<string name="bi">bislama</string>
<string name="menu_video_options_quality">Laatu</string>
<string name="menu_video_options_quality" formatted="true">Laatu (%s)</string>
<string name="api_error">Jotain meni pieleen, yritä myöhemmin!</string>
<string name="bg">bulgaria</string>
<string name="uz">uzbekki</string>
@ -204,7 +204,7 @@
<string name="nv">navajo</string>
<string name="kr">kanuri</string>
<string name="su">sunda</string>
<string name="menu_video_options_playback_speed">Toistonopeus</string>
<string name="menu_video_options_playback_speed" formatted="true">Toistonopeus (%1$s)</string>
<string name="ii">sichuanin-yi</string>
<string name="red">Punainen</string>
<string name="video_row_video_thumbnail">Videon esikatselukuva</string>

View File

@ -99,8 +99,8 @@
<string name="video_meta_button_license">Licence</string>
<string name="video_meta_button_language">Langue</string>
<string name="video_meta_button_tags">Étiquettes</string>
<string name="menu_video_options_playback_speed">Vitesse de lecture</string>
<string name="menu_video_options_quality">Qualité</string>
<string name="menu_video_options_playback_speed" formatted="true">Vitesse de lecture (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">Qualité (%1$s)</string>
<string name="account_bottom_menu_videos">Vidéos</string>
<string name="account_bottom_menu_channels">Chaînes</string>
<string name="account_bottom_menu_about">À propos</string>
@ -343,4 +343,8 @@
<string name="title_activity_select_server">Sélectionner un serveur</string>
<string name="server_book_del_alert_title">Retirer un serveur</string>
<string name="server_book_del_alert_msg">Voulez-vous vraiment retirer ce serveur de votre carnet d\'adresses ?</string>
<string name="menu_video_options_quality_automated">Automatique</string>
<string name="server_selection_nsfw_instance">Instance avec du contenu adulte</string>
<string name="hello_blank_fragment">Bonjour ! Fragment vide</string>
<string name="server_selection_video_totals">Vidéos : %s, Vidéos locales : %s</string>
</resources>

View File

@ -285,8 +285,8 @@
<string name="video_meta_button_license">Ceadachas</string>
<string name="video_meta_button_language">Cànan</string>
<string name="video_meta_button_tags">Tagaichean</string>
<string name="menu_video_options_playback_speed">Luaths na cluiche</string>
<string name="menu_video_options_quality">Càileachd</string>
<string name="menu_video_options_playback_speed" formatted="true">Luaths na cluiche (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">Càileachd (%1$s)</string>
<string name="account_bottom_menu_videos">Videothan</string>
<string name="account_bottom_menu_channels">Seanailean</string>
<string name="account_bottom_menu_about">Mu dhèidhinn</string>

View File

@ -286,8 +286,8 @@
<string name="video_meta_button_license">Licenza</string>
<string name="video_meta_button_language">Lingua</string>
<string name="video_meta_button_tags">Parole chiave</string>
<string name="menu_video_options_playback_speed">Velocità di riproduzione</string>
<string name="menu_video_options_quality">Qualità</string>
<string name="menu_video_options_playback_speed" formatted="true">Velocità di riproduzione (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">Qualità (%1$s)</string>
<string name="account_bottom_menu_videos">Video</string>
<string name="account_bottom_menu_channels">Canali</string>
<string name="account_bottom_menu_about">A proposito</string>

View File

@ -88,8 +88,8 @@
<string name="video_meta_button_license">ラインセンス</string>
<string name="video_meta_button_language">言語</string>
<string name="video_meta_button_tags">タグ</string>
<string name="menu_video_options_playback_speed">再生速度</string>
<string name="menu_video_options_quality">クオリティ</string>
<string name="menu_video_options_playback_speed" formatted="true">再生速度 (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">クオリティ(%1$s)</string>
<string name="account_bottom_menu_videos">ビデオ</string>
<string name="account_bottom_menu_channels">チャンネル</string>
<string name="account_bottom_menu_about">情報</string>

View File

@ -51,8 +51,8 @@
<string name="video_meta_button_license">Lisens</string>
<string name="video_meta_button_language">Språk</string>
<string name="video_meta_button_tags">Etiketter</string>
<string name="menu_video_options_playback_speed">Avspillingshastighet</string>
<string name="menu_video_options_quality">Kvalitet</string>
<string name="menu_video_options_playback_speed" formatted="true">Avspillingshastighet (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">Kvalitet (%1$s)</string>
<string name="account_bottom_menu_videos">Videoer</string>
<string name="account_bottom_menu_channels">Kanaler</string>
<string name="account_bottom_menu_about">Om</string>

View File

@ -275,8 +275,8 @@
<string name="video_meta_button_license">Licentie</string>
<string name="video_meta_button_language">Taal</string>
<string name="video_meta_button_tags">Labels</string>
<string name="menu_video_options_playback_speed">Afspeelsnelheid</string>
<string name="menu_video_options_quality">Kwaliteit</string>
<string name="menu_video_options_playback_speed" formatted="true">Afspeelsnelheid (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">Kwaliteit (%1$s)</string>
<string name="account_bottom_menu_videos">Video\'s</string>
<string name="account_bottom_menu_channels">Kanalen</string>
<string name="account_bottom_menu_about">Over</string>

View File

@ -48,8 +48,8 @@
<string name="account_about_account">Konto:</string>
<string name="account_bottom_menu_channels">Kanały</string>
<string name="account_bottom_menu_videos">Filmy</string>
<string name="menu_video_options_quality">Jakość</string>
<string name="menu_video_options_playback_speed">Prędkość odtwarzania</string>
<string name="menu_video_options_quality" formatted="true">Jakość (%1$s)</string>
<string name="menu_video_options_playback_speed" formatted="true">Prędkość odtwarzania (%1$s)</string>
<string name="video_meta_button_tags">Znaczniki</string>
<string name="video_meta_button_language">Język</string>
<string name="video_meta_button_license">Licencja</string>

View File

@ -277,8 +277,8 @@
<string name="video_meta_button_license">Лицензия</string>
<string name="video_meta_button_language">Язык</string>
<string name="video_meta_button_tags">Теги</string>
<string name="menu_video_options_playback_speed">Скорость воспроизведения</string>
<string name="menu_video_options_quality">Качество</string>
<string name="menu_video_options_playback_speed" formatted="true">Скорость воспроизведения (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">Качество (%1$s)</string>
<string name="account_about_description">Описание:</string>
<string name="api_error">Что-то пошло не так, пожалуйста, попробуйте позже!</string>
<string name="action_set_url">Выберите сервер</string>

View File

@ -272,8 +272,8 @@
<string name="video_meta_button_license">Licens</string>
<string name="video_meta_button_language">Språk</string>
<string name="video_meta_button_tags">Taggar</string>
<string name="menu_video_options_playback_speed">Uppspelningshastighet</string>
<string name="menu_video_options_quality">Kvalitet</string>
<string name="menu_video_options_playback_speed" formatted="true">Uppspelningshastighet (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">Kvalitet (%1$s)</string>
<string name="account_bottom_menu_videos">Videor</string>
<string name="account_bottom_menu_channels">Kanaler</string>
<string name="account_bottom_menu_about">Om</string>

View File

@ -291,8 +291,8 @@
<string name="video_meta_button_license">Lisans</string>
<string name="video_meta_button_language">Dil</string>
<string name="video_meta_button_tags">Etiketler</string>
<string name="menu_video_options_playback_speed">Oynatma hızı</string>
<string name="menu_video_options_quality">Kalite</string>
<string name="menu_video_options_playback_speed" formatted="true">Oynatma hızı (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">Kalite (%1$s)</string>
<!-- Constants, Don't translate -->
<string name="action_bar_title_account">Hesap</string>
<string name="bottom_nav_title_recent">Yeniler</string>
@ -342,7 +342,7 @@
<string name="settings_activity_video_list_category_title">Video Listesi</string>
<string name="title_activity_settings2">SettingsActivity2</string>
<string name="title_activity_me">Hesap</string>
<string name="title_activity_select_server">Sunucu Seç</string>
<string name="title_activity_select_server">Sunucu Ara</string>
<string name="server_book_del_alert_msg">Bu sunucuyu adres defterinden kaldırmak istediğinizden emin misiniz\?</string>
<string name="server_book_del_alert_title">Sunucuyu Kaldır</string>
<string name="bn_rBD">Bengalce (Bangladeş)</string>
@ -353,4 +353,7 @@
<string name="pref_background_behavior">Arka planda oynatma yapılandırması</string>
<string name="pref_background_stop">Tüm oynatmaları durdur</string>
<string name="pref_background_audio">Arka planda ses akışı olarak devam et</string>
<string name="server_selection_nsfw_instance">İş Yeri İçin Uygun Olmayan (NSFW) Örnek</string>
<string name="server_selection_video_totals">Video: %s, Yerel Video: %s</string>
<string name="menu_video_options_quality_automated">Otomatik</string>
</resources>

View File

@ -112,8 +112,8 @@
<string name="video_meta_button_category">类别</string>
<string name="video_meta_button_license">许可</string>
<string name="video_meta_button_tags">标签</string>
<string name="menu_video_options_playback_speed">播放速度</string>
<string name="menu_video_options_quality">画质</string>
<string name="menu_video_options_playback_speed" formatted="true">播放速度 (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">画质 (%1$s)</string>
<string name="account_bottom_menu_videos">视频</string>
<string name="account_bottom_menu_channels">频道</string>
<string name="account_bottom_menu_about">关于</string>

View File

@ -279,8 +279,8 @@
<string name="video_meta_button_license">授權條款</string>
<string name="video_meta_button_language">語言</string>
<string name="video_meta_button_tags">標籤</string>
<string name="menu_video_options_playback_speed">播放速度</string>
<string name="menu_video_options_quality">畫質</string>
<string name="menu_video_options_playback_speed" formatted="true">播放速度 (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">畫質 (%1$s)</string>
<string name="account_bottom_menu_videos">影片</string>
<string name="account_bottom_menu_channels">頻道</string>
<string name="account_bottom_menu_about">關於</string>
@ -339,4 +339,6 @@
<string name="pref_background_float">繼續以懸浮視窗播放影片</string>
<string name="pref_background_stop">停止所有播放</string>
<string name="pref_background_audio">以背景音訊串流繼續</string>
<string name="server_selection_video_totals">影片:%s本地影片%s</string>
<string name="server_selection_nsfw_instance">NSFW 站臺</string>
</resources>

View File

@ -1,6 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">Thorium</string>
<!-- Prefs Settings-->
<string name="pref_language_app_key" translatable="false">pref_language_app</string>
<string name="pref_theme_key" translatable="false">pref_theme</string>
<string name="pref_dark_mode_key" translatable="false">pref_dark_mode</string>
<string name="pref_show_nsfw_key" translatable="false">pref_show_nsfw</string>
<string name="pref_video_language_key" translatable="false">pref_language</string>
<string name="pref_back_pause_key" translatable="false">pref_back_pause</string>
<string name="pref_background_behavior_key" translatable="false">pref_background_behavior</string>
<string name="pref_torrent_player_key" translatable="false">pref_torrent_player</string>
<!-- defaults -->
<string name="pref_default_api_base_url" formatted="false" translatable="false">https://troll.tv</string>
<string name="app_default_theme" translatable="false">AppTheme.BLUE</string>
<!-- Pref internal -->
<string name="pref_token_access" translatable="false">pref_token_access</string>
<string name="pref_token_refresh" translatable="false">pref_token_refresh</string>
<string name="pref_token_expiration" translatable="false">pref_token_expiration</string>
<string name="pref_token_type" translatable="false">pref_token_type</string>
<string name="pref_auth_username" translatable="false">pref_auth_username</string>
<string name="pref_auth_password" translatable="false">pref_auth_password</string>
<string name="pref_api_base_key" translatable="false">pref_api_base</string>
<string name="pref_quality_key" translatable="false">pref_quality</string>
<!-- Pref internal keys -->
<string name="pref_background_audio_key" translatable="false">backgroundAudio</string>
<string name="pref_background_stop_key" translatable="false">backgroundStop</string>
<string name="pref_background_float_key" translatable="false">backgroundFloat</string>
<string name="peertube_required_server_version" translatable="false">1.0.0-alpha.7</string>
<string name="app_background_audio" translatable="false">BACKGROUND_AUDIO</string>
<string name="video_option_speed_icon" translatable="false">{faw-play-circle}</string>
<string name="video_option_quality_icon" translatable="false">{faw-cog}</string>
<string name="video_speed_active_icon" translatable="false">{faw-check}</string>
<string name="video_quality_active_icon" translatable="false">{faw-check}</string>
<string name="video_expand_icon" translatable="false">{faw-expand}</string>
<string name="video_compress_icon" translatable="false">{faw-compress}</string>
<string name="video_more_icon" translatable="false">{faw-ellipsis-v}</string>
<string name="video_thumbs_up_icon" translatable="false">{faw-thumbs-up}</string>
<string name="video_thumbs_down_icon" translatable="false">{faw-thumbs-down}</string>
<string name="video_share_icon" translatable="false">{faw-share}</string>
<string name="video_download_icon" translatable="false">{faw-download}</string>
<string name="video_save_icon" translatable="false">{faw-save}</string>
<string name="meta_data_owner_seperator" translatable="false">\@</string>
<string name="meta_data_seperator" translatable="false">\u0020-\u0020</string>
<string name="title_activity_video_play" translatable="false">VideoPlayActivity</string>
<string name="playback_channel_name" translatable="false">PeerTube</string>
<string name="peertube_instance_search_default_description" translatable="false">PeerTube, a federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser with WebTorrent and Angular.</string>
<string-array name="backgroundBehavior">
<item>@string/pref_background_audio</item>
@ -9,9 +67,9 @@
</string-array>
<string-array name="backgroundBehaviorValues">
<item>backgroundAudio</item>
<item>backgroundStop</item>
<item>backgroundFloat</item>
<item>@string/pref_background_audio_key</item>
<item>@string/pref_background_stop_key</item>
<item>@string/pref_background_float_key</item>
</string-array>
<string-array name="themeArray">
@ -475,7 +533,7 @@
<item>zh-rTW</item>
</string-array>
<string-array name = "supportedLanguagesArray">
<string-array name="supportedLanguagesArray">
<item>@string/ar</item>
<item>@string/bn</item>
<item>@string/bn_rBD</item>
@ -502,7 +560,7 @@
</string-array>
<string-array name="empty_array"/>
<string-array name="empty_array" />
<string-array name="quality">
<item>Low</item>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">Thorium</string>
<string name="title_activity_video_play" translatable="false">VideoPlayActivity</string>
<string name="title_activity_settings">Settings</string>
<string name="title_activity_login">Sign in</string>
<!-- Strings related to login -->
@ -29,9 +28,7 @@
<string name="bottom_nav_title_account">Account</string>
<!-- Strings related to Settings -->
<!-- Strings related to Video meta data -->
<string name="meta_data_seperator" translatable="false">\u0020-\u0020</string>
<string name="meta_data_views">\u0020Views</string>
<string name="meta_data_owner_seperator" translatable="false">\@</string>
<string name="video_row_video_thumbnail">Video Thumbnail</string>
<string name="video_row_account_avatar">Account Avatar</string>
<string name="title_activity_url_video_play">UrlVideoPlayActivity</string>
@ -40,7 +37,6 @@
<string name="no_data_available">No Results</string>
<string name="descr_overflow_button">More</string>
<string name="menu_share">Share</string>
<string name="playback_channel_name" translatable="false">PeerTube</string>
<string name="invalid_url">Invalid URL.</string>
<!-- settings/preferences -->
<string name="pref_title_dark_mode">Dark Mode</string>
@ -56,7 +52,6 @@
<string name="pref_description_show_nsfw">Show NSFW content</string>
<string name="pref_language">Language filter</string>
<string name="pref_description_language">Select a video language, instead of showing all videos in all languages.</string>
<string name="pref_default_api_base_url" formatted="false" translatable="false">https://troll.tv</string>
<string name="pref_title_peertube_server">PeerTube Server</string>
<string name="pref_title_background_play">Background Playback</string>
<string name="pref_description_background_play">If enabled, continues to play video in background.</string>
@ -292,18 +287,7 @@
<string name="video_speed_10">Normal</string>
<string name="video_speed_15">1.5x</string>
<string name="video_speed_20">2x</string>
<string name="video_option_speed_icon" translatable="false">{faw-play-circle}</string>
<string name="video_option_quality_icon" translatable="false">{faw-cog}</string>
<string name="video_speed_active_icon" translatable="false">{faw-check}</string>
<string name="video_quality_active_icon" translatable="false">{faw-check}</string>
<string name="video_expand_icon" translatable="false">{faw-expand}</string>
<string name="video_compress_icon" translatable="false">{faw-compress}</string>
<string name="video_more_icon" translatable="false">{faw-ellipsis-v}</string>
<string name="video_thumbs_up_icon" translatable="false">{faw-thumbs-up}</string>
<string name="video_thumbs_down_icon" translatable="false">{faw-thumbs-down}</string>
<string name="video_share_icon" translatable="false">{faw-share}</string>
<string name="video_download_icon" translatable="false">{faw-download}</string>
<string name="video_save_icon" translatable="false">{faw-save}</string>
<string name="action_set_url">Select Server</string>
<string name="server_selection_signup_allowed">Signup Allowed: %s</string>
<string name="server_selection_signup_allowed_yes">Yes</string>
@ -324,8 +308,8 @@
<string name="video_meta_button_license">License</string>
<string name="video_meta_button_language">Language</string>
<string name="video_meta_button_tags">Tags</string>
<string name="menu_video_options_playback_speed">Playback speed</string>
<string name="menu_video_options_quality">Quality</string>
<string name="menu_video_options_playback_speed" formatted="true">Playback speed (%1$s)</string>
<string name="menu_video_options_quality" formatted="true">Quality (%1$s)</string>
<string name="account_bottom_menu_videos">Videos</string>
<string name="account_bottom_menu_channels">Channels</string>
<string name="account_bottom_menu_about">About</string>
@ -352,10 +336,7 @@
<string name="server_book_add_password">Password</string>
<string name="server_book_add_add_button">Add</string>
<string name="server_book_list_has_login">Has Login</string>
<string name="video_rating_none" translatable="false">none</string>
<string name="video_rating_like" translatable="false">like</string>
<string name="video_rating_dislike" translatable="false">dislike</string>
<string name="peertube_required_server_version" translatable="false">1.0.0-alpha.7</string>
<string name="login_current_server_hint">Current Server</string>
<string name="title_activity_server_address_book">Address Book</string>
<string name="video_speed_075">0.75x</string>
@ -363,7 +344,7 @@
<string name="server_book_del_alert_title">Remove Server</string>
<string name="server_book_del_alert_msg">Are you sure you want to remove this server from the address book?</string>
<string name="title_activity_select_server">Select Server</string>
<string name="title_activity_select_server">Search Server</string>
<string name="title_activity_me">Account</string>
<string name="title_activity_settings2">SettingsActivity2</string>
@ -372,18 +353,11 @@
<string name="settings_activity_about_category_title">About</string>
<string name="settings_activity_look_and_feel_category_title"><![CDATA[Look & Feel]]></string>
<string name="peertube_instance_search_default_description" translatable="false">PeerTube, a federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser with WebTorrent and Angular.</string>
<string name="server_selection_nsfw_instance">NSFW Instance</string>
<string name="server_selection_video_totals">Videos: %s, Local Videos: %s</string>
<!-- Constants, Don't translate -->
<string name="pref_token_access" translatable="false">pref_token_access</string>
<string name="pref_token_refresh" translatable="false">pref_token_refresh</string>
<string name="pref_token_expiration" translatable="false">pref_token_expiration</string>
<string name="pref_token_type" translatable="false">pref_token_type</string>
<string name="pref_auth_username" translatable="false">pref_auth_username</string>
<string name="pref_auth_password" translatable="false">pref_auth_password</string>
<string name="menu_video_options_quality_automated">Automated</string>
<string name="pref_title_buildtime">Build Time</string>
</resources>

View File

@ -1,78 +0,0 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!--<SwitchPreference-->
<!--android:key="pref_background_play"-->
<!--android:title="@string/pref_title_background_play"-->
<!--android:summary="@string/pref_description_background_play"-->
<!--android:defaultValue="true" />-->
<SwitchPreference
android:key="pref_show_nsfw"
android:title="@string/pref_title_show_nsfw"
android:summary="@string/pref_description_show_nsfw"
android:defaultValue="false" />
<MultiSelectListPreference
android:defaultValue="@array/empty_array"
android:entries="@array/languageArray"
android:entryValues="@array/languageValues"
android:key="pref_language"
android:summary="@string/pref_description_language"
android:title="@string/pref_language" />
<SwitchPreference
android:defaultValue="true"
android:key="pref_back_pause"
android:summary="@string/pref_description_back_pause"
android:title="@string/pref_title_back_pause" />
<ListPreference
android:defaultValue="@array/empty_array"
android:entries="@array/supportedLanguagesArray"
android:entryValues="@array/supportedLanguagesValues"
android:key="pref_language_app"
android:summary="@string/pref_description_language_app"
android:title="@string/pref_language_app" />
/>
<ListPreference
android:defaultValue="@array/empty_array"
android:entries="@array/backgroundBehavior"
android:entryValues="@array/backgroundBehaviorValues"
android:key="pref_background_behavior"
android:summary="@string/pref_background_behavior_summary"
android:title="@string/pref_background_behavior" />
/>
<ListPreference
android:title="@string/pref_title_app_theme"
android:summary="@string/pref_description_app_theme"
android:key="pref_theme"
android:defaultValue="AppTheme.BLUE"
android:entries="@array/themeArray"
android:entryValues="@array/themeValues" />
<SwitchPreference
android:key="pref_dark_mode"
android:title="@string/pref_title_dark_mode"
android:summary="@string/pref_description_dark_mode"
android:defaultValue="false" />
<SwitchPreference
android:key="pref_torrent_player"
android:title="@string/pref_title_torrent_player"
android:summary="@string/pref_description_torrent_player"
android:defaultValue="false" />
<Preference
android:title="@string/pref_title_version"
android:summary="@string/versionName" />
<Preference
android:title="@string/pref_title_license"
android:summary="@string/pref_description_license" />
</PreferenceScreen>

View File

@ -1,82 +1,98 @@
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory app:title="@string/settings_activity_look_and_feel_category_title">
<PreferenceCategory app:title="@string/settings_activity_look_and_feel_category_title" app:iconSpaceReserved="false">
<ListPreference
app:defaultValue="@array/empty_array"
app:entries="@array/supportedLanguagesArray"
app:entryValues="@array/supportedLanguagesValues"
app:key="pref_language_app"
app:key="@string/pref_language_app_key"
app:summary="@string/pref_description_language_app"
app:title="@string/pref_language_app" />
app:title="@string/pref_language_app"
app:iconSpaceReserved="false"/>
<ListPreference
app:defaultValue="AppTheme.BLUE"
app:entries="@array/themeArray"
app:entryValues="@array/themeValues"
app:key="pref_theme"
app:key="@string/pref_theme_key"
app:summary="@string/pref_description_app_theme"
app:title="@string/pref_title_app_theme" />
app:title="@string/pref_title_app_theme"
app:iconSpaceReserved="false"/>
<SwitchPreference
app:defaultValue="false"
app:key="pref_dark_mode"
app:key="@string/pref_dark_mode_key"
app:summary="@string/pref_description_dark_mode"
app:title="@string/pref_title_dark_mode" />
app:title="@string/pref_title_dark_mode"
app:iconSpaceReserved="false"/>
</PreferenceCategory>
<PreferenceCategory app:title="@string/settings_activity_video_list_category_title">
<PreferenceCategory app:title="@string/settings_activity_video_list_category_title" app:iconSpaceReserved="false">
<SwitchPreference
app:defaultValue="false"
app:key="pref_show_nsfw"
app:key="@string/pref_show_nsfw_key"
app:summary="@string/pref_description_show_nsfw"
app:title="@string/pref_title_show_nsfw" />
app:title="@string/pref_title_show_nsfw"
app:iconSpaceReserved="false"/>
<MultiSelectListPreference
app:defaultValue="@array/empty_array"
app:entries="@array/languageArray"
app:entryValues="@array/languageValues"
app:key="pref_language"
app:key="@string/pref_video_language_key"
app:summary="@string/pref_description_language"
app:title="@string/pref_language" />
app:title="@string/pref_language"
app:iconSpaceReserved="false"/>
</PreferenceCategory>
<PreferenceCategory app:title="@string/settings_activity_video_playback_category_title">
<PreferenceCategory app:title="@string/settings_activity_video_playback_category_title" app:iconSpaceReserved="false">
<SwitchPreference
app:defaultValue="true"
app:key="pref_back_pause"
app:key="@string/pref_back_pause_key"
app:summary="@string/pref_description_back_pause"
app:title="@string/pref_title_back_pause" />
app:title="@string/pref_title_back_pause"
app:iconSpaceReserved="false"/>
<ListPreference
app:defaultValue="@array/empty_array"
app:entries="@array/backgroundBehavior"
app:entryValues="@array/backgroundBehaviorValues"
app:key="pref_background_behavior"
app:key="@string/pref_background_behavior_key"
app:summary="@string/pref_background_behavior_summary"
app:title="@string/pref_background_behavior" />
app:title="@string/pref_background_behavior"
app:iconSpaceReserved="false"/>
<SwitchPreference
app:defaultValue="false"
app:key="pref_torrent_player"
app:key="@string/pref_torrent_player_key"
app:summary="@string/pref_description_torrent_player"
app:title="@string/pref_title_torrent_player" />
app:title="@string/pref_title_torrent_player"
app:iconSpaceReserved="false"/>
</PreferenceCategory>
<PreferenceCategory app:title="@string/settings_activity_about_category_title">
<PreferenceCategory app:title="@string/settings_activity_about_category_title" app:iconSpaceReserved="false">
<Preference
app:summary="@string/versionName"
app:title="@string/pref_title_version" />
app:title="@string/pref_title_version"
app:iconSpaceReserved="false"/>
<Preference
app:summary="@string/buildTime"
app:title="@string/pref_title_buildtime"
app:iconSpaceReserved="false"/>
<Preference
app:summary="@string/pref_description_license"
app:title="@string/pref_title_license" />
app:title="@string/pref_title_license"
app:iconSpaceReserved="false"/>
</PreferenceCategory>