diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4bf6ef19..9299f85f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -55,8 +55,8 @@
android:name=".activities.ContextActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
+ android:name=".activities.DraftActivity"
+ android:configChanges="keyboardHidden|orientation|screenSize" />
+
diff --git a/app/src/main/java/app/fedilab/android/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/BaseMainActivity.java
index ed528220..e1ec26b5 100644
--- a/app/src/main/java/app/fedilab/android/BaseMainActivity.java
+++ b/app/src/main/java/app/fedilab/android/BaseMainActivity.java
@@ -83,6 +83,7 @@ import app.fedilab.android.activities.ComposeActivity;
import app.fedilab.android.activities.ContextActivity;
import app.fedilab.android.activities.DraftActivity;
import app.fedilab.android.activities.FilterActivity;
+import app.fedilab.android.activities.FollowRequestActivity;
import app.fedilab.android.activities.InstanceActivity;
import app.fedilab.android.activities.InstanceHealthActivity;
import app.fedilab.android.activities.LoginActivity;
@@ -333,6 +334,9 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
} else if (id == R.id.nav_scheduled) {
Intent intent = new Intent(this, ScheduledActivity.class);
startActivity(intent);
+ } else if (id == R.id.nav_follow_requests) {
+ Intent intent = new Intent(this, FollowRequestActivity.class);
+ startActivity(intent);
}
binding.drawerLayout.close();
return false;
@@ -564,7 +568,9 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
return;
}
bottomMenu = new BottomMenu(BaseMainActivity.this).hydrate(account, binding.bottomNavView);
-
+ if (account.mastodon_account.locked) {
+ binding.navView.getMenu().findItem(R.id.nav_follow_requests).setVisible(true);
+ }
if (bottomMenu != null) {
//ManageClick on bottom menu items
if (binding.bottomNavView.findViewById(R.id.nav_home) != null) {
diff --git a/app/src/main/java/app/fedilab/android/activities/FollowRequestActivity.java b/app/src/main/java/app/fedilab/android/activities/FollowRequestActivity.java
new file mode 100644
index 00000000..f869073a
--- /dev/null
+++ b/app/src/main/java/app/fedilab/android/activities/FollowRequestActivity.java
@@ -0,0 +1,127 @@
+package app.fedilab.android.activities;
+/* Copyright 2022 Thomas Schneider
+ *
+ * This file is a part of Fedilab
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Fedilab; if not,
+ * see . */
+
+
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.view.MenuItem;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import app.fedilab.android.BaseMainActivity;
+import app.fedilab.android.R;
+import app.fedilab.android.client.entities.api.Account;
+import app.fedilab.android.client.entities.api.Accounts;
+import app.fedilab.android.databinding.ActivityStatusInfoBinding;
+import app.fedilab.android.helper.MastodonHelper;
+import app.fedilab.android.helper.ThemeHelper;
+import app.fedilab.android.ui.drawer.AccountFollowRequestAdapter;
+import app.fedilab.android.viewmodel.mastodon.AccountsVM;
+
+
+public class FollowRequestActivity extends BaseActivity {
+
+ private ActivityStatusInfoBinding binding;
+ private List accountList;
+ private AccountFollowRequestAdapter accountAdapter;
+ private String max_id;
+ private boolean flagLoading;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ThemeHelper.applyTheme(this);
+ binding = ActivityStatusInfoBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+ setSupportActionBar(binding.toolbar);
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setDisplayShowHomeEnabled(true);
+ getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
+ }
+ accountList = new ArrayList<>();
+ flagLoading = false;
+ max_id = null;
+ binding.title.setText(R.string.follow_request);
+ AccountsVM accountsVM = new ViewModelProvider(FollowRequestActivity.this).get(AccountsVM.class);
+ accountAdapter = new AccountFollowRequestAdapter(accountList);
+ LinearLayoutManager mLayoutManager = new LinearLayoutManager(FollowRequestActivity.this);
+ binding.lvAccounts.setLayoutManager(mLayoutManager);
+ binding.lvAccounts.setAdapter(accountAdapter);
+
+ binding.lvAccounts.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
+ int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
+ if (dy > 0) {
+ int visibleItemCount = mLayoutManager.getChildCount();
+ int totalItemCount = mLayoutManager.getItemCount();
+ if (firstVisibleItem + visibleItemCount == totalItemCount) {
+ if (!flagLoading) {
+ flagLoading = true;
+ binding.loadingNextAccounts.setVisibility(View.VISIBLE);
+ accountsVM.getFollowRequests(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, max_id, MastodonHelper.accountsPerCall(FollowRequestActivity.this))
+ .observe(FollowRequestActivity.this, accounts -> manageView(accounts));
+ }
+ } else {
+ binding.loadingNextAccounts.setVisibility(View.GONE);
+ }
+ }
+ }
+ });
+ accountsVM.getFollowRequests(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, null, MastodonHelper.accountsPerCall(FollowRequestActivity.this))
+ .observe(FollowRequestActivity.this, this::manageView);
+ }
+
+ private void manageView(Accounts accounts) {
+ flagLoading = false;
+ binding.loadingNextAccounts.setVisibility(View.GONE);
+ if (accountList != null && accounts != null && accounts.accounts != null && accounts.accounts.size() > 0) {
+ int startId = 0;
+ //There are some statuses present in the timeline
+ if (accountList.size() > 0) {
+ startId = accountList.size();
+ }
+ accountList.addAll(accounts.accounts);
+ max_id = accounts.pagination.max_id;
+ accountAdapter.notifyItemRangeInserted(startId, accounts.accounts.size());
+ binding.noAction.setVisibility(View.GONE);
+ binding.lvAccounts.setVisibility(View.VISIBLE);
+ } else if (accountList == null || accountList.size() == 0) {
+ binding.noActionText.setText(R.string.no_follow_request);
+ binding.noAction.setVisibility(View.VISIBLE);
+ binding.lvAccounts.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ return true;
+ }
+ return true;
+ }
+
+}
diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java
index cfef921d..9f13b25f 100644
--- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java
+++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java
@@ -373,7 +373,8 @@ public interface MastodonAccountsService {
@GET("follow_requests")
Call> getFollowRequests(
@Header("Authorization") String token,
- @Path("limit") String limit);
+ @Query("max_id") String max_id,
+ @Query("limit") int limit);
//Accept follow request
@POST("follow_requests/{id}/authorize")
diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/AccountFollowRequestAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/AccountFollowRequestAdapter.java
new file mode 100644
index 00000000..f1009ab9
--- /dev/null
+++ b/app/src/main/java/app/fedilab/android/ui/drawer/AccountFollowRequestAdapter.java
@@ -0,0 +1,124 @@
+package app.fedilab.android.ui.drawer;
+/* Copyright 2022 Thomas Schneider
+ *
+ * This file is a part of Fedilab
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Fedilab; if not,
+ * see . */
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.core.app.ActivityOptionsCompat;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.lifecycle.ViewModelStoreOwner;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+import app.fedilab.android.R;
+import app.fedilab.android.activities.MainActivity;
+import app.fedilab.android.activities.ProfileActivity;
+import app.fedilab.android.client.entities.api.Account;
+import app.fedilab.android.databinding.DrawerFollowBinding;
+import app.fedilab.android.helper.Helper;
+import app.fedilab.android.helper.MastodonHelper;
+import app.fedilab.android.viewmodel.mastodon.AccountsVM;
+
+
+public class AccountFollowRequestAdapter extends RecyclerView.Adapter {
+ private final List accountList;
+ private Context context;
+
+ public AccountFollowRequestAdapter(List accountList) {
+ this.accountList = accountList;
+ }
+
+ public int getCount() {
+ return accountList.size();
+ }
+
+ public Account getItem(int position) {
+ return accountList.get(position);
+ }
+
+ @NonNull
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ context = parent.getContext();
+ DrawerFollowBinding itemBinding = DrawerFollowBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
+ return new ViewHolderFollow(itemBinding);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
+ Account account = accountList.get(position);
+ ViewHolderFollow holderFollow = (ViewHolderFollow) viewHolder;
+ MastodonHelper.loadPPMastodon(holderFollow.binding.avatar, account);
+ holderFollow.binding.displayName.setText(account.display_name);
+ holderFollow.binding.username.setText(String.format("@%s", account.acct));
+ holderFollow.binding.rejectButton.setVisibility(View.VISIBLE);
+ holderFollow.binding.acceptButton.setVisibility(View.VISIBLE);
+ holderFollow.binding.title.setText(R.string.follow_request);
+ AccountsVM accountsVM = new ViewModelProvider((ViewModelStoreOwner) context).get(AccountsVM.class);
+ holderFollow.binding.acceptButton.setOnClickListener(v -> {
+ accountsVM.acceptFollow(MainActivity.currentInstance, MainActivity.currentToken, account.id)
+ .observe((LifecycleOwner) context, relationShip -> {
+ accountList.remove(position);
+ notifyItemRemoved(position);
+ });
+ });
+ holderFollow.binding.rejectButton.setOnClickListener(v -> {
+ accountsVM.rejectFollow(MainActivity.currentInstance, MainActivity.currentToken, account.id)
+ .observe((LifecycleOwner) context, relationShip -> {
+ accountList.remove(position);
+ notifyItemRemoved(position);
+ });
+ });
+ holderFollow.binding.avatar.setOnClickListener(v -> {
+ Intent intent = new Intent(context, ProfileActivity.class);
+ Bundle b = new Bundle();
+ b.putSerializable(Helper.ARG_ACCOUNT, account);
+ intent.putExtras(b);
+ ActivityOptionsCompat options = ActivityOptionsCompat
+ .makeSceneTransitionAnimation((Activity) context, holderFollow.binding.avatar, context.getString(R.string.activity_porfile_pp));
+ // start the new activity
+ context.startActivity(intent, options.toBundle());
+ });
+ }
+
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemCount() {
+ return accountList.size();
+ }
+
+
+ static class ViewHolderFollow extends RecyclerView.ViewHolder {
+ DrawerFollowBinding binding;
+
+ ViewHolderFollow(DrawerFollowBinding itemView) {
+ super(itemView.getRoot());
+ binding = itemView;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java
index e5bfc3b9..c20b983f 100644
--- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java
+++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java
@@ -1288,28 +1288,30 @@ public class AccountsVM extends AndroidViewModel {
* @param limit Maximum number of results to return. Defaults to 40.
* @return {@link LiveData} containing a {@link List} of {@link Account}s
*/
- public LiveData> getFollowRequests(@NonNull String instance, String token, String limit) {
- accountListMutableLiveData = new MutableLiveData<>();
+ public LiveData getFollowRequests(@NonNull String instance, String token, String max_id, int limit) {
+ accountsMutableLiveData = new MutableLiveData<>();
MastodonAccountsService mastodonAccountsService = init(instance);
new Thread(() -> {
List accountList = null;
- Call> followRequestsCall = mastodonAccountsService.getFollowRequests(token, limit);
+ Accounts accounts = new Accounts();
+ Call> followRequestsCall = mastodonAccountsService.getFollowRequests(token, max_id, limit);
if (followRequestsCall != null) {
try {
Response> followRequestsResponse = followRequestsCall.execute();
if (followRequestsResponse.isSuccessful()) {
accountList = followRequestsResponse.body();
+ accounts.accounts = SpannableHelper.convertAccounts(getApplication().getApplicationContext(), accountList);
+ accounts.pagination = MastodonHelper.getPagination(followRequestsResponse.headers());
}
} catch (IOException e) {
e.printStackTrace();
}
Handler mainHandler = new Handler(Looper.getMainLooper());
- List finalAccountList = accountList;
- Runnable myRunnable = () -> accountListMutableLiveData.setValue(finalAccountList);
+ Runnable myRunnable = () -> accountsMutableLiveData.setValue(accounts);
mainHandler.post(myRunnable);
}
}).start();
- return accountListMutableLiveData;
+ return accountsMutableLiveData;
}
/**
diff --git a/app/src/main/res/drawable/ic_baseline_group_add_24.xml b/app/src/main/res/drawable/ic_baseline_group_add_24.xml
new file mode 100644
index 00000000..485dcc21
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_group_add_24.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_status_info.xml b/app/src/main/res/layout/activity_status_info.xml
index 67019446..b7ccb65b 100644
--- a/app/src/main/res/layout/activity_status_info.xml
+++ b/app/src/main/res/layout/activity_status_info.xml
@@ -40,6 +40,7 @@
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:fitsSystemWindows="true">
+
+
+
+
+
+
+
+
+