package com.fox2code.mmm; import android.annotation.SuppressLint; import android.content.res.Resources; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.cardview.widget.CardView; import androidx.recyclerview.widget.RecyclerView; import com.fox2code.mmm.manager.ModuleInfo; import com.fox2code.mmm.manager.ModuleManager; import com.google.android.material.switchmaterial.SwitchMaterial; import com.topjohnwu.superuser.internal.UiThreadHandler; import java.util.ArrayList; public final class ModuleViewAdapter extends RecyclerView.Adapter { private static final boolean DEBUG = false; public final ArrayList moduleHolders = new ArrayList<>(); @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.module_entry, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { final ModuleHolder moduleHolder = this.moduleHolders.get(position); if (holder.update(moduleHolder)) { UiThreadHandler.handler.post(() -> { if (this.moduleHolders.get(position) == moduleHolder) { this.moduleHolders.remove(position); this.notifyItemRemoved(position); } }); } } @Override public int getItemCount() { return this.moduleHolders.size(); } public static class ViewHolder extends RecyclerView.ViewHolder { private final CardView cardView; private final ImageButton buttonAction; private final SwitchMaterial switchMaterial; private final TextView titleText; private final TextView creditText; private final TextView descriptionText; private final TextView updateText; private final ImageButton[] actionsButtons; private final ArrayList actionButtonsTypes; private boolean initState; public ModuleHolder moduleHolder; public Drawable background; public ViewHolder(@NonNull View itemView) { super(itemView); this.initState = true; this.cardView = itemView.findViewById(R.id.card_view); this.buttonAction = itemView.findViewById(R.id.button_action); this.switchMaterial = itemView.findViewById(R.id.switch_action); this.titleText = itemView.findViewById(R.id.title_text); this.creditText = itemView.findViewById(R.id.credit_text); this.descriptionText = itemView.findViewById(R.id.description_text); this.updateText = itemView.findViewById(R.id.updated_text); this.actionsButtons = new ImageButton[6]; this.actionsButtons[0] = itemView.findViewById(R.id.button_action1); this.actionsButtons[1] = itemView.findViewById(R.id.button_action2); this.actionsButtons[2] = itemView.findViewById(R.id.button_action3); this.actionsButtons[3] = itemView.findViewById(R.id.button_action4); this.actionsButtons[4] = itemView.findViewById(R.id.button_action5); this.actionsButtons[5] = itemView.findViewById(R.id.button_action6); this.background = this.cardView.getBackground(); // Apply default this.cardView.setOnClickListener(v -> { ModuleHolder moduleHolder = this.moduleHolder; if (moduleHolder != null && moduleHolder.notificationType != null) { View.OnClickListener onClickListener = moduleHolder.notificationType.onClickListener; if (onClickListener != null) onClickListener.onClick(v); } }); this.switchMaterial.setEnabled(false); this.switchMaterial.setOnCheckedChangeListener((v, checked) -> { if (this.initState) return; // Skip if non user ModuleHolder moduleHolder = this.moduleHolder; if (moduleHolder != null && moduleHolder.moduleInfo != null) { ModuleInfo moduleInfo = moduleHolder.moduleInfo; if (!ModuleManager.getINSTANCE().setEnabledState(moduleInfo, checked)) { this.switchMaterial.setChecked( // Reset to valid state if action failed (moduleInfo.flags & ModuleInfo.FLAG_MODULE_DISABLED) == 0); } } }); this.actionButtonsTypes = new ArrayList<>(); for (int i = 0; i < this.actionsButtons.length; i++) { final int index = i; this.actionsButtons[i].setOnClickListener(v -> { if (this.initState) return; // Skip if non user ModuleHolder moduleHolder = this.moduleHolder; if (index < this.actionButtonsTypes.size() && moduleHolder != null) { this.actionButtonsTypes.get(index) .doAction((ImageButton) v, moduleHolder); if (moduleHolder.shouldRemove()) { this.cardView.setVisibility(View.GONE); } } }); this.actionsButtons[i].setOnLongClickListener(v -> { if (this.initState) return false; // Skip if non user ModuleHolder moduleHolder = this.moduleHolder; boolean didSomething = false; if (index < this.actionButtonsTypes.size() && moduleHolder != null) { didSomething = this.actionButtonsTypes.get(index) .doActionLong((ImageButton) v, moduleHolder); if (moduleHolder.shouldRemove()) { this.cardView.setVisibility(View.GONE); } } return didSomething; }); } this.initState = false; } @SuppressLint("SetTextI18n") public boolean update(ModuleHolder moduleHolder) { this.initState = true; if (moduleHolder.isModuleHolder() && moduleHolder.shouldRemove()) { this.cardView.setVisibility(View.GONE); this.moduleHolder = null; this.initState = false; return true; } ModuleHolder.Type type = moduleHolder.getType(); ModuleHolder.Type vType = moduleHolder.getCompareType(type); this.cardView.setVisibility(View.VISIBLE); boolean showCaseMode = MainApplication.isShowcaseMode(); if (moduleHolder.isModuleHolder()) { this.buttonAction.setVisibility(View.GONE); ModuleInfo localModuleInfo = moduleHolder.moduleInfo; if (localModuleInfo != null) { this.switchMaterial.setVisibility(View.VISIBLE); this.switchMaterial.setChecked((localModuleInfo.flags & ModuleInfo.FLAG_MODULE_DISABLED) == 0); } else { this.switchMaterial.setVisibility(View.GONE); } this.creditText.setVisibility(View.VISIBLE); this.descriptionText.setVisibility(View.VISIBLE); ModuleInfo moduleInfo = moduleHolder.getMainModuleInfo(); this.titleText.setText(moduleInfo.name); this.creditText.setText(moduleInfo.version + " by " + moduleInfo.author); this.descriptionText.setText(moduleInfo.description); String updateText = moduleHolder.getUpdateTimeText(); if (!updateText.isEmpty()) { this.updateText.setVisibility(View.VISIBLE); this.updateText.setText(this.updateText.getContext() .getString(R.string.last_updated) + " " + updateText); } else if (moduleHolder.moduleId.equals("hosts")) { this.updateText.setVisibility(View.VISIBLE); this.updateText.setText(R.string.magisk_builtin_module); } else { this.updateText.setVisibility(View.GONE); } this.actionButtonsTypes.clear(); moduleHolder.getButtons(itemView.getContext(), this.actionButtonsTypes, showCaseMode); this.switchMaterial.setEnabled(!showCaseMode && !moduleHolder.hasFlag(ModuleInfo.FLAG_MODULE_UPDATING)); for (int i = 0; i < this.actionsButtons.length; i++) { ImageButton imageButton = this.actionsButtons[i]; if (i < this.actionButtonsTypes.size()) { imageButton.setVisibility(View.VISIBLE); this.actionButtonsTypes.get(i) .update(imageButton, moduleHolder); } else { imageButton.setVisibility(View.GONE); } } this.cardView.setClickable(false); if (moduleHolder.isModuleHolder() && moduleHolder.hasFlag(ModuleInfo.FLAG_MODULE_ACTIVE)) { this.titleText.setTypeface(Typeface.DEFAULT_BOLD); } else { this.titleText.setTypeface(Typeface.DEFAULT); } } else { this.buttonAction.setVisibility( type == ModuleHolder.Type.NOTIFICATION ? View.VISIBLE : View.GONE); this.switchMaterial.setVisibility(View.GONE); this.creditText.setVisibility(View.GONE); this.descriptionText.setVisibility(View.GONE); this.updateText.setVisibility(View.GONE); this.titleText.setText(" "); this.creditText.setText(" "); this.descriptionText.setText(" "); this.switchMaterial.setEnabled(false); this.actionButtonsTypes.clear(); for (ImageButton button:this.actionsButtons) { button.setVisibility(View.GONE); } if (type == ModuleHolder.Type.NOTIFICATION) { NotificationType notificationType = moduleHolder.notificationType; this.titleText.setText(notificationType.textId); this.buttonAction.setImageResource(notificationType.iconId); this.cardView.setClickable(notificationType.onClickListener != null); this.titleText.setTypeface(notificationType.special ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT); } else { this.cardView.setClickable(false); this.titleText.setTypeface(Typeface.DEFAULT); } } if (type == ModuleHolder.Type.SEPARATOR) { this.titleText.setText(moduleHolder.separator.title); } if (DEBUG) { this.titleText.setText(this.titleText.getText() + " " + formatType(type) + " " + formatType(vType)); } // Coloration system Drawable drawable = this.cardView.getBackground(); if (drawable != null) this.background = drawable; if (type.hasBackground) { if (drawable == null) { this.cardView.setBackground(this.background); } int backgroundAttr = R.attr.colorBackgroundFloating; if (type == ModuleHolder.Type.NOTIFICATION) { backgroundAttr = moduleHolder.notificationType.backgroundAttr; } Resources.Theme theme = this.cardView.getContext().getTheme(); TypedValue value = new TypedValue(); theme.resolveAttribute(backgroundAttr, value, true); this.cardView.setCardBackgroundColor(value.data); } else { this.cardView.setBackground(null); } if (type == ModuleHolder.Type.FOOTER) { this.titleText.setMinHeight(moduleHolder.footerPx); } else { this.titleText.setMinHeight(0); } this.moduleHolder = moduleHolder; this.initState = false; return false; } } private static String formatType(ModuleHolder.Type type) { return type.name().substring(0, 3) + "_" + type.ordinal(); } }