diff options
Diffstat (limited to 'app/src/main/java/app/fedilab/android/activities/admin/AdminAccountActivity.java')
-rw-r--r-- | app/src/main/java/app/fedilab/android/activities/admin/AdminAccountActivity.java | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/app/src/main/java/app/fedilab/android/activities/admin/AdminAccountActivity.java b/app/src/main/java/app/fedilab/android/activities/admin/AdminAccountActivity.java new file mode 100644 index 000000000..c40cace7d --- /dev/null +++ b/app/src/main/java/app/fedilab/android/activities/admin/AdminAccountActivity.java @@ -0,0 +1,416 @@ +package app.fedilab.android.activities.admin; +/* Copyright 2022 Thomas Schneider + * + * This file is a part of Fedilab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Fedilab; if not, + * see <http://www.gnu.org/licenses>. */ + + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.text.style.ForegroundColorSpan; +import android.text.style.UnderlineSpan; +import android.util.TypedValue; +import android.view.MenuItem; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.core.app.ActivityOptionsCompat; +import androidx.core.content.ContextCompat; +import androidx.lifecycle.ViewModelProvider; +import androidx.preference.PreferenceManager; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.target.CustomTarget; +import com.bumptech.glide.request.transition.Transition; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Locale; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import app.fedilab.android.BaseMainActivity; +import app.fedilab.android.R; +import app.fedilab.android.activities.BaseActivity; +import app.fedilab.android.activities.InstanceProfileActivity; +import app.fedilab.android.activities.MainActivity; +import app.fedilab.android.activities.MediaActivity; +import app.fedilab.android.client.entities.api.Attachment; +import app.fedilab.android.client.entities.api.admin.AdminAccount; +import app.fedilab.android.client.entities.api.admin.AdminIp; +import app.fedilab.android.databinding.ActivityAdminAccountBinding; +import app.fedilab.android.helper.Helper; +import app.fedilab.android.helper.MastodonHelper; +import app.fedilab.android.helper.SpannableHelper; +import app.fedilab.android.helper.ThemeHelper; +import app.fedilab.android.viewmodel.mastodon.AdminVM; +import app.fedilab.android.viewmodel.mastodon.NodeInfoVM; +import es.dmoral.toasty.Toasty; + + +public class AdminAccountActivity extends BaseActivity { + + + private ScheduledExecutorService scheduledExecutorService; + private ActivityAdminAccountBinding binding; + private String account_id; + private AdminVM adminVM; + private AdminAccount adminAccount; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ThemeHelper.applyTheme(this); + binding = ActivityAdminAccountBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + setSupportActionBar(binding.toolbar); + ActionBar actionBar = getSupportActionBar(); + Bundle b = getIntent().getExtras(); + adminAccount = null; + if (b != null) { + adminAccount = (AdminAccount) b.getSerializable(Helper.ARG_ACCOUNT); + account_id = b.getString(Helper.ARG_ACCOUNT_ID, null); + } + postponeEnterTransition(); + + //Remove title + if (actionBar != null) { + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary))); + } + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this); + float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f); + binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale); + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); + } + binding.toolbar.setPopupTheme(Helper.popupStyle()); + adminVM = new ViewModelProvider(AdminAccountActivity.this).get(AdminVM.class); + if (account_id != null) { + adminVM.getAccount(MainActivity.currentInstance, MainActivity.currentToken, account_id).observe(this, this::initializeView); + return; + } + if (adminAccount != null && adminAccount.account != null) { + initializeView(adminAccount); + } else { + Toasty.error(AdminAccountActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + finish(); + } + + binding.disableAction.setOnClickListener(v -> { + if (adminAccount.disabled) { + adminVM.enable(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id) + .observe(AdminAccountActivity.this, adminAccountResult -> { + adminAccount.disabled = false; + binding.disableAction.setText(R.string.disable); + binding.disabled.setText(R.string.no); + }); + } else { + adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id, "disable ", null, null, null, null); + adminAccount.disabled = true; + binding.disableAction.setText(R.string.undisable); + binding.disabled.setText(R.string.yes); + } + }); + + binding.approveAction.setOnClickListener(v -> { + if (adminAccount.approved) { + adminVM.reject(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id) + .observe(AdminAccountActivity.this, adminAccountResult -> { + adminAccount = adminAccountResult; + initializeView(adminAccount); + }); + } else { + adminVM.approve(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id); + adminAccount.approved = true; + initializeView(adminAccount); + } + }); + + binding.silenceAction.setOnClickListener(v -> { + if (adminAccount.silenced) { + adminVM.unsilence(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id) + .observe(AdminAccountActivity.this, adminAccountResult -> { + adminAccount = adminAccountResult; + initializeView(adminAccount); + }); + } else { + adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id, "silence", null, null, null, null); + adminAccount.silenced = true; + initializeView(adminAccount); + } + }); + + binding.suspendAction.setOnClickListener(v -> { + if (adminAccount.suspended) { + adminVM.unsuspend(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id) + .observe(AdminAccountActivity.this, adminAccountResult -> { + adminAccount = adminAccountResult; + initializeView(adminAccount); + }); + } else { + adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id, "suspend", null, null, null, null); + adminAccount.suspended = true; + initializeView(adminAccount); + } + }); + + + } + + private void initializeView(AdminAccount adminAccount) { + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(AdminAccountActivity.this); + if (adminAccount == null) { + Toasty.error(AdminAccountActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + finish(); + return; + } + binding.title.setText(String.format(Locale.getDefault(), "@%s", adminAccount.account.acct)); + + // MastodonHelper.loadPPMastodon(binding.profilePicture, account); + binding.appBar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> { + + if (Math.abs(verticalOffset) - binding.appBar.getTotalScrollRange() == 0) { + binding.profilePicture.setVisibility(View.VISIBLE); + binding.title.setVisibility(View.VISIBLE); + } else { + binding.profilePicture.setVisibility(View.GONE); + binding.title.setVisibility(View.GONE); + } + }); + + binding.username.setText(String.format(Locale.getDefault(), "@%s", adminAccount.username)); + binding.domain.setText(adminAccount.domain); + binding.email.setText(adminAccount.email); + StringBuilder lastActive = new StringBuilder(); + if (adminAccount.ips != null) { + int count = 0; + for (AdminIp ip : adminAccount.ips) { + lastActive.append(Helper.shortDateToString(ip.used_at)).append(" - ").append(ip.ip).append("\r\n"); + count++; + if (count > 4) { + break; + } + } + } + if (lastActive.toString().trim().length() == 0) { + binding.lastActiveContainer.setVisibility(View.GONE); + } + if (adminAccount.email == null || adminAccount.email.trim().length() == 0) { + binding.emailContainer.setVisibility(View.GONE); + } + binding.lastActive.setText(lastActive.toString()); + binding.disabled.setText(adminAccount.disabled ? R.string.yes : R.string.no); + binding.approved.setText(adminAccount.approved ? R.string.yes : R.string.no); + binding.silenced.setText(adminAccount.silenced ? R.string.yes : R.string.no); + binding.suspended.setText(adminAccount.suspended ? R.string.yes : R.string.no); + + binding.disableAction.setText(adminAccount.disabled ? R.string.undisable : R.string.disable); + binding.approveAction.setText(adminAccount.approved ? R.string.reject : R.string.approve); + binding.silenceAction.setText(adminAccount.silenced ? R.string.unsilence : R.string.silence); + binding.suspendAction.setText(adminAccount.suspended ? R.string.unsuspend : R.string.suspend); + + + //Animate emojis + if (adminAccount.account.emojis != null && adminAccount.account.emojis.size() > 0) { + boolean disableAnimatedEmoji = sharedpreferences.getBoolean(getString(R.string.SET_DISABLE_ANIMATED_EMOJI), false); + if (!disableAnimatedEmoji) { + scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + scheduledExecutorService.scheduleAtFixedRate(() -> binding.accountDn.invalidate(), 0, 130, TimeUnit.MILLISECONDS); + } + } + + //Tablayout for timelines/following/followers + + boolean disableGif = sharedpreferences.getBoolean(getString(R.string.SET_DISABLE_GIF), false); + String targetedUrl = disableGif ? adminAccount.account.avatar_static : adminAccount.account.avatar; + Glide.with(AdminAccountActivity.this) + .asDrawable() + .dontTransform() + .load(targetedUrl).into( + new CustomTarget<Drawable>() { + @Override + public void onResourceReady(@NonNull final Drawable resource, Transition<? super Drawable> transition) { + binding.profilePicture.setImageDrawable(resource); + startPostponedEnterTransition(); + } + + @Override + public void onLoadFailed(@Nullable Drawable errorDrawable) { + binding.profilePicture.setImageResource(R.drawable.ic_person); + startPostponedEnterTransition(); + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + + } + } + ); + //Load header + MastodonHelper.loadProfileMediaMastodon(binding.bannerPp, adminAccount.account, MastodonHelper.MediaAccountType.HEADER); + //Redraws icon for locked accounts + final float scale = getResources().getDisplayMetrics().density; + if (adminAccount.account.locked) { + Drawable img = ContextCompat.getDrawable(AdminAccountActivity.this, R.drawable.ic_baseline_lock_24); + assert img != null; + img.setBounds(0, 0, (int) (16 * scale + 0.5f), (int) (16 * scale + 0.5f)); + binding.accountUn.setCompoundDrawables(null, null, img, null); + } else { + binding.accountUn.setCompoundDrawables(null, null, null, null); + } + //Peertube account watched by a Mastodon account + //Bot account + if (adminAccount.account.bot) { + binding.accountBot.setVisibility(View.VISIBLE); + } + if (adminAccount.account.acct != null) { + setTitle(adminAccount.account.acct); + } + + + final SpannableString content = new SpannableString(getString(R.string.disclaimer_full)); + content.setSpan(new UnderlineSpan(), 0, content.length(), 0); + content.setSpan(new ForegroundColorSpan(ContextCompat.getColor(AdminAccountActivity.this, R.color.cyanea_accent_reference)), 0, content.length(), + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + + //This account was moved to another one + if (adminAccount.account.moved != null) { + binding.accountMoved.setVisibility(View.VISIBLE); + Drawable imgTravel = ContextCompat.getDrawable(AdminAccountActivity.this, R.drawable.ic_baseline_card_travel_24); + assert imgTravel != null; + imgTravel.setBounds(0, 0, (int) (20 * scale + 0.5f), (int) (20 * scale + 0.5f)); + binding.accountMoved.setCompoundDrawables(imgTravel, null, null, null); + //Retrieves content and make account names clickable + SpannableString spannableString = SpannableHelper.moveToText(AdminAccountActivity.this, adminAccount.account); + binding.accountMoved.setText(spannableString, TextView.BufferType.SPANNABLE); + binding.accountMoved.setMovementMethod(LinkMovementMethod.getInstance()); + } + + + binding.accountDn.setText( + adminAccount.account.getSpanDisplayName(AdminAccountActivity.this, + new WeakReference<>(binding.accountDn)), + TextView.BufferType.SPANNABLE); + binding.accountUn.setText(String.format("@%s", adminAccount.account.acct)); + binding.accountUn.setOnLongClickListener(v -> { + ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); + String account_id = adminAccount.account.acct; + if (account_id.split("@").length == 1) + account_id += "@" + BaseMainActivity.currentInstance; + ClipData clip = ClipData.newPlainText("mastodon_account_id", "@" + account_id); + Toasty.info(AdminAccountActivity.this, getString(R.string.account_id_clipbloard), Toast.LENGTH_SHORT).show(); + assert clipboard != null; + clipboard.setPrimaryClip(clip); + return false; + }); + + MastodonHelper.loadPPMastodon(binding.accountPp, adminAccount.account); + binding.accountPp.setOnClickListener(v -> { + Intent intent = new Intent(AdminAccountActivity.this, MediaActivity.class); + Bundle b = new Bundle(); + Attachment attachment = new Attachment(); + attachment.description = adminAccount.account.acct; + attachment.preview_url = adminAccount.account.avatar; + attachment.url = adminAccount.account.avatar; + attachment.remote_url = adminAccount.account.avatar; + attachment.type = "image"; + ArrayList<Attachment> attachments = new ArrayList<>(); + attachments.add(attachment); + b.putSerializable(Helper.ARG_MEDIA_ARRAY, attachments); + b.putInt(Helper.ARG_MEDIA_POSITION, 1); + intent.putExtras(b); + ActivityOptionsCompat options = ActivityOptionsCompat + .makeSceneTransitionAnimation(AdminAccountActivity.this, binding.accountPp, attachment.url); + // start the new activity + startActivity(intent, options.toBundle()); + }); + + + binding.accountDate.setText(Helper.shortDateToString(adminAccount.created_at)); + binding.accountDate.setVisibility(View.VISIBLE); + + String[] accountInstanceArray = adminAccount.account.acct.split("@"); + String accountInstance = BaseMainActivity.currentInstance; + if (accountInstanceArray.length > 1) { + accountInstance = accountInstanceArray[1]; + } + + NodeInfoVM nodeInfoVM = new ViewModelProvider(AdminAccountActivity.this).get(NodeInfoVM.class); + String finalAccountInstance = accountInstance; + nodeInfoVM.getNodeInfo(accountInstance).observe(AdminAccountActivity.this, nodeInfo -> { + if (nodeInfo != null && nodeInfo.software != null) { + binding.instanceInfo.setText(nodeInfo.software.name); + binding.instanceInfo.setVisibility(View.VISIBLE); + + binding.instanceInfo.setOnClickListener(v -> { + Intent intent = new Intent(AdminAccountActivity.this, InstanceProfileActivity.class); + Bundle b = new Bundle(); + b.putString(Helper.ARG_INSTANCE, finalAccountInstance); + intent.putExtras(b); + startActivity(intent); + + }); + } + }); + + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int itemId = item.getItemId(); + if (itemId == android.R.id.home) { + finish(); + return true; + } + return true; + } + + @Override + public void onDestroy() { + if (scheduledExecutorService != null) { + scheduledExecutorService.shutdownNow(); + scheduledExecutorService = null; + } + super.onDestroy(); + } + + public enum action { + FOLLOW, + UNFOLLOW, + BLOCK, + UNBLOCK, + NOTHING, + MUTE, + UNMUTE, + REPORT, + BLOCK_DOMAIN + } + + +} |