This commit is contained in:
Stefan Schueller 2018-12-29 22:10:13 +01:00
parent 45f0531394
commit 47cf90727a
16 changed files with 411 additions and 95 deletions

View File

@ -18,7 +18,8 @@
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning"> tools:ignore="GoogleAppIndexingWarning"
android:name=".application.AppApplication">
<activity android:name=".activity.VideoListActivity" <activity android:name=".activity.VideoListActivity"
android:theme="@style/AppTheme.NoActionBar" android:theme="@style/AppTheme.NoActionBar"
@ -50,7 +51,9 @@
<activity android:name=".activity.SelectServerActivity" <activity android:name=".activity.SelectServerActivity"
android:theme="@style/AppTheme.NoActionBar"/> android:theme="@style/AppTheme.NoActionBar"/>
<activity android:name=".activity.UserActivity"
<activity android:name=".activity.AccountActivity"
android:label="@string/title_activity_account"
android:theme="@style/AppTheme.NoActionBar"/> android:theme="@style/AppTheme.NoActionBar"/>

View File

@ -0,0 +1,123 @@
/*
* 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.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import com.mikepenz.fontawesome_typeface_library.FontAwesome;
import com.mikepenz.iconics.IconicsDrawable;
import net.schueller.peertube.R;
import net.schueller.peertube.network.Session;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import static net.schueller.peertube.helper.Constants.DEFAULT_THEME;
import static net.schueller.peertube.helper.Constants.THEME_PREF_KEY;
public class AccountActivity extends AppCompatActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_top_user, 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);
return true;
default:
break;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set theme
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
setTheme(getResources().getIdentifier(
sharedPref.getString(THEME_PREF_KEY, DEFAULT_THEME),
"style",
getPackageName())
);
setContentView(R.layout.activity_account);
// Attaching the layout to the toolbar object
Toolbar toolbar = findViewById(R.id.tool_bar_user);
// Setting toolbar as the ActionBar with setSupportActionBar() call
setSupportActionBar(toolbar);
init();
}
private void init() {
// try to get user data
getUserData();
}
private boolean getUserData() {
// TODO
return false;
}
@Override
protected void onResume() {
super.onResume();
init();
}
}

View File

@ -18,10 +18,10 @@
package net.schueller.peertube.activity; package net.schueller.peertube.activity;
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.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.widget.AutoCompleteTextView; import android.widget.AutoCompleteTextView;
@ -35,6 +35,8 @@ 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.app.AppCompatActivity;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
@ -78,6 +80,8 @@ public class LoginActivity extends AppCompatActivity {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
Context context = this;
// Reset errors. // Reset errors.
mEmailView.setError(null); mEmailView.setError(null);
mPasswordView.setError(null); mPasswordView.setError(null);
@ -129,6 +133,12 @@ public class LoginActivity extends AppCompatActivity {
editor.putString(getString(R.string.pref_token_type), token.getTokenType()); editor.putString(getString(R.string.pref_token_type), token.getTokenType());
editor.commit(); editor.commit();
Log.wtf(TAG, "Logged in");
Intent intent = new Intent(context, AccountActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
} else { } else {
Log.wtf(TAG, response2.toString()); Log.wtf(TAG, response2.toString());
} }

View File

@ -1,41 +0,0 @@
package net.schueller.peertube.activity;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import net.schueller.peertube.R;
public class UserActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user);
init();
}
private void init() {
// try to get user data
if (!getUserData()) {
Intent intent = new Intent(this, LoginActivity.class);
this.startActivity(intent);
}
}
private boolean getUserData() {
// TODO
return false;
}
@Override
protected void onResume() {
super.onResume();
init();
}
}

View File

@ -53,8 +53,10 @@ import net.schueller.peertube.R;
import net.schueller.peertube.adapter.VideoAdapter; import net.schueller.peertube.adapter.VideoAdapter;
import net.schueller.peertube.helper.APIUrlHelper; import net.schueller.peertube.helper.APIUrlHelper;
import net.schueller.peertube.model.VideoList; import net.schueller.peertube.model.VideoList;
import net.schueller.peertube.network.GetUserService;
import net.schueller.peertube.network.GetVideoDataService; import net.schueller.peertube.network.GetVideoDataService;
import net.schueller.peertube.network.RetrofitInstance; import net.schueller.peertube.network.RetrofitInstance;
import net.schueller.peertube.network.Session;
import net.schueller.peertube.provider.SearchSuggestionsProvider; import net.schueller.peertube.provider.SearchSuggestionsProvider;
import net.schueller.peertube.service.VideoPlayerService; import net.schueller.peertube.service.VideoPlayerService;
@ -82,6 +84,7 @@ public class VideoListActivity extends AppCompatActivity {
private String sort = "-createdAt"; private String sort = "-createdAt";
private String filter = null; private String filter = null;
private String searchQuery = ""; private String searchQuery = "";
private Boolean subscriptions = false;
private TextView emptyView; private TextView emptyView;
private RecyclerView recyclerView; private RecyclerView recyclerView;
@ -125,7 +128,7 @@ public class VideoListActivity extends AppCompatActivity {
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater(); MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_main, 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( menu.findItem(R.id.action_settings).setIcon(
@ -261,6 +264,9 @@ public class VideoListActivity extends AppCompatActivity {
Call<VideoList> call; Call<VideoList> call;
if (!searchQuery.equals("")) { if (!searchQuery.equals("")) {
call = service.searchVideosData(start, count, sort, nsfw, searchQuery, filter); call = service.searchVideosData(start, count, sort, nsfw, searchQuery, filter);
} else if (subscriptions) {
GetUserService userService = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetUserService.class);
call = userService.getVideosSubscripions(start, count, sort);
} else { } else {
call = service.getVideosData(start, count, sort, nsfw, filter); call = service.getVideosData(start, count, sort, nsfw, filter);
} }
@ -380,6 +386,7 @@ public class VideoListActivity extends AppCompatActivity {
sort = "-createdAt"; sort = "-createdAt";
currentStart = 0; currentStart = 0;
filter = null; filter = null;
subscriptions = false;
loadVideos(currentStart, count, sort, filter); loadVideos(currentStart, count, sort, filter);
} }
@ -391,6 +398,7 @@ public class VideoListActivity extends AppCompatActivity {
sort = "-trending"; sort = "-trending";
currentStart = 0; currentStart = 0;
filter = null; filter = null;
subscriptions = false;
loadVideos(currentStart, count, sort, filter); loadVideos(currentStart, count, sort, filter);
} }
@ -402,24 +410,43 @@ public class VideoListActivity extends AppCompatActivity {
sort = "-publishedAt"; sort = "-publishedAt";
filter = "local"; filter = "local";
currentStart = 0; currentStart = 0;
subscriptions = false;
loadVideos(currentStart, count, sort, filter); loadVideos(currentStart, count, sort, filter);
} }
return true; return true;
case R.id.navigation_subscriptions: case R.id.navigation_subscriptions:
//Log.v(TAG, "navigation_subscriptions"); //Log.v(TAG, "navigation_subscriptions");
Toast.makeText(VideoListActivity.this, "Subscriptions Not Implemented", Toast.LENGTH_SHORT).show();
return false; if (!Session.getInstance().isLoggedIn()) {
Intent intent = new Intent(this, LoginActivity.class);
this.startActivity(intent);
} else {
if (!isLoading) {
sort = "-publishedAt";
filter = null;
currentStart = 0;
subscriptions = true;
loadVideos(currentStart, count, sort, filter);
}
}
return true;
case R.id.navigation_account: case R.id.navigation_account:
//Log.v(TAG, "navigation_account"); //Log.v(TAG, "navigation_account");
Toast.makeText(VideoListActivity.this, "Account Not Implemented", Toast.LENGTH_SHORT).show(); //Toast.makeText(VideoListActivity.this, "Account Not Implemented", Toast.LENGTH_SHORT).show();
// Intent intent = new Intent(this, LoginActivity.class); if (!Session.getInstance().isLoggedIn()) {
// this.startActivity(intent); Intent intent = new Intent(this, LoginActivity.class);
this.startActivity(intent);
} else {
Intent intent = new Intent(this, AccountActivity.class);
this.startActivity(intent);
}
return false; return true;
} }
return false; return false;
}); });

View File

@ -0,0 +1,18 @@
package net.schueller.peertube.application;
import android.app.Application;
import android.content.Context;
public class AppApplication extends Application {
private static Application instance;
@Override
public void onCreate() {
super.onCreate();
instance = this;
}
public static Context getContext() {
return instance.getApplicationContext();
}
}

View File

@ -1,24 +1,58 @@
/*
* 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.network; package net.schueller.peertube.network;
import net.schueller.peertube.model.Token; import android.util.Log;
import java.io.IOException; import java.io.IOException;
import okhttp3.Interceptor; import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
public class AuthorizationInterceptor implements Interceptor { public class AuthorizationInterceptor implements Interceptor {
public AuthorizationInterceptor() { public AuthorizationInterceptor() {
} }
@Override @Override
public Response intercept(Chain chain) throws IOException { public Response intercept(Chain chain) throws IOException {
Response mainResponse = chain.proceed(chain.request());
if (mainResponse.code() == 401 || mainResponse.code() == 403) {
Session session = Session.getInstance();
Response mainResponse = chain.proceed(chain.request());
Request mainRequest = chain.request();
if (session.isLoggedIn()) {
// if (mainResponse.code() == 401 || mainResponse.code() == 403) {
// session.invalidate();
// return mainResponse;
// }
Request.Builder builder = mainRequest.newBuilder().header("Authorization", session.getToken()).
method(mainRequest.method(), mainRequest.body());
mainResponse = chain.proceed(builder.build());
Log.v("Authorization", "Intercept: " + session.getToken());
} }
return mainResponse; return mainResponse;
} }
} }

View File

@ -1,6 +1,7 @@
package net.schueller.peertube.network; package net.schueller.peertube.network;
import net.schueller.peertube.model.Me; import net.schueller.peertube.model.Me;
import net.schueller.peertube.model.VideoList;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.http.GET; import retrofit2.http.GET;
@ -11,4 +12,12 @@ public interface GetUserService {
@GET("users/me") @GET("users/me")
Call<Me> getMe(@Header("Authorization") String authorization); Call<Me> getMe(@Header("Authorization") String authorization);
@GET("users/me/subscriptions/videos")
Call<VideoList> getVideosSubscripions(
@Query("start") int start,
@Query("count") int count,
@Query("sort") String sort
);
} }

View File

@ -32,7 +32,6 @@ public class RetrofitInstance {
OkHttpClient.Builder okhttpClientBuilder = new OkHttpClient.Builder(); OkHttpClient.Builder okhttpClientBuilder = new OkHttpClient.Builder();
okhttpClientBuilder.addInterceptor(new TokenRenewInterceptor());
okhttpClientBuilder.addInterceptor(new AuthorizationInterceptor()); okhttpClientBuilder.addInterceptor(new AuthorizationInterceptor());
retrofit = new retrofit2.Retrofit.Builder() retrofit = new retrofit2.Retrofit.Builder()

View File

@ -0,0 +1,128 @@
/*
* 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.network;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import net.schueller.peertube.R;
import net.schueller.peertube.application.AppApplication;
public class Session {
private static volatile Session sSoleInstance;
private static SharedPreferences sharedPreferences;
//private constructor.
private Session(){
Context context = AppApplication.getContext();
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
//Prevent form the reflection api.
if (sSoleInstance != null){
throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
}
}
public static Session getInstance() {
if (sSoleInstance == null) { //if there is no instance available... create new one
synchronized (Session.class) {
if (sSoleInstance == null) sSoleInstance = new Session();
}
}
return sSoleInstance;
}
//Make singleton from serialize and deserialize operation.
protected Session readResolve() {
return getInstance();
}
public boolean isLoggedIn() {
// check if token exist or not
// return true if exist otherwise false
// assuming that token exists
//Log.v("Session", "isLoggedIn: " + (getToken() != null));
return getToken() != null;
}
public void saveToken(String token) {
// save the token
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(AppApplication.getContext().getString(R.string.pref_token_access), token);
editor.commit();
}
public String getToken() {
// return the token that was saved earlier
String token = sharedPreferences.getString(AppApplication.getContext().getString(R.string.pref_token_access), null);
String type = sharedPreferences.getString(AppApplication.getContext().getString(R.string.pref_token_type), "Bearer");
if (token != null) {
return type + " " + token;
}
return null;
}
public void saveUsername(String username) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(AppApplication.getContext().getString(R.string.pref_auth_username), username);
editor.commit();
}
public String getEmail() {
return sharedPreferences.getString(AppApplication.getContext().getString(R.string.pref_auth_username), null);
}
public void savePassword(String password) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(AppApplication.getContext().getString(R.string.pref_auth_password), password);
editor.commit();
}
public String getPassword() {
return sharedPreferences.getString(AppApplication.getContext().getString(R.string.pref_auth_password), null);
}
public void invalidate() {
// get called when user become logged out
// delete token and other user info
// (i.e: email, password)
// from the storage
Context context = AppApplication.getContext();
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(context.getString(R.string.pref_auth_password), null);
editor.putString(context.getString(R.string.pref_auth_username), null);
editor.putString(context.getString(R.string.pref_token_access), null);
editor.commit();
}
}

View File

@ -1,29 +0,0 @@
package net.schueller.peertube.network;
import net.schueller.peertube.model.Token;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Response;
public class TokenRenewInterceptor implements Interceptor {
public TokenRenewInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
// if 'x-auth-token' is available into the response header
// save the new token into session.The header key can be
// different upon implementation of backend.
String newToken = response.header("x-auth-token");
if (newToken != null) {
}
return response;
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".activity.AccountActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_user"
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_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways"
android:elevation="4dp" />
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout >

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
tools:context=".activity.UserActivity">
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu 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"
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

@ -22,6 +22,7 @@
<!-- Action bar --> <!-- Action bar -->
<string name="action_bar_title_search">Search</string> <string name="action_bar_title_search">Search</string>
<string name="action_bar_title_settings">Settings</string> <string name="action_bar_title_settings">Settings</string>
<string name="action_bar_title_logout">Logout</string>
<!-- Bottom navigation bar --> <!-- Bottom navigation bar -->
<string name="bottom_nav_title_home">Home</string> <string name="bottom_nav_title_home">Home</string>
@ -96,9 +97,15 @@
<string name="pref_title_background_play">Background Playback</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_description_background_play">If enabled, continues to play video in background.</string>
<string name="bottom_nav_title_local">Local</string> <string name="bottom_nav_title_local">Local</string>
<string name="title_activity_account">Account</string>
<!-- Constants, Don't translate -->
<string name="pref_token_access">pref_token_access</string> <string name="pref_token_access">pref_token_access</string>
<string name="pref_token_refresh">pref_token_refresh</string> <string name="pref_token_refresh">pref_token_refresh</string>
<string name="pref_token_expiration">pref_token_expiration</string> <string name="pref_token_expiration">pref_token_expiration</string>
<string name="pref_token_type">pref_token_type</string> <string name="pref_token_type">pref_token_type</string>
<string name="pref_auth_username">pref_auth_username</string>
<string name="pref_auth_password">pref_auth_password</string>
</resources> </resources>