Merge pull request #6 from sschueller/develop

updating my fork
This commit is contained in:
Don Kimberlin 2020-06-27 14:22:44 -07:00 committed by GitHub
commit e462e00bab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 2389 additions and 585 deletions

View File

@ -1,3 +1,20 @@
### Version 1.0.39 Tag: v1.0.39 (2020-06-27)
* exoplayer update (@lishoujun)
* Floating window support (@dhk2)
* Various translations
### Version 1.0.38 Tag: v1.0.38 (2020-06-21)
* Multi server login address book
* Clear search history (@dhk2)
* Android SDK to 29
* Various translations
### Version 1.0.37 Tag: v1.0.37 (2020-06-19)
* Making Selecting a search suggestion fill search field (@dhk2)
* Adding configuration setting and supporting code to choose language (@dhk2)
* Adding configuration setting and code for configurable back button behavior (@dhk2)
* Various translations
### Version 1.0.36 Tag: v1.0.36 (2020-06-14)
* fix 'cannot make a new request because the previous response (@lishoujun)
* Various translations
@ -17,6 +34,11 @@
* Gradle update
* Translations
### Version 1.0.31 Tag: v1.0.31 (2019-09-25)
* Renamed overview to discover (PeerTube v1.4.0)
* Translations
* Gradle dependencies updates
### Version 1.0.30 Tag: v1.0.30 (2019-08-07)
* Gradle update
* Translations

View File

@ -1,19 +1,27 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
compileSdkVersion 29
defaultConfig {
applicationId "net.schueller.peertube"
minSdkVersion 21
targetSdkVersion 28
versionCode 1036
versionName "1.0.36"
targetSdkVersion 29
versionCode 1039
versionName "1.0.39"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ext {
libVersions = [
exoplayer: '2.9.3'
exoplayer: '2.11.6'
]
}
javaCompileOptions {
annotationProcessorOptions {
arguments = [
"room.schemaLocation" : "$projectDir/schemas".toString(),
"room.incremental" : "true",
"room.expandProjection": "true"]
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
@ -70,7 +78,6 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildToolsVersion '28.0.3'
applicationVariants.all { variant ->
variant.resValue "string", "versionName", variant.versionName
@ -78,6 +85,23 @@ android {
}
dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta6'
def room_version = "2.2.5"
def archLifecycleVersion = '2.1.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta7'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.1.0'
// database lib
implementation "androidx.room:room-runtime:$room_version"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
annotationProcessor "androidx.room:room-compiler:$room_version"
androidTestImplementation "androidx.room:room-testing:$room_version"
// Lifecycle components
implementation "androidx.lifecycle:lifecycle-extensions:$archLifecycleVersion"
annotationProcessor "androidx.lifecycle:lifecycle-common-java8:$archLifecycleVersion"
}

View File

@ -2,11 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="net.schueller.peertube">
<!-- connect to peertube server -->
<uses-permission android:name="android.permission.INTERNET" /> <!-- required for torrent downloading -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- required to play video in background via notification -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- required for torrent downloading -->
<application
android:name=".application.AppApplication"
android:allowBackup="true"
@ -15,6 +11,10 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".activity.ServerAddressBookActivity"
android:label="@string/title_activity_server_address_book"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activity.VideoListActivity"
android:launchMode="singleTop"
@ -28,17 +28,14 @@
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable"></meta-data>
android:resource="@xml/searchable" />
</activity>
<activity
android:name=".activity.LoginActivity"
android:label="@string/title_activity_login"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activity.VideoPlayActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
android:label="@string/title_activity_video_play"
android:launchMode="singleTop"
android:launchMode="singleInstance"
android:supportsPictureInPicture="true"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activity.SettingsActivity"
@ -61,6 +58,10 @@
android:exported="false" />
<service android:name=".service.VideoPlayerService" />
</application>
</application> <!-- required to play video in background via notification -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- connect to peertube server -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>

View File

@ -48,6 +48,7 @@ import net.schueller.peertube.network.RetrofitInstance;
import java.util.ArrayList;
import java.util.Objects;
import java.util.Set;
import androidx.annotation.NonNull;
@ -145,11 +146,10 @@ public class AccountActivity extends CommonActivity {
Toolbar toolbar = findViewById(R.id.tool_bar_account);
// Setting toolbar as the ActionBar with setSupportActionBar() call
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_baseline_close_24);
getSupportActionBar().setTitle(displayNameAndHost);
getSupportActionBar().setHomeAsUpIndicator(
new IconicsDrawable(this, FontAwesome.Icon.faw_chevron_left).actionBar()
);
loadAccountVideos(displayNameAndHost);

View File

@ -18,6 +18,7 @@
package net.schueller.peertube.activity;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceActivity;
@ -25,10 +26,14 @@ 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.
@ -42,6 +47,20 @@ public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
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

View File

@ -19,12 +19,15 @@
package net.schueller.peertube.activity;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceManager;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import java.util.Locale;
import static net.schueller.peertube.helper.Constants.DEFAULT_THEME;
import static net.schueller.peertube.helper.Constants.THEME_PREF_KEY;
@ -45,6 +48,21 @@ public class CommonActivity extends AppCompatActivity {
"style",
getPackageName())
);
// Set language
String countryCode=sharedPref.getString("pref_language_app","en");
Locale locale=new Locale(countryCode);;
//Neither Chinese language choice was working, found this fix on stack overflow
if(countryCode.equals("zh-rCN"))
locale = Locale.SIMPLIFIED_CHINESE;
if(countryCode.equals("zh-rTW"))
locale = Locale.TRADITIONAL_CHINESE;
Locale.setDefault(locale);
Configuration config = getBaseContext().getResources().getConfiguration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
}
}

View File

@ -19,18 +19,20 @@
package net.schueller.peertube.activity;
import android.content.Intent;
import android.net.Uri;
import android.nfc.Tag;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.mikepenz.fontawesome_typeface_library.FontAwesome;
import com.mikepenz.iconics.IconicsDrawable;
import net.schueller.peertube.R;
import net.schueller.peertube.helper.APIUrlHelper;
import net.schueller.peertube.model.Avatar;
import net.schueller.peertube.model.Me;
import net.schueller.peertube.network.GetUserService;
import net.schueller.peertube.network.RetrofitInstance;
@ -38,10 +40,17 @@ import net.schueller.peertube.network.Session;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import com.squareup.picasso.Picasso;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static net.schueller.peertube.application.AppApplication.getContext;
public class MeActivity extends CommonActivity {
@ -52,34 +61,10 @@ public class MeActivity extends CommonActivity {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_top_account, menu);
// Set an icon in the ActionBar
menu.findItem(R.id.action_logout).setIcon(
new IconicsDrawable(this, FontAwesome.Icon.faw_sign_out_alt).actionBar());
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// action with ID action_refresh was selected
case R.id.action_logout:
Session.getInstance().invalidate();
Intent intent = new Intent(this, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
this.startActivity(intent);
finish();
return true;
default:
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onSupportNavigateUp() {
finish(); // close this activity as oppose to navigating up
@ -97,66 +82,99 @@ public class MeActivity extends CommonActivity {
Toolbar toolbar = findViewById(R.id.tool_bar_me);
// Setting toolbar as the ActionBar with setSupportActionBar() call
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(
new IconicsDrawable(this, FontAwesome.Icon.faw_chevron_left).actionBar()
);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_baseline_close_24);
LinearLayout account = findViewById(R.id.a_me_account_line);
LinearLayout settings = findViewById(R.id.a_me_settings);
LinearLayout help = findViewById(R.id.a_me_helpnfeedback);
TextView logout = findViewById(R.id.a_me_logout);
init();
}
settings.setOnClickListener(view -> {
Intent settingsActivity = new Intent(getContext(), SettingsActivity.class);
//overridePendingTransition(R.anim.slide_in_bottom, 0);
startActivity(settingsActivity);
});
help.setOnClickListener(view -> {
String url = "https://github.com/sschueller/peertube-android/issues";
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
});
logout.setOnClickListener(view -> {
Session.getInstance().invalidate();
account.setVisibility(View.GONE);
});
private void init() {
// try to get user data
getUserData();
}
private boolean getUserData() {
// TODO
private void getUserData() {
String apiBaseURL = APIUrlHelper.getUrlWithVersion(this);
String baseURL = APIUrlHelper.getUrl(this);
GetUserService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetUserService.class);
Call<Me> call = service.getMe();
call.enqueue(new Callback<Me>() {
LinearLayout account = findViewById(R.id.a_me_account_line);
@Override
public void onResponse(@NonNull Call<Me> call, @NonNull Response<Me> response) {
if (response.isSuccessful()) {
Me me = response.body();
TextView username = findViewById(R.id.account_username);
TextView email = findViewById(R.id.account_email);
Log.d(TAG, response.body().toString());
TextView username = findViewById(R.id.a_me_username);
TextView email = findViewById(R.id.a_me_email);
ImageView avatarView = findViewById(R.id.a_me_avatar);
username.setText(me.getUsername());
email.setText(me.getEmail());
Log.v(TAG, me.getEmail());
Avatar avatar = me.getAccount().getAvatar();
if (avatar != null) {
String avatarPath = avatar.getPath();
Picasso.get()
.load(baseURL + avatarPath)
.into(avatarView);
}
account.setVisibility(View.VISIBLE);
} else {
account.setVisibility(View.GONE);
}
}
@Override
public void onFailure(Call<Me> call, Throwable t) {
public void onFailure(@NonNull Call<Me> call, @NonNull Throwable t) {
account.setVisibility(View.GONE);
}
});
return true;
}
@Override
protected void onResume() {
super.onResume();
init();
getUserData();
}
}

View File

@ -1,3 +1,20 @@
/*
* 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 androidx.annotation.NonNull;
@ -9,6 +26,7 @@ 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;
@ -54,28 +72,6 @@ public class SelectServerActivity extends AppCompatActivity {
loadList();
// set url
TextView selectedUrl = findViewById(R.id.serverSelectedUrl);
selectedUrl.setText(APIUrlHelper.getUrl(SelectServerActivity.this));
Button setServerButton = findViewById(R.id.server_selection_set);
setServerButton.setOnClickListener(v -> {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = sharedPref.edit();
String serverUrl = APIUrlHelper.cleanServerUrl(selectedUrl.getText().toString());
if (!Patterns.WEB_URL.matcher(serverUrl).matches()) {
Toast.makeText(this, R.string.invalid_url, Toast.LENGTH_LONG).show();
} else {
editor.putString("pref_api_base", serverUrl);
editor.apply();
this.finish();
}
});
}

View File

@ -0,0 +1,173 @@
/*
* 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.app.AlertDialog;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import net.schueller.peertube.R;
import net.schueller.peertube.adapter.ServerListAdapter;
import net.schueller.peertube.database.Server;
import net.schueller.peertube.database.ServerViewModel;
import net.schueller.peertube.fragment.AddServerFragment;
public class ServerAddressBookActivity extends CommonActivity implements AddServerFragment.OnFragmentInteractionListener {
private String TAG = "ServerAddressBookActivity";
public static final String EXTRA_REPLY = "net.schueller.peertube.room.REPLY";
private ServerViewModel mServerViewModel;
private AddServerFragment addServerFragment;
private FloatingActionButton floatingActionButton;
private FragmentManager fragmentManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_server_address_book);
mServerViewModel = new ViewModelProvider(this).get(ServerViewModel.class);
showServers();
floatingActionButton = findViewById(R.id.add_server);
floatingActionButton.setOnClickListener(view -> {
Log.d(TAG, "Click");
fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
addServerFragment = new AddServerFragment();
fragmentTransaction.replace(R.id.server_book, addServerFragment);
fragmentTransaction.commit();
floatingActionButton.hide();
});
}
@Override
public void onFragmentInteraction(Uri uri) {
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
public void showServers()
{
RecyclerView recyclerView = findViewById(R.id.server_list_recyclerview);
final ServerListAdapter adapter = new ServerListAdapter(this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// Delete items on swipe
ItemTouchHelper helper = new ItemTouchHelper(
new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView,
@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder,
int direction) {
new AlertDialog.Builder(ServerAddressBookActivity.this)
.setTitle(getString(R.string.server_book_del_alert_title))
.setMessage(getString(R.string.server_book_del_alert_msg))
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
int position = viewHolder.getAdapterPosition();
Server server = adapter.getServerAtPosition(position);
// Toast.makeText(ServerAddressBookActivity.this, "Deleting " +
// server.getServerName(), Toast.LENGTH_LONG).show();
// Delete the server
mServerViewModel.delete(server);
})
.setNegativeButton(android.R.string.no, (dialog, which) -> {
adapter.notifyItemChanged(viewHolder.getAdapterPosition());
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
});
helper.attachToRecyclerView(recyclerView);
// Update the cached copy of the words in the adapter.
mServerViewModel.getAllServers().observe(this, adapter::setServers);
}
public void addServer(View view)
{
Log.d(TAG, "addServer");
EditText serverLabel = view.findViewById(R.id.serverLabel);
EditText serverUrl = view.findViewById(R.id.serverUrl);
EditText serverUsername = view.findViewById(R.id.serverUsername);
EditText serverPassword = view.findViewById(R.id.serverPassword);
Server server = new Server(serverLabel.getText().toString());
server.setServerHost(serverUrl.getText().toString());
server.setUsername(serverUsername.getText().toString());
server.setPassword(serverPassword.getText().toString());
mServerViewModel.insert(server);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(addServerFragment);
fragmentTransaction.commit();
floatingActionButton.show();
}
public void testServer()
{
}
}

View File

@ -135,13 +135,6 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// Set theme
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
setTheme(getResources().getIdentifier(
sharedPref.getString(THEME_PREF_KEY, DEFAULT_THEME),
"style",
getPackageName())
);
super.onCreate(savedInstanceState);
@ -202,7 +195,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("pref_api_base"));
//bindPreferenceSummaryToValue(findPreference("pref_api_base"));
bindPreferenceSummaryToValue(findPreference("pref_theme"));
}
@ -219,12 +212,12 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
String key = preference.getKey();
if ("pref_api_base".equals(key)) {
Intent intentServer = new Intent(preference.getContext(), SelectServerActivity.class);
startActivity(intentServer);
return true;
}
// String key = preference.getKey();
// if ("pref_api_base".equals(key)) {
// Intent intentServer = new Intent(preference.getContext(), SelectServerActivity.class);
// startActivity(intentServer);
// return true;
// }
return false;
}
@ -232,7 +225,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
public void onResume() {
setPreferenceScreen(null);
addPreferencesFromResource(R.xml.pref_general);
bindPreferenceSummaryToValue(findPreference("pref_api_base"));
//bindPreferenceSummaryToValue(findPreference("pref_api_base"));
super.onResume();
}

View File

@ -19,11 +19,14 @@
package net.schueller.peertube.activity;
import android.Manifest;
import android.app.AlertDialog;
import android.app.SearchManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.preference.PreferenceManager;
import android.provider.SearchRecentSuggestions;
@ -47,6 +50,7 @@ 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;
@ -78,6 +82,7 @@ public class VideoListActivity extends CommonActivity {
public static final String EXTRA_VIDEOID = "VIDEOID";
public static final String EXTRA_ACCOUNTDISPLAYNAME = "ACCOUNTDISPLAYNAMEANDHOST";
public static final Integer SWITCH_INSTANCE = 2;
private VideoAdapter videoAdapter;
private SwipeRefreshLayout swipeRefreshLayout;
@ -122,14 +127,11 @@ public class VideoListActivity extends CommonActivity {
inflater.inflate(R.menu.menu_top_videolist, menu);
// Set an icon in the ActionBar
menu.findItem(R.id.action_settings).setIcon(
new IconicsDrawable(this, FontAwesome.Icon.faw_cog).actionBar());
menu.findItem(R.id.action_account).setIcon(
new IconicsDrawable(this, FontAwesome.Icon.faw_user_circle).actionBar());
// menu.findItem(R.id.action_server_selection).setIcon(
// new IconicsDrawable(this, FontAwesome.Icon.faw_server).actionBar());
menu.findItem(R.id.action_server_address_book).setIcon(
new IconicsDrawable(this, FontAwesome.Icon.faw_server).actionBar());
MenuItem searchMenuItem = menu.findItem(R.id.action_search);
@ -145,6 +147,26 @@ public class VideoListActivity extends CommonActivity {
searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default
searchView.setQueryRefinementEnabled(true);
searchMenuItem.getActionView().setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
new AlertDialog.Builder(VideoListActivity.this)
.setTitle(getString(R.string.clear_search_history))
.setMessage(getString(R.string.clear_search_history_prompt))
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(getApplicationContext(),
SearchSuggestionsProvider.AUTHORITY,
SearchSuggestionsProvider.MODE);
suggestions.clearHistory();
}
})
.setNegativeButton(android.R.string.no, null)
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
return true;
}
});
searchMenuItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem menuItem) {
@ -166,7 +188,27 @@ public class VideoListActivity extends CommonActivity {
Log.d(TAG, "onDismiss: ");
loadVideos(0, count, sort, filter);
});
searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
@Override
public boolean onSuggestionClick(int position) {
String suggestion = getSuggestion(position);
searchView.setQuery(suggestion, true);
return true;
}
private String getSuggestion(int position) {
Cursor cursor = (Cursor) searchView.getSuggestionsAdapter().getItem(
position);
return cursor.getString(cursor
.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1));
}
@Override
public boolean onSuggestionSelect(int position) {
/* Required to implement */
return true;
}
});
return true;
}
@ -176,6 +218,16 @@ public class VideoListActivity extends CommonActivity {
stopService(new Intent(this, VideoPlayerService.class));
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == SWITCH_INSTANCE) {
if(resultCode == RESULT_OK) {
loadVideos(currentStart, count, sort, filter);
}
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
@ -188,25 +240,28 @@ public class VideoListActivity extends CommonActivity {
//Toast.makeText(this, "Search Selected", Toast.LENGTH_SHORT).show();
return false;
case R.id.action_settings:
// Toast.makeText(this, "Login Selected", Toast.LENGTH_SHORT).show();
Intent intentSettings = new Intent(this, SettingsActivity.class);
this.startActivity(intentSettings);
return true;
case R.id.action_account:
if (!Session.getInstance().isLoggedIn()) {
Intent intentLogin = new Intent(this, LoginActivity.class);
this.startActivity(intentLogin);
} else {
// if (!Session.getInstance().isLoggedIn()) {
//Intent intentLogin = new Intent(this, ServerAddressBookActivity.class);
Intent intentMe = new Intent(this, MeActivity.class);
this.startActivity(intentMe);
}
//overridePendingTransition(R.anim.slide_in_bottom, 0);
// this.startActivity(intentLogin);
// } else {
// Intent intentMe = new Intent(this, MeActivity.class);
// this.startActivity(intentMe);
// }
return false;
case R.id.action_server_address_book:
Intent addressBookActivityIntent = new Intent(this, ServerAddressBookActivity.class);
this.startActivityForResult(addressBookActivityIntent, SWITCH_INSTANCE);
return false;
// case R.id.action_server_selection:
// Intent intentServer = new Intent(this, SelectServerActivity.class);
// this.startActivity(intentServer);
// return false;
default:
break;
}
@ -335,6 +390,7 @@ public class VideoListActivity extends CommonActivity {
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
handleIntent(intent);
}
@ -440,8 +496,10 @@ public class VideoListActivity extends CommonActivity {
//Log.v(TAG, "navigation_subscriptions");
if (!Session.getInstance().isLoggedIn()) {
Intent intent = new Intent(this, LoginActivity.class);
this.startActivity(intent);
// Intent intent = new Intent(this, LoginActivity.class);
// this.startActivity(intent);
Intent addressBookActivityIntent = new Intent(this, ServerAddressBookActivity.class);
this.startActivityForResult(addressBookActivityIntent, SWITCH_INSTANCE);
return false;
} else {

View File

@ -19,16 +19,24 @@
package net.schueller.peertube.activity;
import android.annotation.SuppressLint;
import android.app.AppOpsManager;
import android.app.PictureInPictureParams;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.util.Rational;
import android.util.TypedValue;
import android.view.WindowManager;
@ -39,6 +47,7 @@ import android.widget.RelativeLayout;
import net.schueller.peertube.R;
import net.schueller.peertube.fragment.VideoMetaDataFragment;
import net.schueller.peertube.fragment.VideoPlayerFragment;
import net.schueller.peertube.service.VideoPlayerService;
import java.util.Objects;
@ -71,13 +80,23 @@ public class VideoPlayActivity extends AppCompatActivity {
// get video ID
Intent intent = getIntent();
String videoUuid = intent.getStringExtra(VideoListActivity.EXTRA_VIDEOID);
Log.v(TAG, "click: " + videoUuid);
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);
assert videoPlayerFragment != null;
videoPlayerFragment.start(videoUuid);
String playingVideo = videoPlayerFragment.getVideoUuid();
Log.v(TAG, "oncreate click: " + videoUuid +" is trying to replace: "+playingVideo);
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");
videoPlayerFragment.stopVideo();
videoPlayerFragment.start(videoUuid);
} else {
Log.v(TAG,"oncreate same video playing currently");
}
// if we are in landscape set the video to fullscreen
int orientation = this.getResources().getConfiguration().orientation;
@ -86,6 +105,36 @@ public class VideoPlayActivity extends AppCompatActivity {
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
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;
String playingVideo = videoPlayerFragment.getVideoUuid();
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");
videoPlayerFragment.stopVideo();
videoPlayerFragment.start(videoUuid);
} else {
Log.v(TAG,"new intent same video playing currently");
}
// if we are in landscape set the video to fullscreen
int orientation = this.getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
setOrientation(true);
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
@ -199,4 +248,115 @@ public class VideoPlayActivity extends AppCompatActivity {
Log.v(TAG, "onStart()...");
}
@SuppressLint("NewApi")
@Override
public void 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");
videoPlayerFragment.pauseVideo();
stopService(new Intent(this, VideoPlayerService.class));
super.onBackPressed();
break;
case "backgroundAudio":
Log.v(TAG,"play the Audio");
super.onBackPressed();
break;
case "backgroundFloat":
Log.v(TAG,"play in floating video");
//canEnterPIPMode makes sure API level is high enough
if (canEnterPipMode(this)) {
Log.v(TAG, "enabling pip");
enterPipMode();
} else {
Log.v(TAG, "unable to use pip");
}
break;
}
Log.v(TAG, "onUserLeaveHint()...");
}
// @RequiresApi(api = Build.VERSION_CODES.O)
@SuppressLint("NewApi")
public void 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");
videoPlayerFragment.fullScreenToggle();
return;
}
if (sharedPref.getBoolean("pref_back_pause", true)) {
assert videoPlayerFragment != null;
videoPlayerFragment.pauseVideo();
}
String backgroundBehavior = sharedPref.getString("pref_background_behavior","backgroundStop");
switch (backgroundBehavior){
case "backgroundStop":
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");
super.onBackPressed();
break;
case "backgroundFloat":
Log.v(TAG,"play in floating video");
//canEnterPIPMode makes sure API level is high enough
if (canEnterPipMode(this)) {
Log.v(TAG, "enabling pip");
enterPipMode();
//fixes problem where back press doesn't bring up video list after returning from PIP mode
Intent intentSettings = new Intent(this, VideoListActivity.class);
this.startActivity(intentSettings);
} else {
Log.v(TAG,"Unable to enter PIP mode");
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());
PictureInPictureParams mParams =
new PictureInPictureParams.Builder()
.setAspectRatio(rational)
// .setSourceRectHint(new Rect(0,500,400,600))
.build();
enterPictureInPictureMode(mParams);
}
@Override
public void onPictureInPictureModeChanged (boolean isInPictureInPictureMode, Configuration newConfig) {
if (isInPictureInPictureMode) {
Log.v(TAG,"switched to pip ");
} else {
Log.v(TAG,"switched to normal");
}
}
}

View File

@ -18,6 +18,7 @@
package net.schueller.peertube.adapter;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
@ -37,6 +38,8 @@ import java.util.ArrayList;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import static android.app.Activity.RESULT_OK;
public class ServerAdapter extends RecyclerView.Adapter<ServerAdapter.AccountViewHolder> {
@ -75,18 +78,25 @@ public class ServerAdapter extends RecyclerView.Adapter<ServerAdapter.AccountVie
holder.itemView.setOnClickListener(v -> {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor editor = sharedPref.edit();
// SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(activity);
// SharedPreferences.Editor editor = sharedPref.edit();
String serverUrl = APIUrlHelper.cleanServerUrl(serverList.get(position).getHost());
editor.putString("pref_api_base", serverUrl);
editor.apply();
activity.finish();
// editor.putString("pref_api_base", serverUrl);
// editor.apply();
//
//
Toast.makeText(activity, activity.getString(R.string.server_selection_set_server, serverUrl), Toast.LENGTH_LONG).show();
Intent intent = new Intent();
intent.putExtra("serverUrl", serverUrl);
intent.putExtra("serverName", serverList.get(position).getName());
activity.setResult(RESULT_OK, intent);
activity.finish();
});
//

View File

@ -0,0 +1,158 @@
/*
* 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.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;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
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;
import java.util.List;
import static android.app.Activity.RESULT_OK;
public class ServerListAdapter extends RecyclerView.Adapter<ServerListAdapter.ServerViewHolder> {
private final LayoutInflater mInflater;
private List<Server> mServers; // Cached copy of Servers
public ServerListAdapter(Context context) {
this.mInflater = LayoutInflater.from(context);
}
@NonNull
@Override
public ServerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = mInflater.inflate(R.layout.row_serverbook, parent, false);
return new ServerViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull ServerViewHolder holder, int position) {
if (mServers != null) {
Server current = mServers.get(position);
holder.serverLabel.setText(current.getServerName());
holder.serverUrl.setText(current.getServerHost());
if (TextUtils.isEmpty(current.getUsername())) {
holder.hasLogin.setVisibility(View.GONE);
} else {
holder.hasLogin.setVisibility(View.VISIBLE);
}
} else {
// Covers the case of data not being ready yet.
holder.serverLabel.setText(R.string.server_book_no_servers_found);
}
holder.itemView.setOnClickListener(v -> {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mInflater.getContext());
SharedPreferences.Editor editor = sharedPref.edit();
String serverUrl = APIUrlHelper.cleanServerUrl(getServerAtPosition(position).getServerHost());
editor.putString("pref_api_base", serverUrl);
editor.apply();
// attempt authentication if we have a username
if (!TextUtils.isEmpty(getServerAtPosition(position).getUsername())) {
LoginService.Authenticate(
getServerAtPosition(position).getUsername(),
getServerAtPosition(position).getPassword()
);
}
// tell server list activity to reload list
Intent intent = new Intent();
((Activity) mInflater.getContext()).setResult(RESULT_OK, intent);
// close this activity
((Activity) mInflater.getContext()).finish();
Toast.makeText(mInflater.getContext(), mInflater.getContext().getString(R.string.server_selection_set_server, serverUrl), Toast.LENGTH_LONG).show();
});
//
// holder.itemView.setOnLongClickListener(v -> {
// Log.v("ServerListAdapter", "setOnLongClickListener " + position);
// return true;
// });
}
public void setServers(List<Server> Servers) {
mServers = Servers;
this.notifyDataSetChanged();
}
// getItemCount() is called many times, and when it is first called,
// mServers has not been updated (means initially, it's null, and we can't return null).
@Override
public int getItemCount() {
if (mServers != null)
return mServers.size();
else return 0;
}
static class ServerViewHolder extends RecyclerView.ViewHolder {
TextView serverLabel, serverUrl, serverUsername;
ImageView hasLogin;
private ServerViewHolder(View itemView) {
super(itemView);
serverLabel = itemView.findViewById(R.id.serverLabelRow);
serverUrl = itemView.findViewById(R.id.serverUrlRow);
hasLogin = itemView.findViewById(R.id.sb_row_has_login_icon);
}
}
public Server getServerAtPosition (int position) {
return mServers.get(position);
}
}

View File

@ -1,3 +1,20 @@
/*
* 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.application;
import android.app.Application;

View File

@ -0,0 +1,26 @@
/*
* 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.database;
import androidx.room.Database;
import androidx.room.RoomDatabase;
@Database(entities = {Server.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract ServerDao serverDao();
}

View File

@ -0,0 +1,87 @@
/*
* 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.database;
import androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity(tableName = "server_table")
public class Server {
@PrimaryKey(autoGenerate = true)
private int id;
@NonNull
@ColumnInfo(name = "server_name")
private String serverName;
@ColumnInfo(name = "server_host")
private String serverHost;
@ColumnInfo(name = "username")
private String username;
@ColumnInfo(name = "password")
private String password;
public Server(@NonNull String serverName) {
this.serverName = serverName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getServerName() {
return serverName;
}
public void setServerName(String serverName) {
this.serverName = serverName;
}
public String getServerHost() {
return serverHost;
}
public void setServerHost(String serverHost) {
this.serverHost = serverHost;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.database;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import java.util.List;
@Dao
public interface ServerDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Server server);
@Query("DELETE FROM server_table")
void deleteAll();
@Delete
void delete(Server server);
@Query("SELECT * from server_table ORDER BY server_name DESC")
LiveData<List<Server>> getAllServers();
}

View File

@ -0,0 +1,80 @@
/*
* 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.database;
import android.app.Application;
import android.os.AsyncTask;
import androidx.lifecycle.LiveData;
import java.util.List;
class ServerRepository {
private ServerDao mServerDao;
private LiveData<List<Server>> mAllServers;
ServerRepository(Application application) {
ServerRoomDatabase db = ServerRoomDatabase.getDatabase(application);
mServerDao = db.serverDao();
mAllServers = mServerDao.getAllServers();
}
LiveData<List<Server>> getAllServers() {
return mAllServers;
}
void insert (Server server) {
new insertAsyncTask(mServerDao).execute(server);
}
public void delete(Server server) {
new deleteServerAsyncTask(mServerDao).execute(server);
}
private static class insertAsyncTask extends AsyncTask<Server, Void, Void> {
private ServerDao mAsyncTaskDao;
insertAsyncTask(ServerDao dao) {
mAsyncTaskDao = dao;
}
@Override
protected Void doInBackground(final Server... params) {
mAsyncTaskDao.insert(params[0]);
return null;
}
}
private static class deleteServerAsyncTask extends AsyncTask<Server, Void, Void> {
private ServerDao mAsyncTaskDao;
deleteServerAsyncTask(ServerDao dao) {
mAsyncTaskDao = dao;
}
@Override
protected Void doInBackground(final Server... params) {
mAsyncTaskDao.delete(params[0]);
return null;
}
}
}

View File

@ -0,0 +1,57 @@
/*
* 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.database;
import android.content.Context;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Database(entities = {Server.class}, version = 1, exportSchema = false)
public abstract class ServerRoomDatabase extends RoomDatabase {
public abstract ServerDao serverDao();
private static volatile ServerRoomDatabase INSTANCE;
private static final int NUMBER_OF_THREADS = 4;
static final ExecutorService databaseWriteExecutor =
Executors.newFixedThreadPool(NUMBER_OF_THREADS);
public static ServerRoomDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (ServerRoomDatabase.class) {
if (INSTANCE == null) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
ServerRoomDatabase.class, "server_database")
.build();
}
}
}
}
return INSTANCE;
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.database;
import android.app.Application;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import java.util.List;
public class ServerViewModel extends AndroidViewModel {
private ServerRepository mRepository;
private LiveData<List<Server>> mAllServers;
public ServerViewModel (Application application) {
super(application);
mRepository = new ServerRepository(application);
mAllServers = mRepository.getAllServers();
}
public LiveData<List<Server>> getAllServers() { return mAllServers; }
public void insert(Server server) { mRepository.insert(server); }
public void delete(Server server) {mRepository.delete(server);}
}

View File

@ -0,0 +1,178 @@
/*
* 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.fragment;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.text.TextUtils;
import android.util.Log;
import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import net.schueller.peertube.R;
import net.schueller.peertube.activity.SelectServerActivity;
import net.schueller.peertube.activity.ServerAddressBookActivity;
import net.schueller.peertube.helper.APIUrlHelper;
import static android.app.Activity.RESULT_OK;
public class AddServerFragment extends Fragment {
public static final String TAG = "AddServerFragment";
public static final Integer PICK_SERVER = 1;
private OnFragmentInteractionListener mListener;
private View mView;
public AddServerFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
// Inflate the layout for this fragment
mView = inflater.inflate(R.layout.fragment_add_server, container, false);
// bind button click
Button addServerButton = mView.findViewById(R.id.addServerButton);
addServerButton.setOnClickListener(view -> {
Activity act = getActivity();
Boolean formValid = true;
// close keyboard
try {
InputMethodManager inputManager = (InputMethodManager)
act.getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(act.getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
} catch (Exception e) {
}
EditText selectedLabel = mView.findViewById(R.id.serverLabel);
if ( TextUtils.isEmpty(selectedLabel.getText())){
selectedLabel.setError( act.getString(R.string.server_book_label_is_required ));
Toast.makeText(act, R.string.invalid_url, Toast.LENGTH_LONG).show();
formValid = false;
}
// validate url
EditText selectedUrl = mView.findViewById(R.id.serverUrl);
String serverUrl = APIUrlHelper.cleanServerUrl(selectedUrl.getText().toString());
selectedUrl.setText(serverUrl);
if (!Patterns.WEB_URL.matcher(serverUrl).matches()) {
selectedUrl.setError( act.getString(R.string.server_book_valid_url_is_required ) );
Toast.makeText(act, R.string.invalid_url, Toast.LENGTH_LONG).show();
formValid = false;
}
if (formValid) {
if (act instanceof ServerAddressBookActivity) {
((ServerAddressBookActivity) act).addServer(mView);
}
}
});
// Button testServerButton = mView.findViewById(R.id.testServerButton);
// testServerButton.setOnClickListener(view -> {
// Activity act = getActivity();
// if (act instanceof ServerAddressBookActivity) {
// ((ServerAddressBookActivity) act).testServer();
// }
// });
Button pickServerUrl = mView.findViewById(R.id.pickServerUrl);
pickServerUrl.setOnClickListener(view -> {
Intent intentServer = new Intent(getActivity(), SelectServerActivity.class);
this.startActivityForResult(intentServer, PICK_SERVER);
});
return mView;
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_SERVER) {
if(resultCode == RESULT_OK) {
String serverUrlTest = data.getStringExtra("serverUrl");
//Log.d(TAG, "serverUrl " + serverUrlTest);
EditText serverUrl = mView.findViewById(R.id.serverUrl);
serverUrl.setText(serverUrlTest);
EditText serverLabel = mView.findViewById(R.id.serverLabel);
if ("".equals(serverLabel.getText().toString())) {
serverLabel.setText(data.getStringExtra("serverName"));
}
}
}
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}

View File

@ -18,6 +18,7 @@
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;
@ -25,12 +26,15 @@ import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
@ -65,6 +69,7 @@ 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;
@ -83,7 +88,7 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
private LinearLayout torrentStatus;
private static final String TAG = "VideoPlayerFragment";
private GestureDetector mDetector;
private ServiceConnection mConnection = new ServiceConnection() {
@ -135,6 +140,9 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
simpleExoPlayerView.setControllerShowTimeoutMs(1000);
simpleExoPlayerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIT);
mDetector = new GestureDetector(context, new MyGestureListener());
simpleExoPlayerView.setOnTouchListener(touchListener);
torrentStatus = activity.findViewById(R.id.exo_torrent_status);
// Full screen Icon
@ -146,13 +154,7 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
fullscreenButton.setOnClickListener(view -> {
Log.d(TAG, "Fullscreen");
if (!isFullscreen) {
isFullscreen = true;
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
isFullscreen = false;
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
fullScreenToggle();
});
if (!mBound) {
@ -182,7 +184,7 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
mService.setCurrentVideo(video);
if (video == null) {
Toast.makeText(context, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
Toast.makeText(context, "Unable to retrieve video information, try again later.", Toast.LENGTH_SHORT).show();
return;
}
@ -193,7 +195,7 @@ 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...Please try later!", Toast.LENGTH_SHORT).show();
Toast.makeText(context, "Something went wrong: "+t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
}
});
}
@ -252,6 +254,16 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL
}
}
public void pauseVideo() {
if (mBound){
mService.player.setPlayWhenReady(false);
}
}
public void pauseToggle() {
if (mBound) {
mService.player.setPlayWhenReady(!mService.player.getPlayWhenReady());
}
}
public void stopVideo() {
if (mBound) {
@ -275,7 +287,15 @@ 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);
} else {
setIsFullscreen(false);
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
/**
* Torrent Playback
*
@ -369,4 +389,84 @@ 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) {
return mDetector.onTouchEvent(event);
}
};
public String getVideoUuid(){
return mVideoUuid;
}
class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
/*
@Override
public boolean onDown(MotionEvent event) {
Log.d("TAG","onDown: ");
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.i("TAG", "onSingleTapConfirmed: ");
pauseToggle();
return true;
}
@Override
public void onLongPress(MotionEvent e) {
Log.i("TAG", "onLongPress: ");
}
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.i("TAG", "onDoubleTap: ");
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
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, String.valueOf(velocityX));
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 (canEnterPipMode(getContext())) {
getActivity().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 left "+velocityY);
}
return true;
}
}
}

View File

@ -69,7 +69,9 @@ public class Intents {
public static void Download(Context context, Video video) {
String url = video.getFiles().get(0).getFileDownloadUrl();
String destFilename = video.getName() + "." + MimeTypeMap.getFileExtensionFromUrl(URLUtil.guessFileName(url,null,null));
// make sure it is a valid filename
String destFilename = video.getName().replaceAll("[^a-zA-Z0-9]", "_") + "." + MimeTypeMap.getFileExtensionFromUrl(URLUtil.guessFileName(url,null,null));
//Toast.makeText(context, destFilename, Toast.LENGTH_LONG).show();
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription(video.getDescription());

View File

@ -57,7 +57,7 @@ public class AuthorizationInterceptor implements Interceptor {
Log.v("Authorization", "Intercept: Logout forced");
}
}else{
} else {
mainResponse = chain.proceed(chain.request());
}

View File

@ -15,23 +15,15 @@
* 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;
package net.schueller.peertube.service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.os.Bundle;
import android.text.InputType;
import android.util.Log;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.mikepenz.fontawesome_typeface_library.FontAwesome;
import com.mikepenz.iconics.IconicsDrawable;
import androidx.annotation.NonNull;
import net.schueller.peertube.R;
import net.schueller.peertube.helper.APIUrlHelper;
@ -40,88 +32,23 @@ import net.schueller.peertube.model.Token;
import net.schueller.peertube.network.AuthenticationService;
import net.schueller.peertube.network.RetrofitInstance;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class LoginActivity extends CommonActivity {
import static net.schueller.peertube.application.AppApplication.getContext;
private String TAG = "LoginActivity";
public class LoginService {
// UI references.
private AutoCompleteTextView mEmailView;
private EditText mPasswordView;
private static final String TAG = "LoginService";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
public static void Authenticate(String username, String password)
{
Context context = getContext();
setContentView(R.layout.activity_login);
String apiBaseURL = APIUrlHelper.getUrlWithVersion(context);
// bind button click
Button mEmailSignInButton = findViewById(R.id.email_sign_in_button);
mEmailSignInButton.setOnClickListener(view -> attemptLogin());
mEmailView = findViewById(R.id.email);
mPasswordView = findViewById(R.id.password);
// Attaching the layout to the toolbar object
Toolbar toolbar = findViewById(R.id.tool_bar_login);
// Setting toolbar as the ActionBar with setSupportActionBar() call
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(
new IconicsDrawable(this, FontAwesome.Icon.faw_chevron_left).actionBar()
);
}
@Override
public void onResume() {
EditText mServerName = findViewById(R.id.login_current_server);
mServerName.setText(APIUrlHelper.getUrl(this));
mServerName.setInputType(InputType.TYPE_NULL);
super.onResume();
}
@Override
public boolean onSupportNavigateUp() {
finish(); // close this activity as oppose to navigating up
return false;
}
private void attemptLogin() {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
Context context = this;
// Reset errors.
mEmailView.setError(null);
mPasswordView.setError(null);
// Store values at the time of the login attempt.
String email = mEmailView.getText().toString();
String password = mPasswordView.getText().toString();
//check values
if (email.isEmpty()) {
Toast.makeText(LoginActivity.this, "Email/Username is empty", Toast.LENGTH_LONG).show();
return;
}
if (password.isEmpty()) {
Toast.makeText(LoginActivity.this, "Password is empty", Toast.LENGTH_LONG).show();
return;
}
// make http call to login and save access tokens
String apiBaseURL = APIUrlHelper.getUrlWithVersion(this);
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
AuthenticationService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(AuthenticationService.class);
@ -141,7 +68,7 @@ public class LoginActivity extends CommonActivity {
"code",
"password",
"upload",
email,
username,
password
);
call2.enqueue(new Callback<Token>() {
@ -157,23 +84,19 @@ public class LoginActivity extends CommonActivity {
// TODO: calc expiration
//editor.putInt(getString(R.string.pref_token_expiration), token.getRefreshToken());
editor.putString(getString(R.string.pref_token_access), token.getAccessToken());
editor.putString(getString(R.string.pref_token_refresh), token.getExpiresIn());
editor.putString(getString(R.string.pref_token_type), token.getTokenType());
editor.commit();
editor.putString(context.getString(R.string.pref_token_access), token.getAccessToken());
editor.putString(context.getString(R.string.pref_token_refresh), token.getExpiresIn());
editor.putString(context.getString(R.string.pref_token_type), token.getTokenType());
editor.apply();
Log.wtf(TAG, "Logged in");
Intent intent = new Intent(context, MeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
Toast.makeText(context, context.getString(R.string.authentication_login_success), Toast.LENGTH_LONG).show();
finish(); // close this activity
} else {
Log.wtf(TAG, response2.toString());
Toast.makeText(LoginActivity.this, "Login Error!", Toast.LENGTH_LONG).show();
Toast.makeText(context, context.getString(R.string.authentication_login_failed), Toast.LENGTH_LONG).show();
}
}
@ -181,21 +104,24 @@ public class LoginActivity extends CommonActivity {
@Override
public void onFailure(@NonNull Call<Token> call2, @NonNull Throwable t2) {
Log.wtf("err", t2.fillInStackTrace());
Toast.makeText(context, context.getString(R.string.authentication_login_failed), Toast.LENGTH_LONG).show();
}
});
} else {
Log.wtf(TAG, response.toString());
Toast.makeText(context, context.getString(R.string.authentication_login_failed), Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(@NonNull Call<OauthClient> call, @NonNull Throwable t) {
Log.wtf("err", t.fillInStackTrace());
Toast.makeText(context, context.getString(R.string.authentication_login_failed), Toast.LENGTH_LONG).show();
}
});
}
}

View File

@ -19,15 +19,18 @@ package net.schueller.peertube.service;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import androidx.annotation.Nullable;
@ -35,9 +38,11 @@ import androidx.annotation.Nullable;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.util.Log;
import android.util.Rational;
import android.widget.Toast;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
@ -124,6 +129,10 @@ public class VideoPlayerService extends Service {
if (playerNotificationManager != null) {
playerNotificationManager.setPlayer(null);
}
//Was seeing an error when exiting the program about about not unregistering the receiver.
if (null!=myNoisyAudioStreamReceiver) {
this.unregisterReceiver(myNoisyAudioStreamReceiver);
}
if (player != null) {
player.release();
player = null;
@ -261,7 +270,7 @@ public class VideoPlayerService extends Service {
return Video.getMediaDescription(context, currentVideo);
}
});
mediaSessionConnector.setPlayer(player, null);
mediaSessionConnector.setPlayer(player);
// Audio Focus
AudioAttributes audioAttributes = new AudioAttributes.Builder()

View File

@ -0,0 +1,6 @@
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="250"
android:fromYDelta="0%p"
android:toYDelta="-100%p">
</translate>

View File

@ -0,0 +1,6 @@
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:fromYDelta="100%p"
android:toYDelta="0">
</translate>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2c-4.97,0 -9,4.03 -9,9 0,4.17 2.84,7.67 6.69,8.69L12,22l2.31,-2.31C18.16,18.67 21,15.17 21,11c0,-4.97 -4.03,-9 -9,-9zM12,4c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,18.3c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M4,6L2,6v14c0,1.1 0.9,2 2,2h14v-2L4,20L4,6zM20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM12,14.5v-9l6,4.5 -6,4.5z"/>
</vector>

View File

@ -1,113 +0,0 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tool_bar_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="4dp" />
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="net.schueller.peertube.activity.LoginActivity">
<ScrollView
android:id="@+id/login_form"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/email_login_form"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Alpha! Login is still in heavy development and may not work correctly! You must have an account on the instance you are connecting to. Registration is currently not supported"
android:textSize="16sp" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/login_current_server"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_current_server_hint"
android:inputType="none"
android:focusable="false"
android:maxLines="1"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<AutoCompleteTextView
android:id="@+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_email"
android:inputType="textEmailAddress"
android:maxLines="1"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_password"
android:imeActionId="6"
android:imeActionLabel="@string/action_sign_in_short"
android:imeOptions="actionUnspecified"
android:inputType="textPassword"
android:maxLines="1"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/email_sign_in_button"
style="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/action_sign_in"
android:textStyle="bold" />
</LinearLayout>
</ScrollView>
</LinearLayout>
</LinearLayout>

View File

@ -5,6 +5,7 @@
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".activity.MeActivity"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
@ -13,7 +14,7 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.appcompat.widget.Toolbar
android:id="@+id/tool_bar_me"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -23,26 +24,154 @@
</com.google.android.material.appbar.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_marginBottom="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/account_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/account_email"
<LinearLayout
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="" />
android:layout_marginTop="12dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="12dp"
android:id="@+id/a_me_account_line"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/a_me_avatar"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_marginTop="0dp"
android:paddingStart="12dp"
android:paddingTop="12dp"
android:paddingEnd="12dp"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/a_me_username"
android:drawablePadding="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=""
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" />
<TextView
android:id="@+id/a_me_email"
android:drawablePadding="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=""
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" />
<TextView
android:drawablePadding="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/me_logout_button"
android:id="@+id/a_me_logout"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:background="@android:color/darker_gray" />
<LinearLayout
android:id="@+id/a_me_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="12dp"
android:orientation="horizontal">
<TextView
android:drawableStart="@drawable/ic_baseline_settings_24"
android:drawablePadding="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/title_activity_settings"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" />
</LinearLayout>
<LinearLayout
android:id="@+id/a_me_helpnfeedback"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="12dp"
android:orientation="horizontal">
<TextView
android:drawableStart="@drawable/ic_baseline_help_24"
android:drawablePadding="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/me_help_and_feedback_button"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<!-- <LinearLayout-->
<!-- android:layout_marginBottom="0dp"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:orientation="vertical">-->
<!-- <androidx.appcompat.widget.AppCompatTextView-->
<!-- android:id="@+id/account_username"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="" />-->
<!-- <androidx.appcompat.widget.AppCompatTextView-->
<!-- android:id="@+id/account_email"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="" />-->
<!-- </LinearLayout>-->
</LinearLayout>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.ServerAddressBookActivity"
android:id="@+id/server_book">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/add_server"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@drawable/ic_baseline_add_24" />
<include layout="@layout/content_server_address_book" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -12,46 +12,6 @@
android:orientation="vertical"
>
<LinearLayout
android:padding="@dimen/fab_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:text="@string/server_selection_select_a_server" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<AutoCompleteTextView
android:hint="@string/server_selection_peertube_server_url"
android:id="@+id/serverSelectedUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textUri"
android:maxLines="1"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/server_selection_set"
style="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/action_set_url"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".activity.ServerAddressBookActivity"
tools:showIn="@layout/activity_server_address_book">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/server_list_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/darker_gray"
tools:listitem="@layout/row_serverbook" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingTop="100dp"
android:paddingRight="16dp"
tools:context=".fragment.AddServerFragment"
android:background="?android:colorBackground">
<EditText
android:id="@+id/serverLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/server_book_add_label"
android:inputType="textPersonName" />
<RelativeLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content">
<EditText
android:layout_alignParentStart="true"
android:id="@+id/serverUrl"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/server_book_add_server_url"
android:inputType="textUri"
android:layout_toStartOf="@+id/pickServerUrl"/>
<Button
android:layout_alignParentEnd="true"
android:id="@+id/pickServerUrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/server_book_add_pick_server_button" />
</RelativeLayout>
<EditText
android:id="@+id/serverUsername"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/server_book_add_username"
android:inputType="textPersonName" />
<EditText
android:id="@+id/serverPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/server_book_add_password"
android:inputType="textPassword" />
<!-- <Button-->
<!-- android:id="@+id/testServerButton"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="Test" />-->
<Button
android:id="@+id/addServerButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/server_book_add_add_button" />
</LinearLayout>

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
card_view:cardCornerRadius="0dp"
card_view:cardElevation="0dp"
card_view:cardUseCompatPadding="true">
<RelativeLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:padding="12dp">
<LinearLayout
android:layout_alignParentStart="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="@+id/serverLabelRow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Headline" />
<TextView
android:id="@+id/serverUrlRow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="0dp"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Subhead" />
</LinearLayout>
<ImageView
android:id="@+id/sb_row_has_login_icon"
android:src="@drawable/ic_baseline_account_circle_24"
android:visibility="visible"
android:contentDescription="@string/server_book_list_has_login"
android:layout_width="24dp"
android:layout_alignParentEnd="true"
android:layout_height="wrap_content"/>
</RelativeLayout>
</androidx.cardview.widget.CardView>

View File

@ -3,10 +3,5 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="activity.VideoListActivity">
<item
android:id="@+id/action_logout"
android:orderInCategory="300"
android:title="@string/action_bar_title_logout"
app:showAsAction="ifRoom" />
</menu>

View File

@ -12,13 +12,15 @@
android:textAppearance="@style/Base.TextAppearance.AppCompat.Caption"
app:actionViewClass="androidx.appcompat.widget.SearchView" />
<item
android:id="@+id/action_settings"
android:id="@+id/action_server_address_book"
android:orderInCategory="300"
android:title="@string/action_bar_title_settings"
android:title="@string/action_bar_title_address_book"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Caption"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_account"
android:orderInCategory="300"

View File

@ -42,9 +42,9 @@
<string name="pref_description_torrent_player">تشغيل الفيديو عبر بث التورنت . يتطلب أذونات التخزين. (ألفا ، غير مستقر!)</string>
<string name="pref_title_license">الرخصة</string>
<string name="pref_description_license">
<b>رخصة جنو العمومية v3.0</b>\n
\n
إن أذونات هذا الترخيص الأقوى للحقوق المتروكة مشروطة بإتاحة الشفرة المصدرية الكاملة للأعمال والتعديلات المرخصة ، والتي تشتمل على أعمال أكبر باستخدام عمل مرخص ، تحت نفس الترخيص. يجب الحفاظ على حقوق النشر وإشعارات الترخيص. يقدم المساهمون منحة صريحة لحقوق البراءة. عند استخدام إصدار معدل لتوفير خدمة عبر شبكة ، يجب توفير شفرة المصدر الكاملة للإصدار المعدل.</string>
\n<b>رخصة جنو العمومية v3.0</b>
\n
\nإن أذونات هذا الترخيص الأقوى للحقوق المتروكة مشروطة بإتاحة الشفرة المصدرية الكاملة للأعمال والتعديلات المرخصة ، والتي تشتمل على أعمال أكبر باستخدام عمل مرخص ، تحت نفس الترخيص. يجب الحفاظ على حقوق النشر وإشعارات الترخيص. يقدم المساهمون منحة صريحة لحقوق البراءة. عند استخدام إصدار معدل لتوفير خدمة عبر شبكة ، يجب توفير شفرة المصدر الكاملة للإصدار المعدل.</string>
<string name="pref_title_version">الإصدار</string>
<string name="search_hint">مشاركة PeerTube</string>
<string name="title_activity_search">بحث</string>

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="br">ব্রেটন</string>
<string name="bzs">ব্রাজিলিয়ান সাইন ভাষা</string>
<string name="bs">বসনিয়ান</string>
<string name="bi">বিসলামা</string>
<string name="bn">বাংলা</string>
<string name="be">বেলারুসিয়ান</string>
<string name="eu">বাস্ক</string>
<string name="ba">বাশকির</string>
<string name="bm">বাম্বারা</string>
<string name="az">আজারবাইজান</string>
<string name="ay">আয়মারা</string>
<string name="av">অভরিক</string>
<string name="as">অসমি</string>
<string name="hy">আর্মেনিয়ান</string>
<string name="an">আরাগনিস</string>
<string name="ar">আরবি</string>
<string name="am">আমহারিক</string>
<string name="ase">আমেরিকান সাইন ভাষা</string>
<string name="sq">আলবানিয়ান</string>
<string name="ak">আকান</string>
<string name="af">আফ্রিকান</string>
<string name="aa">আফার</string>
<string name="ab">আবখাজিয়ান</string>
<string name="pref_description_background_play">সক্রিয় থাকলে ব্যাকগ্রাউন্ডে ভিডিও প্লে করতে থাকবে।</string>
<string name="pref_title_background_play">ব্যাকগ্রাউন্ড প্লেব্যাক</string>
<string name="pref_description_language">ভিডিওর ভাষা পছন্দ করো, কিছু পছন্দ না করলে সব ভাষার ভিডিও দেখা যাবে।</string>
<string name="pref_language">ভাষা ফিল্টার</string>
<string name="pref_description_show_nsfw">নিষিদ্ধ কন্টেন্ট দেখাও</string>
<string name="pref_title_show_nsfw">নিষিদ্ধ কন্টেন্ট</string>
<string name="pref_title_version">সংস্করণ</string>
<string name="pref_description_license">"
\n&lt;b&gt;গাহ্নু অফেরও সাধারণ গণ অনুমতিপত্র সং.৩.&lt;/b&gt;
\n
\nএই শক্তিশালী কপিলেফট লাইসেন্সের অনুমতি এই চুক্তির উপর নির্ভরশীল যে অনুমতিপত্রের দ্বারা আবদ্ধ সকল কাজ ও পরিবর্তনের সোর্স কোড উপলব্ধ করার মাধ্যমে, যার আওতায় পড়ে অনুমতিপত্রের দ্বারা আবদ্ধ কাজের বৃহত্তর অংশ একই অনুমতিপত্রের আওতায় আনার মাধ্যমে। কপিরাইট এবং লাইসেন্স নোটিশ সংরক্ষণ করা আবশ্যক। অবদানকারীগণ তাদের পেটেন্টর অধিকার অবশ্যই দেয়, যখন একটি পরিমার্জিত সংস্করণ ব্যবহার করে একটি পরিসেবা একটি নেটওয়ার্ক দিয়ে দেয়া হয়, সম্পূর্ণ সোর্স কোড এর পরিমার্জিত সংস্করণ উপলব্ধ তৈরি করা আবশ্যক।"<b>GNU Affero General Public License v3.0</b>\n\nPermissions of this strongest copyleft license are conditioned on making available complete source code of licensed works and modifications, which include larger works using a licensed work, under the same license. Copyright and license notices must be preserved. Contributors provide an express grant of patent rights. When a modified version is used to provide a service over a network, the complete source code of the modified version must be made available.</string>
<string name="pref_description_torrent_player">একটি টরেন্ট স্ট্রিমের মাধ্যমে ভিডিও প্লেব্যাক করুন। এর জন্য স্টোরেজ অনুমতির প্রয়োজন । (আলফা, স্থিতিশীল নয়!)</string>
<string name="pref_title_torrent_player">টরেন্ট ভিডিও প্লেয়ার</string>
<string name="pref_description_app_theme">থিমটি কার্যকর হওয়ার জন্য অ্যাপ্লিকেশন পুনরায় চালু করো।</string>
<string name="pref_title_app_theme">অ্যাপ থিম</string>
<string name="pref_description_dark_mode">অন্ধকার মোড কার্যকর করার জন্য অ্যাপ্লিকেশন রিস্টার্ট করো।</string>
<string name="pref_title_dark_mode">অন্ধকার মোড</string>
<string name="invalid_url">অবৈধ ইউআরএল।</string>
<string name="menu_share">শেয়ার</string>
<string name="descr_overflow_button">আরও</string>
<string name="no_data_available">ফলাফল নেই</string>
<string name="title_activity_search">সার্চ</string>
<string name="search_hint">সার্চ পিয়ারটিউব</string>
<string name="title_activity_url_video_play">ইউআরএলভিডিওপ্লেক্রিয়া</string>
<string name="video_row_account_avatar">অ্যাকাউন্ট অবতার</string>
<string name="video_row_video_thumbnail">ভিডিও থাম্বনেইল</string>
<string name="meta_data_views">" দৃষ্ট"</string>
<string name="bottom_nav_title_account">অ্যাকাউন্ট</string>
<string name="bottom_nav_title_subscriptions">সাবস্ক্রিপশন</string>
<string name="bottom_nav_title_local">স্থানীয়</string>
<string name="bottom_nav_title_recent">সাম্প্রতিক</string>
<string name="bottom_nav_title_trending">আলোচিত</string>
<string name="bottom_nav_title_discover">আবিষ্কার</string>
<string name="action_bar_title_account">অ্যাকাউন্ট</string>
<string name="action_bar_title_logout">লগ আউট</string>
<string name="action_bar_title_settings">সেটিংস</string>
<string name="action_bar_title_search">সার্চ</string>
<string name="permission_rationale">ই-মেইল পূরণ করার জন্য কন্টাক্ট-এর অনুমতি দিন।</string>
<string name="error_field_required">এটি প্রয়োজনীয় ফিল্ড</string>
<string name="error_incorrect_password">ভুল পাসওয়ার্ড</string>
<string name="error_invalid_password">পাসওয়ার্ড খুব ছোট</string>
<string name="error_invalid_email">ভুল ইমেইল আইডি</string>
<string name="action_sign_in_short">সাইন ইন</string>
<string name="action_sign_in">সাইন ইন</string>
<string name="prompt_password">পাসওয়ার্ড</string>
<string name="prompt_email">ইমেল / ব্যবহারকারীর নাম</string>
<string name="prompt_server">সার্ভার</string>
<string name="title_activity_login">সাইন ইন</string>
<string name="title_activity_settings">সেটিংস</string>
</resources>

View File

@ -6,42 +6,42 @@
<string name="title_activity_login">সাইন ইন</string>
<!-- Strings related to login -->
<string name="prompt_server">সার্ভার</string>
<string name="prompt_email">ইমেল / ইয়ুজারনে</string>
<string name="prompt_email">ইমেল / ব্যবহারকারীর না</string>
<string name="prompt_password">পাসওয়ার্ড</string>
<string name="action_sign_in">সাইন ইন</string>
<string name="action_sign_in_short">সাইন ইন</string>
<string name="error_invalid_email">ভুল ইমেল আইডি</string>
<string name="error_invalid_email">ভুল ইমেল আইডি</string>
<string name="error_invalid_password">পাসওয়ার্ড খুব ছোট</string>
<string name="error_incorrect_password">ভুল পাসওয়ার্ড</string>
<string name="error_field_required">এটি জরুরি ফিল্ড</string>
<string name="error_field_required">এটি প্রয়োজনীয় ফিল্ড</string>
<string name="permission_rationale">ই-মেইল পূরণ করার জন্য কন্টাক্ট-এর অনুমতি দিন।</string>
<!-- Action bar -->
<string name="action_bar_title_search">সার্চ</string>
<string name="action_bar_title_settings">সেটিং</string>
<string name="action_bar_title_settings">সেটিং</string>
<string name="action_bar_title_logout">লগ আউট</string>
<!-- Bottom navigation bar -->
<string name="bottom_nav_title_discover">হোম</string>
<string name="bottom_nav_title_discover">আবিষ্কার</string>
<string name="bottom_nav_title_trending">আলোচিত</string>
<string name="bottom_nav_title_subscriptions">সাবস্ক্রিপশন</string>
<string name="bottom_nav_title_account">কাউন্ট</string>
<string name="bottom_nav_title_account">অ্যাকাউন্ট</string>
<!-- Strings related to Settings -->
<string name="peertube_required_server_version" translatable="false">1.0.0-alpha.7</string>
<string name="pref_default_api_base_url" formatted="false" translatable="false">https://troll.tv</string>
<string name="pref_title_peertube_server">পিয়ারটিউব সার্ভার</string>
<!-- 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_views">" দৃষ্ট"</string>
<string name="meta_data_owner_seperator" translatable="false">\@</string>
<string name="video_row_video_thumbnail">ভিডিও থাম্বনেল</string>
<string name="video_row_account_avatar">Account Avatar</string>
<string name="video_row_video_thumbnail">ভিডিও থাম্বনে</string>
<string name="video_row_account_avatar">অ্যাকাউন্ট অবতার</string>
<string name="pref_title_show_nsfw">নিষিদ্ধ কন্টেন্ট</string>
<string name="pref_description_show_nsfw">নিষিদ্ধ কন্টেন্ট দেখাও</string>
<string name="pref_language">ভাষা ফিল্টার</string>
<string name="pref_description_language">ভিডিওর ভাষা পছন্দ করুন, কিছু পছন্দ না করলে সব ভাষার ভিডিও দেখা যাবে.</string>
<string name="title_activity_url_video_play">ইউআরএলভিডিওপ্লেঅ্যাক্টিভিটি</string>
<string name="pref_description_language">ভিডিওর ভাষা পছন্দ কর, কিছু পছন্দ না করলে সব ভাষার ভিডিও দেখা যাবে</string>
<string name="title_activity_url_video_play">ইউআরএলভিডিওপ্লেক্রিয়া</string>
<string name="pref_title_torrent_player">টরেন্ট ভিডিও প্লেয়ার</string>
<string name="pref_description_torrent_player">একটি টরেন্ট স্ট্রিম মাধ্যমে ভিডিও প্লেব্যাক করুন। এর জন্য স্টোরেজ অনুমতির প্রয়োজন । (আলফা, স্থিতিশীল নয়!)</string>
<string name="pref_title_license">লাইসেন্স</string>
<string name="pref_description_torrent_player">একটি টরেন্ট স্ট্রিমের মাধ্যমে ভিডিও প্লেব্যাক করুন। এর জন্য স্টোরেজ অনুমতির প্রয়োজন । (আলফা, স্থিতিশীল নয়!)</string>
<string name="pref_title_license">অনুমতিপত্র</string>
<string name="pref_description_license">
\n<b>গাহ্নু অফেরও সাধারণ গণ অনুমতিপত্র সং.৩.</b>
\n
@ -49,15 +49,15 @@
<string name="pref_title_version">সংস্করণ</string>
<string name="search_hint">সার্চ পিয়ারটিউব</string>
<string name="title_activity_search">সার্চ</string>
<string name="no_data_available">" কোন উত্তর নেই"</string>
<string name="no_data_available">ফলাফল নেই</string>
<string name="descr_overflow_button">আরও</string>
<string name="menu_share">শেয়ার</string>
<string name="playback_channel_name" translatable="false">PeerTube</string>
<string name="invalid_url">অবৈধ ইউআরএল।</string>
<string name="pref_title_dark_mode">ডার্ক মোড</string>
<string name="pref_description_dark_mode">ডার্ক মোড কার্যকর করার জন্য অ্যাপ্লিকেশন রিস্টার্ট করুন</string>
<string name="pref_title_dark_mode">অন্ধকার মোড</string>
<string name="pref_description_dark_mode">অন্ধকার মোড কার্যকর করার জন্য অ্যাপ্লিকেশন রিস্টার্ট কর</string>
<string name="pref_title_app_theme">অ্যাপ থিম</string>
<string name="pref_description_app_theme">থিমটি কার্যকর হওয়ার জন্য অ্যাপ্লিকেশন পুনরায় চালু করুন</string>
<string name="pref_description_app_theme">থিমটি কার্যকর হওয়ার জন্য অ্যাপ্লিকেশন পুনরায় চালু কর</string>
<string name="ab">আবখাজিয়ান</string>
<string name="aa">আফার</string>
<string name="af">আফ্রিকান</string>
@ -98,74 +98,74 @@
<string name="cse">চেক সাইন ভাষা</string>
<string name="da">ড্যানিশ</string>
<string name="dsl">ড্যানিশ সাংকেতিক ভাষা</string>
<string name="dv">ধিভেি</string>
<string name="nl">ডাচ</string>
<string name="dv">ধিভেি</string>
<string name="nl">ডাচ</string>
<string name="dz">জংখ্যা</string>
<string name="en">ইংলিশ</string>
<string name="eo">Esperanto</string>
<string name="et">Estonian</string>
<string name="ee">Ewe</string>
<string name="fo">Faroese</string>
<string name="fj">Fijian</string>
<string name="fi">Finnish</string>
<string name="fr">French</string>
<string name="en">ইংরেজি</string>
<string name="eo">এসপেরানটা</string>
<string name="et">এসটোনীয়</string>
<string name="ee">ইওয়ি</string>
<string name="fo">ফারোয়েস</string>
<string name="fj">ফিজান</string>
<string name="fi">ফিনিশ</string>
<string name="fr">ফরাসি</string>
<string name="fsl">ফরাসি সাংকেতিক ভাষা</string>
<string name="ff">Fulah</string>
<string name="gl">Galician</string>
<string name="lg">Ganda</string>
<string name="ka">Georgian</string>
<string name="de">German</string>
<string name="ff">ফুলাহ</string>
<string name="gl">গালিসীয়</string>
<string name="lg">গানডা</string>
<string name="ka">জর্জিয়</string>
<string name="de">জার্মান</string>
<string name="gsg">জার্মান সাংকেতিক ভাষা</string>
<string name="gn">Guarani</string>
<string name="gu">Gujarati</string>
<string name="ht">Haitian</string>
<string name="ha">Hausa</string>
<string name="he">Hebrew</string>
<string name="hz">Herero</string>
<string name="hi">Hindi</string>
<string name="ho">Hiri Motu</string>
<string name="hu">Hungarian</string>
<string name="is">Icelandic</string>
<string name="ig">Igbo</string>
<string name="id">Indonesian</string>
<string name="iu">Inuktitut</string>
<string name="ik">Inupiaq</string>
<string name="ga">Irish</string>
<string name="it">Italian</string>
<string name="ja">Japanese</string>
<string name="gn">গুরানি</string>
<string name="gu">গুজরাটি</string>
<string name="ht">হাইতান</string>
<string name="ha">হাওসা</string>
<string name="he">হিব্রু</string>
<string name="hz">হেরেরো</string>
<string name="hi">হিন্দি</string>
<string name="ho">হিরি মোটু</string>
<string name="hu">হানগেরীয়</string>
<string name="is">আইসল্যান্ডিক</string>
<string name="ig">ইগবো</string>
<string name="id">ইন্দোনেশীয়</string>
<string name="iu">ইনুক্টিটুট</string>
<string name="ik">ইনুপিয়াক</string>
<string name="ga">আইরিশ</string>
<string name="it">ইতালিয়</string>
<string name="ja">জাপানিজ</string>
<string name="jsl">জাপানি সাইন ভাষা</string>
<string name="jv">Javanese</string>
<string name="kl">Kalaallisut</string>
<string name="kn">Kannada</string>
<string name="kr">Kanuri</string>
<string name="ks">Kashmiri</string>
<string name="kk">Kazakh</string>
<string name="km">Khmer</string>
<string name="ki">Kikuyu</string>
<string name="rw">Kinyarwanda</string>
<string name="ky">Kirghiz</string>
<string name="tlh">Klingon</string>
<string name="kv">Komi</string>
<string name="kg">Kongo</string>
<string name="ko">Korean</string>
<string name="avk">Kotava</string>
<string name="kj">Kuanyama</string>
<string name="ku">Kurdish</string>
<string name="lo">Lao</string>
<string name="lv">Latvian</string>
<string name="li">Limburgan</string>
<string name="ln">Lingala</string>
<string name="lt">Lithuanian</string>
<string name="jbo">Lojban</string>
<string name="lu">Luba-Katanga</string>
<string name="lb">Luxembourgish</string>
<string name="mk">Macedonian</string>
<string name="mg">Malagasy</string>
<string name="ms">Malay (macrolanguage)</string>
<string name="ml">Malayalam</string>
<string name="mt">Maltese</string>
<string name="gv">Manx</string>
<string name="mi">Maori</string>
<string name="jv">জাভানিজ</string>
<string name="kl">কালাল্লিসুট</string>
<string name="kn">কান্নাডা</string>
<string name="kr">কানুরি</string>
<string name="ks">কাশমিরি</string>
<string name="kk">কাযাখ</string>
<string name="km">খমার</string>
<string name="ki">কিকুয়ু</string>
<string name="rw">কিনয়ারওয়ান্ডা</string>
<string name="ky">কিরঘিয</string>
<string name="tlh">ক্লিন্টোন</string>
<string name="kv">কোমি</string>
<string name="kg">কঙ্গো</string>
<string name="ko">কোরিয়ান</string>
<string name="avk">কোটাভা</string>
<string name="kj">কুয়ানইয়ামা</string>
<string name="ku">কুর্ডিশ</string>
<string name="lo">লাও</string>
<string name="lv">লাটভীয়</string>
<string name="li">লিমবুরগান</string>
<string name="ln">লিনগালা</string>
<string name="lt">লিথুনীয়</string>
<string name="jbo">লোজবান</string>
<string name="lu"></string>
<string name="lb">লাক্সেমবোর্গীয়</string>
<string name="mk">ম্যাসিডোনিয়</string>
<string name="mg">মালাগাসি</string>
<string name="ms">মালয় (বড়ভাষা)</string>
<string name="ml">মালায়ালাম</string>
<string name="mt">মাল্টিজ</string>
<string name="gv">মান্ক্স</string>
<string name="mi">মাওরি</string>
<string name="mr">Marathi</string>
<string name="mh">Marshallese</string>
<string name="el">Modern Greek (1453-)</string>
@ -174,8 +174,8 @@
<string name="nv">Navajo</string>
<string name="ng">Ndonga</string>
<string name="ne">Nepali (macrolanguage)</string>
<string name="nd">North Ndebele</string>
<string name="se">Northern Sami</string>
<string name="nd">উত্তর ডেবেলে</string>
<string name="se">উত্তর সামি</string>
<string name="no">Norwegian</string>
<string name="nb">Norwegian Bokmål</string>
<string name="nn">Norwegian Nynorsk</string>
@ -212,8 +212,8 @@
<string name="sl">Slovenian</string>
<string name="so">Somali</string>
<string name="sfs">দক্ষিণ আফ্রিকান সাংকেতিক ভাষা</string>
<string name="nr">South Ndebele</string>
<string name="st">Southern Sotho</string>
<string name="nr">দক্ষিণ ডেবেলে</string>
<string name="st">দক্ষিণ সোথো</string>
<string name="es">Spanish</string>
<string name="su">Sundanese</string>
<string name="sw">Swahili (macrolanguage)</string>
@ -243,7 +243,7 @@
<string name="vi">Vietnamese</string>
<string name="wa">Walloon</string>
<string name="cy">Welsh</string>
<string name="fy">Western Frisian</string>
<string name="fy">পশ্চিম ফ্রিসিয়ান</string>
<string name="wo">Wolof</string>
<string name="xh">Xhosa</string>
<string name="yi">Yiddish</string>
@ -268,9 +268,9 @@
<string name="brown">বাদামী</string>
<string name="gray">ধুসর</string>
<string name="bluegray">নীলচে ধূসর</string>
<string name="video_speed_05">0.5x</string>
<string name="video_speed_05">.৫x</string>
<string name="video_speed_10">Normal</string>
<string name="video_speed_15">1.5x</string>
<string name="video_speed_15">১.৫x</string>
<string name="video_speed_20">2x</string>
<string name="video_speed_active_icon" translatable="false">{faw-check}</string>
<string name="video_expand_icon" translatable="false">{faw-expand}</string>
@ -282,8 +282,8 @@
<string name="video_download_icon" translatable="false">{faw-download}</string>
<string name="video_save_icon" translatable="false">{faw-save}</string>
<string name="pref_title_background_play">ব্যাকগ্রাউন্ড প্লেব্যাক</string>
<string name="pref_description_background_play">সক্রিয় থাকলে ব্যাকগ্রাউন্ডে ভিডিও প্লে করতে থাকুন</string>
<string name="bottom_nav_title_local">Local</string>
<string name="pref_description_background_play">সক্রিয় থাকলে ব্যাকগ্রাউন্ডে ভিডিও প্লে করতে থাকবে</string>
<string name="bottom_nav_title_local">স্থানীয়</string>
<string name="title_activity_account">একাউন্ট</string>
<string name="menu_video_more_report">রিপোর্ট</string>
<string name="menu_video_more_blacklist">নিষিদ্ধ তালিকা</string>
@ -308,7 +308,7 @@
<string name="video_rating_like" translatable="false">like</string>
<string name="video_rating_dislike" translatable="false">dislike</string>
<string name="deeppurple">গাঢ় বেগুনি</string>
<string name="action_bar_title_account">কাউন্ট</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>

View File

@ -31,4 +31,10 @@
<string name="error_invalid_password">Toto heslo je příliš krátké</string>
<string name="bottom_nav_title_trending">Trendy</string>
<string name="title_activity_search">Hledat</string>
<string name="video_speed_125">1,25×</string>
<string name="video_speed_075">0,75×</string>
<string name="video_speed_20">2×</string>
<string name="video_speed_15">1,5×</string>
<string name="video_speed_10">Normální</string>
<string name="video_speed_05">0,5×</string>
</resources>

View File

@ -88,7 +88,7 @@
<string name="en">Englisch</string>
<string name="eo">Esperanto</string>
<string name="et">Estnisch</string>
<string name="pref_title_torrent_player">Torrent-Video-Player</string>
<string name="pref_title_torrent_player">Torrent-Videoabspieler</string>
<string name="ee">Ewe-Sprache</string>
<string name="fo">Färöisch</string>
<string name="fj">Fidschianisch</string>
@ -286,7 +286,7 @@
<string name="account_about_subscribers">Abonnenten:</string>
<string name="account_about_description">Beschreibung:</string>
<string name="account_about_joined">Mitglied seit:</string>
<string name="api_error">Etwas ist schief gelaufen, bitte versuchen Sie es später!</string>
<string name="api_error">Etwas ist schiefgelaufen, bitte versuche es später noch einmal!</string>
<string name="action_bar_title_server_selection">Server auswählen</string>
<string name="permission_rationale">Kontaktberechtigung für die E-Mail-Vervollständigung erteilen.</string>
<string name="pref_description_language">Eine Videosprache auswählen, statt alle Videos in allen Sprachen anzuzeigen.</string>
@ -295,8 +295,24 @@
<string name="login_current_server_hint">Aktueller Server</string>
<string name="title_activity_url_video_play">UrlVideoPlayActivity</string>
<string name="pref_description_license">
\n<b>GNU Affero General Public License v3.0</b>
\n
\nPermissions of this strongest copyleft license are conditioned on making available complete source code of licensed works and modifications, which include larger works using a licensed work, under the same license. Copyright and license notices must be preserved. Contributors provide an express grant of patent rights. When a modified version is used to provide a service over a network, the complete source code of the modified version must be made available.</string>
\n<b>GNU Affero General Public License v3.0</b>
\n
\nBerechtigungen dieser stärksten Copyleft-Lizenz bedingen, sämtlichen Quellcode von lizenzierten Werken und Modifikationen, einschließlich größere Werke, die ein lizenziertes Werk verwenden, unter derselben Lizenz bereitzustellen. Urheberrechts- und Lizenzhinweise müssen erhalten bleiben. Mitarbeitende gewähren eine ausdrückliche Genehmigung der Verwertungsrechte. Wenn eine modifizierte Version verwendet wird, um einen Dienst über ein Netzwerk anzubieten, muss der vollständige Quellcode der modifizierten Version verfügbar gemacht werden.</string>
<string name="pref_description_torrent_player">Videowiedergabe über einen Torrentstream. Dies erfordert Speicherberechtigungen. (Alphastadium, nicht stabil!)</string>
<string name="video_speed_125">1,25×</string>
<string name="video_speed_075">0,75×</string>
<string name="server_book_add_add_button">Hinzufügen</string>
<string name="server_book_add_password">Passwort</string>
<string name="server_book_add_username">Benutzername</string>
<string name="server_book_add_pick_server_button">Suchen</string>
<string name="server_book_add_server_url">Server-URL</string>
<string name="me_help_and_feedback_button">Hilfe &amp; Rückmeldung</string>
<string name="me_logout_button">Abmelden</string>
<string name="server_book_valid_url_is_required">Gültige URL ist erforderlich</string>
<string name="authentication_login_failed">Anmeldung fehlgeschlagen!</string>
<string name="authentication_login_success">Anmeldung erfolgreich</string>
<string name="clear_search_history_prompt">Möchten Sie den Suchverlauf dauerhaft löschen\?</string>
<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>
</resources>

View File

@ -35,4 +35,9 @@
<string name="pref_title_dark_mode">Σκοτεινή λειτουργία</string>
<string name="pref_description_dark_mode">Επανεκκινήστε την εφαρμογή για να τεθεί σε ισχύ η σκοτεινή λειτουργία.</string>
<string name="pref_title_app_theme">Θέμα εφαρμογής</string>
<string name="video_speed_125">1,25×</string>
<string name="video_speed_075">0,75×</string>
<string name="video_speed_20">2×</string>
<string name="video_speed_15">1,5×</string>
<string name="video_speed_05">0,5×</string>
</resources>

View File

@ -72,10 +72,10 @@
<string name="brown">Marrón</string>
<string name="gray">Gris</string>
<string name="bluegray">Gris azulado</string>
<string name="video_speed_05">0.5x</string>
<string name="video_speed_05">0,5×</string>
<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_speed_15">1,5×</string>
<string name="video_speed_20">2×</string>
<string name="action_set_url">Seleccione servidor</string>
<string name="server_selection_signup_allowed">Registro permitido: %s</string>
<string name="server_selection_signup_allowed_yes"></string>
@ -111,4 +111,6 @@
\n<b>GNU Affero General Public License v3.0</b>
\n
\nLos permisos de esta fuerte licencia copyleft están condicionados a hacer disponible el código fuente completo de los trabajos licenciados y las modificaciones, que incluyen trabajos más grandes usando un trabajo licenciado, bajo la misma licencia. Los derechos de autor y los avisos de licencia deben ser preservados. Los colaboradores proporcionan una concesión expresa de los derechos de patente. Cuando se utiliza una versión modificada para proporcionar un servicio a través de una red, el código fuente completo de la versión modificada debe estar disponible.</string>
<string name="video_speed_125">1,25×</string>
<string name="video_speed_075">0,75×</string>
</resources>

View File

@ -298,6 +298,6 @@
<string name="na">nauru</string>
<string name="ky">kirgiisi</string>
<string name="tk">turkmeeni</string>
<string name="video_speed_125">1.25x</string>
<string name="video_speed_075">0.75x</string>
<string name="video_speed_125">1,25×</string>
<string name="video_speed_075">0,75×</string>
</resources>

View File

@ -6,15 +6,15 @@
<string name="title_activity_login">Se connecter</string>
<!-- Strings related to login -->
<string name="prompt_server">Serveur</string>
<string name="prompt_email">Courriel / Nom dutilisateur</string>
<string name="prompt_email">Courriel / nom dutilisateur</string>
<string name="prompt_password">Mot de passe</string>
<string name="action_sign_in">Se connecter</string>
<string name="action_sign_in_short">Se connecter</string>
<string name="error_invalid_email">Cette adresse de courriel n\'est pas valide</string>
<string name="error_invalid_password">Ce mot de passe est trop court</string>
<string name="error_incorrect_password">Ce mot de passe est incorrect</string>
<string name="error_field_required">Ce champs est requis</string>
<string name="permission_rationale">Permission contacts requise pour la complétion des adresses de courriel.</string>
<string name="error_field_required">Ce champ est requis</string>
<string name="permission_rationale">Accorder la permission de contact pour la complétion des adresses de courriel.</string>
<!-- Action bar -->
<string name="action_bar_title_search">Rechercher</string>
<string name="action_bar_title_settings">Paramètres</string>
@ -39,7 +39,10 @@
<string name="pref_title_torrent_player">Lecteur vidéo torrent</string>
<string name="pref_description_torrent_player">Lecture de vidéo via un flux torrent. Ceci requiert les permissions de stockage. (Alpha, instable !)</string>
<string name="pref_title_license">Licence</string>
<string name="pref_description_license"> Strings related to login </string>
<string name="pref_description_license">
\n<b>GNU Affero General Public License v3.0</b>
\n
\nLes autorisations de cette licence de copyleft la plus forte sont conditionnées à la mise à disposition d\'un code source complet des œuvres sous licence et des modifications, qui comprennent des œuvres plus grandes utilisant une œuvre sous licence, sous la même licence. Les avis de droit d\'auteur et de licence doivent être conservés. Les contributeurs accordent expressément des droits de brevet. Lorsqu\'une version modifiée est utilisée pour fournir un service sur un réseau, le code source complet de la version modifiée doit être mis à disposition.</string>
<string name="pref_title_version">Version</string>
<string name="search_hint">Rechercher sur PeerTube</string>
<string name="title_activity_search">Rechercher</string>
@ -114,7 +117,7 @@
<string name="account_about_joined">Inscrit·e le :</string>
<string name="api_error">Quelque chose sest mal passé, veuillez essayer plus tard !</string>
<string name="action_bar_title_server_selection">Sélectionnez un serveur</string>
<string name="ab">Abkhaze</string>
<string name="ab">abkhaze</string>
<string name="aa">afar</string>
<string name="af">afrikaans</string>
<string name="ak">akan</string>
@ -307,6 +310,27 @@
<string name="za">zhuang</string>
<string name="zu">zoulou</string>
<string name="login_current_server_hint">Serveur actuel</string>
<string name="video_speed_075">0.75x</string>
<string name="video_speed_125">1.25x</string>
<string name="video_speed_075">0,75×</string>
<string name="video_speed_125">1,25×</string>
<string name="title_activity_server_address_book">Livre d\'adresse</string>
<string name="authentication_login_success">Identification réussie</string>
<string name="authentication_login_failed">Identification échouée !</string>
<string name="server_book_list_has_login">a un identifiant</string>
<string name="server_book_add_add_button">Ajouter</string>
<string name="server_book_add_password">Mot de passe</string>
<string name="server_book_add_username">Nom d\'utilisateur</string>
<string name="server_book_add_pick_server_button">Rechercher</string>
<string name="server_book_add_server_url">Url du serveur</string>
<string name="server_book_add_label">Étiquette</string>
<string name="me_help_and_feedback_button">Aide et commentaire</string>
<string name="me_logout_button">Déconnexion</string>
<string name="server_book_valid_url_is_required">Une URL valide est requise</string>
<string name="server_book_label_is_required">L\'étiquette du serveur est obligatoire</string>
<string name="server_book_no_servers_found">Le livre des serveurs est vide</string>
<string name="clear_search_history_prompt">Souhaitez-vous supprimer définitivement l\'historique de recherche \?</string>
<string name="clear_search_history">Effacer l\'historique de la recherche</string>
<string name="pref_description_language_app">Sélectionnez la langue de l\'interface de l\'application. Redémarrez l\'application pour que le changement prenne effet.</string>
<string name="pref_language_app">Langue de l\'application</string>
<string name="pref_description_back_pause">Mettre la lecture d\'arrière-plan en pause en appuyant sur la touche de retour pendant la lecture de la vidéo.</string>
<string name="pref_title_back_pause">Pause sur le bouton retour</string>
</resources>

View File

@ -49,7 +49,7 @@
<string name="pref_title_dark_mode">Modo scuro</string>
<string name="pref_description_license">
\n<b>GNU Affero General Public License v3.0</b>
\n
\n
\nLe autorizzazioni di questa licenza copyleft più forte sono condizionate a rendere disponibile il codice sorgente completo delle opere concesse in licenza e delle modifiche, che includono opere più grandi utilizzando un lavoro concesso in licenza, sotto la stessa licenza. Le note di copyright e di licenza devono essere conservate. I contributori forniscono una concessione espressa dei diritti di brevetto. Quando si utilizza una versione modificata per fornire un servizio in rete, è necessario rendere disponibile il codice sorgente completo della versione modificata.</string>
<string name="ab">abcaso</string>
<string name="aa">afar</string>
@ -298,4 +298,22 @@
<string name="api_error">Qualcosa è andato storto, per favore prova più tardi!</string>
<string name="action_bar_title_server_selection">Seleziona un server</string>
<string name="login_current_server_hint">Server attuale</string>
<string name="video_speed_125">1,25×</string>
<string name="video_speed_075">0,75×</string>
<string name="server_book_list_has_login">ha dati di accesso</string>
<string name="server_book_add_add_button">Aggiungi</string>
<string name="server_book_add_password">Password</string>
<string name="server_book_add_username">Nome utente</string>
<string name="server_book_add_pick_server_button">Cerca</string>
<string name="server_book_add_server_url">URL del server</string>
<string name="me_help_and_feedback_button">Aiuto &amp; suggerimenti</string>
<string name="me_logout_button">Esci</string>
<string name="server_book_valid_url_is_required">Un URL valido è richiesto</string>
<string name="server_book_no_servers_found">Il libro del server è vuoto</string>
<string name="authentication_login_failed">Accesso fallito!</string>
<string name="authentication_login_success">Accesso riuscito</string>
<string name="clear_search_history_prompt">Vuoi eliminare definitivamente la cronologia delle ricerche\?</string>
<string name="clear_search_history">Cancella la cronologia delle ricerche</string>
<string name="pref_description_language_app">Seleziona la lingua per l\'interfaccia dell\'applicazione. Riavvia l\'app per rendere effettive le modifiche.</string>
<string name="pref_language_app">Lingua dell\'applicazione</string>
</resources>

View File

@ -93,9 +93,9 @@
<string name="cyan">Turkis</string>
<string name="lime">Lime</string>
<string name="amber">Rav</string>
<string name="video_speed_05">0.5x</string>
<string name="video_speed_15">1.5x</string>
<string name="video_speed_20">2x</string>
<string name="video_speed_05">0,5×</string>
<string name="video_speed_15">1,5×</string>
<string name="video_speed_20">2×</string>
<string name="pref_description_background_play">Hvis påskrudd vil videoer spilles videre i bakgrunnen.</string>
<string name="video_login_required_for_service">Du må logge inn for å bruke denne tjenesten</string>
<string name="ko">Koreansk</string>
@ -123,4 +123,6 @@
<string name="uk">Ukrainsk</string>
<string name="ur">Urdu</string>
<string name="vi">Vietnamesisk</string>
<string name="video_speed_125">1,25×</string>
<string name="video_speed_075">0,75×</string>
</resources>

View File

@ -12,8 +12,7 @@
<string name="error_invalid_password">Dit wachtwoord is te kort</string>
<string name="error_incorrect_password">Dit wachtwoord is onjuist</string>
<string name="error_field_required">Dit veld is vereist</string>
<string name="permission_rationale">"Toegang tot contactpersonen is benodigd om e-mailadressen
\n aan te vullen."</string>
<string name="permission_rationale">Toegang tot contactpersonen is benodigd om e-mailadressen aan te vullen.</string>
<string name="action_bar_title_search">Zoeken</string>
<string name="action_bar_title_settings">Instellingen</string>
<string name="action_bar_title_logout">Uitloggen</string>
@ -258,10 +257,10 @@
<string name="brown">Bruin</string>
<string name="gray">Grijs</string>
<string name="bluegray">Blauwgrijs</string>
<string name="video_speed_05">0.5x</string>
<string name="video_speed_05">0,5×</string>
<string name="video_speed_10">Normaal</string>
<string name="video_speed_15">1.5x</string>
<string name="video_speed_20">2x</string>
<string name="video_speed_15">1,5×</string>
<string name="video_speed_20">2×</string>
<string name="pref_title_background_play">Afspelen op achtergrond</string>
<string name="pref_description_background_play">Als dit wordt ingeschakeld, dan speelt de video na minimaliseren af op de achtergrond.</string>
<string name="title_activity_account">Account</string>
@ -300,6 +299,28 @@
<string name="server_selection_peertube_server_url">PeerTube-server-url</string>
<string name="action_bar_title_server_selection">Server kiezen</string>
<string name="login_current_server_hint">Huidige server</string>
<string name="video_speed_075">0.75x</string>
<string name="video_speed_125">1.25x</string>
<string name="video_speed_075">0,75×</string>
<string name="video_speed_125">1,25×</string>
<string name="title_activity_server_address_book">Adresboek</string>
<string name="server_book_list_has_login">Inloggen benodigd</string>
<string name="server_book_add_add_button">Toevoegen</string>
<string name="server_book_add_password">Wachtwoord</string>
<string name="server_book_add_username">Gebruikersnaam</string>
<string name="server_book_add_pick_server_button">Zoeken</string>
<string name="server_book_add_server_url">Server-url</string>
<string name="server_book_add_label">Label</string>
<string name="me_help_and_feedback_button">Hulp en feedback</string>
<string name="me_logout_button">Uitloggen</string>
<string name="server_book_valid_url_is_required">Geldige url vereist</string>
<string name="server_book_label_is_required">Serverlabel vereist</string>
<string name="server_book_no_servers_found">De serverboeken zijn leeg</string>
<string name="authentication_login_failed">Inloggen mislukt!</string>
<string name="authentication_login_success">Ingelogd</string>
<string name="hello_blank_fragment">Hallo blanco fragment</string>
<string name="clear_search_history_prompt">Weet je zeker dat je de zoekgeschiedenis permanent wilt wissen\?</string>
<string name="clear_search_history">Zoekgeschiedenis wissen</string>
<string name="pref_description_language_app">Kies de in de app te gebruiken taal. Herstart de app om de wijziging toe te passen.</string>
<string name="pref_language_app">App-taal</string>
<string name="pref_description_back_pause">Pauzeer het afspelen als er op de terugknop wordt gedrukt.</string>
<string name="pref_title_back_pause">Pauzeren na drukken op terugknop</string>
</resources>

View File

@ -70,10 +70,10 @@
<string name="server_selection_signup_allowed_yes">Tak</string>
<string name="server_selection_signup_allowed">Rejestracja dozwolona: %s</string>
<string name="action_set_url">Wybierz serwer</string>
<string name="video_speed_20">2x</string>
<string name="video_speed_15">1.5x</string>
<string name="video_speed_20">2×</string>
<string name="video_speed_15">1,5×</string>
<string name="video_speed_10">Normalny</string>
<string name="video_speed_05">0.5x</string>
<string name="video_speed_05">0,5×</string>
<string name="bluegray">Szaroniebieski</string>
<string name="gray">Szary</string>
<string name="brown">Brązowy</string>
@ -291,11 +291,13 @@
<string name="pref_description_show_nsfw">Pokaż zawartość NSFW</string>
<string name="pref_title_show_nsfw">Zawartość NSFW</string>
<string name="pref_description_license">
\n<b> Powszechna Licencja Publiczna GNU Affero v3.0 </b>
\n<b> Powszechna Licencja Publiczna GNU Affero v3.0</b>
\n
\nUprawnienia tej najsilniejszej licencji copyleft są uzależnione od udostępnienia pełnego kodu źródłowego licencjonowanych utworów i modyfikacji, które obejmują większe dzieła przy użyciu licencjonowanego dzieła, na tej samej licencji. Informacje o prawach autorskich i licencjach należy zachować. Autorzy zapewniają wyraźne przyznanie praw patentowych. Gdy zmodyfikowana wersja jest używana do świadczenia usługi przez sieć, należy udostępnić pełny kod źródłowy zmodyfikowanej wersji.</string>
<string name="pref_description_torrent_player">Odtwarzanie wideo przez strumień torrentów. Wymaga to uprawnień do przechowywania. (Alfa, niestabilny!)</string>
<string name="permission_rationale">Udziel pozwolenia na kontakt w celu uzupełnienia wiadomości e-mail.</string>
<string name="pref_title_version">Wersja</string>
<string name="pref_title_license">Licencja</string>
<string name="video_speed_125">1,25×</string>
<string name="video_speed_075">0,75×</string>
</resources>

View File

@ -239,10 +239,10 @@
<string name="brown">Коричневый</string>
<string name="gray">Серый</string>
<string name="bluegray">Серо-голубой</string>
<string name="video_speed_05">0.5x</string>
<string name="video_speed_05">0,5×</string>
<string name="video_speed_10">Нормальная</string>
<string name="video_speed_15">1.5x</string>
<string name="video_speed_20">2x</string>
<string name="video_speed_15">1,5×</string>
<string name="video_speed_20">2×</string>
<string name="pref_title_background_play">Фоновое воспроизведение</string>
<string name="pref_description_background_play">Если включено, продолжает воспроизводить видео в фоновом режиме.</string>
<string name="bottom_nav_title_local">Местоположение</string>
@ -301,4 +301,6 @@
<string name="action_bar_title_server_selection">Выберите сервер</string>
<string name="server_selection_set_server">Сервер: %s</string>
<string name="title_activity_url_video_play">UrlVideoPlayActivity</string>
<string name="video_speed_125">1,25×</string>
<string name="video_speed_075">0,75×</string>
</resources>

View File

@ -299,4 +299,6 @@
<string name="server_selection_peertube_server_url">PeerTube server URL</string>
<string name="action_bar_title_server_selection">Välj server</string>
<string name="login_current_server_hint">Aktuell server</string>
<string name="video_speed_125">1,25×</string>
<string name="video_speed_075">0,75×</string>
</resources>

View File

@ -6,12 +6,12 @@
<!-- Strings related to login -->
<string name="prompt_server">Sunucu</string>
<string name="prompt_email">E-posta / Kullanıcı adı</string>
<string name="prompt_password">Şifre</string>
<string name="prompt_password">Parola</string>
<string name="action_sign_in">Oturum aç</string>
<string name="action_sign_in_short">Oturum aç</string>
<string name="error_invalid_email">Bu e-posta adresi geçersiz</string>
<string name="error_invalid_password">Bu şifre çok kısa</string>
<string name="error_incorrect_password">Bu şifre yanlış</string>
<string name="error_invalid_password">Bu parola çok kısa</string>
<string name="error_incorrect_password">Bu parola yanlış</string>
<string name="error_field_required">Bu alan gereklidir</string>
<string name="permission_rationale">E-posta tanımlamaları için Rehber izni verin.</string>
<!-- Action bar -->
@ -29,7 +29,7 @@
<string name="pref_title_peertube_server">PeerTube Sunucusu</string>
<!-- Strings related to Video meta data -->
<string name="meta_data_seperator" translatable="false">\u0020-\u0020</string>
<string name="meta_data_views">\u0020 Görüntüleme</string>
<string name="meta_data_views">" Görüntüleme"</string>
<string name="meta_data_owner_seperator" translatable="false">\@</string>
<string name="video_row_video_thumbnail">İzleti Küçük Resmi</string>
<string name="video_row_account_avatar">Hesap Resmi</string>
@ -265,10 +265,10 @@
<string name="brown">Kahverengi</string>
<string name="gray">Gri</string>
<string name="bluegray">Mavi gri</string>
<string name="video_speed_05">0.5x</string>
<string name="video_speed_05">0,5×</string>
<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_speed_15">1,5×</string>
<string name="video_speed_20">2×</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>
@ -328,4 +328,27 @@
<string name="server_selection_peertube_server_url">PeerTube Sunucusu URL\'si</string>
<string name="action_bar_title_server_selection">Sunucu Seç</string>
<string name="login_current_server_hint">Mevcut Sunucu</string>
<string name="server_book_list_has_login">Oturum Açma Var</string>
<string name="server_book_no_servers_found">Sunucu defteri boş</string>
<string name="pref_description_back_pause">Video oynatımı sırasında geri düğmesine basıldığında arka planda oynatmayı duraklat.</string>
<string name="pref_title_back_pause">Geri düğmesine basıldığında duraklat</string>
<string name="video_speed_125">1,25×</string>
<string name="video_speed_075">0,75×</string>
<string name="title_activity_server_address_book">Adres Defteri</string>
<string name="server_book_add_add_button">Ekle</string>
<string name="server_book_add_password">Parola</string>
<string name="server_book_add_username">Kullanıcı adı</string>
<string name="server_book_add_pick_server_button">Arama</string>
<string name="server_book_add_server_url">Sunucu URL\'si</string>
<string name="server_book_add_label">Etiket</string>
<string name="me_help_and_feedback_button">Yardım &amp; Geri Bildirim</string>
<string name="me_logout_button">Oturumu kapat</string>
<string name="server_book_valid_url_is_required">Geçerli URL gerekli</string>
<string name="server_book_label_is_required">Sunucu etiketi gerekli</string>
<string name="authentication_login_failed">Oturum Açma Başarısız!</string>
<string name="authentication_login_success">Oturum Açma Başarılı</string>
<string name="clear_search_history_prompt">Arama geçmişini kalıcı olarak silmek istiyor musunuz\?</string>
<string name="clear_search_history">Arama Geçmişini Temizle</string>
<string name="pref_description_language_app">Uygulama arayüzü için dil seçin. Değişikliklerin etkili olması için uygulamayı yeniden başlatın.</string>
<string name="pref_language_app">Uygulama Dili</string>
</resources>

View File

@ -36,8 +36,8 @@
<string name="pref_description_torrent_player">透過種子串流播放影片。這需要儲存權限。Alpha 版,不穩定!)</string>
<string name="pref_title_license">授權條款</string>
<string name="pref_description_license">
\n<b>Affero通用公眾授權條款 v3.0</b>
\n
\n<b>GNU Affero通用公眾授權條款 v3.0</b>
\n
\n這份最強的著作傳式授權條款提供作品完整的原始碼與修改其中包含了使用同一個授權條款的作品。著作權與授權條款聲明都必須保留。貢獻者提供明確的專利權授予。當修改版被用於提供透過網路的服務時修改版的完整原始碼也必須釋出。</string>
<string name="pref_title_version">版本</string>
<string name="search_hint">搜尋 PeerTube</string>
@ -301,4 +301,26 @@
<string name="login_current_server_hint">目前的伺服器</string>
<string name="video_speed_125">1.25x</string>
<string name="video_speed_075">0.75x</string>
<string name="title_activity_server_address_book">地址簿</string>
<string name="server_book_list_has_login">已登入</string>
<string name="server_book_add_add_button">新增</string>
<string name="server_book_add_password">密碼</string>
<string name="server_book_add_username">使用者名稱</string>
<string name="server_book_add_pick_server_button">搜尋</string>
<string name="server_book_add_server_url">伺服器 Url</string>
<string name="server_book_add_label">標籤</string>
<string name="me_help_and_feedback_button">說明與回饋</string>
<string name="me_logout_button">登出</string>
<string name="server_book_valid_url_is_required">有效的 URL 必填</string>
<string name="server_book_label_is_required">伺服器標籤必填</string>
<string name="server_book_no_servers_found">伺服器參考書為空</string>
<string name="authentication_login_failed">登入失敗!</string>
<string name="authentication_login_success">登入成功</string>
<string name="hello_blank_fragment">您好空白片段</string>
<string name="clear_search_history_prompt">您想要永久刪除搜尋歷史紀錄嗎?</string>
<string name="clear_search_history">清除搜尋歷史</string>
<string name="pref_description_language_app">選取應用程式界面的語言。重新啟動應用程式以讓變更生效。</string>
<string name="pref_language_app">應用程式語言</string>
<string name="pref_description_back_pause">當影片播放時按下後退鈕後暫停背景播放。</string>
<string name="pref_title_back_pause">在後退鈕上暫停</string>
</resources>

View File

@ -1,6 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="backgroundBehavior">
<item>@string/pref_background_audio</item>
<item>@string/pref_background_stop</item>
<item>@string/pref_background_float</item>
</string-array>
<string-array name="backgroundBehaviorValues">
<item>backgroundAudio</item>
<item>backgroundStop</item>
<item>backgroundFloat</item>
</string-array>
<string-array name="themeArray">
<item>@string/red</item>
<item>@string/pink</item>
@ -64,6 +77,7 @@
<item>@string/eu</item>
<item>@string/be</item>
<item>@string/bn</item>
<item>@string/bn_rBD</item>
<item>@string/bi</item>
<item>@string/bs</item>
<item>@string/bzs</item>
@ -259,6 +273,7 @@
<item>eu</item>
<item>be</item>
<item>bn</item>
<item>bn_rBD</item>
<item>bi</item>
<item>bs</item>
<item>bzs</item>
@ -433,6 +448,60 @@
<item>za</item>
<item>zu</item>
</string-array>
<string-array name="supportedLanguagesValues">
<item>ar</item>
<item>bn</item>
<item>bn_rBD</item>
<item>cs</item>
<item>de</item>
<item>el</item>
<item>en</item>
<item>es</item>
<item>fa</item>
<item>fi</item>
<item>fr</item>
<item>gd</item>
<item>hi</item>
<item>it</item>
<item>ja</item>
<item>no</item>
<item>nl</item>
<item>pl</item>
<item>ru</item>
<item>sv</item>
<item>tr</item>
<item>zh-rCN</item>
<item>zh-rTW</item>
</string-array>
<string-array name = "supportedLanguagesArray">
<item>@string/ar</item>
<item>@string/bn</item>
<item>@string/bn_rBD</item>
<item>@string/cs</item>
<item>@string/de</item>
<item>@string/el</item>
<item>@string/en</item>
<item>@string/es</item>
<item>@string/fa</item>
<item>@string/fi</item>
<item>@string/fr</item>
<item>@string/gd</item>
<item>@string/hi</item>
<item>@string/it</item>
<item>@string/ja</item>
<item>@string/no</item>
<item>@string/nl</item>
<item>@string/pl</item>
<item>@string/ru</item>
<item>@string/sv</item>
<item>@string/tr</item>
<item>@string/zh</item>
<item>@string/tw</item>
</string-array>
<string-array name="empty_array"/>
<string-array name="quality">

View File

@ -60,6 +60,20 @@
<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>
<string name="pref_title_back_pause">Pause on back button</string>
<string name="pref_description_back_pause">Pause background play when pressing back during video playback.</string>
<string name="pref_language_app">Application Language</string>
<string name="pref_description_language_app">Select language for application interface. Restart app for change to take effect.</string>
<string name="pref_background_audio">Continue as a background audio stream</string>
<string name="pref_background_stop">Stop all playback</string>
<string name="pref_background_float">Continue playing video in floating window</string>
<string name="pref_background_behavior">Background playing Configuration</string>
<string name="settings_api_error_float">Android version does not support floating video</string>
<string name="settings_permissions_error_float">Picture in picture permission is disabled for this app in Android Settings</string>
<string name="pref_background_behavior_summary">How a playing video responds when going to background</string>
<string name="clear_search_history">Clear Search History</string>
<string name="clear_search_history_prompt">Do you want to permanently delete the search history?</string>
<!-- languages -->
<string name="ab">Abkhazian</string>
<string name="aa">Afar</string>
@ -80,6 +94,7 @@
<string name="eu">Basque</string>
<string name="be">Belarusian</string>
<string name="bn">Bengali</string>
<string name="bn_rBD">Bengali (Bangladesh)</string>
<string name="bi">Bislama</string>
<string name="bs">Bosnian</string>
<string name="bzs">Brazilian Sign Language</string>
@ -320,6 +335,34 @@
<string name="account_about_joined">Joined:</string>
<string name="api_error">Something went wrong, please try later!</string>
<string name="action_bar_title_server_selection">Select Server</string>
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="action_bar_title_address_book" />
<string name="authentication_login_success">Login Successful</string>
<string name="authentication_login_failed">Login Failed!</string>
<string name="server_book_no_servers_found">Server Books is empty</string>
<string name="server_book_label_is_required">Server label is required</string>
<string name="server_book_valid_url_is_required">Valid URL is required</string>
<string name="me_logout_button">Logout</string>
<string name="me_help_and_feedback_button"><![CDATA[Help & Feedback]]></string>
<string name="server_book_add_label">Label</string>
<string name="server_book_add_server_url">Server Url</string>
<string name="server_book_add_pick_server_button">Search</string>
<string name="server_book_add_username">Username</string>
<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>
<string name="video_speed_125">1.25x</string>
<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>
<!-- 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>
@ -327,12 +370,6 @@
<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="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="video_speed_075">0.75x</string>
<string name="video_speed_125">1.25x</string>
</resources>

View File

@ -150,25 +150,40 @@
<!-- Text styles -->
<style name="Text" parent="TextAppearance.AppCompat"></style>
<style name="Text.Caption" parent="TextAppearance.AppCompat.Caption"></style>
<style name="Text.Small" parent="TextAppearance.AppCompat.Small"></style>
<style name="Text.Body1" parent="TextAppearance.AppCompat.Body1"></style>
<style name="Text.Body2" parent="TextAppearance.AppCompat.Body2"></style>
<style name="Text.Medium" parent="TextAppearance.AppCompat.Medium"></style>
<style name="Text.Large" parent="TextAppearance.AppCompat.Large"></style>
<style name="Text.Headline" parent="TextAppearance.AppCompat.Headline"></style>
<style name="Text.Title" parent="TextAppearance.AppCompat.Title"></style>
<style name="Text.Display1" parent="TextAppearance.AppCompat.Display1"></style>
<style name="Text.Subhead" parent="TextAppearance.AppCompat.Subhead"></style>
<style name="Text.Button" parent="TextAppearance.AppCompat.Button"></style>
<style name="Text" parent="TextAppearance.AppCompat" />
<style name="Text.Caption" parent="TextAppearance.AppCompat.Caption" />
<style name="Text.Small" parent="TextAppearance.AppCompat.Small" />
<style name="Text.Body1" parent="TextAppearance.AppCompat.Body1" />
<style name="Text.Body2" parent="TextAppearance.AppCompat.Body2" />
<style name="Text.Medium" parent="TextAppearance.AppCompat.Medium" />
<style name="Text.Large" parent="TextAppearance.AppCompat.Large" />
<style name="Text.Headline" parent="TextAppearance.AppCompat.Headline" />
<style name="Text.Title" parent="TextAppearance.AppCompat.Title" />
<style name="Text.Display1" parent="TextAppearance.AppCompat.Display1" />
<style name="Text.Subhead" parent="TextAppearance.AppCompat.Subhead" />
<style name="Text.Button" parent="TextAppearance.AppCompat.Button" />
<!-- Button Styles-->
<style name="Buton" parent="Widget.AppCompat.Button"></style>
<style name="Buton.Small" parent="Widget.AppCompat.Button.Small"></style>
<style name="Buton.Colored" parent="Widget.AppCompat.Button.Colored"></style>
<style name="Buton.Borderless" parent="Widget.AppCompat.Button.Borderless"></style>
<style name="Buton.Borderless.Colored" parent="Widget.AppCompat.Button.Borderless.Colored"></style>
<style name="Buton" parent="Widget.AppCompat.Button" />
<style name="Buton.Small" parent="Widget.AppCompat.Button.Small" />
<style name="Buton.Colored" parent="Widget.AppCompat.Button.Colored" />
<style name="Buton.Borderless" parent="Widget.AppCompat.Button.Borderless" />
<style name="Buton.Borderless.Colored" parent="Widget.AppCompat.Button.Borderless.Colored" />
</resources>

View File

@ -1,8 +1,5 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference
android:key="pref_api_base"
android:title="@string/pref_title_peertube_server" />
<!--<SwitchPreference-->
<!--android:key="pref_background_play"-->
@ -24,6 +21,31 @@
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"

View File

@ -1,4 +1,4 @@
#Mon Jun 01 12:58:36 CEST 2020
#Fri Jun 12 19:07:10 CEST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME