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