diff --git a/CHANGELOG.md b/CHANGELOG.md
index fc7448a..a3e7768 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+### Version 1.0.20 Tag: v1.0.20 (2019-01-02)
+ * Added basic login framework
+ * AR Strings update (@rex07)
+
### Version 1.0.19 Tag: v1.0.19 (2018-12-31)
* Video Language Filter (@lishoujun)
diff --git a/app/build.gradle b/app/build.gradle
index 8b69e35..7d6b93b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -6,8 +6,8 @@ android {
applicationId "net.schueller.peertube"
minSdkVersion 21
targetSdkVersion 28
- versionCode 1019
- versionName "1.0.19"
+ versionCode 1020
+ versionName "1.0.20"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
@@ -71,3 +71,6 @@ android {
}
}
+dependencies {
+ implementation 'com.android.support.constraint:constraint-layout:+'
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6cc2ae4..de4a1d2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -18,7 +18,8 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
- tools:ignore="GoogleAppIndexingWarning">
+ tools:ignore="GoogleAppIndexingWarning"
+ android:name=".application.AppApplication">
+
+
+
+
+
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/net/schueller/peertube/activity/AccountActivity.java b/app/src/main/java/net/schueller/peertube/activity/AccountActivity.java
new file mode 100644
index 0000000..755c5c3
--- /dev/null
+++ b/app/src/main/java/net/schueller/peertube/activity/AccountActivity.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2018 Stefan Schüller
+ *
+ * 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 .
+ */
+
+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 android.widget.TextView;
+
+import com.mikepenz.fontawesome_typeface_library.FontAwesome;
+import com.mikepenz.iconics.IconicsDrawable;
+
+import net.schueller.peertube.R;
+import net.schueller.peertube.helper.APIUrlHelper;
+import net.schueller.peertube.model.Me;
+import net.schueller.peertube.model.OauthClient;
+import net.schueller.peertube.model.Token;
+import net.schueller.peertube.network.AuthenticationService;
+import net.schueller.peertube.network.GetUserService;
+import net.schueller.peertube.network.RetrofitInstance;
+import net.schueller.peertube.network.Session;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.SearchView;
+import androidx.appcompat.widget.Toolbar;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+
+import static net.schueller.peertube.helper.Constants.DEFAULT_THEME;
+import static net.schueller.peertube.helper.Constants.THEME_PREF_KEY;
+
+public class AccountActivity extends AppCompatActivity {
+
+
+ private static final String TAG = "AccountActivity";
+
+ @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);
+ finish();
+ return true;
+ default:
+ break;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public boolean onSupportNavigateUp() {
+ finish(); // close this activity as oppose to navigating up
+
+ return false;
+ }
+
+ @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);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setHomeAsUpIndicator(
+ new IconicsDrawable(this, FontAwesome.Icon.faw_chevron_left).actionBar()
+ );
+
+
+ init();
+ }
+
+ private void init() {
+ // try to get user data
+ getUserData();
+ }
+
+ private boolean getUserData() {
+
+ // TODO
+
+
+ String apiBaseURL = APIUrlHelper.getUrlWithVersion(this);
+
+ GetUserService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetUserService.class);
+
+ Call call = service.getMe();
+
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(@NonNull Call call, @NonNull Response response) {
+
+ if (response.isSuccessful()) {
+
+ Me me = response.body();
+
+ TextView username = findViewById(R.id.account_username);
+ TextView email = findViewById(R.id.account_email);
+
+ username.setText(me.getUsername());
+ email.setText(me.getEmail());
+
+ Log.v(TAG, me.getEmail());
+
+ }
+
+
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+
+ }
+ });
+
+ return true;
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ init();
+
+ }
+}
diff --git a/app/src/main/java/net/schueller/peertube/activity/LoginActivity.java b/app/src/main/java/net/schueller/peertube/activity/LoginActivity.java
index 4ea13ea..a1cc45c 100644
--- a/app/src/main/java/net/schueller/peertube/activity/LoginActivity.java
+++ b/app/src/main/java/net/schueller/peertube/activity/LoginActivity.java
@@ -18,16 +18,19 @@
package net.schueller.peertube.activity;
+import android.content.Context;
+import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
-import android.view.View;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.Toast;
+
+import com.mikepenz.fontawesome_typeface_library.FontAwesome;
+import com.mikepenz.iconics.IconicsDrawable;
import net.schueller.peertube.R;
import net.schueller.peertube.helper.APIUrlHelper;
@@ -36,27 +39,23 @@ import net.schueller.peertube.model.Token;
import net.schueller.peertube.network.AuthenticationService;
import net.schueller.peertube.network.RetrofitInstance;
-import okhttp3.MediaType;
-import okhttp3.OkHttpClient;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
import retrofit2.Call;
import retrofit2.Callback;
+import retrofit2.Response;
import static net.schueller.peertube.helper.Constants.DEFAULT_THEME;
import static net.schueller.peertube.helper.Constants.THEME_PREF_KEY;
public class LoginActivity extends AppCompatActivity {
- OkHttpClient client = new OkHttpClient();
- public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
-
private String TAG = "LoginActivity";
-
// UI references.
private AutoCompleteTextView mEmailView;
private EditText mPasswordView;
- private View mProgressView;
- private View mLoginFormView;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -79,17 +78,30 @@ public class LoginActivity extends AppCompatActivity {
mEmailView = findViewById(R.id.email);
mPasswordView = findViewById(R.id.password);
-// if (android.os.Build.VERSION.SDK_INT > 9) {
-// StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
-// StrictMode.setThreadPolicy(policy);
-// }
+
+ // 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 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);
@@ -106,15 +118,18 @@ public class LoginActivity extends AppCompatActivity {
AuthenticationService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(AuthenticationService.class);
Call call = service.getOauthClientLocal();
+
call.enqueue(new Callback() {
@Override
- public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) {
+ public void onResponse(@NonNull Call call, @NonNull Response response) {
- if (response.body() != null) {
+ if (response.isSuccessful()) {
+
+ OauthClient oauthClient = response.body();
Call call2 = service.getAuthenticationToken(
- response.body().getClientId(),
- response.body().getClientSecret(),
+ oauthClient.getClientId(),
+ oauthClient.getClientSecret(),
"code",
"password",
"upload",
@@ -125,13 +140,33 @@ public class LoginActivity extends AppCompatActivity {
@Override
public void onResponse(@NonNull Call call2, @NonNull retrofit2.Response response2) {
- if (response2.body() != null) {
- Log.wtf(TAG, response2.body().getAccessToken());
- Log.wtf(TAG, response2.body().getExpiresIn());
- Log.wtf(TAG, response2.body().getRefreshToken());
- Log.wtf(TAG, response2.body().getTokenType());
+ if (response2.isSuccessful()) {
+
+ Token token = response2.body();
+
+ SharedPreferences.Editor editor = sharedPref.edit();
+
+ // TODO: calc expiration
+ //editor.putInt(getString(R.string.pref_token_expiration), token.getRefreshToken());
+
+ editor.putString(getString(R.string.pref_token_access), token.getAccessToken());
+ editor.putString(getString(R.string.pref_token_refresh), token.getExpiresIn());
+ editor.putString(getString(R.string.pref_token_type), token.getTokenType());
+ editor.commit();
+
+ Log.wtf(TAG, "Logged in");
+
+ Intent intent = new Intent(context, AccountActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ context.startActivity(intent);
+
+ finish(); // close this activity
+
} else {
Log.wtf(TAG, response2.toString());
+
+ Toast.makeText(LoginActivity.this, "Login Error!", Toast.LENGTH_LONG).show();
+
}
}
diff --git a/app/src/main/java/net/schueller/peertube/activity/VideoListActivity.java b/app/src/main/java/net/schueller/peertube/activity/VideoListActivity.java
index e850419..df82443 100644
--- a/app/src/main/java/net/schueller/peertube/activity/VideoListActivity.java
+++ b/app/src/main/java/net/schueller/peertube/activity/VideoListActivity.java
@@ -53,8 +53,10 @@ import net.schueller.peertube.R;
import net.schueller.peertube.adapter.VideoAdapter;
import net.schueller.peertube.helper.APIUrlHelper;
import net.schueller.peertube.model.VideoList;
+import net.schueller.peertube.network.GetUserService;
import net.schueller.peertube.network.GetVideoDataService;
import net.schueller.peertube.network.RetrofitInstance;
+import net.schueller.peertube.network.Session;
import net.schueller.peertube.provider.SearchSuggestionsProvider;
import net.schueller.peertube.service.VideoPlayerService;
@@ -83,6 +85,7 @@ public class VideoListActivity extends AppCompatActivity {
private String sort = "-createdAt";
private String filter = null;
private String searchQuery = "";
+ private Boolean subscriptions = false;
private TextView emptyView;
private RecyclerView recyclerView;
@@ -126,7 +129,7 @@ public class VideoListActivity extends AppCompatActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.menu_main, menu);
+ inflater.inflate(R.menu.menu_top_videolist, menu);
// Set an icon in the ActionBar
menu.findItem(R.id.action_settings).setIcon(
@@ -262,6 +265,9 @@ public class VideoListActivity extends AppCompatActivity {
Call call;
if (!searchQuery.equals("")) {
call = service.searchVideosData(start, count, sort, nsfw, searchQuery, filter, languages);
+ } else if (subscriptions) {
+ GetUserService userService = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetUserService.class);
+ call = userService.getVideosSubscripions(start, count, sort);
} else {
call = service.getVideosData(start, count, sort, nsfw, filter, languages);
}
@@ -381,6 +387,7 @@ public class VideoListActivity extends AppCompatActivity {
sort = "-createdAt";
currentStart = 0;
filter = null;
+ subscriptions = false;
loadVideos(currentStart, count, sort, filter);
}
@@ -392,6 +399,7 @@ public class VideoListActivity extends AppCompatActivity {
sort = "-trending";
currentStart = 0;
filter = null;
+ subscriptions = false;
loadVideos(currentStart, count, sort, filter);
}
@@ -403,22 +411,42 @@ public class VideoListActivity extends AppCompatActivity {
sort = "-publishedAt";
filter = "local";
currentStart = 0;
+ subscriptions = false;
loadVideos(currentStart, count, sort, filter);
}
return true;
case R.id.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);
+ return false;
+ } else {
+
+ if (!isLoading) {
+ sort = "-publishedAt";
+ filter = null;
+ currentStart = 0;
+ subscriptions = true;
+ loadVideos(currentStart, count, sort, filter);
+ }
+ return true;
+ }
+
case R.id.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);
-// this.startActivity(intent);
+ if (!Session.getInstance().isLoggedIn()) {
+ Intent intent = new Intent(this, LoginActivity.class);
+ this.startActivity(intent);
+ } else {
+ Intent intent = new Intent(this, AccountActivity.class);
+ this.startActivity(intent);
+ }
return false;
}
diff --git a/app/src/main/java/net/schueller/peertube/application/AppApplication.java b/app/src/main/java/net/schueller/peertube/application/AppApplication.java
new file mode 100644
index 0000000..05869b4
--- /dev/null
+++ b/app/src/main/java/net/schueller/peertube/application/AppApplication.java
@@ -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();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/net/schueller/peertube/model/Me.java b/app/src/main/java/net/schueller/peertube/model/Me.java
new file mode 100644
index 0000000..1a0c96e
--- /dev/null
+++ b/app/src/main/java/net/schueller/peertube/model/Me.java
@@ -0,0 +1,144 @@
+package net.schueller.peertube.model;
+
+public class Me {
+
+ private Integer id;
+ private Account account;
+ private Boolean autoPlayVideo;
+ private Boolean blocked;
+ private String blockedReason;
+ private String createdAt;
+ private String email;
+ private String emailVerified;
+ private String nsfwPolicy;
+ private Integer role;
+ private String roleLabel;
+ private String username;
+
+ // private VideoChannels videoChannels;
+ private Integer videoQuota;
+ private Integer videoQuotaDaily;
+ private String webTorrentEnabled;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Account getAccount() {
+ return account;
+ }
+
+ public void setAccount(Account account) {
+ this.account = account;
+ }
+
+ public Boolean getAutoPlayVideo() {
+ return autoPlayVideo;
+ }
+
+ public void setAutoPlayVideo(Boolean autoPlayVideo) {
+ this.autoPlayVideo = autoPlayVideo;
+ }
+
+ public Boolean getBlocked() {
+ return blocked;
+ }
+
+ public void setBlocked(Boolean blocked) {
+ this.blocked = blocked;
+ }
+
+ public String getBlockedReason() {
+ return blockedReason;
+ }
+
+ public void setBlockedReason(String blockedReason) {
+ this.blockedReason = blockedReason;
+ }
+
+ public String getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(String createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getEmailVerified() {
+ return emailVerified;
+ }
+
+ public void setEmailVerified(String emailVerified) {
+ this.emailVerified = emailVerified;
+ }
+
+ public String getNsfwPolicy() {
+ return nsfwPolicy;
+ }
+
+ public void setNsfwPolicy(String nsfwPolicy) {
+ this.nsfwPolicy = nsfwPolicy;
+ }
+
+ public Integer getRole() {
+ return role;
+ }
+
+ public void setRole(Integer role) {
+ this.role = role;
+ }
+
+ public String getRoleLabel() {
+ return roleLabel;
+ }
+
+ public void setRoleLabel(String roleLabel) {
+ this.roleLabel = roleLabel;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public Integer getVideoQuota() {
+ return videoQuota;
+ }
+
+ public void setVideoQuota(Integer videoQuota) {
+ this.videoQuota = videoQuota;
+ }
+
+ public Integer getVideoQuotaDaily() {
+ return videoQuotaDaily;
+ }
+
+ public void setVideoQuotaDaily(Integer videoQuotaDaily) {
+ this.videoQuotaDaily = videoQuotaDaily;
+ }
+
+ public String getWebTorrentEnabled() {
+ return webTorrentEnabled;
+ }
+
+ public void setWebTorrentEnabled(String webTorrentEnabled) {
+ this.webTorrentEnabled = webTorrentEnabled;
+ }
+}
+
+
diff --git a/app/src/main/java/net/schueller/peertube/model/OauthClient.java b/app/src/main/java/net/schueller/peertube/model/OauthClient.java
index e8044be..9dd016f 100644
--- a/app/src/main/java/net/schueller/peertube/model/OauthClient.java
+++ b/app/src/main/java/net/schueller/peertube/model/OauthClient.java
@@ -17,9 +17,14 @@
*/
package net.schueller.peertube.model;
+import com.google.gson.annotations.SerializedName;
+
public class OauthClient {
+ @SerializedName("client_id")
private String clientId;
+
+ @SerializedName("client_secret")
private String clientSecret;
public String getClientId() {
diff --git a/app/src/main/java/net/schueller/peertube/model/Token.java b/app/src/main/java/net/schueller/peertube/model/Token.java
index a4ac1f1..f43bad0 100644
--- a/app/src/main/java/net/schueller/peertube/model/Token.java
+++ b/app/src/main/java/net/schueller/peertube/model/Token.java
@@ -17,11 +17,20 @@
*/
package net.schueller.peertube.model;
+import com.google.gson.annotations.SerializedName;
+
public class Token {
+ @SerializedName("access_token")
private String accessToken;
+
+ @SerializedName("expires_in")
private String expiresIn;
+
+ @SerializedName("refresh_token")
private String refreshToken;
+
+ @SerializedName("token_type")
private String tokenType;
public String getAccessToken() {
diff --git a/app/src/main/java/net/schueller/peertube/network/AuthorizationInterceptor.java b/app/src/main/java/net/schueller/peertube/network/AuthorizationInterceptor.java
new file mode 100644
index 0000000..37786c7
--- /dev/null
+++ b/app/src/main/java/net/schueller/peertube/network/AuthorizationInterceptor.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 Stefan Schüller
+ *
+ * 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 .
+ */
+
+package net.schueller.peertube.network;
+
+import android.util.Log;
+
+import java.io.IOException;
+
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class AuthorizationInterceptor implements Interceptor {
+
+ public AuthorizationInterceptor() {
+ }
+
+
+
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+
+ Session session = Session.getInstance();
+
+ Response mainResponse = chain.proceed(chain.request());
+ Request mainRequest = chain.request();
+
+ if (session.isLoggedIn()) {
+
+ // add authentication header to each request if we are logged in
+ Request.Builder builder = mainRequest.newBuilder().header("Authorization", session.getToken()).
+ method(mainRequest.method(), mainRequest.body());
+ // Log.v("Authorization", "Intercept: " + session.getToken());
+
+ // build request
+ mainResponse = chain.proceed(builder.build());
+
+ // logout on auth error
+ if (mainResponse.code() == 401 || mainResponse.code() == 403) {
+ session.invalidate();
+ Log.v("Authorization", "Intercept: Logout forced");
+ }
+
+ }
+
+ return mainResponse;
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/net/schueller/peertube/network/GetUserService.java b/app/src/main/java/net/schueller/peertube/network/GetUserService.java
new file mode 100644
index 0000000..850b9f5
--- /dev/null
+++ b/app/src/main/java/net/schueller/peertube/network/GetUserService.java
@@ -0,0 +1,23 @@
+package net.schueller.peertube.network;
+
+import net.schueller.peertube.model.Me;
+import net.schueller.peertube.model.VideoList;
+
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+import retrofit2.http.Query;
+
+public interface GetUserService {
+
+ @GET("users/me")
+ Call getMe();
+
+ @GET("users/me/subscriptions/videos")
+ Call getVideosSubscripions(
+ @Query("start") int start,
+ @Query("count") int count,
+ @Query("sort") String sort
+ );
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/net/schueller/peertube/network/RetrofitInstance.java b/app/src/main/java/net/schueller/peertube/network/RetrofitInstance.java
index fc8936f..23e38da 100644
--- a/app/src/main/java/net/schueller/peertube/network/RetrofitInstance.java
+++ b/app/src/main/java/net/schueller/peertube/network/RetrofitInstance.java
@@ -17,6 +17,7 @@
*/
package net.schueller.peertube.network;
+import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
@@ -28,7 +29,13 @@ public class RetrofitInstance {
public static Retrofit getRetrofitInstance(String newBaseUrl) {
if (retrofit == null || !newBaseUrl.equals(baseUrl)) {
baseUrl = newBaseUrl;
+
+ OkHttpClient.Builder okhttpClientBuilder = new OkHttpClient.Builder();
+
+ okhttpClientBuilder.addInterceptor(new AuthorizationInterceptor());
+
retrofit = new retrofit2.Retrofit.Builder()
+ .client(okhttpClientBuilder.build())
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
diff --git a/app/src/main/java/net/schueller/peertube/network/Session.java b/app/src/main/java/net/schueller/peertube/network/Session.java
new file mode 100644
index 0000000..525cbb9
--- /dev/null
+++ b/app/src/main/java/net/schueller/peertube/network/Session.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2018 Stefan Schüller
+ *
+ * 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 .
+ */
+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();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_account.xml b/app/src/main/res/layout/activity_account.xml
new file mode 100644
index 0000000..bfa68ce
--- /dev/null
+++ b/app/src/main/res/layout/activity_account.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index 82d760d..6ea1ec6 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -3,74 +3,93 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
- android:orientation="vertical"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- tools:context="net.schueller.peertube.activity.LoginActivity">
+ android:orientation="vertical">
-
-
-
-
+ android:orientation="vertical">
-
+ android:elevation="4dp" />
-
+
-
+
-
-
+
-
-
-
-
-
-
-
+ android:orientation="vertical">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_top_user.xml b/app/src/main/res/menu/menu_top_user.xml
new file mode 100644
index 0000000..efd2356
--- /dev/null
+++ b/app/src/main/res/menu/menu_top_user.xml
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_top_videolist.xml
similarity index 100%
rename from app/src/main/res/menu/menu_main.xml
rename to app/src/main/res/menu/menu_top_videolist.xml
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index e090072..ab8ed73 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -35,8 +35,8 @@
- \0020-\0020
- \0020مشاهدات
+ \u0020-\u0020
+ \u0020 مشاهدات
\@
@@ -49,7 +49,7 @@
مشغل فيديو التورنت
تشغيل الفيديو عبر بث التورنت . يتطلب هذا أذونات التخزين. (ألفا ، غير مستقر!)
الرخصة
- GNU Affero General Public License v3.0\n
+ رخصة جنو العمومية v3.0\n
\n
إن أذونات هذا الترخيص الأقوى للحقوق المتروكة مشروطة بإتاحة الشفرة المصدرية الكاملة للأعمال والتعديلات المرخصة ، والتي تشتمل على أعمال أكبر باستخدام عمل مرخص ، تحت نفس الترخيص. يجب الحفاظ على حقوق النشر وإشعارات الترخيص. يقدم المساهمون منحة صريحة لحقوق البراءة. عند استخدام إصدار معدل لتوفير خدمة عبر شبكة ، يجب توفير شفرة المصدر الكاملة للإصدار المعدل.
الإصدار
@@ -91,7 +91,7 @@
التشغيل في الخلفية
- إن تم تنشيطه، ستواصل الفيديو في الإشتغال في الخلفية.
+ إن تم تنشيطه، سيستمر تشغيل الفيديو في الخلفية.
المحلي
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index e28c726..f31f9c9 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -8,7 +8,7 @@
Serveur
Email
- Mot de passe (optionnel)
+ Mot de passe
Connexion
Connexion
Cette adresse mail n\'est pas valide
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index aac92cf..959ad98 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -8,7 +8,7 @@
Server
Email
- Password (optional)
+ Password
Sign in
Sign in
This email address is invalid
@@ -22,6 +22,7 @@
Search
Settings
+ Logout
Home
@@ -293,4 +294,14 @@
If enabled, continues to play video in background.
Local
+ Account
+
+
+ pref_token_access
+ pref_token_refresh
+ pref_token_expiration
+ pref_token_type
+ pref_auth_username
+ pref_auth_password
+