diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f69f8a04d..a63593396 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -232,6 +232,11 @@
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
/>
+
. */
+package app.fedilab.android.activities;
+
+import android.annotation.SuppressLint;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import androidx.appcompat.app.ActionBar;
+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.google.android.material.tabs.TabLayout;
+import app.fedilab.android.R;
+import app.fedilab.android.fragments.DisplayAdminAccountsFragment;
+import app.fedilab.android.fragments.DisplayAdminReportsFragment;
+import app.fedilab.android.helper.Helper;
+
+
+/**
+ * Created by Thomas on 19/06/2019.
+ * Admin activity
+ */
+
+public class AdminActivity extends BaseActivity {
+
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
+
+ setTheme(R.style.AppAdminTheme);
+
+ if( getSupportActionBar() != null)
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ ActionBar actionBar = getSupportActionBar();
+ if( actionBar != null ) {
+ LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
+ assert inflater != null;
+ @SuppressLint("InflateParams") View view = inflater.inflate(R.layout.simple_bar, null);
+ actionBar.setCustomView(view, new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
+ ImageView toolbar_close = actionBar.getCustomView().findViewById(R.id.toolbar_close);
+ TextView toolbar_title = actionBar.getCustomView().findViewById(R.id.toolbar_title);
+ toolbar_close.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ finish();
+ }
+ });
+ toolbar_title.setText(String.format(getString(R.string.administration)+ " %s", Helper.getLiveInstance(getApplicationContext())));
+ }
+ setContentView(R.layout.activity_admin);
+
+
+ ViewPager admin_viewpager = findViewById(R.id.admin_viewpager);
+
+ TabLayout admin_tablayout = findViewById(R.id.admin_tablayout);
+ admin_tablayout.addTab(admin_tablayout.newTab().setText(getString(R.string.reports)));
+ admin_tablayout.addTab(admin_tablayout.newTab().setText(getString(R.string.accounts)));
+
+
+ PagerAdapter mPagerAdapter = new AdminPagerAdapter(getSupportFragmentManager());
+ admin_viewpager.setAdapter(mPagerAdapter);
+
+ admin_viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ TabLayout.Tab tab = admin_tablayout.getTabAt(position);
+ if( tab != null)
+ tab.select();
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+
+ }
+ });
+
+ admin_tablayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
+ @Override
+ public void onTabSelected(TabLayout.Tab tab) {
+ admin_viewpager.setCurrentItem(tab.getPosition());
+ }
+
+ @Override
+ public void onTabUnselected(TabLayout.Tab tab) {
+
+ }
+
+ @Override
+ public void onTabReselected(TabLayout.Tab tab) {
+ Fragment fragment = null;
+ if( admin_viewpager.getAdapter() != null)
+ fragment = (Fragment) admin_viewpager.getAdapter().instantiateItem(admin_viewpager, tab.getPosition());
+ switch (tab.getPosition()){
+ case 0:
+ if( fragment != null) {
+ DisplayAdminReportsFragment displayAdminReportsFragment = ((DisplayAdminReportsFragment) fragment);
+ displayAdminReportsFragment.scrollToTop();
+ }
+ break;
+ case 1:
+ if( fragment != null) {
+ DisplayAdminAccountsFragment displayAdminAccountsFragment = ((DisplayAdminAccountsFragment) fragment);
+ displayAdminAccountsFragment.scrollToTop();
+ }
+ break;
+
+ }
+ }
+ });
+
+ }
+
+
+ private class AdminPagerAdapter extends FragmentStatePagerAdapter {
+
+ AdminPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ Bundle bundle = new Bundle();
+ switch (position){
+ case 0:
+ DisplayAdminReportsFragment displayAdminReportsFragment = new DisplayAdminReportsFragment();
+ return displayAdminReportsFragment;
+ case 1:
+ DisplayAdminAccountsFragment displayAdminAccountsFragment = new DisplayAdminAccountsFragment();
+ return displayAdminAccountsFragment;
+ }
+ return null;
+ }
+
+
+ @Override
+ public int getCount() {
+ return 2;
+ }
+ }
+
+}
diff --git a/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java
index 67495f241..c35974af2 100644
--- a/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java
+++ b/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java
@@ -86,6 +86,7 @@ import app.fedilab.android.client.Entities.Status;
import app.fedilab.android.client.Entities.TagTimeline;
import app.fedilab.android.client.Entities.Version;
import app.fedilab.android.fragments.DisplayAccountsFragment;
+import app.fedilab.android.fragments.DisplayAdminReportsFragment;
import app.fedilab.android.fragments.DisplayBookmarksFragment;
import app.fedilab.android.fragments.DisplayDraftsFragment;
import app.fedilab.android.fragments.DisplayFavoritesPeertubeFragment;
@@ -284,6 +285,7 @@ public abstract class BaseMainActivity extends BaseActivity
viewPager = findViewById(R.id.viewpager);
new PostAdminActionAsyncTask(getApplicationContext(), API.adminAction.GET_ACCOUNTS, null, null, BaseMainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ new PostAdminActionAsyncTask(getApplicationContext(), API.adminAction.GET_REPORTS, null, null, BaseMainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
display_timeline.setOnClickListener(new View.OnClickListener() {
@Override
@@ -1512,6 +1514,10 @@ public abstract class BaseMainActivity extends BaseActivity
Intent intent = new Intent(getApplicationContext(), ReorderTimelinesActivity.class);
startActivity(intent);
return false;
+ }else if(id == R.id.nav_administration){
+ Intent intent = new Intent(getApplicationContext(), AdminActivity.class);
+ startActivity(intent);
+ return false;
} else if( id == R.id.nav_about) {
Intent intent = new Intent(getApplicationContext(), AboutActivity.class);
startActivity(intent);
diff --git a/app/src/main/java/app/fedilab/android/activities/LoginActivity.java b/app/src/main/java/app/fedilab/android/activities/LoginActivity.java
index 19aff3d16..6f59e6ce0 100644
--- a/app/src/main/java/app/fedilab/android/activities/LoginActivity.java
+++ b/app/src/main/java/app/fedilab/android/activities/LoginActivity.java
@@ -114,12 +114,14 @@ public class LoginActivity extends BaseActivity {
private TextView instance_chosen;
private ImageView info_instance;
private final int PICK_IMPORT = 5557;
+ private boolean admin;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle b = getIntent().getExtras();
socialNetwork = UpdateAccountInfoAsyncTask.SOCIAL.MASTODON;
+ admin = false;
if(b != null) {
autofilledInstance = b.getString("instance", null);
social = b.getString("social", null);
@@ -136,6 +138,7 @@ public class LoginActivity extends BaseActivity {
break;
}
}
+ admin = b.getBoolean("admin", false);
}
if( getIntent() != null && getIntent().getData() != null && getIntent().getData().toString().contains("mastalab://backtomastalab?code=")){
@@ -551,7 +554,11 @@ public class LoginActivity extends BaseActivity {
parameters.put(Helper.CLIENT_NAME, Helper.CLIENT_NAME_VALUE);
parameters.put(Helper.REDIRECT_URIS, client_id_for_webview?Helper.REDIRECT_CONTENT_WEB:Helper.REDIRECT_CONTENT);
if( socialNetwork != UpdateAccountInfoAsyncTask.SOCIAL.PEERTUBE) {
- parameters.put(Helper.SCOPES, Helper.OAUTH_SCOPES);
+ if( admin ) {
+ parameters.put(Helper.SCOPES, Helper.OAUTH_SCOPES_ADMIN);
+ }else{
+ parameters.put(Helper.SCOPES, Helper.OAUTH_SCOPES);
+ }
}else {
parameters.put(Helper.SCOPES, Helper.OAUTH_SCOPES_PEERTUBE);
}
diff --git a/app/src/main/java/app/fedilab/android/client/API.java b/app/src/main/java/app/fedilab/android/client/API.java
index 6748d4c8c..52780aa58 100644
--- a/app/src/main/java/app/fedilab/android/client/API.java
+++ b/app/src/main/java/app/fedilab/android/client/API.java
@@ -19,6 +19,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
+import android.util.Log;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
@@ -234,6 +235,7 @@ public class API {
}
try {
String response = new HttpsConnection(context, this.instance).get(getAbsoluteUrl(endpoint), 60, params, prefKeyOauthTokenT);
+ Log.v(Helper.TAG,response);
switch (action){
case GET_ACCOUNTS:
List accountAdmins = parseAccountAdminResponse(new JSONArray(response));
diff --git a/app/src/main/java/app/fedilab/android/drawers/AccountsAdminListAdapter.java b/app/src/main/java/app/fedilab/android/drawers/AccountsAdminListAdapter.java
new file mode 100644
index 000000000..7acede193
--- /dev/null
+++ b/app/src/main/java/app/fedilab/android/drawers/AccountsAdminListAdapter.java
@@ -0,0 +1,157 @@
+package app.fedilab.android.drawers;
+/* Copyright 2019 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.content.Context;
+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 androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+import app.fedilab.android.R;
+import app.fedilab.android.asynctasks.RetrieveAccountsAsyncTask;
+import app.fedilab.android.client.Entities.Account;
+import app.fedilab.android.client.Entities.AccountAdmin;
+import app.fedilab.android.client.Entities.Report;
+import app.fedilab.android.helper.Helper;
+import app.fedilab.android.interfaces.OnRetrieveEmojiAccountInterface;
+
+
+/**
+ * Created by Thomas on 19/06/2019.
+ * Adapter for account admins
+ */
+public class AccountsAdminListAdapter extends RecyclerView.Adapter implements OnRetrieveEmojiAccountInterface {
+
+ private List accountAdmins;
+ private LayoutInflater layoutInflater;
+ private RetrieveAccountsAsyncTask.Type action;
+ private Context context;
+ private AccountsAdminListAdapter accountsAdminListAdapter;
+ private String targetedId;
+
+ public AccountsAdminListAdapter(Context context, List accountAdmins){
+ this.context = context;
+ this.accountAdmins = accountAdmins;
+ layoutInflater = LayoutInflater.from(context);
+ this.accountsAdminListAdapter = this;
+ }
+
+
+
+
+ @NonNull
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new ViewHolder(layoutInflater.inflate(R.layout.drawer_account_admin, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
+ final AccountsAdminListAdapter.ViewHolder holder = (AccountsAdminListAdapter.ViewHolder) viewHolder;
+ AccountAdmin accountAdmin = accountAdmins.get(position);
+ Account account = accountAdmin.getAccount();
+
+
+ account.makeAccountNameEmoji(context, AccountsAdminListAdapter.this, account);
+ if( account.getdisplayNameSpan() == null || account.getdisplayNameSpan().toString().trim().equals("")) {
+ if( account.getDisplay_name() != null && !account.getDisplay_name().trim().equals(""))
+ holder.account_dn.setText(Helper.shortnameToUnicode(account.getDisplay_name(), true));
+ else
+ holder.account_dn.setText(account.getDisplay_name().replace("@",""));
+ }else
+ holder.account_dn.setText( account.getdisplayNameSpan(), TextView.BufferType.SPANNABLE);
+
+ if( account.getdisplayNameSpan() == null || account.getdisplayNameSpan().toString().trim().equals("")) {
+ if( account.getDisplay_name() != null && !account.getDisplay_name().trim().equals(""))
+ holder.account_dn.setText(Helper.shortnameToUnicode(account.getDisplay_name(), true));
+ else
+ holder.account_dn.setText(account.getDisplay_name().replace("@",""));
+ }else
+ holder.account_dn.setText( account.getdisplayNameSpan(), TextView.BufferType.SPANNABLE);
+ holder.account_un.setText(String.format("@%s",account.getUsername()));
+ holder.account_ac.setText(account.getAcct());
+ if( account.getDisplay_name().equals(account.getAcct()))
+ holder.account_ac.setVisibility(View.GONE);
+ else
+ holder.account_ac.setVisibility(View.VISIBLE);
+
+ holder.report_action_taken.setText(accountAdmin.getIp());
+
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemCount() {
+ return accountAdmins.size();
+ }
+
+ private AccountAdmin getItemAt(int position){
+ if( accountAdmins.size() > position)
+ return accountAdmins.get(position);
+ else
+ return null;
+ }
+
+ @Override
+ public void onRetrieveEmojiAccount(Account account) {
+ notifyAccountChanged(account);
+ }
+
+ private void notifyAccountChanged(Account account){
+ for (int i = 0; i < accountsAdminListAdapter.getItemCount(); i++) {
+ //noinspection ConstantConditions
+ if (accountsAdminListAdapter.getItemAt(i) != null && accountsAdminListAdapter.getItemAt(i).getAccount().getId().equals(account.getId())) {
+ try {
+ accountsAdminListAdapter.notifyItemChanged(i);
+ } catch (Exception ignored) {
+ }
+ }
+ }
+ }
+
+
+ private class ViewHolder extends RecyclerView.ViewHolder{
+ ImageView account_pp;
+ TextView account_ac;
+ TextView account_dn;
+ TextView account_un;
+ TextView report_action_taken;
+
+ 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);
+ report_action_taken = itemView.findViewById(R.id.report_action_taken);
+ account_container = itemView.findViewById(R.id.account_container);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/app/fedilab/android/drawers/ReportsListAdapter.java b/app/src/main/java/app/fedilab/android/drawers/ReportsListAdapter.java
new file mode 100644
index 000000000..3a3f5e1ce
--- /dev/null
+++ b/app/src/main/java/app/fedilab/android/drawers/ReportsListAdapter.java
@@ -0,0 +1,160 @@
+package app.fedilab.android.drawers;
+/* Copyright 2019 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.content.Context;
+import android.os.Build;
+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 androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+
+import java.util.List;
+import app.fedilab.android.R;
+import app.fedilab.android.asynctasks.RetrieveAccountsAsyncTask;
+import app.fedilab.android.client.Entities.Account;
+import app.fedilab.android.client.Entities.Report;
+import app.fedilab.android.helper.Helper;
+import app.fedilab.android.interfaces.OnRetrieveEmojiAccountInterface;
+
+
+/**
+ * Created by Thomas on 19/06/2019.
+ * Adapter for reports
+ */
+public class ReportsListAdapter extends RecyclerView.Adapter implements OnRetrieveEmojiAccountInterface {
+
+ private List reports;
+ private LayoutInflater layoutInflater;
+ private RetrieveAccountsAsyncTask.Type action;
+ private Context context;
+ private ReportsListAdapter reportsListAdapter;
+ private String targetedId;
+
+ public ReportsListAdapter(Context context, List reports){
+ this.context = context;
+ this.reports = reports;
+ layoutInflater = LayoutInflater.from(context);
+ this.reportsListAdapter = this;
+ }
+
+
+
+
+ @NonNull
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new ViewHolder(layoutInflater.inflate(R.layout.drawer_report, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
+ final ReportsListAdapter.ViewHolder holder = (ReportsListAdapter.ViewHolder) viewHolder;
+ Report report = reports.get(position);
+ Account account = report.getStatuses().get(0).getAccount();
+
+
+ account.makeAccountNameEmoji(context, ReportsListAdapter.this, account);
+ if( account.getdisplayNameSpan() == null || account.getdisplayNameSpan().toString().trim().equals("")) {
+ if( account.getDisplay_name() != null && !account.getDisplay_name().trim().equals(""))
+ holder.account_dn.setText(Helper.shortnameToUnicode(account.getDisplay_name(), true));
+ else
+ holder.account_dn.setText(account.getDisplay_name().replace("@",""));
+ }else
+ holder.account_dn.setText( account.getdisplayNameSpan(), TextView.BufferType.SPANNABLE);
+
+ if( account.getdisplayNameSpan() == null || account.getdisplayNameSpan().toString().trim().equals("")) {
+ if( account.getDisplay_name() != null && !account.getDisplay_name().trim().equals(""))
+ holder.account_dn.setText(Helper.shortnameToUnicode(account.getDisplay_name(), true));
+ else
+ holder.account_dn.setText(account.getDisplay_name().replace("@",""));
+ }else
+ holder.account_dn.setText( account.getdisplayNameSpan(), TextView.BufferType.SPANNABLE);
+ holder.account_un.setText(String.format("@%s",account.getUsername()));
+ holder.account_ac.setText(account.getAcct());
+ if( account.getDisplay_name().equals(account.getAcct()))
+ holder.account_ac.setVisibility(View.GONE);
+ else
+ holder.account_ac.setVisibility(View.VISIBLE);
+
+ holder.report_action_taken.setText(report.getAction_taken());
+
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemCount() {
+ return reports.size();
+ }
+
+ private Report getItemAt(int position){
+ if( reports.size() > position)
+ return reports.get(position);
+ else
+ return null;
+ }
+
+ @Override
+ public void onRetrieveEmojiAccount(Account account) {
+ notifyAccountChanged(account);
+ }
+
+ private void notifyAccountChanged(Account account){
+ for (int i = 0; i < reportsListAdapter.getItemCount(); i++) {
+ //noinspection ConstantConditions
+ if (reportsListAdapter.getItemAt(i) != null && reportsListAdapter.getItemAt(i).getStatuses().get(0).getAccount().getId().equals(account.getId())) {
+ try {
+ reportsListAdapter.notifyItemChanged(i);
+ } catch (Exception ignored) {
+ }
+ }
+ }
+ }
+
+
+ private class ViewHolder extends RecyclerView.ViewHolder{
+ ImageView account_pp;
+ TextView account_ac;
+ TextView account_dn;
+ TextView account_un;
+ TextView report_action_taken;
+
+ 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);
+ report_action_taken = itemView.findViewById(R.id.report_action_taken);
+ account_container = itemView.findViewById(R.id.account_container);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/app/fedilab/android/fragments/DisplayAdminAccountsFragment.java b/app/src/main/java/app/fedilab/android/fragments/DisplayAdminAccountsFragment.java
new file mode 100644
index 000000000..1fe0bacb4
--- /dev/null
+++ b/app/src/main/java/app/fedilab/android/fragments/DisplayAdminAccountsFragment.java
@@ -0,0 +1,215 @@
+package app.fedilab.android.fragments;
+/* Copyright 2019 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.content.Context;
+import android.content.SharedPreferences;
+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.core.content.ContextCompat;
+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.android.R;
+import app.fedilab.android.asynctasks.PostAdminActionAsyncTask;
+import app.fedilab.android.asynctasks.RetrieveAccountsAsyncTask;
+import app.fedilab.android.client.API;
+import app.fedilab.android.client.APIResponse;
+import app.fedilab.android.client.Entities.AccountAdmin;
+import app.fedilab.android.drawers.AccountsAdminListAdapter;
+import app.fedilab.android.helper.Helper;
+import app.fedilab.android.interfaces.OnAdminActionInterface;
+import es.dmoral.toasty.Toasty;
+
+
+/**
+ * Created by Thomas on 19/06/2019.
+ * Fragment to display content related to reports
+ */
+public class DisplayAdminAccountsFragment extends Fragment implements OnAdminActionInterface {
+
+ private boolean flag_loading;
+ private Context context;
+ private AsyncTask asyncTask;
+ private AccountsAdminListAdapter accountsAdminListAdapter;
+ private String max_id;
+ private List accountAdmins;
+ private RetrieveAccountsAsyncTask.Type type;
+ private RelativeLayout mainLoader, nextElementLoader, textviewNoAction;
+ private boolean firstLoad;
+ private SwipeRefreshLayout swipeRefreshLayout;
+ private boolean swiped;
+ private RecyclerView lv_admin_accounts;
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+ View rootView = inflater.inflate(R.layout.fragment_admin_accounts, container, false);
+
+ context = getContext();
+
+ accountAdmins = new ArrayList<>();
+
+ max_id = null;
+ firstLoad = true;
+ flag_loading = true;
+ swiped = false;
+
+ swipeRefreshLayout = rootView.findViewById(R.id.swipeContainer);
+ lv_admin_accounts = rootView.findViewById(R.id.lv_admin_accounts);
+ lv_admin_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);
+ accountsAdminListAdapter = new AccountsAdminListAdapter(context, this.accountAdmins);
+ lv_admin_accounts.setAdapter(accountsAdminListAdapter);
+
+ final LinearLayoutManager mLayoutManager;
+ mLayoutManager = new LinearLayoutManager(context);
+ lv_admin_accounts.setLayoutManager(mLayoutManager);
+ lv_admin_accounts.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ public void onScrolled(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 PostAdminActionAsyncTask(context, API.adminAction.GET_REPORTS, null, null, DisplayAdminAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ nextElementLoader.setVisibility(View.VISIBLE);
+ }
+ } else {
+ nextElementLoader.setVisibility(View.GONE);
+ }
+ }
+ }
+ });
+
+ swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
+ @Override
+ public void onRefresh() {
+ max_id = null;
+ accountAdmins = new ArrayList<>();
+ firstLoad = true;
+ flag_loading = true;
+ swiped = true;
+ asyncTask = new PostAdminActionAsyncTask(context, API.adminAction.GET_REPORTS, null, null, DisplayAdminAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ });
+ SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
+ int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
+ switch (theme){
+ case Helper.THEME_LIGHT:
+ swipeRefreshLayout.setColorSchemeResources(R.color.mastodonC4,
+ R.color.mastodonC2,
+ R.color.mastodonC3);
+ swipeRefreshLayout.setProgressBackgroundColorSchemeColor(ContextCompat.getColor(context, R.color.white));
+ break;
+ case Helper.THEME_DARK:
+ swipeRefreshLayout.setColorSchemeResources(R.color.mastodonC4__,
+ R.color.mastodonC4,
+ R.color.mastodonC4);
+ swipeRefreshLayout.setProgressBackgroundColorSchemeColor(ContextCompat.getColor(context, R.color.mastodonC1_));
+ break;
+ case Helper.THEME_BLACK:
+ swipeRefreshLayout.setColorSchemeResources(R.color.dark_icon,
+ R.color.mastodonC2,
+ R.color.mastodonC3);
+ swipeRefreshLayout.setProgressBackgroundColorSchemeColor(ContextCompat.getColor(context, R.color.black_3));
+ break;
+ }
+
+ asyncTask = new PostAdminActionAsyncTask(context, API.adminAction.GET_REPORTS, null, null, DisplayAdminAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ return rootView;
+ }
+
+ @Override
+ public void onCreate(Bundle saveInstance)
+ {
+ super.onCreate(saveInstance);
+ }
+
+
+
+ @Override
+ public void onAttach(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_admin_accounts != null)
+ lv_admin_accounts.setAdapter(accountsAdminListAdapter);
+ }
+
+
+ @Override
+ public void onAdminAction(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 accountAdmins = apiResponse.getAccountAdmins();
+
+ if( !swiped && firstLoad && (accountAdmins == null || accountAdmins.size() == 0))
+ textviewNoAction.setVisibility(View.VISIBLE);
+ else
+ textviewNoAction.setVisibility(View.GONE);
+
+ max_id = apiResponse.getMax_id();
+
+ if( swiped ){
+ accountsAdminListAdapter = new AccountsAdminListAdapter(context, this.accountAdmins);
+ lv_admin_accounts.setAdapter(accountsAdminListAdapter);
+ swiped = false;
+ }
+ if( accountAdmins != null && accountAdmins.size() > 0) {
+ int currentPosition = this.accountAdmins.size();
+ this.accountAdmins.addAll(accountAdmins);
+ accountsAdminListAdapter.notifyItemRangeChanged(currentPosition,accountAdmins.size());
+ }
+ swipeRefreshLayout.setRefreshing(false);
+ firstLoad = false;
+ }
+}
diff --git a/app/src/main/java/app/fedilab/android/fragments/DisplayAdminReportsFragment.java b/app/src/main/java/app/fedilab/android/fragments/DisplayAdminReportsFragment.java
new file mode 100644
index 000000000..811217076
--- /dev/null
+++ b/app/src/main/java/app/fedilab/android/fragments/DisplayAdminReportsFragment.java
@@ -0,0 +1,245 @@
+package app.fedilab.android.fragments;
+/* Copyright 2019 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.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+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.android.R;
+import app.fedilab.android.activities.LoginActivity;
+import app.fedilab.android.activities.PeertubeActivity;
+import app.fedilab.android.asynctasks.PostActionAsyncTask;
+import app.fedilab.android.asynctasks.PostAdminActionAsyncTask;
+import app.fedilab.android.asynctasks.RetrieveAccountsAsyncTask;
+import app.fedilab.android.client.API;
+import app.fedilab.android.client.APIResponse;
+import app.fedilab.android.client.Entities.Report;
+import app.fedilab.android.drawers.ReportsListAdapter;
+import app.fedilab.android.helper.Helper;
+import app.fedilab.android.interfaces.OnAdminActionInterface;
+import es.dmoral.toasty.Toasty;
+
+
+/**
+ * Created by Thomas on 19/06/2019.
+ * Fragment to display content related to reports
+ */
+public class DisplayAdminReportsFragment extends Fragment implements OnAdminActionInterface {
+
+ private boolean flag_loading;
+ private Context context;
+ private AsyncTask asyncTask;
+ private ReportsListAdapter reportsListAdapter;
+ private String max_id;
+ private List reports;
+ private RetrieveAccountsAsyncTask.Type type;
+ private RelativeLayout mainLoader, nextElementLoader, textviewNoAction;
+ private boolean firstLoad;
+ private SwipeRefreshLayout swipeRefreshLayout;
+ private boolean swiped;
+ private RecyclerView lv_reports;
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+ View rootView = inflater.inflate(R.layout.fragment_admin_reports, container, false);
+
+ context = getContext();
+
+ reports = new ArrayList<>();
+
+ max_id = null;
+ firstLoad = true;
+ flag_loading = true;
+ swiped = false;
+
+ swipeRefreshLayout = rootView.findViewById(R.id.swipeContainer);
+ lv_reports = rootView.findViewById(R.id.lv_reports);
+ lv_reports.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);
+ reportsListAdapter = new ReportsListAdapter(context, this.reports);
+ lv_reports.setAdapter(reportsListAdapter);
+
+ final LinearLayoutManager mLayoutManager;
+ mLayoutManager = new LinearLayoutManager(context);
+ lv_reports.setLayoutManager(mLayoutManager);
+ lv_reports.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ public void onScrolled(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 PostAdminActionAsyncTask(context, API.adminAction.GET_REPORTS, null, null, DisplayAdminReportsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ nextElementLoader.setVisibility(View.VISIBLE);
+ }
+ } else {
+ nextElementLoader.setVisibility(View.GONE);
+ }
+ }
+ }
+ });
+
+ swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
+ @Override
+ public void onRefresh() {
+ max_id = null;
+ reports = new ArrayList<>();
+ firstLoad = true;
+ flag_loading = true;
+ swiped = true;
+ asyncTask = new PostAdminActionAsyncTask(context, API.adminAction.GET_REPORTS, null, null, DisplayAdminReportsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ });
+ SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
+ int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
+ switch (theme){
+ case Helper.THEME_LIGHT:
+ swipeRefreshLayout.setColorSchemeResources(R.color.mastodonC4,
+ R.color.mastodonC2,
+ R.color.mastodonC3);
+ swipeRefreshLayout.setProgressBackgroundColorSchemeColor(ContextCompat.getColor(context, R.color.white));
+ break;
+ case Helper.THEME_DARK:
+ swipeRefreshLayout.setColorSchemeResources(R.color.mastodonC4__,
+ R.color.mastodonC4,
+ R.color.mastodonC4);
+ swipeRefreshLayout.setProgressBackgroundColorSchemeColor(ContextCompat.getColor(context, R.color.mastodonC1_));
+ break;
+ case Helper.THEME_BLACK:
+ swipeRefreshLayout.setColorSchemeResources(R.color.dark_icon,
+ R.color.mastodonC2,
+ R.color.mastodonC3);
+ swipeRefreshLayout.setProgressBackgroundColorSchemeColor(ContextCompat.getColor(context, R.color.black_3));
+ break;
+ }
+
+ asyncTask = new PostAdminActionAsyncTask(context, API.adminAction.GET_REPORTS, null, null, DisplayAdminReportsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ return rootView;
+ }
+
+ @Override
+ public void onCreate(Bundle saveInstance)
+ {
+ super.onCreate(saveInstance);
+ }
+
+
+
+ @Override
+ public void onAttach(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_reports != null)
+ lv_reports.setAdapter(reportsListAdapter);
+ }
+
+
+ @Override
+ public void onAdminAction(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;
+ //Admin right not granted through the API?
+ if( apiResponse.getError().getStatusCode() == 403){
+ AlertDialog.Builder builderInner;
+ builderInner = new AlertDialog.Builder(context, R.style.AppAdminTheme);
+ builderInner.setTitle(R.string.reconnect_account);
+ builderInner.setMessage(R.string.reconnect_account_message);
+ builderInner.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog,int which) {
+ dialog.dismiss();
+ }
+ });
+ builderInner.setPositiveButton(R.string.validate, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog,int which) {
+ Intent intent = new Intent(context, LoginActivity.class);
+ intent.putExtra("admin", true);
+ context.startActivity(intent);
+ }
+ });
+ builderInner.show();
+ }
+ return;
+ }
+ flag_loading = (apiResponse.getMax_id() == null );
+ List reports = apiResponse.getReports();
+
+ if( !swiped && firstLoad && (reports == null || reports.size() == 0))
+ textviewNoAction.setVisibility(View.VISIBLE);
+ else
+ textviewNoAction.setVisibility(View.GONE);
+
+ max_id = apiResponse.getMax_id();
+
+ if( swiped ){
+ reportsListAdapter = new ReportsListAdapter(context, this.reports);
+ lv_reports.setAdapter(reportsListAdapter);
+ swiped = false;
+ }
+ if( reports != null && reports.size() > 0) {
+ int currentPosition = this.reports.size();
+ this.reports.addAll(reports);
+ reportsListAdapter.notifyItemRangeChanged(currentPosition,reports.size());
+ }
+ swipeRefreshLayout.setRefreshing(false);
+ firstLoad = false;
+ }
+}
diff --git a/app/src/main/res/drawable/ic_security_admin.xml b/app/src/main/res/drawable/ic_security_admin.xml
new file mode 100644
index 000000000..d66f92794
--- /dev/null
+++ b/app/src/main/res/drawable/ic_security_admin.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_admin.xml b/app/src/main/res/layout/activity_admin.xml
new file mode 100644
index 000000000..16e7279f9
--- /dev/null
+++ b/app/src/main/res/layout/activity_admin.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/drawer_account_admin.xml b/app/src/main/res/layout/drawer_account_admin.xml
new file mode 100644
index 000000000..17ae31a2b
--- /dev/null
+++ b/app/src/main/res/layout/drawer_account_admin.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/drawer_report.xml b/app/src/main/res/layout/drawer_report.xml
new file mode 100644
index 000000000..17ae31a2b
--- /dev/null
+++ b/app/src/main/res/layout/drawer_report.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_admin_accounts.xml b/app/src/main/res/layout/fragment_admin_accounts.xml
new file mode 100644
index 000000000..e9bc00da4
--- /dev/null
+++ b/app/src/main/res/layout/fragment_admin_accounts.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_admin_reports.xml b/app/src/main/res/layout/fragment_admin_reports.xml
new file mode 100644
index 000000000..1e6b84a18
--- /dev/null
+++ b/app/src/main/res/layout/fragment_admin_reports.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml
index 5ebb902f6..5dce65bb0 100644
--- a/app/src/main/res/menu/activity_main_drawer.xml
+++ b/app/src/main/res/menu/activity_main_drawer.xml
@@ -58,6 +58,10 @@
android:id="@+id/nav_drag_timelines"
android:icon="@drawable/ic_drag_handle_menu"
android:title="@string/reorder_timelines" />
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d17082264..228e2639a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1028,6 +1028,11 @@
Important: If your instance required validation, you will receive an email once it is validated!
Save the message in drafts?
+ Administration
+ Reports
+ No reports to display!
+ Reconnect the account
+ The application failed to access the admin features. You might need to reconnect the account for having the correct scope.
- %d vote
- %d votes
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index da3485a32..8d8981bc8 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -392,4 +392,39 @@
+
+
+
+
+
+