diff --git a/app/build.gradle b/app/build.gradle
index 755132b..9d8e175 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -38,7 +38,6 @@ allprojects {
}
dependencies {
-
implementation "androidx.multidex:multidex:2.0.1"
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.1.0'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ca41210..3e73c03 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -46,6 +46,14 @@
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
android:windowSoftInputMode="stateAlwaysHidden" />
+
+
+
diff --git a/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java b/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java
new file mode 100644
index 0000000..a27aa84
--- /dev/null
+++ b/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java
@@ -0,0 +1,489 @@
+package app.fedilab.fedilabtube;
+
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.ColorStateList;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.Html;
+import android.text.SpannableString;
+import android.text.method.LinkMovementMethod;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+import androidx.viewpager.widget.PagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+
+import com.bumptech.glide.Glide;
+import com.google.android.material.appbar.AppBarLayout;
+import com.google.android.material.tabs.TabLayout;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import app.fedilab.fedilabtube.asynctasks.PostActionAsyncTask;
+import app.fedilab.fedilabtube.asynctasks.RetrieveFeedsAsyncTask;
+import app.fedilab.fedilabtube.asynctasks.RetrieveRelationshipAsyncTask;
+import app.fedilab.fedilabtube.client.APIResponse;
+import app.fedilab.fedilabtube.client.PeertubeAPI;
+import app.fedilab.fedilabtube.client.entities.Account;
+import app.fedilab.fedilabtube.client.entities.Error;
+import app.fedilab.fedilabtube.client.entities.InstanceNodeInfo;
+import app.fedilab.fedilabtube.client.entities.Relationship;
+import app.fedilab.fedilabtube.client.entities.Status;
+import app.fedilab.fedilabtube.client.entities.StatusDrawerParams;
+import app.fedilab.fedilabtube.drawer.StatusListAdapter;
+import app.fedilab.fedilabtube.fragment.DisplayAccountsFragment;
+import app.fedilab.fedilabtube.fragment.DisplayStatusFragment;
+import app.fedilab.fedilabtube.helper.Helper;
+import app.fedilab.fedilabtube.interfaces.OnPostActionInterface;
+import app.fedilab.fedilabtube.interfaces.OnRetrieveFeedsAccountInterface;
+import app.fedilab.fedilabtube.interfaces.OnRetrieveFeedsInterface;
+import app.fedilab.fedilabtube.interfaces.OnRetrieveRelationshipInterface;
+import app.fedilab.fedilabtube.sqlite.AccountDAO;
+import app.fedilab.fedilabtube.sqlite.Sqlite;
+import es.dmoral.toasty.Toasty;
+
+import static androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY;
+import static app.fedilab.fedilabtube.helper.Helper.getLiveInstance;
+
+
+public class ShowAccountActivity extends AppCompatActivity implements OnPostActionInterface, OnRetrieveFeedsAccountInterface, OnRetrieveRelationshipInterface, OnRetrieveFeedsInterface {
+
+
+ private List statuses;
+ private StatusListAdapter statusListAdapter;
+ private ImageButton account_follow;
+ private ViewPager mPager;
+ private TabLayout tabLayout;
+ private TextView account_note;
+ private String userId;
+ private Relationship relationship;
+ private ImageButton header_edit_profile;
+ private List pins;
+ private int maxScrollSize;
+ private boolean avatarShown = true;
+ private ImageView account_pp;
+ private TextView account_dn;
+ private TextView account_un;
+ private Account account;
+ private String accountId;
+ private boolean ischannel;
+ private AsyncTask retrieveRelationship;
+ private action doAction;
+ private PeertubeAPI.StatusAction doActionAccount;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
+ setContentView(R.layout.activity_show_account);
+ setTitle("");
+ pins = new ArrayList<>();
+ Bundle b = getIntent().getExtras();
+ account_follow = findViewById(R.id.account_follow);
+ header_edit_profile = findViewById(R.id.header_edit_profile);
+ account_follow.setEnabled(false);
+ account_pp = findViewById(R.id.account_pp);
+ account_dn = findViewById(R.id.account_dn);
+ account_un = findViewById(R.id.account_un);
+ account_pp.setBackgroundResource(R.drawable.account_pp_border);
+ if (b != null) {
+ account = b.getParcelable("account");
+ if (account == null) {
+ accountId = b.getString("accountId");
+ } else {
+ accountId = account.getId();
+ }
+ ischannel = b.getBoolean("ischannel", false);
+ userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
+
+ } else {
+ Toasty.error(ShowAccountActivity.this, getString(R.string.toast_error_loading_account), Toast.LENGTH_LONG).show();
+ }
+ statuses = new ArrayList<>();
+ StatusDrawerParams statusDrawerParams = new StatusDrawerParams();
+ statusDrawerParams.setType(RetrieveFeedsAsyncTask.Type.USER);
+ statusDrawerParams.setTargetedId(accountId);
+ statusDrawerParams.setStatuses(statuses);
+ statusListAdapter = new StatusListAdapter(statusDrawerParams);
+
+
+ tabLayout = findViewById(R.id.account_tabLayout);
+ account_note = findViewById(R.id.account_note);
+
+
+ /*header_edit_profile.setOnClickListener(v -> {
+ Intent intent = new Intent(ShowAccountActivity.this, EditProfileActivity.class);
+ startActivity(intent);
+ });*/
+
+ ImageView action_back = findViewById(R.id.action_back);
+ action_back.setOnClickListener(v -> finish());
+ if (account != null) {
+ ManageAccount();
+ }
+ }
+
+ private void ManageAccount() {
+ SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
+
+ String accountIdRelation = account.getAcct();
+ retrieveRelationship = new RetrieveRelationshipAsyncTask(ShowAccountActivity.this, accountIdRelation, ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+
+ String urlHeader = account.getHeader();
+ if (urlHeader != null && urlHeader.startsWith("/")) {
+ urlHeader = "https://"+Helper.getLiveInstance(ShowAccountActivity.this) + account.getHeader();
+ }
+ if (urlHeader != null && !urlHeader.contains("missing.png")) {
+ ImageView banner_pp = findViewById(R.id.banner_pp);
+ Glide.with(banner_pp.getContext())
+ .load(urlHeader)
+ .into(banner_pp);
+ }
+ //Peertube account watched by a Mastodon account
+ //Bot account
+
+ TextView actionbar_title = findViewById(R.id.show_account_title);
+ if (account.getAcct() != null)
+ actionbar_title.setText(account.getAcct());
+ ImageView pp_actionBar = findViewById(R.id.pp_actionBar);
+ if (account.getAvatar() != null) {
+ Helper.loadGiF(ShowAccountActivity.this, account, pp_actionBar);
+
+ }
+ final AppBarLayout appBar = findViewById(R.id.appBar);
+ maxScrollSize = appBar.getTotalScrollRange();
+
+
+ //Timed muted account
+ String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
+ String instance = sharedpreferences.getString(Helper.PREF_INSTANCE, null);
+ final SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
+ final Account authenticatedAccount = new AccountDAO(ShowAccountActivity.this, db).getUniqAccount(userId, instance);
+
+ appBar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> {
+ LinearLayout toolbarContent = findViewById(R.id.toolbar_content);
+ if (toolbarContent != null) {
+ if (Math.abs(verticalOffset) - appBar.getTotalScrollRange() == 0) {
+ if (toolbarContent.getVisibility() == View.GONE)
+ toolbarContent.setVisibility(View.VISIBLE);
+ } else {
+ if (toolbarContent.getVisibility() == View.VISIBLE)
+ toolbarContent.setVisibility(View.GONE);
+ }
+ }
+ if (maxScrollSize == 0)
+ maxScrollSize = appBarLayout.getTotalScrollRange();
+
+ int percentage = (Math.abs(verticalOffset)) * 100 / maxScrollSize;
+
+ if (percentage >= 40 && avatarShown) {
+ avatarShown = false;
+
+ account_pp.animate()
+ .scaleY(0).scaleX(0)
+ .setDuration(400)
+ .start();
+ }
+ if (percentage <= 40 && !avatarShown) {
+ avatarShown = true;
+ account_pp.animate()
+ .scaleY(1).scaleX(1)
+ .start();
+ }
+ });
+ mPager = findViewById(R.id.account_viewpager);
+ if (!ischannel) {
+ tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.videos)));
+ tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.channels)));
+ mPager.setOffscreenPageLimit(2);
+ } else {
+ tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.videos)));
+ mPager.setOffscreenPageLimit(1);
+ }
+
+
+ PagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
+ mPager.setAdapter(mPagerAdapter);
+
+ mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ TabLayout.Tab tab = tabLayout.getTabAt(position);
+ if (tab != null)
+ tab.select();
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+
+ }
+ });
+
+ tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
+ @Override
+ public void onTabSelected(TabLayout.Tab tab) {
+ mPager.setCurrentItem(tab.getPosition());
+ }
+
+ @Override
+ public void onTabUnselected(TabLayout.Tab tab) {
+
+ }
+
+ @Override
+ public void onTabReselected(TabLayout.Tab tab) {
+ Fragment fragment = null;
+ if (mPager.getAdapter() != null)
+ fragment = (Fragment) mPager.getAdapter().instantiateItem(mPager, tab.getPosition());
+ switch (tab.getPosition()) {
+ case 0:
+ if (fragment != null) {
+ DisplayStatusFragment displayStatusFragment = ((DisplayStatusFragment) fragment);
+ displayStatusFragment.scrollToTop();
+ }
+ break;
+ case 1:
+ if (fragment != null) {
+ DisplayAccountsFragment displayAccountsFragment = ((DisplayAccountsFragment) fragment);
+ displayAccountsFragment.scrollToTop();
+ }
+ break;
+ }
+ }
+ });
+
+ account_dn.setText(account.getDisplay_name());
+ if (!ischannel || account.getAcct().split("-").length < 4) {
+ account_un.setText(String.format("@%s", account.getAcct()));
+ } else {
+ account_un.setVisibility(View.GONE);
+ }
+
+ SpannableString spannableString;
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
+ spannableString = new SpannableString(Html.fromHtml(account.getNote(), FROM_HTML_MODE_LEGACY));
+ else
+ spannableString = new SpannableString(Html.fromHtml(account.getNote()));
+
+ account.setNoteSpan(spannableString);
+ account_note.setText(account.getNoteSpan(), TextView.BufferType.SPANNABLE);
+ account_note.setMovementMethod(LinkMovementMethod.getInstance());
+ Helper.loadGiF(ShowAccountActivity.this, account, account_pp);
+ //Follow button
+ String target = account.getAcct();
+ String finalTarget = target;
+ account_follow.setOnClickListener(v -> {
+ if (doAction == action.NOTHING) {
+ Toasty.info(ShowAccountActivity.this, getString(R.string.nothing_to_do), Toast.LENGTH_LONG).show();
+ } else if (doAction == action.FOLLOW) {
+ account_follow.setEnabled(false);
+ new PostActionAsyncTask(ShowAccountActivity.this, PeertubeAPI.StatusAction.FOLLOW, finalTarget, ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ } else if (doAction == action.UNFOLLOW) {
+ boolean confirm_unfollow = sharedpreferences.getBoolean(Helper.SET_UNFOLLOW_VALIDATION, true);
+ if (confirm_unfollow) {
+ AlertDialog.Builder unfollowConfirm = new AlertDialog.Builder(ShowAccountActivity.this);
+ unfollowConfirm.setTitle(getString(R.string.unfollow_confirm));
+ unfollowConfirm.setMessage(account.getAcct());
+ unfollowConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
+ unfollowConfirm.setPositiveButton(R.string.yes, (dialog, which) -> {
+ account_follow.setEnabled(false);
+ new PostActionAsyncTask(ShowAccountActivity.this, PeertubeAPI.StatusAction.UNFOLLOW, finalTarget, ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ dialog.dismiss();
+ });
+ unfollowConfirm.show();
+ } else {
+ account_follow.setEnabled(false);
+ new PostActionAsyncTask(ShowAccountActivity.this, PeertubeAPI.StatusAction.UNFOLLOW, finalTarget, ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ }
+ });
+
+
+ TextView account_date = findViewById(R.id.account_date);
+ account_date.setText(Helper.shortDateToString(account.getCreated_at()));
+ account_date.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onRetrieveFeedsAccount(List statuses) {
+ if (statuses != null) {
+ this.statuses.addAll(statuses);
+ statusListAdapter.notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onRetrieveFeeds(APIResponse apiResponse) {
+ if (apiResponse.getError() != null) {
+ Toasty.error(ShowAccountActivity.this, apiResponse.getError().getError(), Toast.LENGTH_LONG).show();
+ return;
+ }
+ }
+
+ @Override
+ public void onRetrieveRelationship(Relationship relationship, Error error) {
+
+ if (error != null) {
+ Toasty.error(ShowAccountActivity.this, error.getError(), Toast.LENGTH_LONG).show();
+ return;
+ }
+ this.relationship = relationship;
+ manageButtonVisibility();
+
+
+ //The authenticated account is followed by the account
+ if (relationship != null && relationship.isFollowed_by() && !accountId.equals(userId)) {
+ TextView account_followed_by = findViewById(R.id.account_followed_by);
+ account_followed_by.setVisibility(View.VISIBLE);
+ }
+ invalidateOptionsMenu();
+
+ }
+
+ //Manages the visibility of the button
+ private void manageButtonVisibility() {
+ if (relationship == null)
+ return;
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ int[][] states = new int[][]{
+ new int[]{android.R.attr.state_enabled}, // enabled
+ new int[]{-android.R.attr.state_enabled}, // disabled
+ new int[]{-android.R.attr.state_checked}, // unchecked
+ new int[]{android.R.attr.state_pressed} // pressed
+ };
+
+ int[] colors = new int[]{
+ ContextCompat.getColor(ShowAccountActivity.this, R.color.colorAccent),
+ ContextCompat.getColor(ShowAccountActivity.this, R.color.colorAccent),
+ ContextCompat.getColor(ShowAccountActivity.this, R.color.colorAccent),
+ ContextCompat.getColor(ShowAccountActivity.this, R.color.colorAccent)
+ };
+ account_follow.setBackgroundTintList(new ColorStateList(states, colors));
+ }
+ account_follow.setEnabled(true);
+ if (relationship.isFollowing()) {
+ account_follow.setImageResource(R.drawable.ic_user_minus);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ account_follow.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(ShowAccountActivity.this, R.color.red_1)));
+ }
+ doAction = action.UNFOLLOW;
+ account_follow.setContentDescription(getString(R.string.action_unfollow));
+ account_follow.setVisibility(View.VISIBLE);
+ } else if (!relationship.isFollowing()) {
+ account_follow.setImageResource(R.drawable.ic_user_plus);
+ doAction = action.FOLLOW;
+ account_follow.setVisibility(View.VISIBLE);
+ account_follow.setContentDescription(getString(R.string.action_follow));
+ } else {
+ account_follow.setVisibility(View.GONE);
+ doAction = action.NOTHING;
+ }
+ }
+
+
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (retrieveRelationship != null && !retrieveRelationship.isCancelled()) {
+ retrieveRelationship.cancel(true);
+ }
+ }
+
+ @Override
+ public void onPostAction(int statusCode, PeertubeAPI.StatusAction statusAction, String targetedId, Error error) {
+
+ if (error != null) {
+ Toasty.error(ShowAccountActivity.this, error.getError(), Toast.LENGTH_LONG).show();
+ return;
+ }
+ String target = account.getAcct();
+ //IF action is unfollow or mute, sends an intent to remove statuses
+ if (statusAction == PeertubeAPI.StatusAction.UNFOLLOW ) {
+ Bundle b = new Bundle();
+ b.putString("receive_action", targetedId);
+ Intent intentBC = new Intent(Helper.RECEIVE_ACTION);
+ intentBC.putExtras(b);
+ }
+ retrieveRelationship = new RetrieveRelationshipAsyncTask(ShowAccountActivity.this, target, ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+
+
+ public enum action {
+ FOLLOW,
+ UNFOLLOW,
+ NOTHING
+ }
+
+ /**
+ * Pager adapter for the 4 fragments
+ */
+ private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
+
+ ScreenSlidePagerAdapter(FragmentManager fm) {
+ super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
+ }
+
+ @NotNull
+ @Override
+ public Fragment getItem(int position) {
+ Bundle bundle = new Bundle();
+ if (position == 0) {
+ DisplayStatusFragment displayStatusFragment = new DisplayStatusFragment();
+ bundle = new Bundle();
+ bundle.putSerializable("type", RetrieveFeedsAsyncTask.Type.USER);
+ bundle.putString("targetedid", account.getAcct());
+ bundle.putBoolean("showReply", false);
+ bundle.putBoolean("ischannel", ischannel);
+ displayStatusFragment.setArguments(bundle);
+ return displayStatusFragment;
+ }
+ DisplayAccountsFragment displayAccountsFragment = new DisplayAccountsFragment();
+ bundle.putString("targetedid", account.getId());
+ bundle.putString("instance", getLiveInstance(ShowAccountActivity.this));
+ bundle.putString("name", account.getAcct());
+ displayAccountsFragment.setArguments(bundle);
+ return displayAccountsFragment;
+ }
+
+
+ @Override
+ public int getCount() {
+ if (ischannel)
+ return 1;
+ else
+ return 2;
+ }
+ }
+
+}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveAccountAsyncTask.java b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveAccountAsyncTask.java
new file mode 100644
index 0000000..af4c148
--- /dev/null
+++ b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveAccountAsyncTask.java
@@ -0,0 +1,43 @@
+
+package app.fedilab.fedilabtube.asynctasks;
+
+import android.content.Context;
+import android.os.AsyncTask;
+
+import java.lang.ref.WeakReference;
+
+import app.fedilab.fedilabtube.client.PeertubeAPI;
+import app.fedilab.fedilabtube.client.entities.Account;
+import app.fedilab.fedilabtube.client.entities.Error;
+import app.fedilab.fedilabtube.interfaces.OnRetrieveAccountInterface;
+
+
+public class RetrieveAccountAsyncTask extends AsyncTask {
+
+
+ private String targetedId;
+ private Account account;
+ private OnRetrieveAccountInterface listener;
+ private Error error;
+ private WeakReference contextReference;
+
+ public RetrieveAccountAsyncTask(Context context, String targetedId, OnRetrieveAccountInterface onRetrieveAccountInterface) {
+ this.contextReference = new WeakReference<>(context);
+ this.targetedId = targetedId;
+ this.listener = onRetrieveAccountInterface;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ PeertubeAPI peertubeAPI = new PeertubeAPI(this.contextReference.get());
+ account = peertubeAPI.getAccount(targetedId);
+ error = peertubeAPI.getError();
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ listener.onRetrieveAccount(account, error);
+ }
+
+}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveAccountsAsyncTask.java b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveAccountsAsyncTask.java
new file mode 100644
index 0000000..60dc62b
--- /dev/null
+++ b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveAccountsAsyncTask.java
@@ -0,0 +1,41 @@
+
+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.interfaces.OnRetrieveAccountsInterface;
+
+
+public class RetrieveAccountsAsyncTask extends AsyncTask {
+
+ private APIResponse apiResponse;
+ private OnRetrieveAccountsInterface listener;
+ private WeakReference contextReference;
+ private String name;
+
+ public RetrieveAccountsAsyncTask(Context context, String name, OnRetrieveAccountsInterface onRetrieveAccountsInterface) {
+ this.contextReference = new WeakReference<>(context);
+ this.name = name;
+ this.listener = onRetrieveAccountsInterface;
+ }
+
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ PeertubeAPI peertubeAPI = new PeertubeAPI(this.contextReference.get());
+ apiResponse = peertubeAPI.getPeertubeChannel(name);
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ listener.onRetrieveAccounts(apiResponse);
+ }
+
+
+}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveRelationshipAsyncTask.java b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveRelationshipAsyncTask.java
new file mode 100644
index 0000000..4f2c114
--- /dev/null
+++ b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveRelationshipAsyncTask.java
@@ -0,0 +1,45 @@
+
+package app.fedilab.fedilabtube.asynctasks;
+
+import android.content.Context;
+import android.os.AsyncTask;
+
+import java.lang.ref.WeakReference;
+
+import app.fedilab.fedilabtube.client.PeertubeAPI;
+import app.fedilab.fedilabtube.client.entities.Error;
+import app.fedilab.fedilabtube.client.entities.Relationship;
+import app.fedilab.fedilabtube.interfaces.OnRetrieveRelationshipInterface;
+
+
+public class RetrieveRelationshipAsyncTask extends AsyncTask {
+
+
+ private String accountId;
+ private Relationship relationship;
+ private OnRetrieveRelationshipInterface listener;
+ private Error error;
+ private WeakReference contextReference;
+
+ public RetrieveRelationshipAsyncTask(Context context, String accountId, OnRetrieveRelationshipInterface onRetrieveRelationshipInterface) {
+ this.contextReference = new WeakReference<>(context);
+ this.listener = onRetrieveRelationshipInterface;
+ this.accountId = accountId;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+
+ PeertubeAPI api = new PeertubeAPI(this.contextReference.get());
+ relationship = new Relationship();
+ relationship.setFollowing(api.isFollowing(accountId));
+ error = api.getError();
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ listener.onRetrieveRelationship(relationship, error);
+ }
+
+}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeAPI.java b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeAPI.java
index c8d9089..17aa534 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeAPI.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeAPI.java
@@ -420,7 +420,7 @@ public class PeertubeAPI {
account.setDisplay_name(accountObject.get("name").toString());
account.setHost(accountObject.get("host").toString());
account.setSocial("PEERTUBE");
-
+ account.setInstance(accountObject.getString("host"));
if (accountObject.has("createdAt"))
account.setCreated_at(Helper.mstStringToDate(accountObject.get("createdAt").toString()));
else
diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/Relationship.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/Relationship.java
new file mode 100644
index 0000000..a3c83dc
--- /dev/null
+++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/Relationship.java
@@ -0,0 +1,96 @@
+package app.fedilab.fedilabtube.client.entities;
+
+public class Relationship {
+
+ private String id;
+ private boolean following;
+ private boolean followed_by;
+ private boolean blocking;
+ private boolean muting;
+ private boolean requested;
+ private boolean muting_notifications;
+ private boolean endorsed;
+ private boolean showing_reblogs;
+ private boolean blocked_by;
+
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public boolean isFollowing() {
+ return following;
+ }
+
+ public void setFollowing(boolean following) {
+ this.following = following;
+ }
+
+ public boolean isFollowed_by() {
+ return followed_by;
+ }
+
+ public void setFollowed_by(boolean followed_by) {
+ this.followed_by = followed_by;
+ }
+
+ public boolean isBlocking() {
+ return blocking;
+ }
+
+ public void setBlocking(boolean blocking) {
+ this.blocking = blocking;
+ }
+
+ public boolean isMuting() {
+ return muting;
+ }
+
+ public void setMuting(boolean muting) {
+ this.muting = muting;
+ }
+
+ public boolean isRequested() {
+ return requested;
+ }
+
+ public void setRequested(boolean requested) {
+ this.requested = requested;
+ }
+
+ public boolean isMuting_notifications() {
+ return muting_notifications;
+ }
+
+ public void setMuting_notifications(boolean muting_notifications) {
+ this.muting_notifications = muting_notifications;
+ }
+
+ public boolean isEndorsed() {
+ return endorsed;
+ }
+
+ public void setEndorsed(boolean endorsed) {
+ this.endorsed = endorsed;
+ }
+
+ public boolean isShowing_reblogs() {
+ return showing_reblogs;
+ }
+
+ public void setShowing_reblogs(boolean showing_reblogs) {
+ this.showing_reblogs = showing_reblogs;
+ }
+
+ public boolean isBlocked_by() {
+ return blocked_by;
+ }
+
+ public void setBlocked_by(boolean blocked_by) {
+ this.blocked_by = blocked_by;
+ }
+}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/drawer/AccountsListAdapter.java b/app/src/main/java/app/fedilab/fedilabtube/drawer/AccountsListAdapter.java
new file mode 100644
index 0000000..52a144b
--- /dev/null
+++ b/app/src/main/java/app/fedilab/fedilabtube/drawer/AccountsListAdapter.java
@@ -0,0 +1,199 @@
+package app.fedilab.fedilabtube.drawer;
+
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.Html;
+import android.text.util.Linkify;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+
+import java.util.List;
+
+import app.fedilab.fedilabtube.R;
+import app.fedilab.fedilabtube.ShowAccountActivity;
+import app.fedilab.fedilabtube.client.PeertubeAPI;
+import app.fedilab.fedilabtube.client.entities.Account;
+import app.fedilab.fedilabtube.client.entities.Error;
+import app.fedilab.fedilabtube.helper.Helper;
+import app.fedilab.fedilabtube.interfaces.OnPostActionInterface;
+import es.dmoral.toasty.Toasty;
+
+
+
+public class AccountsListAdapter extends RecyclerView.Adapter implements OnPostActionInterface {
+
+ private List accounts;
+
+ private Context context;
+ private AccountsListAdapter accountsListAdapter;
+ private String targetedId;
+
+ public AccountsListAdapter(String targetedId, List accounts) {
+ this.accounts = accounts;
+ this.accountsListAdapter = this;
+ this.targetedId = targetedId;
+ }
+
+
+ @NonNull
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ context = parent.getContext();
+ LayoutInflater layoutInflater = LayoutInflater.from(context);
+ return new ViewHolder(layoutInflater.inflate(R.layout.drawer_account, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
+ final AccountsListAdapter.ViewHolder holder = (AccountsListAdapter.ViewHolder) viewHolder;
+ final Account account = accounts.get(position);
+
+
+ PeertubeAPI.StatusAction doAction = null;
+ holder.account_follow.hide();
+
+ if (account.getDisplay_name() != null && !account.getDisplay_name().trim().equals(""))
+ holder.account_dn.setText(account.getDisplay_name());
+ else
+ holder.account_dn.setText(account.getUsername().replace("@", ""));
+ holder.account_un.setText(String.format("@%s", account.getUsername()));
+ holder.account_ac.setText(account.getAcct());
+ if (account.getUsername().equals(account.getAcct()))
+ holder.account_ac.setVisibility(View.GONE);
+ else
+ holder.account_ac.setVisibility(View.VISIBLE);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
+ holder.account_ds.setText(Html.fromHtml(account.getNote(), Html.FROM_HTML_MODE_LEGACY));
+ else
+ holder.account_ds.setText(Html.fromHtml(account.getNote()));
+ holder.account_ds.setAutoLinkMask(Linkify.WEB_URLS);
+ holder.account_sc.setText(Helper.withSuffix(account.getStatuses_count()));
+ holder.account_fgc.setText(Helper.withSuffix(account.getFollowing_count()));
+ holder.account_frc.setText(Helper.withSuffix(account.getFollowers_count()));
+ //Profile picture
+ Helper.loadGiF(context, account, holder.account_pp);
+ if (account.isMakingAction()) {
+ holder.account_follow.setEnabled(false);
+ } else {
+ holder.account_follow.setEnabled(true);
+ }
+ //Follow button
+ PeertubeAPI.StatusAction finalDoAction = doAction;
+ holder.account_follow.setOnClickListener(v -> {
+
+ });
+ Intent intent = new Intent(context, ShowAccountActivity.class);
+ Bundle b = new Bundle();
+ b.putBoolean("peertubeaccount", true);
+ b.putBoolean("ischannel", true);
+ b.putString("targetedid", account.getAcct());
+ b.putParcelable("account", account);
+ intent.putExtras(b);
+ context.startActivity(intent);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemCount() {
+ return accounts.size();
+ }
+
+ private Account getItemAt(int position) {
+ if (accounts.size() > position)
+ return accounts.get(position);
+ else
+ return null;
+ }
+
+ @Override
+ public void onPostAction(int statusCode, PeertubeAPI.StatusAction statusAction, String targetedId, Error error) {
+ if (error != null) {
+ Toasty.error(context, error.getError(), Toast.LENGTH_LONG).show();
+ return;
+ }
+ /*
+ if (statusAction == PeertubeAPI.StatusAction.FOLLOW) {
+ if (action == RetrieveAccountsAsyncTask.Type.CHANNELS) {
+ SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
+ new InstancesDAO(context, db).insertInstance(accounts.get(0).getAcct().split("@")[1], accounts.get(0).getAcct().split("@")[0], "PEERTUBE_CHANNEL");
+ } else {
+ for (Account account : accounts) {
+ if (account.getId().equals(targetedId)) {
+ account.setFollowType(Account.followAction.FOLLOW);
+ account.setMakingAction(false);
+ }
+ }
+ accountsListAdapter.notifyDataSetChanged();
+ }
+ }
+ if (statusAction == PeertubeAPI.StatusAction.UNFOLLOW) {
+ for (Account account : accounts) {
+ if (account.getId().equals(targetedId)) {
+ account.setFollowType(Account.followAction.NOT_FOLLOW);
+ account.setMakingAction(false);
+ }
+ }
+ accountsListAdapter.notifyDataSetChanged();
+ }*/
+ }
+
+ private void notifyAccountChanged(Account account) {
+ for (int i = 0; i < accountsListAdapter.getItemCount(); i++) {
+ //noinspection ConstantConditions
+ if (accountsListAdapter.getItemAt(i) != null && accountsListAdapter.getItemAt(i).getId().equals(account.getId())) {
+ try {
+ accountsListAdapter.notifyItemChanged(i);
+ } catch (Exception ignored) {
+ }
+ }
+ }
+ }
+
+
+ private static class ViewHolder extends RecyclerView.ViewHolder {
+ ImageView account_pp;
+ TextView account_ac;
+ TextView account_dn;
+ TextView account_un;
+ TextView account_ds;
+ TextView account_sc;
+ TextView account_fgc;
+ TextView account_frc;
+ LinearLayout account_info;
+ FloatingActionButton account_follow;
+ LinearLayout account_container;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+ account_pp = itemView.findViewById(R.id.account_pp);
+ account_dn = itemView.findViewById(R.id.account_dn);
+ account_ac = itemView.findViewById(R.id.account_ac);
+ account_un = itemView.findViewById(R.id.account_un);
+ account_ds = itemView.findViewById(R.id.account_ds);
+ account_sc = itemView.findViewById(R.id.account_sc);
+ account_fgc = itemView.findViewById(R.id.account_fgc);
+ account_frc = itemView.findViewById(R.id.account_frc);
+ account_follow = itemView.findViewById(R.id.account_follow);
+ account_info = itemView.findViewById(R.id.account_info);
+ account_container = itemView.findViewById(R.id.account_container);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/app/fedilab/fedilabtube/drawer/PeertubeAdapter.java b/app/src/main/java/app/fedilab/fedilabtube/drawer/PeertubeAdapter.java
index 2a6249f..1972796 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/drawer/PeertubeAdapter.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/drawer/PeertubeAdapter.java
@@ -3,6 +3,7 @@ package app.fedilab.fedilabtube.drawer;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -20,6 +21,7 @@ import java.util.List;
import app.fedilab.fedilabtube.PeertubeActivity;
import app.fedilab.fedilabtube.R;
+import app.fedilab.fedilabtube.ShowAccountActivity;
import app.fedilab.fedilabtube.client.APIResponse;
import app.fedilab.fedilabtube.client.entities.Account;
import app.fedilab.fedilabtube.client.entities.Peertube;
@@ -32,6 +34,7 @@ public class PeertubeAdapter extends RecyclerView.Adapter peertubes;
private Context context;
+ private boolean ownVideos;
public PeertubeAdapter(List peertubes) {
this.peertubes = peertubes;
@@ -56,13 +59,18 @@ public class PeertubeAdapter extends RecyclerView.Adapter {
+ Intent intent = new Intent(context, ShowAccountActivity.class);
+ Bundle b = new Bundle();
+ b.putParcelable("account", peertube.getAccount());
+ intent.putExtras(b);
+ context.startActivity(intent);
+ });
+ }
if (peertube.getHeaderType() != null && peertube.getHeaderTypeValue() != null) {
String type = peertube.getHeaderType();
diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayAccountsFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayAccountsFragment.java
new file mode 100644
index 0000000..e4a5a51
--- /dev/null
+++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayAccountsFragment.java
@@ -0,0 +1,181 @@
+package app.fedilab.fedilabtube.fragment;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import app.fedilab.fedilabtube.R;
+import app.fedilab.fedilabtube.asynctasks.RetrieveAccountsAsyncTask;
+import app.fedilab.fedilabtube.client.APIResponse;
+import app.fedilab.fedilabtube.client.entities.Account;
+import app.fedilab.fedilabtube.drawer.AccountsListAdapter;
+import app.fedilab.fedilabtube.interfaces.OnRetrieveAccountsInterface;
+import es.dmoral.toasty.Toasty;
+
+
+public class DisplayAccountsFragment extends Fragment implements OnRetrieveAccountsInterface {
+
+ private boolean flag_loading;
+ private Context context;
+ private AsyncTask asyncTask;
+ private AccountsListAdapter accountsListAdapter;
+ private String max_id;
+ private List accounts;
+ private RelativeLayout mainLoader, nextElementLoader, textviewNoAction;
+ private boolean firstLoad;
+ private SwipeRefreshLayout swipeRefreshLayout;
+ private String targetedId, name;
+ private boolean swiped;
+ private RecyclerView lv_accounts;
+ private View rootView;
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+ rootView = inflater.inflate(R.layout.fragment_accounts, container, false);
+
+ context = getContext();
+ Bundle bundle = this.getArguments();
+ accounts = new ArrayList<>();
+ if (bundle != null) {
+ if (bundle.containsKey("tag"))
+ targetedId = bundle.getString("tag", null);
+ else
+ targetedId = bundle.getString("targetedid", null);
+ name = bundle.getString("name", null);
+ }
+ max_id = null;
+ firstLoad = true;
+ flag_loading = true;
+ swiped = false;
+
+ swipeRefreshLayout = rootView.findViewById(R.id.swipeContainer);
+
+
+ lv_accounts = rootView.findViewById(R.id.lv_accounts);
+ lv_accounts.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL));
+ mainLoader = rootView.findViewById(R.id.loader);
+ nextElementLoader = rootView.findViewById(R.id.loading_next_accounts);
+ textviewNoAction = rootView.findViewById(R.id.no_action);
+ mainLoader.setVisibility(View.VISIBLE);
+ nextElementLoader.setVisibility(View.GONE);
+ accountsListAdapter = new AccountsListAdapter(targetedId, this.accounts);
+ lv_accounts.setAdapter(accountsListAdapter);
+
+ final LinearLayoutManager mLayoutManager;
+ mLayoutManager = new LinearLayoutManager(context);
+ lv_accounts.setLayoutManager(mLayoutManager);
+ lv_accounts.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
+ if (dy > 0) {
+ int visibleItemCount = mLayoutManager.getChildCount();
+ int totalItemCount = mLayoutManager.getItemCount();
+ int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
+ if (firstVisibleItem + visibleItemCount == totalItemCount) {
+ if (!flag_loading) {
+ flag_loading = true;
+ asyncTask = new RetrieveAccountsAsyncTask(context, name, DisplayAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ nextElementLoader.setVisibility(View.VISIBLE);
+ }
+ } else {
+ nextElementLoader.setVisibility(View.GONE);
+ }
+ }
+ }
+ });
+ swipeRefreshLayout.setOnRefreshListener(this::pullToRefresh);
+
+ asyncTask = new RetrieveAccountsAsyncTask(context, name, DisplayAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ return rootView;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ rootView = null;
+ }
+
+ @Override
+ public void onCreate(Bundle saveInstance) {
+ super.onCreate(saveInstance);
+ }
+
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ this.context = context;
+ }
+
+ public void onDestroy() {
+ super.onDestroy();
+ if (asyncTask != null && asyncTask.getStatus() == AsyncTask.Status.RUNNING)
+ asyncTask.cancel(true);
+ }
+
+ public void scrollToTop() {
+ if (lv_accounts != null)
+ lv_accounts.setAdapter(accountsListAdapter);
+ }
+
+ @Override
+ public void onRetrieveAccounts(APIResponse apiResponse) {
+ mainLoader.setVisibility(View.GONE);
+ nextElementLoader.setVisibility(View.GONE);
+ if (apiResponse.getError() != null) {
+ Toasty.error(context, apiResponse.getError().getError(), Toast.LENGTH_LONG).show();
+ swipeRefreshLayout.setRefreshing(false);
+ swiped = false;
+ flag_loading = false;
+ return;
+ }
+ flag_loading = (apiResponse.getMax_id() == null);
+
+ List accounts = apiResponse.getAccounts();
+ if (!swiped && firstLoad && (accounts == null || accounts.size() == 0))
+ textviewNoAction.setVisibility(View.VISIBLE);
+ else
+ textviewNoAction.setVisibility(View.GONE);
+
+ max_id = apiResponse.getMax_id();
+
+ if (swiped) {
+ accountsListAdapter = new AccountsListAdapter(targetedId, this.accounts);
+ lv_accounts.setAdapter(accountsListAdapter);
+ swiped = false;
+ }
+ if (accounts != null && accounts.size() > 0) {
+ int currentPosition = this.accounts.size();
+ this.accounts.addAll(accounts);
+ accountsListAdapter.notifyItemRangeChanged(currentPosition, accounts.size());
+ }
+ swipeRefreshLayout.setRefreshing(false);
+ firstLoad = false;
+ }
+
+ public void pullToRefresh() {
+ max_id = null;
+ accounts = new ArrayList<>();
+ firstLoad = true;
+ flag_loading = true;
+ swiped = true;
+ swipeRefreshLayout.setRefreshing(true);
+ asyncTask = new RetrieveAccountsAsyncTask(context, name, DisplayAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+}
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 75cca29..9701a58 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java
@@ -35,13 +35,11 @@ import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
+
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Date;
-import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.regex.Pattern;
@@ -118,6 +116,8 @@ public class Helper {
public static final String SET_CUSTOM_TABS = "set_custom_tabs";
public static final String SET_DISPLAY_CONFIRM = "set_display_confirm";
public static final String INTENT_ADD_UPLOADED_MEDIA = "intent_add_uploaded_media";
+ public static final String RECEIVE_ACTION = "receive_action";
+ public static final String SET_UNFOLLOW_VALIDATION = "set_unfollow_validation";
//List of available academies
public static String[] academies = {
@@ -308,6 +308,17 @@ public class Helper {
}
}
+ /**
+ * Convert a date in String -> format yyyy-MM-dd HH:mm:ss
+ *
+ * @param date Date
+ * @return String
+ */
+ public static String shortDateToString(Date date) {
+ SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
+ return df.format(date);
+ }
+
public static String dateDiffFull(Date dateToot) {
SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM, Locale.getDefault());
diff --git a/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnRetrieveAccountInterface.java b/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnRetrieveAccountInterface.java
new file mode 100644
index 0000000..13acd2c
--- /dev/null
+++ b/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnRetrieveAccountInterface.java
@@ -0,0 +1,9 @@
+package app.fedilab.fedilabtube.interfaces;
+
+
+import app.fedilab.fedilabtube.client.entities.Account;
+import app.fedilab.fedilabtube.client.entities.Error;
+
+public interface OnRetrieveAccountInterface {
+ void onRetrieveAccount(Account account, Error error);
+}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnRetrieveAccountsInterface.java b/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnRetrieveAccountsInterface.java
new file mode 100644
index 0000000..97cee4d
--- /dev/null
+++ b/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnRetrieveAccountsInterface.java
@@ -0,0 +1,8 @@
+package app.fedilab.fedilabtube.interfaces;
+
+
+import app.fedilab.fedilabtube.client.APIResponse;
+
+public interface OnRetrieveAccountsInterface {
+ void onRetrieveAccounts(APIResponse apiResponse);
+}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnRetrieveFeedsAccountInterface.java b/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnRetrieveFeedsAccountInterface.java
new file mode 100644
index 0000000..6719da4
--- /dev/null
+++ b/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnRetrieveFeedsAccountInterface.java
@@ -0,0 +1,10 @@
+
+package app.fedilab.fedilabtube.interfaces;
+
+
+import java.util.List;
+import app.fedilab.fedilabtube.client.entities.Status;
+
+public interface OnRetrieveFeedsAccountInterface {
+ void onRetrieveFeedsAccount(List statuses);
+}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnRetrieveRelationshipInterface.java b/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnRetrieveRelationshipInterface.java
new file mode 100644
index 0000000..83e73dc
--- /dev/null
+++ b/app/src/main/java/app/fedilab/fedilabtube/interfaces/OnRetrieveRelationshipInterface.java
@@ -0,0 +1,10 @@
+
+package app.fedilab.fedilabtube.interfaces;
+
+
+import app.fedilab.fedilabtube.client.entities.Error;
+import app.fedilab.fedilabtube.client.entities.Relationship;
+
+public interface OnRetrieveRelationshipInterface {
+ void onRetrieveRelationship(Relationship relationship, Error error);
+}
diff --git a/app/src/main/res/drawable/account_pp_border.xml b/app/src/main/res/drawable/account_pp_border.xml
new file mode 100644
index 0000000..d1f6b87
--- /dev/null
+++ b/app/src/main/res/drawable/account_pp_border.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/colored_border.xml b/app/src/main/res/drawable/colored_border.xml
new file mode 100644
index 0000000..320a81e
--- /dev/null
+++ b/app/src/main/res/drawable/colored_border.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/default_banner.xml b/app/src/main/res/drawable/default_banner.xml
new file mode 100644
index 0000000..2324a79
--- /dev/null
+++ b/app/src/main/res/drawable/default_banner.xml
@@ -0,0 +1,10 @@
+
+
+
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
new file mode 100644
index 0000000..bab545a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_edit_24.xml b/app/src/main/res/drawable/ic_baseline_edit_24.xml
new file mode 100644
index 0000000..2844baf
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_edit_24.xml
@@ -0,0 +1,10 @@
+
+
+
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
new file mode 100644
index 0000000..34b93ec
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_more_vert_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_user_minus.xml b/app/src/main/res/drawable/ic_user_minus.xml
new file mode 100644
index 0000000..07f4851
--- /dev/null
+++ b/app/src/main/res/drawable/ic_user_minus.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_user_plus.xml b/app/src/main/res/drawable/ic_user_plus.xml
new file mode 100644
index 0000000..d3db0c3
--- /dev/null
+++ b/app/src/main/res/drawable/ic_user_plus.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_show_account.xml b/app/src/main/res/layout/activity_show_account.xml
new file mode 100644
index 0000000..4a4ca1e
--- /dev/null
+++ b/app/src/main/res/layout/activity_show_account.xml
@@ -0,0 +1,434 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/drawer_account.xml b/app/src/main/res/layout/drawer_account.xml
new file mode 100644
index 0000000..7b1cca9
--- /dev/null
+++ b/app/src/main/res/layout/drawer_account.xml
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_accounts.xml b/app/src/main/res/layout/fragment_accounts.xml
new file mode 100644
index 0000000..e1e0e95
--- /dev/null
+++ b/app/src/main/res/layout/fragment_accounts.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 9523889..2ec01d2 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -7,4 +7,5 @@
#2b90d9
#F44336
+ #F44336
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 71cc1e3..05f7dd8 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -4,4 +4,5 @@
16dp
5dp
2dp
+ 180dp
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 0765224..8fe0dd0 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -97,4 +97,20 @@
Changer d\'instance
Compte
Choisissez une instance
+ Une erreur s’est produite pendant le chargement du compte !
+ Bannière du profil
+ Faire une action
+ Retour
+ Ouvrir le menu
+ Afficher plus
+ Éditer le profil
+ Vous suit
+ Aucune chaîne !
+ Suit
+ Abonné·e·s
+ Aucune action ne peut être réalisée
+ Voulez-vous vous désabonner de ce compte ?
+ Se désabonner
+ Suivre
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 8b1bcff..7c961c3 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -9,4 +9,14 @@
- @color/colorAccent
+
+
+
+
+
\ No newline at end of file