Server login (#175)

This commit is contained in:
Stefan Schüller 2020-06-21 17:01:15 +02:00 committed by GitHub
parent eed9702477
commit 5c7fab1a75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 1546 additions and 426 deletions

View File

@ -23,6 +23,11 @@
* Gradle update * Gradle update
* Translations * 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) ### Version 1.0.30 Tag: v1.0.30 (2019-08-07)
* Gradle update * Gradle update
* Translations * Translations

View File

@ -1,11 +1,11 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 28 compileSdkVersion 29
defaultConfig { defaultConfig {
applicationId "net.schueller.peertube" applicationId "net.schueller.peertube"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 28 targetSdkVersion 29
versionCode 1037 versionCode 1037
versionName "1.0.37" versionName "1.0.37"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -14,6 +14,14 @@ android {
exoplayer: '2.9.3' exoplayer: '2.9.3'
] ]
} }
javaCompileOptions {
annotationProcessorOptions {
arguments = [
"room.schemaLocation" : "$projectDir/schemas".toString(),
"room.incremental" : "true",
"room.expandProjection": "true"]
}
}
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
@ -70,7 +78,6 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
buildToolsVersion '28.0.3'
applicationVariants.all { variant -> applicationVariants.all { variant ->
variant.resValue "string", "versionName", variant.versionName variant.resValue "string", "versionName", variant.versionName
@ -78,6 +85,23 @@ android {
} }
dependencies { 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.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" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="net.schueller.peertube"> package="net.schueller.peertube">
<!-- connect to peertube server --> <!-- required for torrent downloading -->
<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" />
<application <application
android:name=".application.AppApplication" android:name=".application.AppApplication"
android:allowBackup="true" android:allowBackup="true"
@ -15,6 +11,10 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning"> tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".activity.ServerAddressBookActivity"
android:label="@string/title_activity_server_address_book"
android:theme="@style/AppTheme.NoActionBar" />
<activity <activity
android:name=".activity.VideoListActivity" android:name=".activity.VideoListActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
@ -28,12 +28,8 @@
<meta-data <meta-data
android:name="android.app.searchable" android:name="android.app.searchable"
android:resource="@xml/searchable"></meta-data> android:resource="@xml/searchable" />
</activity> </activity>
<activity
android:name=".activity.LoginActivity"
android:label="@string/title_activity_login"
android:theme="@style/AppTheme.NoActionBar" />
<activity <activity
android:name=".activity.VideoPlayActivity" android:name=".activity.VideoPlayActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
@ -61,6 +57,10 @@
android:exported="false" /> android:exported="false" />
<service android:name=".service.VideoPlayerService" /> <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> </manifest>

View File

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

View File

@ -18,6 +18,7 @@
package net.schueller.peertube.activity; package net.schueller.peertube.activity;
import android.content.SharedPreferences;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
@ -25,10 +26,14 @@ import androidx.annotation.LayoutRes;
import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatDelegate; import androidx.appcompat.app.AppCompatDelegate;
import android.preference.PreferenceManager;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; 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 * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
* to be used with AppCompat. * to be used with AppCompat.
@ -42,6 +47,20 @@ public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
getDelegate().installViewFactory(); getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState); getDelegate().onCreate(savedInstanceState);
super.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 @Override

View File

@ -19,18 +19,20 @@
package net.schueller.peertube.activity; package net.schueller.peertube.activity;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.nfc.Tag;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; 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 android.widget.TextView;
import com.mikepenz.fontawesome_typeface_library.FontAwesome;
import com.mikepenz.iconics.IconicsDrawable;
import net.schueller.peertube.R; import net.schueller.peertube.R;
import net.schueller.peertube.helper.APIUrlHelper; import net.schueller.peertube.helper.APIUrlHelper;
import net.schueller.peertube.model.Avatar;
import net.schueller.peertube.model.Me; import net.schueller.peertube.model.Me;
import net.schueller.peertube.network.GetUserService; import net.schueller.peertube.network.GetUserService;
import net.schueller.peertube.network.RetrofitInstance; import net.schueller.peertube.network.RetrofitInstance;
@ -38,10 +40,17 @@ import net.schueller.peertube.network.Session;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import com.squareup.picasso.Picasso;
import java.util.Objects;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
import static net.schueller.peertube.application.AppApplication.getContext;
public class MeActivity extends CommonActivity { public class MeActivity extends CommonActivity {
@ -52,34 +61,10 @@ public class MeActivity extends CommonActivity {
MenuInflater inflater = getMenuInflater(); MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_top_account, menu); 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; 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 @Override
public boolean onSupportNavigateUp() { public boolean onSupportNavigateUp() {
finish(); // close this activity as oppose to navigating up 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); Toolbar toolbar = findViewById(R.id.tool_bar_me);
// Setting toolbar as the ActionBar with setSupportActionBar() call // Setting toolbar as the ActionBar with setSupportActionBar() call
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeAsUpIndicator( getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_baseline_close_24);
new IconicsDrawable(this, FontAwesome.Icon.faw_chevron_left).actionBar()
); 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(); getUserData();
} }
private boolean getUserData() { private void getUserData() {
// TODO
String apiBaseURL = APIUrlHelper.getUrlWithVersion(this); String apiBaseURL = APIUrlHelper.getUrlWithVersion(this);
String baseURL = APIUrlHelper.getUrl(this);
GetUserService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetUserService.class); GetUserService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetUserService.class);
Call<Me> call = service.getMe(); Call<Me> call = service.getMe();
call.enqueue(new Callback<Me>() { call.enqueue(new Callback<Me>() {
LinearLayout account = findViewById(R.id.a_me_account_line);
@Override @Override
public void onResponse(@NonNull Call<Me> call, @NonNull Response<Me> response) { public void onResponse(@NonNull Call<Me> call, @NonNull Response<Me> response) {
if (response.isSuccessful()) { if (response.isSuccessful()) {
Me me = response.body(); Me me = response.body();
TextView username = findViewById(R.id.account_username); Log.d(TAG, response.body().toString());
TextView email = findViewById(R.id.account_email);
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()); username.setText(me.getUsername());
email.setText(me.getEmail()); 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 @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 @Override
protected void onResume() { protected void onResume() {
super.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; package net.schueller.peertube.activity;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -9,6 +26,7 @@ import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
@ -54,28 +72,6 @@ public class SelectServerActivity extends AppCompatActivity {
loadList(); 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,168 @@
/*
* 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.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Observer;
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;
import java.util.List;
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) {
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);
}
});
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 @Override
protected void onCreate(Bundle savedInstanceState) { 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); super.onCreate(savedInstanceState);
@ -202,7 +195,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
// to their values. When their values change, their summaries are // to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design // updated to reflect the new value, per the Android Design
// guidelines. // guidelines.
bindPreferenceSummaryToValue(findPreference("pref_api_base")); //bindPreferenceSummaryToValue(findPreference("pref_api_base"));
bindPreferenceSummaryToValue(findPreference("pref_theme")); bindPreferenceSummaryToValue(findPreference("pref_theme"));
} }
@ -219,12 +212,12 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
@Override @Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) { Preference preference) {
String key = preference.getKey(); // String key = preference.getKey();
if ("pref_api_base".equals(key)) { // if ("pref_api_base".equals(key)) {
Intent intentServer = new Intent(preference.getContext(), SelectServerActivity.class); // Intent intentServer = new Intent(preference.getContext(), SelectServerActivity.class);
startActivity(intentServer); // startActivity(intentServer);
return true; // return true;
} // }
return false; return false;
} }
@ -232,7 +225,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
public void onResume() { public void onResume() {
setPreferenceScreen(null); setPreferenceScreen(null);
addPreferencesFromResource(R.xml.pref_general); addPreferencesFromResource(R.xml.pref_general);
bindPreferenceSummaryToValue(findPreference("pref_api_base")); //bindPreferenceSummaryToValue(findPreference("pref_api_base"));
super.onResume(); super.onResume();
} }

View File

@ -50,6 +50,7 @@ import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -81,6 +82,7 @@ public class VideoListActivity extends CommonActivity {
public static final String EXTRA_VIDEOID = "VIDEOID"; public static final String EXTRA_VIDEOID = "VIDEOID";
public static final String EXTRA_ACCOUNTDISPLAYNAME = "ACCOUNTDISPLAYNAMEANDHOST"; public static final String EXTRA_ACCOUNTDISPLAYNAME = "ACCOUNTDISPLAYNAMEANDHOST";
public static final Integer SWITCH_INSTANCE = 2;
private VideoAdapter videoAdapter; private VideoAdapter videoAdapter;
private SwipeRefreshLayout swipeRefreshLayout; private SwipeRefreshLayout swipeRefreshLayout;
@ -125,14 +127,11 @@ public class VideoListActivity extends CommonActivity {
inflater.inflate(R.menu.menu_top_videolist, menu); inflater.inflate(R.menu.menu_top_videolist, menu);
// Set an icon in the ActionBar // 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( menu.findItem(R.id.action_account).setIcon(
new IconicsDrawable(this, FontAwesome.Icon.faw_user_circle).actionBar()); new IconicsDrawable(this, FontAwesome.Icon.faw_user_circle).actionBar());
// menu.findItem(R.id.action_server_selection).setIcon( menu.findItem(R.id.action_server_address_book).setIcon(
// new IconicsDrawable(this, FontAwesome.Icon.faw_server).actionBar()); new IconicsDrawable(this, FontAwesome.Icon.faw_server).actionBar());
MenuItem searchMenuItem = menu.findItem(R.id.action_search); MenuItem searchMenuItem = menu.findItem(R.id.action_search);
@ -219,6 +218,16 @@ public class VideoListActivity extends CommonActivity {
stopService(new Intent(this, VideoPlayerService.class)); 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 @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will // Handle action bar item clicks here. The action bar will
@ -231,25 +240,28 @@ public class VideoListActivity extends CommonActivity {
//Toast.makeText(this, "Search Selected", Toast.LENGTH_SHORT).show(); //Toast.makeText(this, "Search Selected", Toast.LENGTH_SHORT).show();
return false; 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: case R.id.action_account:
if (!Session.getInstance().isLoggedIn()) { // if (!Session.getInstance().isLoggedIn()) {
Intent intentLogin = new Intent(this, LoginActivity.class);
this.startActivity(intentLogin); //Intent intentLogin = new Intent(this, ServerAddressBookActivity.class);
} else {
Intent intentMe = new Intent(this, MeActivity.class); Intent intentMe = new Intent(this, MeActivity.class);
this.startActivity(intentMe); 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; return false;
// case R.id.action_server_selection:
// Intent intentServer = new Intent(this, SelectServerActivity.class);
// this.startActivity(intentServer);
// return false;
default: default:
break; break;
} }
@ -378,6 +390,7 @@ public class VideoListActivity extends CommonActivity {
@Override @Override
protected void onNewIntent(Intent intent) { protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent); setIntent(intent);
handleIntent(intent); handleIntent(intent);
} }
@ -483,8 +496,10 @@ public class VideoListActivity extends CommonActivity {
//Log.v(TAG, "navigation_subscriptions"); //Log.v(TAG, "navigation_subscriptions");
if (!Session.getInstance().isLoggedIn()) { if (!Session.getInstance().isLoggedIn()) {
Intent intent = new Intent(this, LoginActivity.class); // Intent intent = new Intent(this, LoginActivity.class);
this.startActivity(intent); // this.startActivity(intent);
Intent addressBookActivityIntent = new Intent(this, ServerAddressBookActivity.class);
this.startActivityForResult(addressBookActivityIntent, SWITCH_INSTANCE);
return false; return false;
} else { } else {

View File

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

@ -15,23 +15,15 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package net.schueller.peertube.service;
package net.schueller.peertube.activity;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.os.Bundle;
import android.text.InputType;
import android.util.Log; import android.util.Log;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast; import android.widget.Toast;
import com.mikepenz.fontawesome_typeface_library.FontAwesome; import androidx.annotation.NonNull;
import com.mikepenz.iconics.IconicsDrawable;
import net.schueller.peertube.R; import net.schueller.peertube.R;
import net.schueller.peertube.helper.APIUrlHelper; 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.AuthenticationService;
import net.schueller.peertube.network.RetrofitInstance; import net.schueller.peertube.network.RetrofitInstance;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; 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 static final String TAG = "LoginService";
private AutoCompleteTextView mEmailView;
private EditText mPasswordView;
@Override public static void Authenticate(String username, String password)
protected void onCreate(Bundle savedInstanceState) { {
super.onCreate(savedInstanceState); Context context = getContext();
setContentView(R.layout.activity_login); String apiBaseURL = APIUrlHelper.getUrlWithVersion(context);
// bind button click SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
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);
AuthenticationService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(AuthenticationService.class); AuthenticationService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(AuthenticationService.class);
@ -141,7 +68,7 @@ public class LoginActivity extends CommonActivity {
"code", "code",
"password", "password",
"upload", "upload",
email, username,
password password
); );
call2.enqueue(new Callback<Token>() { call2.enqueue(new Callback<Token>() {
@ -157,23 +84,19 @@ public class LoginActivity extends CommonActivity {
// TODO: calc expiration // TODO: calc expiration
//editor.putInt(getString(R.string.pref_token_expiration), token.getRefreshToken()); //editor.putInt(getString(R.string.pref_token_expiration), token.getRefreshToken());
editor.putString(getString(R.string.pref_token_access), token.getAccessToken()); editor.putString(context.getString(R.string.pref_token_access), token.getAccessToken());
editor.putString(getString(R.string.pref_token_refresh), token.getExpiresIn()); editor.putString(context.getString(R.string.pref_token_refresh), token.getExpiresIn());
editor.putString(getString(R.string.pref_token_type), token.getTokenType()); editor.putString(context.getString(R.string.pref_token_type), token.getTokenType());
editor.commit(); editor.apply();
Log.wtf(TAG, "Logged in"); Log.wtf(TAG, "Logged in");
Intent intent = new Intent(context, MeActivity.class); Toast.makeText(context, context.getString(R.string.authentication_login_success), Toast.LENGTH_LONG).show();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
finish(); // close this activity
} else { } else {
Log.wtf(TAG, response2.toString()); Log.wtf(TAG, response2.toString());
Toast.makeText(context, context.getString(R.string.authentication_login_failed), Toast.LENGTH_LONG).show();
Toast.makeText(LoginActivity.this, "Login Error!", Toast.LENGTH_LONG).show();
} }
} }
@ -181,21 +104,24 @@ public class LoginActivity extends CommonActivity {
@Override @Override
public void onFailure(@NonNull Call<Token> call2, @NonNull Throwable t2) { public void onFailure(@NonNull Call<Token> call2, @NonNull Throwable t2) {
Log.wtf("err", t2.fillInStackTrace()); Log.wtf("err", t2.fillInStackTrace());
Toast.makeText(context, context.getString(R.string.authentication_login_failed), Toast.LENGTH_LONG).show();
} }
}); });
} else { } else {
Log.wtf(TAG, response.toString()); Log.wtf(TAG, response.toString());
Toast.makeText(context, context.getString(R.string.authentication_login_failed), Toast.LENGTH_LONG).show();
} }
} }
@Override @Override
public void onFailure(@NonNull Call<OauthClient> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<OauthClient> call, @NonNull Throwable t) {
Log.wtf("err", t.fillInStackTrace()); Log.wtf("err", t.fillInStackTrace());
Toast.makeText(context, context.getString(R.string.authentication_login_failed), Toast.LENGTH_LONG).show();
} }
}); });
} }
} }

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" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".activity.MeActivity" tools:context=".activity.MeActivity"
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
@ -13,7 +14,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> 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:id="@+id/tool_bar_me"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -23,26 +24,154 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout <LinearLayout
android:layout_marginBottom="0dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> 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 <LinearLayout
android:id="@+id/account_email" android:visibility="gone"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" 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>
</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> </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" 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 <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="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:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:context="activity.VideoListActivity"> tools:context="activity.VideoListActivity">
<item
android:id="@+id/action_logout"
android:orderInCategory="300"
android:title="@string/action_bar_title_logout"
app:showAsAction="ifRoom" />
</menu> </menu>

View File

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

View File

@ -327,6 +327,32 @@
<string name="account_about_joined">Joined:</string> <string name="account_about_joined">Joined:</string>
<string name="api_error">Something went wrong, please try later!</string> <string name="api_error">Something went wrong, please try later!</string>
<string name="action_bar_title_server_selection">Select Server</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 Successfull</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>
<!-- Constants, Don't translate --> <!-- Constants, Don't translate -->
<string name="pref_token_access" translatable="false">pref_token_access</string> <string name="pref_token_access" translatable="false">pref_token_access</string>
<string name="pref_token_refresh" translatable="false">pref_token_refresh</string> <string name="pref_token_refresh" translatable="false">pref_token_refresh</string>
@ -334,12 +360,8 @@
<string name="pref_token_type" translatable="false">pref_token_type</string> <string name="pref_token_type" translatable="false">pref_token_type</string>
<string name="pref_auth_username" translatable="false">pref_auth_username</string> <string name="pref_auth_username" translatable="false">pref_auth_username</string>
<string name="pref_auth_password" translatable="false">pref_auth_password</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> <!-- TODO: Remove or change this placeholder text -->
<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> </resources>

View File

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

View File

@ -1,8 +1,5 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference
android:key="pref_api_base"
android:title="@string/pref_title_peertube_server" />
<!--<SwitchPreference--> <!--<SwitchPreference-->
<!--android:key="pref_background_play"--> <!--android:key="pref_background_play"-->

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 distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME