diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f69f8a04d..28cad2a69 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -232,6 +232,16 @@ android:configChanges="orientation|screenSize" android:label="@string/app_name" /> + + . */ + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.PorterDuff; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.ActionBar; +import androidx.constraintlayout.widget.Group; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; + +import app.fedilab.android.R; +import app.fedilab.android.asynctasks.PostAdminActionAsyncTask; +import app.fedilab.android.client.API; +import app.fedilab.android.client.APIResponse; +import app.fedilab.android.client.Entities.AccountAdmin; +import app.fedilab.android.client.Entities.AdminAction; +import app.fedilab.android.client.Entities.Report; +import app.fedilab.android.client.Entities.Status; +import app.fedilab.android.drawers.StatusReportAdapter; +import app.fedilab.android.helper.Helper; +import app.fedilab.android.interfaces.OnAdminActionInterface; +import es.dmoral.toasty.Toasty; + +import static app.fedilab.android.client.API.adminAction.APPROVE; +import static app.fedilab.android.client.API.adminAction.DISABLE; +import static app.fedilab.android.client.API.adminAction.NONE; +import static app.fedilab.android.client.API.adminAction.REJECT; +import static app.fedilab.android.client.API.adminAction.SILENCE; +import static app.fedilab.android.client.API.adminAction.SUSPEND; + +public class AccountReportActivity extends BaseActivity implements OnAdminActionInterface { + + TextView permissions, username, email, email_status, login_status, joined, recent_ip, comment_label; + Button warn, disable, silence, suspend, allow, reject, assign, status; + private String account_id; + private CheckBox email_user; + private EditText comment; + private Report report; + private Group allow_reject_group; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); + + setTheme(R.style.AppAdminTheme); + report = null; + AccountAdmin targeted_account = null; + Bundle b = getIntent().getExtras(); + + if (b != null) { + account_id = b.getString("account_id", null); + targeted_account = b.getParcelable("targeted_account"); + report = b.getParcelable("report"); + } + + 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_report); + + warn = findViewById(R.id.warn); + disable = findViewById(R.id.disable); + silence = findViewById(R.id.silence); + suspend = findViewById(R.id.suspend); + allow = findViewById(R.id.allow); + reject = findViewById(R.id.reject); + status = findViewById(R.id.status); + assign = findViewById(R.id.assign); + allow_reject_group = findViewById(R.id.allow_reject_group); + allow_reject_group.setVisibility(View.GONE); + allow.getBackground().setColorFilter(ContextCompat.getColor(getApplicationContext(), R.color.green_1), PorterDuff.Mode.MULTIPLY); + reject.getBackground().setColorFilter(ContextCompat.getColor(getApplicationContext(), R.color.red_1), PorterDuff.Mode.MULTIPLY); + comment_label = findViewById(R.id.comment_label); + permissions = findViewById(R.id.permissions); + username = findViewById(R.id.username); + email = findViewById(R.id.email); + email_status = findViewById(R.id.email_status); + login_status = findViewById(R.id.login_status); + joined = findViewById(R.id.joined); + recent_ip = findViewById(R.id.recent_ip); + + email_user = findViewById(R.id.email_user); + comment = findViewById(R.id.comment); + + if( account_id == null && report == null && targeted_account == null){ + Toasty.error(getApplicationContext(), getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + finish(); + } + assign.setVisibility(View.GONE); + status.setVisibility(View.GONE); + if( account_id != null){ + new PostAdminActionAsyncTask(getApplicationContext(), API.adminAction.GET_ONE_ACCOUNT, account_id, null, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + return; + } + if( report != null) { + targeted_account = report.getTarget_account(); + RecyclerView lv_statuses = findViewById(R.id.lv_statuses); + + ArrayList contents = new ArrayList<>(); + for(Status status: report.getStatuses()){ + contents.add(status.getContent()); + } + lv_statuses.setLayoutManager(new LinearLayoutManager(this)); + StatusReportAdapter adapter = new StatusReportAdapter(this, contents); + lv_statuses.setAdapter(adapter); + + Group statuses_group = findViewById(R.id.statuses_group); + statuses_group.setVisibility(View.VISIBLE); + } + account_id = targeted_account.getId(); + fillReport(targeted_account); + + } + + @Override + public void onAdminAction(APIResponse apiResponse) { + if( apiResponse.getError() != null){ + if( apiResponse.getError().getStatusCode() == 403){ + AlertDialog.Builder builderInner; + builderInner = new AlertDialog.Builder(AccountReportActivity.this, R.style.AdminDialog); + 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(AccountReportActivity.this, LoginActivity.class); + intent.putExtra("admin", true); + startActivity(intent); + } + }); + builderInner.show(); + }else{ + Toasty.error(AccountReportActivity.this, apiResponse.getError().getError(),Toast.LENGTH_LONG).show(); + } + return; + } + if( apiResponse.getReports() != null && apiResponse.getReports().size() > 0){ + report = apiResponse.getReports().get(0); + fillReport(apiResponse.getAccountAdmins().get(0)); + } else if( apiResponse.getAccountAdmins() != null && apiResponse.getAccountAdmins().size() > 0) { + fillReport(apiResponse.getAccountAdmins().get(0)); + } + + } + + private void fillReport(AccountAdmin accountAdmin){ + + if( accountAdmin == null){ + Toasty.error(getApplicationContext(), getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + return; + } + if(!accountAdmin.isApproved()){ + allow_reject_group.setVisibility(View.VISIBLE); + } + + reject.setOnClickListener(view->{ + AdminAction adminAction = new AdminAction(); + adminAction.setType(REJECT); + new PostAdminActionAsyncTask(getApplicationContext(), REJECT, account_id, adminAction, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }); + + allow.setOnClickListener(view->{ + AdminAction adminAction = new AdminAction(); + adminAction.setType(APPROVE); + new PostAdminActionAsyncTask(getApplicationContext(), APPROVE, account_id, adminAction, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }); + + warn.setOnClickListener(view->{ + AdminAction adminAction = new AdminAction(); + adminAction.setType(NONE); + adminAction.setSend_email_notification(email_user.isChecked()); + adminAction.setText(comment.getText().toString().trim()); + new PostAdminActionAsyncTask(getApplicationContext(), NONE, account_id, adminAction, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }); + + + if( !accountAdmin.isSilenced() ) { + silence.setText(getString(R.string.silence)); + }else{ + silence.setText(getString(R.string.unsilence)); + } + silence.setOnClickListener(view->{ + if( !accountAdmin.isSilenced() ) { + AdminAction adminAction = new AdminAction(); + adminAction.setType(SILENCE); + adminAction.setSend_email_notification(email_user.isChecked()); + adminAction.setText(comment.getText().toString().trim()); + new PostAdminActionAsyncTask(getApplicationContext(), SILENCE, account_id, adminAction, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }else{ + new PostAdminActionAsyncTask(getApplicationContext(), API.adminAction.UNSILENCE, account_id, null, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + }); + + if( !accountAdmin.isDisabled() ) { + disable.setText(getString(R.string.disable)); + }else{ + disable.setText(getString(R.string.undisable)); + } + disable.setOnClickListener(view->{ + if( !accountAdmin.isDisabled()) { + AdminAction adminAction = new AdminAction(); + adminAction.setType(DISABLE); + adminAction.setSend_email_notification(email_user.isChecked()); + adminAction.setText(comment.getText().toString().trim()); + new PostAdminActionAsyncTask(getApplicationContext(), DISABLE, account_id, adminAction, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }else{ + new PostAdminActionAsyncTask(getApplicationContext(), API.adminAction.ENABLE, account_id, null, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + }); + if( !accountAdmin.isSuspended() ) { + suspend.setText(getString(R.string.suspend)); + }else{ + suspend.setText(getString(R.string.unsuspend)); + } + suspend.setOnClickListener(view->{ + if( !accountAdmin.isSuspended() ){ + AdminAction adminAction = new AdminAction(); + adminAction.setType(SUSPEND); + adminAction.setSend_email_notification(email_user.isChecked()); + adminAction.setText(comment.getText().toString().trim()); + new PostAdminActionAsyncTask(getApplicationContext(), SUSPEND, account_id, adminAction, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }else{ + new PostAdminActionAsyncTask(getApplicationContext(), API.adminAction.UNSUSPEND, account_id, null, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + }); + + + if( accountAdmin.getAction() != null) { + String message = null; + switch (accountAdmin.getAction()) { + case SILENCE: + message = getString(R.string.account_silenced); + break; + case UNSILENCE: + message = getString(R.string.account_unsilenced); + break; + case DISABLE: + message = getString(R.string.account_disabled); + break; + case ENABLE: + message = getString(R.string.account_undisabled); + break; + case SUSPEND: + message = getString(R.string.account_suspended); + break; + case UNSUSPEND: + message = getString(R.string.account_unsuspended); + break; + case NONE: + message = getString(R.string.account_warned); + break; + case APPROVE: + allow_reject_group.setVisibility(View.GONE); + message = getString(R.string.account_approved); + break; + case REJECT: + allow_reject_group.setVisibility(View.GONE); + + message = getString(R.string.account_rejected); + break; + } + if( message != null){ + Toasty.success(getApplicationContext(), message, Toast.LENGTH_LONG).show(); + } + comment.setText(""); + InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(comment.getWindowToken(), 0); + } + if( accountAdmin.getRole() == null) { + return; + } + + switch (accountAdmin.getRole()) { + case "user": + permissions.setText(getString(R.string.user)); + break; + case "mod": + permissions.setText(getString(R.string.moderator)); + break; + case "admin": + permissions.setText(getString(R.string.administrator)); + break; + } + + + username.setText(String.format("@%s", accountAdmin.getAccount().getAcct())); + + email.setText(accountAdmin.getEmail()); + email_status.setText(accountAdmin.isConfirmed()?getString(R.string.confirmed):getString(R.string.unconfirmed)); + + if( accountAdmin.isDisabled()){ + login_status.setText(getString(R.string.disabled)); + }else if( accountAdmin.isSilenced()){ + login_status.setText(getString(R.string.silenced)); + }else if( accountAdmin.isSuspended()){ + login_status.setText(getString(R.string.suspended)); + }else{ + login_status.setText(getString(R.string.active)); + } + if( accountAdmin.getDomain() == null || accountAdmin.getDomain().equals("null")){ + warn.setVisibility(View.VISIBLE); + email_user.setVisibility(View.VISIBLE); + comment_label.setVisibility(View.VISIBLE); + comment.setVisibility(View.VISIBLE); + recent_ip.setText(accountAdmin.getIp()); + disable.setVisibility(View.VISIBLE); + suspend.setVisibility(View.VISIBLE); + }else{ + warn.setVisibility(View.GONE); + email_user.setVisibility(View.GONE); + email_user.setChecked(false); + comment.setVisibility(View.GONE); + recent_ip.setText("-"); + permissions.setText("-"); + email.setText("-"); + disable.setVisibility(View.GONE); + suspend.setVisibility(View.VISIBLE); + comment_label.setVisibility(View.GONE); + } + if( accountAdmin.getRole().equals("admin") || accountAdmin.getRole().equals("mod")){ + warn.setVisibility(View.GONE); + suspend.setVisibility(View.GONE); + silence.setVisibility(View.GONE); + disable.setVisibility(View.GONE); + email_user.setVisibility(View.GONE); + email_user.setChecked(false); + comment.setVisibility(View.GONE); + comment_label.setVisibility(View.GONE); + } + joined.setText(Helper.dateToString(accountAdmin.getCreated_at())); + + + if( report != null){ + assign.setVisibility(View.VISIBLE); + status.setVisibility(View.VISIBLE); + if( report.getAssigned_account() == null){ + assign.setText(getString(R.string.assign_to_me)); + }else{ + assign.setText(getString(R.string.unassign)); + } + assign.setOnClickListener(view ->{ + if( report.getAssigned_account() == null){ + new PostAdminActionAsyncTask(getApplicationContext(), API.adminAction.ASSIGN_TO_SELF, report.getId(), null, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }else{ + new PostAdminActionAsyncTask(getApplicationContext(), API.adminAction.UNASSIGN, report.getId(), null, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + }); + + if( report.isAction_taken()){ + status.setText(getString(R.string.mark_unresolved)); + }else{ + status.setText(getString(R.string.mark_resolved)); + } + status.setOnClickListener(view ->{ + if( report.isAction_taken() ){ + new PostAdminActionAsyncTask(getApplicationContext(), API.adminAction.REOPEN, report.getId(), null, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }else{ + new PostAdminActionAsyncTask(getApplicationContext(), API.adminAction.RESOLVE, report.getId(), null, AccountReportActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + }); + + }else{ + assign.setVisibility(View.GONE); + status.setVisibility(View.GONE); + } + + } +} diff --git a/app/src/main/java/app/fedilab/android/activities/AdminActivity.java b/app/src/main/java/app/fedilab/android/activities/AdminActivity.java new file mode 100644 index 000000000..26204888f --- /dev/null +++ b/app/src/main/java/app/fedilab/android/activities/AdminActivity.java @@ -0,0 +1,363 @@ +/* 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 . */ +package app.fedilab.android.activities; + +import android.annotation.SuppressLint; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.PopupMenu; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentStatePagerAdapter; +import androidx.fragment.app.FragmentTransaction; +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.fragments.DisplayStatusFragment; +import app.fedilab.android.helper.Helper; + +import static app.fedilab.android.activities.BaseMainActivity.mPageReferenceMap; + + +/** + * Created by Thomas on 19/06/2019. + * Admin activity + */ + +public class AdminActivity extends BaseActivity { + + + private boolean unresolved; + private boolean local, remote, active, pending, disabled, silenced, suspended; + private DisplayAdminReportsFragment displayAdminReportsFragment; + private DisplayAdminAccountsFragment displayAdminAccountsFragment; + + + @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); + unresolved = local = active = true; + remote = pending = disabled = silenced = suspended = false; + 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))); + + + final LinearLayout tabStrip = (LinearLayout) admin_tablayout.getChildAt(0); + tabStrip.getChildAt(0).setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + PopupMenu popup = new PopupMenu(AdminActivity.this, tabStrip.getChildAt(0)); + popup.getMenuInflater() + .inflate(R.menu.option_filter_admin_reports, popup.getMenu()); + Menu menu = popup.getMenu(); + final MenuItem itemUnresolved = menu.findItem(R.id.action_unresolved_reports); + + + itemUnresolved.setChecked(unresolved); + + popup.setOnDismissListener(new PopupMenu.OnDismissListener() { + @Override + public void onDismiss(PopupMenu menu) { + FragmentTransaction fragTransaction = getSupportFragmentManager().beginTransaction(); + fragTransaction.detach(displayAdminReportsFragment); + Bundle bundle = new Bundle(); + bundle.putBoolean("unresolved",unresolved); + displayAdminReportsFragment.setArguments(bundle); + fragTransaction.attach(displayAdminReportsFragment); + fragTransaction.commit(); + } + }); + popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); + item.setActionView(new View(getApplicationContext())); + item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() { + @Override + public boolean onMenuItemActionExpand(MenuItem item) { + return false; + } + + @Override + public boolean onMenuItemActionCollapse(MenuItem item) { + return false; + } + }); + if (item.getItemId() == R.id.action_unresolved_reports) { + unresolved = !unresolved; + } + itemUnresolved.setChecked(unresolved); + return false; + } + }); + popup.show(); + return true; + } + }); + + + tabStrip.getChildAt(1).setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + PopupMenu popup = new PopupMenu(AdminActivity.this, tabStrip.getChildAt(1)); + popup.getMenuInflater() + .inflate(R.menu.option_filter_admin_accounts, popup.getMenu()); + Menu menu = popup.getMenu(); + final MenuItem itemLocal = menu.findItem(R.id.action_local); + final MenuItem itemRemote = menu.findItem(R.id.action_remote); + final MenuItem itemActive = menu.findItem(R.id.action_active); + final MenuItem itemPending = menu.findItem(R.id.action_pending); + final MenuItem itemDisabled = menu.findItem(R.id.action_disabled); + final MenuItem itemSilenced = menu.findItem(R.id.action_silenced); + final MenuItem itemSuspended = menu.findItem(R.id.action_suspended); + + itemLocal.setChecked(local); + itemRemote.setChecked(remote); + itemActive.setChecked(active); + itemPending.setChecked(pending); + itemDisabled.setChecked(disabled); + itemSilenced.setChecked(silenced); + itemSuspended.setChecked(suspended); + + popup.setOnDismissListener(new PopupMenu.OnDismissListener() { + @Override + public void onDismiss(PopupMenu menu) { + FragmentTransaction fragTransaction = getSupportFragmentManager().beginTransaction(); + fragTransaction.detach(displayAdminAccountsFragment); + Bundle bundle = new Bundle(); + bundle.putBoolean("local",local); + bundle.putBoolean("remote",remote); + bundle.putBoolean("active",active); + bundle.putBoolean("pending",pending); + bundle.putBoolean("disabled",disabled); + bundle.putBoolean("silenced",silenced); + bundle.putBoolean("suspended",suspended); + displayAdminAccountsFragment.setArguments(bundle); + fragTransaction.attach(displayAdminAccountsFragment); + fragTransaction.commit(); + + } + }); + popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); + item.setActionView(new View(getApplicationContext())); + item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() { + @Override + public boolean onMenuItemActionExpand(MenuItem item) { + return false; + } + + @Override + public boolean onMenuItemActionCollapse(MenuItem item) { + return false; + } + }); + switch (item.getItemId()){ + case R.id.action_local: + if( !local) { + remote = false; + local = true; + } + break; + case R.id.action_remote: + if( !remote) { + remote = true; + local = false; + } + break; + case R.id.action_active: + if( !active) { + active = true; + pending = false; + disabled = false; + silenced = false; + suspended = false; + } + break; + case R.id.action_pending: + if( !pending) { + pending = true; + active = false; + disabled = false; + silenced = false; + suspended = false; + } + break; + case R.id.action_disabled: + if( !disabled) { + disabled = true; + active = false; + pending = false; + silenced = false; + suspended = false; + } + break; + case R.id.action_silenced: + if( !silenced) { + silenced = true; + active = false; + pending = false; + disabled = false; + suspended = false; + } + break; + case R.id.action_suspended: + if( !suspended) { + suspended = true; + active = false; + pending = false; + disabled = false; + silenced = false; + } + break; + } + + itemLocal.setChecked(local); + itemRemote.setChecked(remote); + itemActive.setChecked(active); + itemPending.setChecked(pending); + itemDisabled.setChecked(disabled); + itemSilenced.setChecked(silenced); + itemSuspended.setChecked(suspended); + return false; + } + }); + popup.show(); + return true; + } + }); + + + + PagerAdapter mPagerAdapter = new AdminPagerAdapter(getSupportFragmentManager()); + admin_viewpager.setAdapter(mPagerAdapter); + admin_viewpager.setOffscreenPageLimit(2); + admin_viewpager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(admin_tablayout)); + 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) fragment); + displayAdminReportsFragment.scrollToTop(); + } + break; + case 1: + if( fragment != null) { + 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 = new DisplayAdminReportsFragment(); + bundle = new Bundle(); + bundle.putBoolean("unresolved",unresolved); + displayAdminReportsFragment.setArguments(bundle); + return displayAdminReportsFragment; + case 1: + displayAdminAccountsFragment = new DisplayAdminAccountsFragment(); + bundle = new Bundle(); + bundle.putBoolean("local",local); + bundle.putBoolean("remote",remote); + bundle.putBoolean("active",active); + bundle.putBoolean("pending",pending); + bundle.putBoolean("disabled",disabled); + bundle.putBoolean("silenced",silenced); + bundle.putBoolean("suspended",suspended); + displayAdminAccountsFragment.setArguments(bundle); + 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 92647cf9a..7e445e4fd 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java @@ -74,8 +74,11 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import app.fedilab.android.BuildConfig; +import app.fedilab.android.asynctasks.PostAdminActionAsyncTask; +import app.fedilab.android.client.API; import app.fedilab.android.client.APIResponse; import app.fedilab.android.client.Entities.Account; +import app.fedilab.android.client.Entities.AdminAction; import app.fedilab.android.client.Entities.Filters; import app.fedilab.android.client.Entities.ManageTimelines; import app.fedilab.android.client.Entities.Results; @@ -83,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; @@ -103,6 +107,7 @@ import app.fedilab.android.fragments.WhoToFollowFragment; import app.fedilab.android.helper.CrossActions; import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.MenuFloating; +import app.fedilab.android.interfaces.OnAdminActionInterface; import app.fedilab.android.services.BackupStatusService; import app.fedilab.android.services.LiveNotificationService; import app.fedilab.android.sqlite.AccountDAO; @@ -279,7 +284,6 @@ public abstract class BaseMainActivity extends BaseActivity viewPager = findViewById(R.id.viewpager); - display_timeline.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -1081,7 +1085,20 @@ public abstract class BaseMainActivity extends BaseActivity partnerShipItem.setVisible(false); } } - + if( MainActivity.social != UpdateAccountInfoAsyncTask.SOCIAL.MASTODON){ + MenuItem adminItem = navigationView.getMenu().findItem(R.id.nav_administration); + if( adminItem != null){ + adminItem.setVisible(false); + } + }else{ + boolean display_admin_menu = sharedpreferences.getBoolean(Helper.SET_DISPLAY_ADMIN_MENU + userId + instance, false); + if( !display_admin_menu){ + MenuItem adminItem = navigationView.getMenu().findItem(R.id.nav_administration); + if( adminItem != null){ + adminItem.setVisible(false); + } + } + } LinearLayout owner_container = headerLayout.findViewById(R.id.main_header_container); owner_container.setOnClickListener(new View.OnClickListener() { @Override @@ -1507,6 +1524,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 0d36c0864..4caf3b5c1 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; + public static 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=")){ @@ -547,7 +550,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); } @@ -875,8 +882,14 @@ public class LoginActivity extends BaseActivity { String queryString = Helper.CLIENT_ID + "="+ clientId; queryString += "&" + Helper.REDIRECT_URI + "="+ Uri.encode(Helper.REDIRECT_CONTENT_WEB); queryString += "&" + Helper.RESPONSE_TYPE +"=code"; - if( socialNetwork != UpdateAccountInfoAsyncTask.SOCIAL.PIXELFED ) - queryString += "&" + Helper.SCOPE +"=" + Helper.OAUTH_SCOPES; + if( socialNetwork != UpdateAccountInfoAsyncTask.SOCIAL.PIXELFED ) { + + if( admin ) { + queryString += "&" + Helper.SCOPE + "=" + Helper.OAUTH_SCOPES_ADMIN; + }else{ + queryString += "&" + Helper.SCOPE + "=" + Helper.OAUTH_SCOPES; + } + } return Helper.instanceWithProtocol(context, instance) + Helper.EP_AUTHORIZE + "?" + queryString; } diff --git a/app/src/main/java/app/fedilab/android/asynctasks/PostAdminActionAsyncTask.java b/app/src/main/java/app/fedilab/android/asynctasks/PostAdminActionAsyncTask.java new file mode 100644 index 000000000..eb7a5f7e6 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/asynctasks/PostAdminActionAsyncTask.java @@ -0,0 +1,76 @@ +/* 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 . */ +package app.fedilab.android.asynctasks; + +import android.content.Context; +import android.os.AsyncTask; + +import java.lang.ref.WeakReference; +import app.fedilab.android.client.API; +import app.fedilab.android.client.APIResponse; +import app.fedilab.android.client.Entities.AdminAction; +import app.fedilab.android.helper.Helper; +import app.fedilab.android.interfaces.OnAdminActionInterface; + + + +/** + * Created by Thomas on 18/06/2019. + * Makes actions for post admin calls + */ + +public class PostAdminActionAsyncTask extends AsyncTask { + + private OnAdminActionInterface listener; + private API.adminAction action; + private String id; + private WeakReference contextReference; + private APIResponse apiResponse; + private AdminAction adminAction; + + + + public PostAdminActionAsyncTask(Context context, API.adminAction action, String id, AdminAction adminAction, OnAdminActionInterface onAdminActionInterface){ + this.contextReference = new WeakReference<>(context); + this.listener = onAdminActionInterface; + this.action = action; + this.id = id; + this.adminAction = adminAction; + } + + + @Override + protected Void doInBackground(Void... params) { + switch (action){ + case GET_ACCOUNTS: + case GET_ONE_ACCOUNT: + case GET_REPORTS: + case GET_ONE_REPORT: + apiResponse = new API(contextReference.get()).adminGet(action, id, adminAction); + break; + default: + apiResponse = new API(contextReference.get()).adminDo(action, id, adminAction); + } + + + return null; + } + + @Override + protected void onPostExecute(Void result) { + listener.onAdminAction(apiResponse); + } + +} 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 bf41bb57f..6cf1ed17b 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; @@ -48,10 +49,13 @@ import java.util.Map; import app.fedilab.android.R; import app.fedilab.android.activities.LoginActivity; import app.fedilab.android.activities.MainActivity; +import app.fedilab.android.asynctasks.PostAdminActionAsyncTask; import app.fedilab.android.asynctasks.RetrieveOpenCollectiveAsyncTask; import app.fedilab.android.asynctasks.UpdateAccountInfoAsyncTask; import app.fedilab.android.client.Entities.Account; +import app.fedilab.android.client.Entities.AccountAdmin; import app.fedilab.android.client.Entities.AccountCreation; +import app.fedilab.android.client.Entities.AdminAction; import app.fedilab.android.client.Entities.Application; import app.fedilab.android.client.Entities.Attachment; import app.fedilab.android.client.Entities.Card; @@ -71,6 +75,7 @@ import app.fedilab.android.client.Entities.Peertube; import app.fedilab.android.client.Entities.Poll; import app.fedilab.android.client.Entities.PollOptions; import app.fedilab.android.client.Entities.Relationship; +import app.fedilab.android.client.Entities.Report; import app.fedilab.android.client.Entities.Results; import app.fedilab.android.client.Entities.Schedule; import app.fedilab.android.client.Entities.Status; @@ -114,6 +119,28 @@ public class API { ACCOUNTS } + + public enum adminAction{ + ENABLE, + APPROVE, + REJECT, + NONE, + SILENCE, + DISABLE, + UNSILENCE, + SUSPEND, + UNSUSPEND, + ASSIGN_TO_SELF, + UNASSIGN, + REOPEN, + RESOLVE, + GET_ACCOUNTS, + GET_ONE_ACCOUNT, + GET_REPORTS, + GET_ONE_REPORT + } + + public enum StatusAction{ FAVOURITE, UNFAVOURITE, @@ -149,12 +176,15 @@ public class API { UPDATESERVERSCHEDULE, DELETESCHEDULED, REFRESHPOLL - } + + public enum accountPrivacy { PUBLIC, LOCKED } + + public API(Context context) { this.context = context; if( context == null) { @@ -184,6 +214,246 @@ public class API { APIError = null; } + + /** + * Execute admin get actions + * @param action type of the action + * @param id String can for an account or a status + * @return APIResponse + */ + public APIResponse adminGet(adminAction action, String id, AdminAction adminAction){ + apiResponse = new APIResponse(); + HashMap params = null; + String endpoint = null; + switch (action){ + case GET_ACCOUNTS: + params = new HashMap<>(); + if( adminAction.isLocal()) + params.put("local", String.valueOf(adminAction.isLocal())); + if( adminAction.isRemote() ) + params.put("remote", String.valueOf(adminAction.isRemote())); + if( adminAction.isActive() ) + params.put("active", String.valueOf(adminAction.isActive())); + if( adminAction.isPending() ) + params.put("pending", String.valueOf(adminAction.isPending())); + if( adminAction.isDisabled() ) + params.put("disabled", String.valueOf(adminAction.isDisabled())); + if( adminAction.isSilenced() ) + params.put("silenced", String.valueOf(adminAction.isSilenced())); + if( adminAction.isSuspended() ) + params.put("suspended", String.valueOf(adminAction.isSuspended())); + endpoint = "/admin/accounts"; + break; + case GET_ONE_ACCOUNT: + endpoint = String.format("/admin/accounts/%s", id); + break; + case GET_REPORTS: + endpoint = "/admin/reports"; + if( !adminAction.isUnresolved()) { + params = new HashMap<>(); + params.put("resolved", "present"); + } + break; + case GET_ONE_REPORT: + endpoint = String.format("/admin/reports/%s", id); + break; + } + try { + String response = new HttpsConnection(context, this.instance).get(getAbsoluteUrl(endpoint), 60, params, prefKeyOauthTokenT); + switch (action){ + case GET_ACCOUNTS: + List accountAdmins = parseAccountAdminResponse(new JSONArray(response)); + apiResponse.setAccountAdmins(accountAdmins); + break; + case GET_ONE_ACCOUNT: + AccountAdmin accountAdmin = parseAccountAdminResponse(context, new JSONObject(response)); + accountAdmins = new ArrayList<>(); + accountAdmins.add(accountAdmin); + apiResponse.setAccountAdmins(accountAdmins); + break; + case GET_REPORTS: + List reports = parseReportAdminResponse(new JSONArray(response)); + apiResponse.setReports(reports); + break; + case GET_ONE_REPORT: + reports = new ArrayList<>(); + Report report = parseReportAdminResponse(context, new JSONObject(response)); + reports.add(report); + apiResponse.setReports(reports); + break; + } + } catch (IOException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (KeyManagementException e) { + e.printStackTrace(); + } catch (HttpsConnection.HttpsConnectionException e) { + setError(e.getStatusCode(), e); + e.printStackTrace(); + } catch (JSONException e) { + e.printStackTrace(); + } + return apiResponse; + } + + + /** + * Execute admin post actions + * @param action type of the action + * @param id String can for an account or a status + * @return APIResponse + */ + public APIResponse adminDo(adminAction action, String id, AdminAction adminAction){ + apiResponse = new APIResponse(); + String endpoint = null; + HashMap params = null; + switch (action){ + case ENABLE: + endpoint = String.format("/admin/accounts/%s/enable", id); + break; + case APPROVE: + endpoint = String.format("/admin/accounts/%s/approve", id); + break; + case REJECT: + endpoint = String.format("/admin/accounts/%s/reject", id); + break; + case UNSILENCE: + endpoint = String.format("/admin/accounts/%s/unsilence", id); + break; + case UNSUSPEND: + endpoint = String.format("/admin/accounts/%s/unsuspend", id); + break; + case ASSIGN_TO_SELF: + endpoint = String.format("/admin/reports/%s/assign_to_self", id); + break; + case UNASSIGN: + endpoint = String.format("/admin/reports/%s/unassign", id); + break; + case REOPEN: + endpoint = String.format("/admin/reports/%s/reopen", id); + break; + case RESOLVE: + endpoint = String.format("/admin/reports/%s/resolve", id); + break; + case NONE: + params = new HashMap<>(); + params.put("type","none"); + endpoint = String.format("/admin/accounts/%s/action", id); + params.put("send_email_notification", String.valueOf(adminAction.isSend_email_notification())); + if( adminAction.getText() != null) { + params.put("text", adminAction.getText()); + } + break; + case DISABLE: + params = new HashMap<>(); + params.put("type","disable"); + endpoint = String.format("/admin/accounts/%s/action", id); + params.put("send_email_notification", String.valueOf(adminAction.isSend_email_notification())); + if( adminAction.getText() != null) { + params.put("text", adminAction.getText()); + } + break; + case SILENCE: + params = new HashMap<>(); + params.put("type","silence"); + endpoint = String.format("/admin/accounts/%s/action", id); + params.put("send_email_notification", String.valueOf(adminAction.isSend_email_notification())); + if( adminAction.getText() != null) { + params.put("text", adminAction.getText()); + } + break; + case SUSPEND: + params = new HashMap<>(); + params.put("type","suspend"); + endpoint = String.format("/admin/accounts/%s/action", id); + params.put("send_email_notification", String.valueOf(adminAction.isSend_email_notification())); + if( adminAction.getText() != null) { + params.put("text", adminAction.getText()); + } + break; + } + try { + String response = new HttpsConnection(context, this.instance).post(getAbsoluteUrl(endpoint), 60, params, prefKeyOauthTokenT); + switch (action){ + case ENABLE: + case APPROVE: + case REJECT: + case UNSILENCE: + // case UNDISABLE: + case UNSUSPEND: + List accountAdmins = null; + try { + AccountAdmin accountAdmin = parseAccountAdminResponse(context, new JSONObject(response)); + accountAdmin.setAction(action); + accountAdmins = new ArrayList<>(); + accountAdmins.add(accountAdmin); + } catch (JSONException e) { + e.printStackTrace(); + } + apiResponse.setAccountAdmins(accountAdmins); + break; + case ASSIGN_TO_SELF: + case UNASSIGN: + case REOPEN: + case RESOLVE: + List reports = null; + Report report; + try { + reports = new ArrayList<>(); + report = parseReportAdminResponse(context, new JSONObject(response)); + reports.add(report); + } catch (JSONException e) { + e.printStackTrace(); + } + apiResponse.setReports(reports); + + break; + case NONE: + accountAdmins = new ArrayList<>(); + AccountAdmin accountAdmin = new AccountAdmin(); + accountAdmin.setAction(action); + accountAdmins.add(accountAdmin); + apiResponse.setAccountAdmins(accountAdmins); + break; + case DISABLE: + accountAdmins = new ArrayList<>(); + accountAdmin = new AccountAdmin(); + accountAdmin.setDisabled(true); + accountAdmin.setAction(action); + accountAdmins.add(accountAdmin); + apiResponse.setAccountAdmins(accountAdmins); + break; + case SILENCE: + accountAdmins = new ArrayList<>(); + accountAdmin = new AccountAdmin(); + accountAdmin.setSilenced(true); + accountAdmin.setAction(action); + accountAdmins.add(accountAdmin); + apiResponse.setAccountAdmins(accountAdmins); + break; + case SUSPEND: + accountAdmins = new ArrayList<>(); + accountAdmin = new AccountAdmin(); + accountAdmin.setSuspended(true); + accountAdmin.setAction(action); + accountAdmins.add(accountAdmin); + apiResponse.setAccountAdmins(accountAdmins); + break; + } + } catch (IOException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (KeyManagementException e) { + e.printStackTrace(); + } catch (HttpsConnection.HttpsConnectionException e) { + setError(e.getStatusCode(), e); + e.printStackTrace(); + } + return apiResponse; + } + public InstanceNodeInfo getNodeInfo(String domain){ //Try to guess URL scheme for the onion instance @@ -327,6 +597,9 @@ public class API { } + + + /*** * Get info on the current Instance *synchronously* * @return APIResponse @@ -4814,6 +5087,151 @@ public class API { return account; } + + /** + * Parse json response for list of reports for admins + * @param jsonArray JSONArray + * @return List + */ + private List parseReportAdminResponse(JSONArray jsonArray){ + + List reports = new ArrayList<>(); + try { + int i = 0; + while (i < jsonArray.length() ) { + JSONObject resobj = jsonArray.getJSONObject(i); + Report report = parseReportAdminResponse(context, resobj); + reports.add(report); + i++; + } + } catch (JSONException e) { + setDefaultError(e); + } + return reports; + } + + /** + * Parse json response an unique report for admins + * @param resobj JSONObject + * @return AccountAdmin + */ + private static Report parseReportAdminResponse(Context context, JSONObject resobj){ + + Report report = new Report(); + try { + report.setId(resobj.getString("id")); + report.setAction_taken(resobj.getBoolean("action_taken")); + report.setComment(resobj.getString("comment")); + report.setCreated_at(Helper.mstStringToDate(context, resobj.getString("created_at"))); + report.setUpdated_at(Helper.mstStringToDate(context, resobj.getString("updated_at"))); + if( !resobj.isNull("account")) { + report.setAccount(parseAccountAdminResponse(context, resobj.getJSONObject("account"))); + } + if( !resobj.isNull("target_account")) { + report.setTarget_account(parseAccountAdminResponse(context, resobj.getJSONObject("target_account"))); + } + if( !resobj.isNull("assigned_account")) { + report.setAssigned_account(parseAccountAdminResponse(context, resobj.getJSONObject("assigned_account"))); + } + if( !resobj.isNull("action_taken_by_account")) { + report.setAction_taken_by_account(parseAccountAdminResponse(context, resobj.getJSONObject("action_taken_by_account"))); + } + report.setStatuses(parseStatuses(context, resobj.getJSONArray("statuses"))); + }catch (Exception ignored){ignored.printStackTrace();} + return report; + } + + + /** + * Parse json response for list of accounts for admins + * @param jsonArray JSONArray + * @return List + */ + private List parseAccountAdminResponse(JSONArray jsonArray){ + + List accountAdmins = new ArrayList<>(); + try { + int i = 0; + while (i < jsonArray.length() ) { + JSONObject resobj = jsonArray.getJSONObject(i); + AccountAdmin accountAdmin = parseAccountAdminResponse(context, resobj); + accountAdmins.add(accountAdmin); + i++; + } + } catch (JSONException e) { + setDefaultError(e); + } + return accountAdmins; + } + + /** + * Parse json response an unique account for admins + * @param resobj JSONObject + * @return Account + */ + private static AccountAdmin parseAccountAdminResponse(Context context, JSONObject resobj){ + + AccountAdmin accountAdmin = new AccountAdmin(); + try { + accountAdmin.setId(resobj.get("id").toString()); + accountAdmin.setUsername(resobj.getString("username")); + accountAdmin.setCreated_at(Helper.mstStringToDate(context, resobj.getString("created_at"))); + accountAdmin.setEmail(resobj.getString("email")); + accountAdmin.setRole(resobj.getString("role")); + accountAdmin.setIp(resobj.getString("ip")); + accountAdmin.setDomain(resobj.getString("domain")); + accountAdmin.setAccount(parseAccountResponse(context, resobj.getJSONObject("account"))); + if( !resobj.isNull("confirmed")) { + accountAdmin.setConfirmed(resobj.getBoolean("confirmed")); + }else{ + accountAdmin.setConfirmed(true); + } + if( !resobj.isNull("suspended")) { + accountAdmin.setSuspended(resobj.getBoolean("suspended")); + }else{ + accountAdmin.setSuspended(false); + } + if( !resobj.isNull("silenced")) { + accountAdmin.setSilenced(resobj.getBoolean("silenced")); + }else{ + accountAdmin.setSilenced(false); + } + if( !resobj.isNull("disabled")) { + accountAdmin.setDisabled(resobj.getBoolean("disabled")); + }else{ + accountAdmin.setDisabled(false); + } + if( !resobj.isNull("approved")) { + accountAdmin.setApproved(resobj.getBoolean("approved")); + }else{ + accountAdmin.setApproved(false); + } + }catch (Exception ignored){} + return accountAdmin; + } + + /** + * Parse json response for list of accounts + * @param jsonArray JSONArray + * @return List + */ + private List parseAccountResponse(JSONArray jsonArray){ + + List accounts = new ArrayList<>(); + try { + int i = 0; + while (i < jsonArray.length() ) { + JSONObject resobj = jsonArray.getJSONObject(i); + Account account = parseAccountResponse(context, resobj); + accounts.add(account); + i++; + } + } catch (JSONException e) { + setDefaultError(e); + } + return accounts; + } + /** * Parse json response an unique account * @param resobj JSONObject @@ -5029,27 +5447,7 @@ public class API { } catch (JSONException ignored) {} return account; } - /** - * Parse json response for list of accounts - * @param jsonArray JSONArray - * @return List - */ - private List parseAccountResponse(JSONArray jsonArray){ - List accounts = new ArrayList<>(); - try { - int i = 0; - while (i < jsonArray.length() ) { - JSONObject resobj = jsonArray.getJSONObject(i); - Account account = parseAccountResponse(context, resobj); - accounts.add(account); - i++; - } - } catch (JSONException e) { - setDefaultError(e); - } - return accounts; - } /** diff --git a/app/src/main/java/app/fedilab/android/client/APIResponse.java b/app/src/main/java/app/fedilab/android/client/APIResponse.java index f869dc467..f588973fd 100644 --- a/app/src/main/java/app/fedilab/android/client/APIResponse.java +++ b/app/src/main/java/app/fedilab/android/client/APIResponse.java @@ -19,6 +19,7 @@ import android.content.Context; import java.util.List; import app.fedilab.android.client.Entities.Account; +import app.fedilab.android.client.Entities.AccountAdmin; import app.fedilab.android.client.Entities.Conversation; import app.fedilab.android.client.Entities.Emojis; import app.fedilab.android.client.Entities.Error; @@ -31,6 +32,7 @@ import app.fedilab.android.client.Entities.Peertube; import app.fedilab.android.client.Entities.PeertubeNotification; import app.fedilab.android.client.Entities.Playlist; import app.fedilab.android.client.Entities.Relationship; +import app.fedilab.android.client.Entities.Report; import app.fedilab.android.client.Entities.Results; import app.fedilab.android.client.Entities.Status; import app.fedilab.android.client.Entities.StoredStatus; @@ -64,7 +66,8 @@ public class APIResponse { private boolean fetchmore = false; private List playlistForVideos; private List instanceRegs = null; - + private List accountAdmins = null; + private List reports = null; public List getAccounts() { return accounts; @@ -249,4 +252,20 @@ public class APIResponse { public void setInstanceRegs(List instanceRegs) { this.instanceRegs = instanceRegs; } + + public List getAccountAdmins() { + return accountAdmins; + } + + public void setAccountAdmins(List accountAdmins) { + this.accountAdmins = accountAdmins; + } + + public List getReports() { + return reports; + } + + public void setReports(List reports) { + this.reports = reports; + } } diff --git a/app/src/main/java/app/fedilab/android/client/Entities/Account.java b/app/src/main/java/app/fedilab/android/client/Entities/Account.java index dc98e6ed6..e6884bf97 100644 --- a/app/src/main/java/app/fedilab/android/client/Entities/Account.java +++ b/app/src/main/java/app/fedilab/android/client/Entities/Account.java @@ -120,6 +120,11 @@ public class Account implements Parcelable { private String privacy = "public"; private boolean sensitive = false; + private String locale; + private String invite_request; + private String created_by_application_id; + private String invited_by_account_id; + @@ -176,6 +181,10 @@ public class Account implements Parcelable { dest.writeByte(this.isAdmin ? (byte) 1 : (byte) 0); dest.writeString(this.privacy); dest.writeByte(this.sensitive ? (byte) 1 : (byte) 0); + dest.writeString(this.locale); + dest.writeString(this.invite_request); + dest.writeString(this.created_by_application_id); + dest.writeString(this.invited_by_account_id); } public Account() { @@ -231,6 +240,10 @@ public class Account implements Parcelable { this.isAdmin = in.readByte() != 0; this.privacy = in.readString(); this.sensitive =in.readByte() != 0; + this.locale = in.readString(); + this.invite_request = in.readString(); + this.created_by_application_id = in.readString(); + this.invited_by_account_id = in.readString(); } public static final Creator CREATOR = new Creator() { @@ -406,6 +419,38 @@ public class Account implements Parcelable { this.sensitive = sensitive; } + public String getLocale() { + return locale; + } + + public void setLocale(String locale) { + this.locale = locale; + } + + public String getInvite_request() { + return invite_request; + } + + public void setInvite_request(String invite_request) { + this.invite_request = invite_request; + } + + public String getCreated_by_application_id() { + return created_by_application_id; + } + + public void setCreated_by_application_id(String created_by_application_id) { + this.created_by_application_id = created_by_application_id; + } + + public String getInvited_by_account_id() { + return invited_by_account_id; + } + + public void setInvited_by_account_id(String invited_by_account_id) { + this.invited_by_account_id = invited_by_account_id; + } + public enum followAction{ FOLLOW, diff --git a/app/src/main/java/app/fedilab/android/client/Entities/AccountAdmin.java b/app/src/main/java/app/fedilab/android/client/Entities/AccountAdmin.java new file mode 100644 index 000000000..112567a7b --- /dev/null +++ b/app/src/main/java/app/fedilab/android/client/Entities/AccountAdmin.java @@ -0,0 +1,209 @@ +package app.fedilab.android.client.Entities; +/* 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.os.Parcel; +import android.os.Parcelable; + +import java.util.Date; + +import app.fedilab.android.client.API; + +public class AccountAdmin implements Parcelable { + + private String id; + private String username; + private Date created_at; + private String email; + private String role; + private String ip; + private String domain; + private boolean confirmed; + private boolean suspended; + private boolean silenced; + private boolean disabled; + private Account account; + private API.adminAction action; + private boolean approved; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Date getCreated_at() { + return created_at; + } + + public void setCreated_at(Date created_at) { + this.created_at = created_at; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public boolean isConfirmed() { + return confirmed; + } + + public void setConfirmed(boolean confirmed) { + this.confirmed = confirmed; + } + + public boolean isSuspended() { + return suspended; + } + + public void setSuspended(boolean suspended) { + this.suspended = suspended; + } + + public boolean isSilenced() { + return silenced; + } + + public void setSilenced(boolean silenced) { + this.silenced = silenced; + } + + public boolean isDisabled() { + return disabled; + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + } + + public Account getAccount() { + return account; + } + + public void setAccount(Account account) { + this.account = account; + } + + + public AccountAdmin() { + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public API.adminAction getAction() { + return action; + } + + public void setAction(API.adminAction action) { + this.action = action; + } + + public boolean isApproved() { + return approved; + } + + public void setApproved(boolean approved) { + this.approved = approved; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.id); + dest.writeString(this.username); + dest.writeLong(this.created_at != null ? this.created_at.getTime() : -1); + dest.writeString(this.email); + dest.writeString(this.role); + dest.writeString(this.ip); + dest.writeString(this.domain); + dest.writeByte(this.confirmed ? (byte) 1 : (byte) 0); + dest.writeByte(this.suspended ? (byte) 1 : (byte) 0); + dest.writeByte(this.silenced ? (byte) 1 : (byte) 0); + dest.writeByte(this.disabled ? (byte) 1 : (byte) 0); + dest.writeParcelable(this.account, flags); + dest.writeInt(this.action == null ? -1 : this.action.ordinal()); + dest.writeByte(this.approved ? (byte) 1 : (byte) 0); + } + + protected AccountAdmin(Parcel in) { + this.id = in.readString(); + this.username = in.readString(); + long tmpCreated_at = in.readLong(); + this.created_at = tmpCreated_at == -1 ? null : new Date(tmpCreated_at); + this.email = in.readString(); + this.role = in.readString(); + this.ip = in.readString(); + this.domain = in.readString(); + this.confirmed = in.readByte() != 0; + this.suspended = in.readByte() != 0; + this.silenced = in.readByte() != 0; + this.disabled = in.readByte() != 0; + this.account = in.readParcelable(Account.class.getClassLoader()); + int tmpAction = in.readInt(); + this.action = tmpAction == -1 ? null : API.adminAction.values()[tmpAction]; + this.approved = in.readByte() != 0; + } + + public static final Creator CREATOR = new Creator() { + @Override + public AccountAdmin createFromParcel(Parcel source) { + return new AccountAdmin(source); + } + + @Override + public AccountAdmin[] newArray(int size) { + return new AccountAdmin[size]; + } + }; +} diff --git a/app/src/main/java/app/fedilab/android/client/Entities/AccountCreation.java b/app/src/main/java/app/fedilab/android/client/Entities/AccountCreation.java index 70787fd33..2d38eba37 100644 --- a/app/src/main/java/app/fedilab/android/client/Entities/AccountCreation.java +++ b/app/src/main/java/app/fedilab/android/client/Entities/AccountCreation.java @@ -1,5 +1,18 @@ package app.fedilab.android.client.Entities; - +/* 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 . */ public class AccountCreation { private String username; diff --git a/app/src/main/java/app/fedilab/android/client/Entities/AdminAction.java b/app/src/main/java/app/fedilab/android/client/Entities/AdminAction.java new file mode 100644 index 000000000..05703feb7 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/client/Entities/AdminAction.java @@ -0,0 +1,121 @@ +package app.fedilab.android.client.Entities; + +import app.fedilab.android.client.API; + +/* 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 . */ +public class AdminAction { + + + + private API.adminAction type; + private boolean send_email_notification; + private String text; + private boolean unresolved; + private boolean local, remote, active, pending, disabled, silenced, suspended; + + + public boolean isLocal() { + return local; + } + + public void setLocal(boolean local) { + this.local = local; + } + + public boolean isRemote() { + return remote; + } + + public void setRemote(boolean remote) { + this.remote = remote; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + + public boolean isPending() { + return pending; + } + + public void setPending(boolean pending) { + this.pending = pending; + } + + public boolean isDisabled() { + return disabled; + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + } + + public boolean isSilenced() { + return silenced; + } + + public void setSilenced(boolean silenced) { + this.silenced = silenced; + } + + public boolean isSuspended() { + return suspended; + } + + public void setSuspended(boolean suspended) { + this.suspended = suspended; + } + + + + public boolean isUnresolved() { + return unresolved; + } + + public void setUnresolved(boolean unresolved) { + this.unresolved = unresolved; + } + + + public boolean isSend_email_notification() { + return send_email_notification; + } + + public void setSend_email_notification(boolean send_email_notification) { + this.send_email_notification = send_email_notification; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + + public API.adminAction getType() { + return type; + } + + public void setType(API.adminAction type) { + this.type = type; + } +} diff --git a/app/src/main/java/app/fedilab/android/client/Entities/Report.java b/app/src/main/java/app/fedilab/android/client/Entities/Report.java new file mode 100644 index 000000000..3fd8025d4 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/client/Entities/Report.java @@ -0,0 +1,168 @@ +package app.fedilab.android.client.Entities; +/* 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.os.Parcel; +import android.os.Parcelable; + +import java.util.Date; +import java.util.List; + +public class Report implements Parcelable { + + private String id; + private boolean action_taken; + private String comment; + private Date created_at; + private Date updated_at; + private AccountAdmin account; + private AccountAdmin target_account; + private AccountAdmin assigned_account; + private AccountAdmin action_taken_by_account; + private List statuses; + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public Date getCreated_at() { + return created_at; + } + + public void setCreated_at(Date created_at) { + this.created_at = created_at; + } + + public Date getUpdated_at() { + return updated_at; + } + + public void setUpdated_at(Date updated_at) { + this.updated_at = updated_at; + } + + public List getStatuses() { + return statuses; + } + + public void setStatuses(List statuses) { + this.statuses = statuses; + } + + + public Report() { + } + + public AccountAdmin getAccount() { + return account; + } + + public void setAccount(AccountAdmin account) { + this.account = account; + } + + public AccountAdmin getTarget_account() { + return target_account; + } + + public void setTarget_account(AccountAdmin target_account) { + this.target_account = target_account; + } + + public AccountAdmin getAssigned_account() { + return assigned_account; + } + + public void setAssigned_account(AccountAdmin assigned_account) { + this.assigned_account = assigned_account; + } + + public boolean isAction_taken() { + return action_taken; + } + + public void setAction_taken(boolean action_taken) { + this.action_taken = action_taken; + } + + public AccountAdmin getAction_taken_by_account() { + return action_taken_by_account; + } + + public void setAction_taken_by_account(AccountAdmin action_taken_by_account) { + this.action_taken_by_account = action_taken_by_account; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.id); + dest.writeByte(this.action_taken ? (byte) 1 : (byte) 0); + dest.writeString(this.comment); + dest.writeLong(this.created_at != null ? this.created_at.getTime() : -1); + dest.writeLong(this.updated_at != null ? this.updated_at.getTime() : -1); + dest.writeParcelable(this.account, flags); + dest.writeParcelable(this.target_account, flags); + dest.writeParcelable(this.assigned_account, flags); + dest.writeParcelable(this.action_taken_by_account, flags); + dest.writeTypedList(this.statuses); + } + + protected Report(Parcel in) { + this.id = in.readString(); + this.action_taken = in.readByte() != 0; + this.comment = in.readString(); + long tmpCreated_at = in.readLong(); + this.created_at = tmpCreated_at == -1 ? null : new Date(tmpCreated_at); + long tmpUpdated_at = in.readLong(); + this.updated_at = tmpUpdated_at == -1 ? null : new Date(tmpUpdated_at); + this.account = in.readParcelable(AccountAdmin.class.getClassLoader()); + this.target_account = in.readParcelable(AccountAdmin.class.getClassLoader()); + this.assigned_account = in.readParcelable(AccountAdmin.class.getClassLoader()); + this.action_taken_by_account = in.readParcelable(AccountAdmin.class.getClassLoader()); + this.statuses = in.createTypedArrayList(Status.CREATOR); + } + + public static final Creator CREATOR = new Creator() { + @Override + public Report createFromParcel(Parcel source) { + return new Report(source); + } + + @Override + public Report[] newArray(int size) { + return new Report[size]; + } + }; +} 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..af980fba5 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/drawers/AccountsAdminListAdapter.java @@ -0,0 +1,169 @@ +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.content.Intent; +import android.os.Bundle; +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.activities.AccountReportActivity; +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()); + Helper.loadGiF(context, account.getAvatar(), holder.account_pp); + + + holder.main_container.setOnClickListener(view ->{ + Intent intent = new Intent(context, AccountReportActivity.class); + Bundle b = new Bundle(); + b.putParcelable("targeted_account", accountAdmin); + intent.putExtras(b); + context.startActivity(intent); + }); + } + + @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 main_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); + main_container = itemView.findViewById(R.id.main_container); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/android/drawers/AccountsListAdapter.java b/app/src/main/java/app/fedilab/android/drawers/AccountsListAdapter.java index 393bf1518..1e4554f9b 100644 --- a/app/src/main/java/app/fedilab/android/drawers/AccountsListAdapter.java +++ b/app/src/main/java/app/fedilab/android/drawers/AccountsListAdapter.java @@ -179,12 +179,12 @@ public class AccountsListAdapter extends RecyclerView.Adapter implements OnPostA 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("@","")); + holder.account_dn.setText(account.getUsername().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())) + if( account.getUsername().equals(account.getAcct())) holder.account_ac.setVisibility(View.GONE); else holder.account_ac.setVisibility(View.VISIBLE); 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..e9a427464 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/drawers/ReportsListAdapter.java @@ -0,0 +1,176 @@ +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.content.Intent; +import android.os.Bundle; +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.activities.AccountReportActivity; +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.getAccount().getAccount(); + Account target_account = report.getTarget_account().getAccount(); + + + account.makeAccountNameEmoji(context, ReportsListAdapter.this, account); + target_account.makeAccountNameEmoji(context, ReportsListAdapter.this, target_account); + if( account.getdisplayNameSpan() == null || account.getdisplayNameSpan().toString().trim().equals("")) { + if( account.getDisplay_name() != null && !account.getDisplay_name().trim().equals("")) + holder.account_dn_reporter.setText(Helper.shortnameToUnicode(account.getDisplay_name(), true)); + else + holder.account_dn_reporter.setText(account.getUsername().replace("@","")); + }else + holder.account_dn_reporter.setText( account.getdisplayNameSpan(), TextView.BufferType.SPANNABLE); + + if( target_account.getdisplayNameSpan() == null || target_account.getdisplayNameSpan().toString().trim().equals("")) { + if( target_account.getDisplay_name() != null && !target_account.getDisplay_name().trim().equals("")) + holder.account_dn.setText(Helper.shortnameToUnicode(target_account.getDisplay_name(), true)); + else + holder.account_dn.setText(target_account.getUsername().replace("@","")); + }else + holder.account_dn.setText( target_account.getdisplayNameSpan(), TextView.BufferType.SPANNABLE); + + + + Helper.loadGiF(context, target_account.getAvatar(), holder.account_pp); + Helper.loadGiF(context, account.getAvatar(), holder.account_pp_reporter); + holder.account_ac.setText(target_account.getAcct()); + + holder.report_comment.setText(report.getComment()); + + if( report.getStatuses() != null){ + holder.report_number_status.setText(String.valueOf(report.getStatuses().size())); + }else{ + holder.report_number_status.setText("0"); + } + + holder.main_container.setOnClickListener(view ->{ + Intent intent = new Intent(context, AccountReportActivity.class); + Bundle b = new Bundle(); + b.putParcelable("report", report); + intent.putExtras(b); + context.startActivity(intent); + }); + + } + + @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, account_pp_reporter; + TextView account_ac; + TextView account_dn, account_dn_reporter; + TextView report_comment, report_number_status; + + LinearLayout main_container; + + ViewHolder(View itemView) { + super(itemView); + account_pp = itemView.findViewById(R.id.account_pp); + account_pp_reporter = itemView.findViewById(R.id.account_pp_reporter); + account_dn = itemView.findViewById(R.id.account_dn); + account_dn_reporter = itemView.findViewById(R.id.account_dn_reporter); + account_ac = itemView.findViewById(R.id.account_ac); + report_comment = itemView.findViewById(R.id.report_comment); + main_container = itemView.findViewById(R.id.main_container); + report_number_status = itemView.findViewById(R.id.report_number_status); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/android/drawers/StatusListAdapter.java b/app/src/main/java/app/fedilab/android/drawers/StatusListAdapter.java index b0da9250c..247943837 100644 --- a/app/src/main/java/app/fedilab/android/drawers/StatusListAdapter.java +++ b/app/src/main/java/app/fedilab/android/drawers/StatusListAdapter.java @@ -97,6 +97,7 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import app.fedilab.android.activities.AccountReportActivity; import app.fedilab.android.client.API; import app.fedilab.android.client.APIResponse; import app.fedilab.android.client.Entities.Account; @@ -2361,7 +2362,14 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct popup.getMenu().findItem(R.id.action_schedule_boost).setVisible(false); popup.getMenu().findItem(R.id.action_mention).setVisible(false); } - + if( MainActivity.social != UpdateAccountInfoAsyncTask.SOCIAL.MASTODON){ + popup.getMenu().findItem(R.id.action_admin).setVisible(false); + }else{ + boolean display_admin_statuses = sharedpreferences.getBoolean(Helper.SET_DISPLAY_ADMIN_STATUSES + userId + Helper.getLiveInstance(context), false); + if( !display_admin_statuses){ + popup.getMenu().findItem(R.id.action_admin).setVisible(false); + } + } boolean custom_sharing = sharedpreferences.getBoolean(Helper.SET_CUSTOM_SHARING, false); if( custom_sharing && status.getVisibility().equals("public")) @@ -2393,7 +2401,14 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct break; case R.id.action_schedule_boost: scheduleBoost(status); - + return true; + case R.id.action_admin: + String account_id = status.getReblog() != null ? status.getReblog().getAccount().getId() : status.getAccount().getId(); + Intent intent = new Intent(context, AccountReportActivity.class); + Bundle b = new Bundle(); + b.putString("account_id", account_id); + intent.putExtras(b); + context.startActivity(intent); return true; case R.id.action_info: tootInformation(status); diff --git a/app/src/main/java/app/fedilab/android/drawers/StatusReportAdapter.java b/app/src/main/java/app/fedilab/android/drawers/StatusReportAdapter.java new file mode 100644 index 000000000..8052f0810 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/drawers/StatusReportAdapter.java @@ -0,0 +1,99 @@ +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.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +import app.fedilab.android.R; + +public class StatusReportAdapter extends RecyclerView.Adapter { + + private List mData; + private LayoutInflater mInflater; + private ItemClickListener mClickListener; + + + public StatusReportAdapter(Context context, List data) { + this.mInflater = LayoutInflater.from(context); + this.mData = data; + } + + + @NotNull + @Override + public ViewHolder onCreateViewHolder(@NotNull ViewGroup parent, int viewType) { + View view = mInflater.inflate(R.layout.drawer_status_report, parent, false); + return new ViewHolder(view); + } + + + @Override + public void onBindViewHolder(@NotNull ViewHolder holder, int position) { + String content; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + content = Html.fromHtml(mData.get(position), Html.FROM_HTML_MODE_LEGACY).toString(); + else + content = Html.fromHtml(mData.get(position)).toString(); + holder.report_content.setText(content); + } + + // total number of rows + @Override + public int getItemCount() { + return mData.size(); + } + + + + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + TextView report_content; + + ViewHolder(View itemView) { + super(itemView); + report_content = itemView.findViewById(R.id.report_content); + itemView.setOnClickListener(this); + } + + @Override + public void onClick(View view) { + if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition()); + } + } + + String getItem(int id) { + return mData.get(id); + } + + void setClickListener(ItemClickListener itemClickListener) { + this.mClickListener = itemClickListener; + } + + public interface ItemClickListener { + void onItemClick(View view, int position); + } +} \ 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..ce822f75f --- /dev/null +++ b/app/src/main/java/app/fedilab/android/fragments/DisplayAdminAccountsFragment.java @@ -0,0 +1,259 @@ +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.client.Entities.AdminAction; +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 accounts + */ +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; + private boolean local, remote, active, pending, disabled, silenced, suspended; + + @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<>(); + + + Bundle bundle = this.getArguments(); + if (bundle != null) { + local = bundle.getBoolean("local", false); + remote = bundle.getBoolean("remote", false); + active = bundle.getBoolean("active", false); + pending = bundle.getBoolean("pending", false); + disabled = bundle.getBoolean("disabled", false); + silenced = bundle.getBoolean("silenced", false); + suspended = bundle.getBoolean("suspended", false); + } + + 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; + AdminAction adminAction = new AdminAction(); + adminAction.setLocal(local); + adminAction.setRemote(remote); + adminAction.setActive(active); + adminAction.setPending(pending); + adminAction.setDisabled(disabled); + adminAction.setSilenced(silenced); + adminAction.setSuspended(suspended); + asyncTask = new PostAdminActionAsyncTask(context, API.adminAction.GET_ACCOUNTS, null, adminAction, 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; + AdminAction adminAction = new AdminAction(); + adminAction.setLocal(local); + adminAction.setRemote(remote); + adminAction.setActive(active); + adminAction.setPending(pending); + adminAction.setDisabled(disabled); + adminAction.setSilenced(silenced); + adminAction.setSuspended(suspended); + asyncTask = new PostAdminActionAsyncTask(context, API.adminAction.GET_ACCOUNTS, null, adminAction, 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; + } + AdminAction adminAction = new AdminAction(); + adminAction.setLocal(local); + adminAction.setRemote(remote); + adminAction.setActive(active); + adminAction.setPending(pending); + adminAction.setDisabled(disabled); + adminAction.setSilenced(silenced); + adminAction.setSuspended(suspended); + asyncTask = new PostAdminActionAsyncTask(context, API.adminAction.GET_ACCOUNTS, null, adminAction, DisplayAdminAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + return rootView; + } + + @Override + public void onCreate(Bundle saveInstance) + { + super.onCreate(saveInstance); + } + + + + /** + * Refresh accounts in list + */ + public void refreshFilter(){ + accountsAdminListAdapter.notifyDataSetChanged(); + } + + @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..d139b208e --- /dev/null +++ b/app/src/main/java/app/fedilab/android/fragments/DisplayAdminReportsFragment.java @@ -0,0 +1,262 @@ +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.AdminAction; +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; + private boolean unresolved; + @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<>(); + + Bundle bundle = this.getArguments(); + if (bundle != null) { + unresolved = bundle.getBoolean("unresolved", true); + } + 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; + AdminAction adminAction = new AdminAction(); + adminAction.setUnresolved(unresolved); + asyncTask = new PostAdminActionAsyncTask(context, API.adminAction.GET_REPORTS, null, adminAction, 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; + AdminAction adminAction = new AdminAction(); + adminAction.setUnresolved(unresolved); + asyncTask = new PostAdminActionAsyncTask(context, API.adminAction.GET_REPORTS, null, adminAction, 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; + } + AdminAction adminAction = new AdminAction(); + adminAction.setUnresolved(unresolved); + asyncTask = new PostAdminActionAsyncTask(context, API.adminAction.GET_REPORTS, null, adminAction, DisplayAdminReportsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + return rootView; + } + + @Override + public void onCreate(Bundle saveInstance) + { + super.onCreate(saveInstance); + } + + + /** + * Refresh report in list + */ + public void refreshFilter(){ + reportsListAdapter.notifyDataSetChanged(); + } + + @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){ + 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.AdminDialog); + 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(); + }else{ + Toasty.error(context, apiResponse.getError().getError(),Toast.LENGTH_LONG).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/java/app/fedilab/android/fragments/SettingsFragment.java b/app/src/main/java/app/fedilab/android/fragments/SettingsFragment.java index 3ef99fa6f..cc2d46cda 100644 --- a/app/src/main/java/app/fedilab/android/fragments/SettingsFragment.java +++ b/app/src/main/java/app/fedilab/android/fragments/SettingsFragment.java @@ -342,6 +342,41 @@ public class SettingsFragment extends Fragment { } }); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + String instance = sharedpreferences.getString(Helper.PREF_INSTANCE, Helper.getLiveInstance(context)); + + boolean display_admin_menu = sharedpreferences.getBoolean(Helper.SET_DISPLAY_ADMIN_MENU + userId + instance, false); + + final CheckBox set_display_admin_menu = rootView.findViewById(R.id.set_display_admin_menu); + set_display_admin_menu.setChecked(display_admin_menu); + set_display_admin_menu.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putBoolean(Helper.SET_DISPLAY_ADMIN_MENU + userId + instance, set_display_admin_menu.isChecked()); + editor.apply(); + } + }); + + boolean display_admin_statuses = sharedpreferences.getBoolean(Helper.SET_DISPLAY_ADMIN_STATUSES + userId + instance, false); + + final CheckBox set_display_admin_statuses = rootView.findViewById(R.id.set_display_admin_statuses); + set_display_admin_statuses.setChecked(display_admin_statuses); + set_display_admin_statuses.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putBoolean(Helper.SET_DISPLAY_ADMIN_STATUSES + userId + instance, set_display_admin_statuses.isChecked()); + editor.apply(); + } + }); + + if( MainActivity.social != UpdateAccountInfoAsyncTask.SOCIAL.MASTODON){ + LinearLayout admin_container = rootView.findViewById(R.id.admin_container); + if( admin_container != null){ + admin_container.setVisibility(View.GONE); + } + } boolean show_media_urls = sharedpreferences.getBoolean(Helper.SET_MEDIA_URLS, false); final CheckBox set_auto_add_media_url = rootView.findViewById(R.id.set_auto_add_media_url); @@ -1022,8 +1057,7 @@ public class SettingsFragment extends Fragment { LinearLayout toot_visibility_container = rootView.findViewById(R.id.toot_visibility_container); SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - String instance = sharedpreferences.getString(Helper.PREF_INSTANCE, Helper.getLiveInstance(context)); + final Account account = new AccountDAO(context, db).getUniqAccount(userId, instance); final ImageView set_toot_visibility = rootView.findViewById(R.id.set_toot_visibility); if( theme == Helper.THEME_DARK){ diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java index f11ba2e77..2c19c8215 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -228,6 +228,7 @@ public class Helper { public static final String TAG = "mastodon_etalab"; public static final String CLIENT_NAME_VALUE = "Fedilab"; public static final String OAUTH_SCOPES = "read write follow"; + public static final String OAUTH_SCOPES_ADMIN = "read write follow admin:read admin:write admin"; public static final String OAUTH_SCOPES_PIXELFED = "write follow"; public static final String OAUTH_SCOPES_PEERTUBE = "user"; public static final String PREF_KEY_OAUTH_TOKEN = "oauth_token"; @@ -348,6 +349,9 @@ public class Helper { public static final String SET_DISPLAY_TIMELINE_IN_LIST = "set_display_timeline_in_list"; public static final String SET_ONION_SCHEME = "set_onion_scheme"; public static final String SET_REMEMBER_POSITION_HOME = "set_remember_position"; + public static final String SET_DISPLAY_ADMIN_MENU = "set_display_admin_menu"; + public static final String SET_DISPLAY_ADMIN_STATUSES = "set_display_admin_statuses"; + public static final int S_NO = 0; static final int S_512KO = 1; public static final int S_1MO = 2; diff --git a/app/src/main/java/app/fedilab/android/interfaces/OnAdminActionInterface.java b/app/src/main/java/app/fedilab/android/interfaces/OnAdminActionInterface.java new file mode 100644 index 000000000..f5ee194c6 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/interfaces/OnAdminActionInterface.java @@ -0,0 +1,25 @@ +/* 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 . */ +package app.fedilab.android.interfaces; + +import app.fedilab.android.client.APIResponse; + +/** + * Created by Thomas on 08/06/2019. + * Interface when an admin action is done GET/POST + */ +public interface OnAdminActionInterface { + void onAdminAction(APIResponse apiResponse); +} diff --git a/app/src/main/res/drawable/ic_mode_comment_white.xml b/app/src/main/res/drawable/ic_mode_comment_white.xml new file mode 100644 index 000000000..480b87a57 --- /dev/null +++ b/app/src/main/res/drawable/ic_mode_comment_white.xml @@ -0,0 +1,5 @@ + + + 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-sw600dp/fragment_settings.xml b/app/src/main/res/layout-sw600dp/fragment_settings.xml index 17cca313f..334725c4e 100644 --- a/app/src/main/res/layout-sw600dp/fragment_settings.xml +++ b/app/src/main/res/layout-sw600dp/fragment_settings.xml @@ -155,6 +155,54 @@ android:text="@string/set_display_news_from_fedilab" android:layout_height="wrap_content" /> + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_admin_report.xml b/app/src/main/res/layout/activity_admin_report.xml new file mode 100644 index 000000000..97a8f6a5f --- /dev/null +++ b/app/src/main/res/layout/activity_admin_report.xml @@ -0,0 +1,390 @@ + + + + + + + + + + + +