From 515740d889d65dc524355e14460fedf8c38d125e Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 28 Jun 2020 19:11:39 +0200 Subject: [PATCH] Register + login --- app/src/main/AndroidManifest.xml | 11 + .../fedilab/fedilabtube/LoginActivity.java | 255 ++++++++++++++++++ .../app/fedilab/fedilabtube/MainActivity.java | 22 +- .../fedilabtube/PeertubeRegisterActivity.java | 154 +++++++++++ .../fedilab/fedilabtube/SearchActivity.java | 2 - .../fedilabtube/ShowAccountActivity.java | 4 +- .../CreatePeertubeAccountAsyncTask.java | 42 +++ .../RetrievePeertubeSearchAsyncTask.java | 2 +- .../UpdateAccountInfoAsyncTask.java | 88 ++++++ .../fedilab/fedilabtube/helper/Helper.java | 5 +- .../OnPostStatusActionInterface.java | 8 + .../drawable/ic_baseline_arrow_back_24.xml | 10 +- .../main/res/drawable/ic_baseline_edit_24.xml | 10 +- .../res/drawable/ic_baseline_more_vert_24.xml | 10 +- .../drawable/ic_baseline_track_changes_24.xml | 10 +- app/src/main/res/drawable/ic_launcher.png | Bin 0 -> 16541 bytes .../res/drawable/ic_launcher_foreground.xml | 21 +- app/src/main/res/drawable/red_border.xml | 13 + app/src/main/res/layout/activity_login.xml | 142 ++++++++++ .../res/layout/activity_register_peertube.xml | 148 ++++++++++ .../res/layout/activity_search_result.xml | 3 +- .../main/res/layout/activity_show_account.xml | 26 +- app/src/main/res/layout/drawer_account.xml | 3 +- app/src/main/res/layout/drawer_peertube.xml | 4 +- .../res/layout/exo_playback_control_view.xml | 8 +- app/src/main/res/menu/main_menu.xml | 4 +- .../res/mipmap-anydpi-v26/ic_launcher.xml | 4 +- .../mipmap-anydpi-v26/ic_launcher_round.xml | 4 +- app/src/main/res/values/strings.xml | 28 ++ 29 files changed, 976 insertions(+), 65 deletions(-) create mode 100644 app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java create mode 100644 app/src/main/java/app/fedilab/fedilabtube/PeertubeRegisterActivity.java create mode 100644 app/src/main/java/app/fedilab/fedilabtube/asynctasks/CreatePeertubeAccountAsyncTask.java create mode 100644 app/src/main/java/app/fedilab/fedilabtube/asynctasks/UpdateAccountInfoAsyncTask.java create mode 100644 app/src/main/java/app/fedilab/fedilabtube/interfaces/OnPostStatusActionInterface.java create mode 100644 app/src/main/res/drawable/ic_launcher.png create mode 100644 app/src/main/res/drawable/red_border.xml create mode 100644 app/src/main/res/layout/activity_login.xml create mode 100644 app/src/main/res/layout/activity_register_peertube.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c141e61..ee1f422 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -58,6 +58,17 @@ android:configChanges="orientation|screenSize" android:label="@string/app_name" android:windowSoftInputMode="stateAlwaysHidden" /> + + + diff --git a/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java b/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java new file mode 100644 index 0000000..09d4dcb --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java @@ -0,0 +1,255 @@ +package app.fedilab.fedilabtube; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.AsyncTask; +import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; +import android.text.style.UnderlineSpan; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLEncoder; +import java.util.HashMap; + +import app.fedilab.fedilabtube.asynctasks.UpdateAccountInfoAsyncTask; +import app.fedilab.fedilabtube.client.HttpsConnection; +import app.fedilab.fedilabtube.helper.Helper; +import es.dmoral.toasty.Toasty; + + +public class LoginActivity extends AppCompatActivity { + + + private static String client_id; + private static String client_secret; + private static String instance; + private static String host; + private EditText login_uid; + private EditText login_passwd; + private Button connectionButton; + private String actionToken; + private Spinner info_instance; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + + setContentView(R.layout.activity_login); + if (getSupportActionBar() != null) + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + TextView create_an_account_peertube = findViewById(R.id.create_an_account_peertube); + + SpannableString content_create = new SpannableString(getString(R.string.join_peertube)); + content_create.setSpan(new UnderlineSpan(), 0, content_create.length(), 0); + content_create.setSpan(new ForegroundColorSpan(ContextCompat.getColor(LoginActivity.this, R.color.colorAccent)), 0, content_create.length(), + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + create_an_account_peertube.setText(content_create); + + create_an_account_peertube.setOnClickListener(v -> { + Intent mainActivity = new Intent(LoginActivity.this, PeertubeRegisterActivity.class); + Bundle b = new Bundle(); + b.putString("instance", host); + mainActivity.putExtras(b); + startActivity(mainActivity); + }); + + + login_uid = findViewById(R.id.login_uid); + login_passwd = findViewById(R.id.login_passwd); + connectionButton = findViewById(R.id.login_button); + info_instance = findViewById(R.id.info_instance); + + ArrayAdapter arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, Helper.academies); + info_instance.setAdapter(arrayAdapter); + + info_instance.setSelection(0); + info_instance.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + host = Helper.academies[position]; + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + + ImageView main_logo = findViewById(R.id.main_logo); + main_logo.setImageResource(R.drawable.ic_launcher); + + connectionButton.setEnabled(false); + + } + + @Override + protected void onResume() { + super.onResume(); + retrievesClientId(); + } + + private void retrievesClientId() { + String instanceFromField = info_instance.getSelectedItem().toString(); + if (instanceFromField.startsWith("http://")) { + instanceFromField = instanceFromField.replace("http://", ""); + } + if (instanceFromField.startsWith("https://")) { + instanceFromField = instanceFromField.replace("https://", ""); + } + String host = instanceFromField; + try { + URL url = new URL(instanceFromField); + host = url.getHost(); + } catch (MalformedURLException ignored) { + } + host = Helper.getPeertubeUrl(host); + try { + instance = URLEncoder.encode(host, "utf-8"); + } catch (UnsupportedEncodingException e) { + Toasty.error(LoginActivity.this, getString(R.string.client_error), Toast.LENGTH_LONG).show(); + } + actionToken = "/api/v1/oauth-clients/local"; + final HashMap parameters = new HashMap<>(); + parameters.put(Helper.CLIENT_NAME, Helper.CLIENT_NAME_VALUE); + parameters.put(Helper.REDIRECT_URIS, Helper.REDIRECT_CONTENT); + parameters.put(Helper.SCOPES, Helper.OAUTH_SCOPES_PEERTUBE); + parameters.put(Helper.WEBSITE, Helper.WEBSITE_VALUE); + new Thread(() -> { + try { + String response = new HttpsConnection(LoginActivity.this, instance).get("https://" + instance + actionToken, 30, parameters, null); + runOnUiThread(() -> { + JSONObject resobj; + try { + resobj = new JSONObject(response); + client_id = resobj.get(Helper.CLIENT_ID).toString(); + client_secret = resobj.get(Helper.CLIENT_SECRET).toString(); + manageClient(client_id, client_secret); + } catch (JSONException e) { + e.printStackTrace(); + } + }); + } catch (final Exception e) { + e.printStackTrace(); + + runOnUiThread(() -> { + + String message = null; + if (e.getLocalizedMessage() != null) { + message = e.getMessage(); + } + if (message == null) { + message = getString(R.string.client_error); + } + + Toasty.error(LoginActivity.this, message, Toast.LENGTH_LONG).show(); + }); + } + }).start(); + connectionButton.setOnClickListener(v -> { + connectionButton.setEnabled(false); + parameters.clear(); + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); + parameters.put(Helper.CLIENT_ID, sharedpreferences.getString(Helper.CLIENT_ID, null)); + parameters.put(Helper.CLIENT_SECRET, sharedpreferences.getString(Helper.CLIENT_SECRET, null)); + parameters.put("grant_type", "password"); + try { + parameters.put("username", URLEncoder.encode(login_uid.getText().toString().trim().toLowerCase(), "UTF-8")); + } catch (UnsupportedEncodingException e) { + parameters.put("username", login_uid.getText().toString().trim().toLowerCase()); + } + try { + parameters.put("password", URLEncoder.encode(login_passwd.getText().toString(), "UTF-8")); + } catch (UnsupportedEncodingException e) { + parameters.put("password", login_passwd.getText().toString()); + } + parameters.put("scope", "user"); + String oauthUrl = "/api/v1/users/token"; + new Thread(() -> { + try { + String response = new HttpsConnection(LoginActivity.this, instance).post("https://" + instance + oauthUrl, 30, parameters, null); + runOnUiThread(() -> { + JSONObject resobj; + try { + resobj = new JSONObject(response); + String token = resobj.get("access_token").toString(); + String refresh_token = null; + if (resobj.has("refresh_token")) + refresh_token = resobj.getString("refresh_token"); + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, token); + editor.apply(); + //Update the account with the token; + if (instance != null) { + new UpdateAccountInfoAsyncTask(LoginActivity.this, token, client_id, client_secret, refresh_token, instance).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + connectionButton.setEnabled(true); + Toasty.error(LoginActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + } + } catch (JSONException e) { + e.printStackTrace(); + } + }); + } catch (final Exception e) { + e.printStackTrace(); + runOnUiThread(() -> { + connectionButton.setEnabled(true); + runOnUiThread(() -> { + String message; + if (e.getLocalizedMessage() != null && e.getLocalizedMessage().trim().length() > 0) + message = e.getLocalizedMessage(); + else if (e.getMessage() != null && e.getMessage().trim().length() > 0) + message = e.getMessage(); + else + message = getString(R.string.client_error); + Toasty.error(LoginActivity.this, message, Toast.LENGTH_LONG).show(); + }); + }); + } + }).start(); + }); + } + + private void manageClient(String client_id, String client_secret) { + + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(Helper.CLIENT_ID, client_id); + editor.putString(Helper.CLIENT_SECRET, client_secret); + editor.apply(); + connectionButton.setEnabled(true); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + +} \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java b/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java index 8b2d7ab..09662a6 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java @@ -51,7 +51,7 @@ public class MainActivity extends AppCompatActivity { @Override public boolean onCreateOptionsMenu(@NotNull Menu menu) { getMenuInflater().inflate(R.menu.main_menu, menu); - MenuItem myActionMenuItem = menu.findItem( R.id.action_search); + MenuItem myActionMenuItem = menu.findItem(R.id.action_search); SearchView searchView = (SearchView) myActionMenuItem.getActionView(); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override @@ -61,12 +61,13 @@ public class MainActivity extends AppCompatActivity { b.putString("search", query.trim()); intent.putExtras(b); startActivity(intent); - if( ! searchView.isIconified()) { + if (!searchView.isIconified()) { searchView.setIconified(true); } myActionMenuItem.collapseActionView(); return false; } + @Override public boolean onQueryTextChange(String s) { return false; @@ -81,10 +82,27 @@ public class MainActivity extends AppCompatActivity { showRadioButtonDialog(); return true; } + if (item.getItemId() == R.id.action_account) { + Intent intent = new Intent(MainActivity.this, LoginActivity.class); + startActivity(intent); + return true; + } return super.onOptionsItemSelected(item); } + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + if (intent == null) + return; + Bundle extras = intent.getExtras(); + if (extras != null && extras.containsKey(Helper.INTENT_ACTION)) { + if (extras.getInt(Helper.INTENT_ACTION) == Helper.ADD_USER_INTENT) { + recreate(); + } + } + } private void showRadioButtonDialog() { diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeRegisterActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeRegisterActivity.java new file mode 100644 index 0000000..3eb4e6d --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeRegisterActivity.java @@ -0,0 +1,154 @@ +package app.fedilab.fedilabtube; + +import android.os.Bundle; +import android.text.Html; +import android.text.method.LinkMovementMethod; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.TextView; + +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; + +import app.fedilab.fedilabtube.asynctasks.CreatePeertubeAccountAsyncTask; +import app.fedilab.fedilabtube.client.APIResponse; +import app.fedilab.fedilabtube.client.entities.AccountCreation; +import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.interfaces.OnPostStatusActionInterface; +import es.dmoral.toasty.Toasty; + +import static android.os.AsyncTask.THREAD_POOL_EXECUTOR; + +public class PeertubeRegisterActivity extends AppCompatActivity implements OnPostStatusActionInterface { + + + private Button signup; + private TextView error_message; + private String instance; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_register_peertube); + + if (getSupportActionBar() != null) + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + Bundle b = getIntent().getExtras(); + if (b != null) { + instance = b.getString("instance"); + } + if (instance == null) { + finish(); + return; + } + signup = findViewById(R.id.signup); + EditText username = findViewById(R.id.username); + EditText email = findViewById(R.id.email); + EditText password = findViewById(R.id.password); + EditText password_confirm = findViewById(R.id.password_confirm); + CheckBox agreement = findViewById(R.id.agreement); + error_message = findViewById(R.id.error_message); + + signup.setOnClickListener(view -> { + error_message.setVisibility(View.GONE); + if (username.getText().toString().trim().length() == 0 || email.getText().toString().trim().length() == 0 || + password.getText().toString().trim().length() == 0 || password_confirm.getText().toString().trim().length() == 0 || !agreement.isChecked()) { + Toasty.error(PeertubeRegisterActivity.this, getString(R.string.all_field_filled)).show(); + return; + } + if (!password.getText().toString().trim().equals(password_confirm.getText().toString().trim())) { + Toasty.error(PeertubeRegisterActivity.this, getString(R.string.password_error)).show(); + return; + } + if (!android.util.Patterns.EMAIL_ADDRESS.matcher(email.getText().toString().trim()).matches()) { + Toasty.error(PeertubeRegisterActivity.this, getString(R.string.email_error)).show(); + return; + } + if (password.getText().toString().trim().length() < 8) { + Toasty.error(PeertubeRegisterActivity.this, getString(R.string.password_too_short)).show(); + return; + } + if (username.getText().toString().matches("[a-zA-Z0-9_]")) { + Toasty.error(PeertubeRegisterActivity.this, getString(R.string.username_error)).show(); + return; + } + signup.setEnabled(false); + AccountCreation accountCreation = new AccountCreation(); + accountCreation.setEmail(email.getText().toString().trim()); + accountCreation.setPassword(password.getText().toString().trim()); + accountCreation.setPasswordConfirm(password_confirm.getText().toString().trim()); + accountCreation.setUsername(username.getText().toString().trim()); + new CreatePeertubeAccountAsyncTask(PeertubeRegisterActivity.this, accountCreation, Helper.getPeertubeUrl(instance), PeertubeRegisterActivity.this).executeOnExecutor(THREAD_POOL_EXECUTOR); + }); + + TextView agreement_text = findViewById(R.id.agreement_text); + String tos = getString(R.string.tos); + String serverrules = getString(R.string.server_rules); + String content_agreement = getString(R.string.agreement_check, + "" + serverrules + "", + "" + tos + "" + ); + agreement_text.setMovementMethod(LinkMovementMethod.getInstance()); + agreement_text.setText(Html.fromHtml(content_agreement)); + setTitle(instance); + } + + @Override + protected void onResume() { + super.onResume(); + } + + + @Override + public void onPostStatusAction(APIResponse apiResponse) { + if (apiResponse.getError() != null) { + String errorMessage; + if (apiResponse.getError().getError() != null) { + try { + String[] resp = apiResponse.getError().getError().split(":"); + if (resp.length == 2) + errorMessage = apiResponse.getError().getError().split(":")[1]; + else if (resp.length == 3) + errorMessage = apiResponse.getError().getError().split(":")[2]; + else + errorMessage = getString(R.string.toast_error); + } catch (Exception e) { + errorMessage = getString(R.string.toast_error); + } + } else { + errorMessage = getString(R.string.toast_error); + } + error_message.setText(errorMessage); + error_message.setVisibility(View.VISIBLE); + signup.setEnabled(true); + return; + } + + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(PeertubeRegisterActivity.this); + dialogBuilder.setCancelable(false); + dialogBuilder.setPositiveButton(R.string.validate, (dialog, which) -> { + dialog.dismiss(); + finish(); + }); + AlertDialog alertDialog = dialogBuilder.create(); + alertDialog.setTitle(getString(R.string.account_created)); + alertDialog.setMessage(getString(R.string.account_created_message, this.instance)); + alertDialog.show(); + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + +} \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/fedilabtube/SearchActivity.java b/app/src/main/java/app/fedilab/fedilabtube/SearchActivity.java index c1d5977..c2c2caf 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/SearchActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/SearchActivity.java @@ -1,4 +1,3 @@ - package app.fedilab.fedilabtube; import android.os.Bundle; @@ -14,7 +13,6 @@ import app.fedilab.fedilabtube.interfaces.OnRetrieveFeedsInterface; import es.dmoral.toasty.Toasty; - public class SearchActivity extends AppCompatActivity implements OnRetrieveFeedsInterface { diff --git a/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java b/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java index 084e928..623a690 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java @@ -268,7 +268,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi SpannableString spannableString; - if( account.getNote() != null && account.getNote().compareTo("null") != 0 && account.getNote().trim().length() > 0 ) { + if (account.getNote() != null && account.getNote().compareTo("null") != 0 && account.getNote().trim().length() > 0) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) spannableString = new SpannableString(Html.fromHtml(account.getNote(), FROM_HTML_MODE_LEGACY)); else @@ -278,7 +278,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi account_note.setText(account.getNoteSpan(), TextView.BufferType.SPANNABLE); account_note.setMovementMethod(LinkMovementMethod.getInstance()); account_note.setVisibility(View.VISIBLE); - }else{ + } else { account_note.setVisibility(View.GONE); } Helper.loadGiF(ShowAccountActivity.this, account, account_pp); diff --git a/app/src/main/java/app/fedilab/fedilabtube/asynctasks/CreatePeertubeAccountAsyncTask.java b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/CreatePeertubeAccountAsyncTask.java new file mode 100644 index 0000000..e75dbdc --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/CreatePeertubeAccountAsyncTask.java @@ -0,0 +1,42 @@ +package app.fedilab.fedilabtube.asynctasks; + +import android.content.Context; +import android.os.AsyncTask; + +import java.lang.ref.WeakReference; + +import app.fedilab.fedilabtube.client.APIResponse; +import app.fedilab.fedilabtube.client.PeertubeAPI; +import app.fedilab.fedilabtube.client.entities.AccountCreation; +import app.fedilab.fedilabtube.interfaces.OnPostStatusActionInterface; + + +public class CreatePeertubeAccountAsyncTask extends AsyncTask { + + private OnPostStatusActionInterface listener; + private APIResponse apiResponse; + private app.fedilab.fedilabtube.client.entities.Status status; + private AccountCreation accountCreation; + private WeakReference contextReference; + private String instance; + + public CreatePeertubeAccountAsyncTask(Context context, AccountCreation accountCreation, String instance, OnPostStatusActionInterface onPostStatusActionInterface) { + this.contextReference = new WeakReference<>(context); + this.listener = onPostStatusActionInterface; + this.accountCreation = accountCreation; + this.instance = instance; + } + + @Override + protected Void doInBackground(Void... params) { + apiResponse = new PeertubeAPI(contextReference.get(), instance, null).createAccount(accountCreation); + return null; + } + + @Override + protected void onPostExecute(Void result) { + listener.onPostStatusAction(apiResponse); + + } + +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrievePeertubeSearchAsyncTask.java b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrievePeertubeSearchAsyncTask.java index 32fc73a..be97c11 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrievePeertubeSearchAsyncTask.java +++ b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrievePeertubeSearchAsyncTask.java @@ -17,7 +17,7 @@ public class RetrievePeertubeSearchAsyncTask extends AsyncTask private OnRetrieveFeedsInterface listener; private WeakReference contextReference; - public RetrievePeertubeSearchAsyncTask(Context context, String max_id, String query, OnRetrieveFeedsInterface onRetrieveFeedsInterface) { + public RetrievePeertubeSearchAsyncTask(Context context, String max_id, String query, OnRetrieveFeedsInterface onRetrieveFeedsInterface) { this.contextReference = new WeakReference<>(context); this.query = query; this.listener = onRetrieveFeedsInterface; diff --git a/app/src/main/java/app/fedilab/fedilabtube/asynctasks/UpdateAccountInfoAsyncTask.java b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/UpdateAccountInfoAsyncTask.java new file mode 100644 index 0000000..02c406f --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/UpdateAccountInfoAsyncTask.java @@ -0,0 +1,88 @@ +package app.fedilab.fedilabtube.asynctasks; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; +import android.os.AsyncTask; + +import java.io.UnsupportedEncodingException; +import java.lang.ref.WeakReference; +import java.net.URLDecoder; + +import app.fedilab.fedilabtube.MainActivity; +import app.fedilab.fedilabtube.client.PeertubeAPI; +import app.fedilab.fedilabtube.client.entities.Account; +import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.sqlite.AccountDAO; +import app.fedilab.fedilabtube.sqlite.Sqlite; + + +public class UpdateAccountInfoAsyncTask extends AsyncTask { + + private String token, client_id, client_secret, refresh_token; + private String instance; + private WeakReference contextReference; + + public UpdateAccountInfoAsyncTask(Context context, String token, String client_id, String client_secret, String refresh_token, String instance) { + this.contextReference = new WeakReference<>(context); + this.token = token; + this.instance = instance; + this.client_id = client_id; + this.client_secret = client_secret; + this.refresh_token = refresh_token; + } + + @Override + protected Void doInBackground(Void... params) { + Account account; + if (this.contextReference == null) { + return null; + } + account = new PeertubeAPI(this.contextReference.get(), instance, null).verifyCredentials(); + if (account == null) + return null; + try { + //At the state the instance can be encoded + instance = URLDecoder.decode(instance, "utf-8"); + } catch (UnsupportedEncodingException ignored) { + } + + SharedPreferences sharedpreferences = this.contextReference.get().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + account.setToken(token); + account.setClient_id(client_id); + account.setClient_secret(client_secret); + account.setRefresh_token(refresh_token); + account.setInstance(instance); + SQLiteDatabase db = Sqlite.getInstance(this.contextReference.get().getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + boolean userExists = new AccountDAO(this.contextReference.get(), db).userExist(account); + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(Helper.PREF_KEY_ID, account.getId()); + editor.putBoolean(Helper.PREF_IS_MODERATOR, account.isModerator()); + editor.putBoolean(Helper.PREF_IS_ADMINISTRATOR, account.isAdmin()); + editor.putString(Helper.PREF_INSTANCE, instance); + editor.apply(); + if (userExists) + new AccountDAO(this.contextReference.get(), db).updateAccountCredential(account); + else { + if (account.getUsername() != null && account.getCreated_at() != null) + new AccountDAO(this.contextReference.get(), db).insertAccount(account); + } + + return null; + } + + @Override + protected void onPostExecute(Void result) { + + if (this.contextReference.get() != null) { + Intent mainActivity = new Intent(this.contextReference.get(), MainActivity.class); + mainActivity.putExtra(Helper.INTENT_ACTION, Helper.ADD_USER_INTENT); + this.contextReference.get().startActivity(mainActivity); + ((Activity) this.contextReference.get()).finish(); + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java b/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java index b71c8c1..a402a08 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java +++ b/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java @@ -59,6 +59,7 @@ public class Helper { public static final int VIDEO_MODE_TORRENT = 0; public static final int VIDEO_MODE_WEBVIEW = 1; public static final int VIDEO_MODE_DIRECT = 2; + public static final int ADD_USER_INTENT = 5; public static final String SET_SHARE_DETAILS = "set_share_details"; public static final int DEFAULT_VIDEO_CACHE_MB = 100; public static final String TAG = "mastodon_etalab"; @@ -159,7 +160,7 @@ public class Helper { * @param acad String academic domain name * @return String the peertube URL */ - private static String getPeertubeUrl(String acad) { + public static String getPeertubeUrl(String acad) { return "tube-" + acad.replaceAll("ac-|\\.fr", "") + ".beta.education.fr"; } @@ -362,7 +363,7 @@ public class Helper { if (url.startsWith("/")) { url = Helper.getLiveInstance(context) + url; } - if( !url.startsWith("http")){ + if (!url.startsWith("http")) { url = "https://" + url; } try { diff --git a/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnPostStatusActionInterface.java b/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnPostStatusActionInterface.java new file mode 100644 index 0000000..ad14112 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnPostStatusActionInterface.java @@ -0,0 +1,8 @@ +package app.fedilab.fedilabtube.interfaces; + + +import app.fedilab.fedilabtube.client.APIResponse; + +public interface OnPostStatusActionInterface { + void onPostStatusAction(APIResponse apiResponse); +} diff --git a/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml b/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml index bab545a..c9d2255 100644 --- a/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml +++ b/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml @@ -1,10 +1,10 @@ - + android:viewportHeight="24"> + diff --git a/app/src/main/res/drawable/ic_baseline_edit_24.xml b/app/src/main/res/drawable/ic_baseline_edit_24.xml index 2844baf..5fb90ad 100644 --- a/app/src/main/res/drawable/ic_baseline_edit_24.xml +++ b/app/src/main/res/drawable/ic_baseline_edit_24.xml @@ -1,10 +1,10 @@ - + android:viewportHeight="24"> + diff --git a/app/src/main/res/drawable/ic_baseline_more_vert_24.xml b/app/src/main/res/drawable/ic_baseline_more_vert_24.xml index 34b93ec..14ff51e 100644 --- a/app/src/main/res/drawable/ic_baseline_more_vert_24.xml +++ b/app/src/main/res/drawable/ic_baseline_more_vert_24.xml @@ -1,10 +1,10 @@ - + android:viewportHeight="24"> + diff --git a/app/src/main/res/drawable/ic_baseline_track_changes_24.xml b/app/src/main/res/drawable/ic_baseline_track_changes_24.xml index 0909be1..489b286 100644 --- a/app/src/main/res/drawable/ic_baseline_track_changes_24.xml +++ b/app/src/main/res/drawable/ic_baseline_track_changes_24.xml @@ -1,10 +1,10 @@ - + android:viewportHeight="24"> + diff --git a/app/src/main/res/drawable/ic_launcher.png b/app/src/main/res/drawable/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..5c7ff54904d08b331c89bae4dd53460018606ca6 GIT binary patch literal 16541 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index 74f2585..5271fa5 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -1,15 +1,16 @@ - - - + android:viewportHeight="108"> + + + diff --git a/app/src/main/res/drawable/red_border.xml b/app/src/main/res/drawable/red_border.xml new file mode 100644 index 0000000..24f709a --- /dev/null +++ b/app/src/main/res/drawable/red_border.xml @@ -0,0 +1,13 @@ + + + + + + \ 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 new file mode 100644 index 0000000..fb0e5fb --- /dev/null +++ b/app/src/main/res/layout/activity_login.xml @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +