From 41295e0c4dbd32c4366369b9fb93c8bb24fa9429 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 18 Sep 2016 22:56:12 +0800 Subject: [PATCH] Refactor modules fragment --- .../topjohnwu/magisk/BaseModuleFragment.java | 390 ------------------ .../com/topjohnwu/magisk/ModulesAdapter.java | 308 ++++++++++++++ .../com/topjohnwu/magisk/ModulesFragment.java | 212 +++------- .../com/topjohnwu/magisk/ReposFragment.java | 4 +- .../com/topjohnwu/magisk/WelcomeActivity.java | 1 - .../com/topjohnwu/magisk/module/Module.java | 82 ++-- .../com/topjohnwu/magisk/utils/Utils.java | 6 +- app/src/main/res/layout/modules_fragment.xml | 86 ++-- ...e_repo_fragment.xml => repos_fragment.xml} | 0 .../res/layout/single_module_fragment.xml | 31 -- 10 files changed, 435 insertions(+), 685 deletions(-) delete mode 100644 app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java rename app/src/main/res/layout/{single_repo_fragment.xml => repos_fragment.xml} (100%) delete mode 100644 app/src/main/res/layout/single_module_fragment.xml diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java deleted file mode 100644 index e5fe56942..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java +++ /dev/null @@ -1,390 +0,0 @@ -package com.topjohnwu.magisk; - -import android.animation.Animator; -import android.animation.ValueAnimator; -import android.content.Context; -import android.content.DialogInterface; -import android.content.SharedPreferences; -import android.graphics.Color; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; -import android.support.v4.app.Fragment; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.app.AlertDialog; -import android.support.v7.widget.RecyclerView; -import android.util.DisplayMetrics; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.view.WindowManager; -import android.widget.CheckBox; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.topjohnwu.magisk.module.Module; -import com.topjohnwu.magisk.module.RepoHelper; -import com.topjohnwu.magisk.utils.Shell; -import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.magisk.utils.WebWindow; - -import java.io.File; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public abstract class BaseModuleFragment extends Fragment { - @BindView(R.id.swipeRefreshLayout) - SwipeRefreshLayout mSwipeRefreshLayout; - @BindView(R.id.recyclerView) - RecyclerView recyclerView; - @BindView(R.id.empty_rv) - TextView emptyTv; - - private RepoHelper.TaskDelegate mDelegate; - private SharedPreferences prefs; - - public BaseModuleFragment SetDelegate(RepoHelper.TaskDelegate delegate) { - mDelegate = delegate; - return null; - } - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View viewMain = inflater.inflate(R.layout.single_module_fragment, container, false); - - - ButterKnife.bind(this, viewMain); - - - prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); - mSwipeRefreshLayout.setOnRefreshListener(() -> { - - mDelegate.taskCompletionResult("OK"); - prefs.edit().putBoolean("ignoreUpdateAlerts", false).apply(); - - - }); - prefs.registerOnSharedPreferenceChangeListener((sharedPreferences, s) -> { - if (s.contains("updated")) { - viewMain.invalidate(); - viewMain.requestLayout(); - - } - }); - if (listModules().size() == 0) { - emptyTv.setVisibility(View.VISIBLE); - recyclerView.setVisibility(View.GONE); - - return viewMain; - } - - recyclerView.setAdapter(new ModulesAdapter(listModules(), (chk, position) -> { - // On Checkbox change listener - CheckBox chbox = (CheckBox) chk; - - if (!chbox.isChecked()) { - listModules().get(position).createDisableFile(); - Snackbar.make(chk, R.string.disable_file_created, Snackbar.LENGTH_SHORT).show(); - } else { - listModules().get(position).removeDisableFile(); - Snackbar.make(chk, R.string.disable_file_removed, Snackbar.LENGTH_SHORT).show(); - } - }, (deleteBtn, position) -> { - // On delete button click listener - - listModules().get(position).createRemoveFile(); - Snackbar.make(deleteBtn, R.string.remove_file_created, Snackbar.LENGTH_SHORT).show(); - }, (undeleteBtn, position) -> { - // On undelete button click listener - - listModules().get(position).deleteRemoveFile(); - Snackbar.make(undeleteBtn, R.string.remove_file_deleted, Snackbar.LENGTH_SHORT).show(); - })); - - - return viewMain; - } - - - protected abstract List listModules(); - - public class ModulesAdapter extends RecyclerView.Adapter { - - private final List mList; - private final List mListToUpdate = new ArrayList<>(); - List mExpandedList; - @BindView(R.id.expand_layout) - LinearLayout expandedLayout; - private View viewMain; - private Context context; - private final Utils.ItemClickListener chboxListener; - private final Utils.ItemClickListener deleteBtnListener; - private final Utils.ItemClickListener unDeleteBtnListener; - private boolean alertUpdate, ignoreAlertUpdate; - - public ModulesAdapter(List list, Utils.ItemClickListener chboxListener, Utils.ItemClickListener deleteBtnListener, Utils.ItemClickListener undeleteBtnListener) { - alertUpdate = false; - this.mList = list; - mExpandedList = new ArrayList<>(mList.size()); - for (int i = 0; i < mList.size(); i++) { - mExpandedList.add(false); - if (listModules().get(i).isUpdateAvailable()) { - alertUpdate = true; - mListToUpdate.add(listModules().get(i)); - } - } - this.chboxListener = chboxListener; - this.deleteBtnListener = deleteBtnListener; - this.unDeleteBtnListener = undeleteBtnListener; - } - - @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - viewMain = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_module, parent, false); - context = parent.getContext(); - ButterKnife.bind(this, viewMain); - return new ViewHolder(viewMain); - } - - @Override - public void onBindViewHolder(final ViewHolder holder, int position) { - final Module module = mList.get(position); - Log.d("Magisk", "ModulesAdapter: Trying set up bindview from list pos " + position + " and " + module.getName()); - Log.d("Magisk", "BaseModuleFragment: Log ID is " + module.getmLogUrl()); - holder.title.setText(module.getName()); - holder.versionName.setText(module.getVersion()); - holder.description.setText(module.getDescription()); - holder.author.setText(module.getAuthor()); - String logUrl = module.getmLogUrl(); - String supportUrl = module.getmSupportUrl(); - String donateUrl = module.getmDonateUrl(); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - if (prefs.contains("ignoreUpdateAlerts")) { - ignoreAlertUpdate = prefs.getBoolean("ignoreUpdateAlerts", false); - } - if (prefs.contains("repo-canUpdate_" + module.getId())) { - if (prefs.getBoolean("repo-canUpdate_" + module.getId(), false)) { - holder.updateStatus.setText(R.string.module_update_available); - holder.updateStatus.setVisibility(View.VISIBLE); - } else { - holder.updateStatus.setVisibility(View.GONE); - } - - if (alertUpdate && !ignoreAlertUpdate) { - Iterator iterRepo = mListToUpdate.iterator(); - while (iterRepo.hasNext()) { - Module mModule = iterRepo.next(); - DialogInterface.OnClickListener dialogClickListener = (dialog, which) -> { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - Utils.DownloadReceiver receiver = new Utils.DownloadReceiver() { - @Override - public void task(File file) { - Log.d("Magisk", "Task firing"); - new Utils.FlashZIP(context, mModule.getId(), file.toString()).execute(); - } - }; - String filename = mModule.getId().replace(" ", "") + ".zip"; - Utils.downloadAndReceive(context, receiver, mModule.getmZipUrl(), filename); - - break; - - case DialogInterface.BUTTON_NEGATIVE: - ignoreAlertUpdate = true; - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean("ignoreUpdateAlerts", ignoreAlertUpdate); - editor.apply(); - break; - } - }; - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setMessage("An update is available for " + mModule.getName() + ". Would you like to install it?").setPositiveButton("Yes", dialogClickListener) - .setNegativeButton("No", dialogClickListener).show(); - mListToUpdate.remove(mModule); - } - } - } - - View.OnClickListener oCl = view -> { - if (view.getId() == holder.changeLog.getId()) { - - new WebWindow("Changelog", module.getmLogUrl(), context); - } - if (view.getId() == holder.authorLink.getId()) { - new WebWindow("Donate", module.getmDonateUrl(), context); - } - if (view.getId() == holder.supportLink.getId()) { - new WebWindow("Support", module.getmSupportUrl(), context); - } - }; - - holder.authorLink.setOnClickListener(oCl); - holder.changeLog.setOnClickListener(oCl); - holder.supportLink.setOnClickListener(oCl); - holder.checkBox.setChecked(module.isEnabled()); - holder.checkBox.setOnCheckedChangeListener((compoundButton, b) -> chboxListener.onItemClick(compoundButton, holder.getAdapterPosition())); - - holder.delete.setOnClickListener(view -> { - if (module.willBeRemoved()) { - unDeleteBtnListener.onItemClick(holder.delete, holder.getAdapterPosition()); - } else { - deleteBtnListener.onItemClick(holder.delete, holder.getAdapterPosition()); - } - - updateDeleteButton(holder, module); - }); - - updateDeleteButton(holder, module); - } - - private void updateDeleteButton(ViewHolder holder, Module module) { - holder.warning.setVisibility(module.willBeRemoved() ? View.VISIBLE : View.GONE); - - if (module.willBeRemoved()) { - holder.delete.setImageResource(R.drawable.ic_undelete); - } else { - holder.delete.setImageResource(R.drawable.ic_delete); - } - } - - @Override - public int getItemCount() { - return mList.size(); - } - - class ViewHolder extends RecyclerView.ViewHolder { - - @BindView(R.id.title) - TextView title; - - @BindView(R.id.version_name) - TextView versionName; - @BindView(R.id.description) - TextView description; - @BindView(R.id.warning) - TextView warning; - @BindView(R.id.checkbox) - CheckBox checkBox; - @BindView(R.id.author) - TextView author; - @BindView(R.id.updateStatus) - TextView updateStatus; - @BindView(R.id.delete) - ImageView delete; - @BindView(R.id.changeLog) - ImageView changeLog; - @BindView(R.id.authorLink) - ImageView authorLink; - @BindView(R.id.supportLink) - ImageView supportLink; - @BindView(R.id.expand_layout) - LinearLayout expandLayout; - private ValueAnimator mAnimator; - private int mMeasuredHeight; - - public ViewHolder(View itemView) { - super(itemView); - WindowManager windowmanager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - ButterKnife.bind(this, itemView); - DisplayMetrics dimension = new DisplayMetrics(); - windowmanager.getDefaultDisplay().getMetrics(dimension); - - expandLayout.getViewTreeObserver().addOnPreDrawListener( - new ViewTreeObserver.OnPreDrawListener() { - - - @Override - public boolean onPreDraw() { - expandLayout.getViewTreeObserver().removeOnPreDrawListener(this); - expandLayout.setVisibility(View.GONE); - final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); - final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); - expandLayout.measure(widthSpec, heightSpec); - mAnimator = slideAnimator(0, expandLayout.getMeasuredHeight()); - return true; - } - }); - - viewMain.setOnClickListener(view -> { - int position = getAdapterPosition(); - Log.d("Magisk", "ReposFragment: CLICK. " + position + " and " + mExpandedList.get(position)); - - if (mExpandedList.get(position)) { - collapse(expandLayout); - } else { - expand(expandLayout); - } - mExpandedList.set(position, !mExpandedList.get(position)); - - }); - if (!Shell.rootAccess()) { - checkBox.setEnabled(false); - delete.setEnabled(false); - } - } - - private void expand(View view) { - - // set Visible - - - Log.d("Magisk", "ReposFragment: Expand anim called " + mMeasuredHeight + " and " + view.getId()); - view.setVisibility(View.VISIBLE); - mAnimator.start(); - } - - private void collapse(View view) { - int finalHeight = view.getHeight(); - ValueAnimator mAnimator = slideAnimator(finalHeight, 0); - Log.d("Magisk", "ReposFragment: Collapse anim called " + finalHeight + " and " + view.getId()); - - mAnimator.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationEnd(Animator animator) { - // Height=0, but it set visibility to GONE - view.setVisibility(View.GONE); - } - - @Override - public void onAnimationStart(Animator animator) { - } - - @Override - public void onAnimationCancel(Animator animator) { - } - - @Override - public void onAnimationRepeat(Animator animator) { - } - }); - mAnimator.start(); - } - - private ValueAnimator slideAnimator(int start, int end) { - - ValueAnimator animator = ValueAnimator.ofInt(start, end); - - animator.addUpdateListener(valueAnimator -> { - // Update Height - int value = (Integer) valueAnimator.getAnimatedValue(); - - ViewGroup.LayoutParams layoutParams = expandLayout - .getLayoutParams(); - layoutParams.height = value; - expandLayout.setLayoutParams(layoutParams); - }); - return animator; - } - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java new file mode 100644 index 000000000..28d66304c --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java @@ -0,0 +1,308 @@ +package com.topjohnwu.magisk; + +import android.animation.Animator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.RecyclerView; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.WindowManager; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.topjohnwu.magisk.module.Module; +import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.WebWindow; + +import java.io.File; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class ModulesAdapter extends RecyclerView.Adapter { + + private final List mList; + private final List mListToUpdate = new ArrayList<>(); + List mExpandedList; + @BindView(R.id.expand_layout) + LinearLayout expandedLayout; + private View viewMain; + private Context context; + private final Utils.ItemClickListener chboxListener; + private final Utils.ItemClickListener deleteBtnListener; + private final Utils.ItemClickListener unDeleteBtnListener; + private boolean alertUpdate, ignoreAlertUpdate; + + public ModulesAdapter(List list, Utils.ItemClickListener chboxListener, Utils.ItemClickListener deleteBtnListener, Utils.ItemClickListener undeleteBtnListener) { + alertUpdate = false; + this.mList = list; + mExpandedList = new ArrayList<>(mList.size()); + for (int i = 0; i < mList.size(); i++) { + mExpandedList.add(false); + if (mList.get(i).isUpdateAvailable()) { + alertUpdate = true; + mListToUpdate.add(mList.get(i)); + } + } + this.chboxListener = chboxListener; + this.deleteBtnListener = deleteBtnListener; + this.unDeleteBtnListener = undeleteBtnListener; + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + viewMain = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_module, parent, false); + context = parent.getContext(); + ButterKnife.bind(this, viewMain); + return new ViewHolder(viewMain); + } + + @Override + public void onBindViewHolder(final ViewHolder holder, int position) { + final Module module = mList.get(position); + Log.d("Magisk", "ModulesAdapter: Trying set up bindview from list pos " + position + " and " + module.getName()); + Log.d("Magisk", "ModulesFragment: Log ID is " + module.getmLogUrl()); + if (module.isCache()) + holder.title.setText("[Cache] " + module.getName()); + else + holder.title.setText(module.getName()); + holder.versionName.setText(module.getVersion()); + holder.description.setText(module.getDescription()); + holder.author.setText(module.getAuthor()); + String logUrl = module.getmLogUrl(); + String supportUrl = module.getmSupportUrl(); + String donateUrl = module.getmDonateUrl(); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + if (prefs.contains("ignoreUpdateAlerts")) { + ignoreAlertUpdate = prefs.getBoolean("ignoreUpdateAlerts", false); + } + if (prefs.contains("repo-canUpdate_" + module.getId())) { + if (prefs.getBoolean("repo-canUpdate_" + module.getId(), false)) { + holder.updateStatus.setText(R.string.module_update_available); + holder.updateStatus.setVisibility(View.VISIBLE); + } else { + holder.updateStatus.setVisibility(View.GONE); + } + + if (alertUpdate && !ignoreAlertUpdate) { + Iterator iterRepo = mListToUpdate.iterator(); + while (iterRepo.hasNext()) { + Module mModule = iterRepo.next(); + DialogInterface.OnClickListener dialogClickListener = (dialog, which) -> { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + Utils.DownloadReceiver receiver = new Utils.DownloadReceiver() { + @Override + public void task(File file) { + Log.d("Magisk", "Task firing"); + new Utils.FlashZIP(context, mModule.getId(), file.toString()).execute(); + } + }; + String filename = mModule.getId().replace(" ", "") + ".zip"; + Utils.downloadAndReceive(context, receiver, mModule.getmZipUrl(), filename); + + break; + + case DialogInterface.BUTTON_NEGATIVE: + ignoreAlertUpdate = true; + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean("ignoreUpdateAlerts", ignoreAlertUpdate); + editor.apply(); + break; + } + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setMessage("An update is available for " + mModule.getName() + ". Would you like to install it?").setPositiveButton("Yes", dialogClickListener) + .setNegativeButton("No", dialogClickListener).show(); + mListToUpdate.remove(mModule); + } + } + } + + View.OnClickListener oCl = view -> { + if (view.getId() == holder.changeLog.getId()) { + + new WebWindow("Changelog", module.getmLogUrl(), context); + } + if (view.getId() == holder.authorLink.getId()) { + new WebWindow("Donate", module.getmDonateUrl(), context); + } + if (view.getId() == holder.supportLink.getId()) { + new WebWindow("Support", module.getmSupportUrl(), context); + } + }; + + holder.authorLink.setOnClickListener(oCl); + holder.changeLog.setOnClickListener(oCl); + holder.supportLink.setOnClickListener(oCl); + holder.checkBox.setChecked(module.isEnabled()); + holder.checkBox.setOnCheckedChangeListener((compoundButton, b) -> chboxListener.onItemClick(compoundButton, holder.getAdapterPosition())); + + holder.delete.setOnClickListener(view -> { + if (module.willBeRemoved()) { + unDeleteBtnListener.onItemClick(holder.delete, holder.getAdapterPosition()); + } else { + deleteBtnListener.onItemClick(holder.delete, holder.getAdapterPosition()); + } + + updateDeleteButton(holder, module); + }); + + updateDeleteButton(holder, module); + } + + private void updateDeleteButton(ViewHolder holder, Module module) { + holder.warning.setVisibility(module.willBeRemoved() ? View.VISIBLE : View.GONE); + + if (module.willBeRemoved()) { + holder.delete.setImageResource(R.drawable.ic_undelete); + } else { + holder.delete.setImageResource(R.drawable.ic_delete); + } + } + + @Override + public int getItemCount() { + return mList.size(); + } + + class ViewHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.title) + TextView title; + + @BindView(R.id.version_name) + TextView versionName; + @BindView(R.id.description) + TextView description; + @BindView(R.id.warning) + TextView warning; + @BindView(R.id.checkbox) + CheckBox checkBox; + @BindView(R.id.author) + TextView author; + @BindView(R.id.updateStatus) + TextView updateStatus; + @BindView(R.id.delete) + ImageView delete; + @BindView(R.id.changeLog) + ImageView changeLog; + @BindView(R.id.authorLink) + ImageView authorLink; + @BindView(R.id.supportLink) + ImageView supportLink; + @BindView(R.id.expand_layout) + LinearLayout expandLayout; + private ValueAnimator mAnimator; + private int mMeasuredHeight; + + public ViewHolder(View itemView) { + super(itemView); + WindowManager windowmanager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + ButterKnife.bind(this, itemView); + DisplayMetrics dimension = new DisplayMetrics(); + windowmanager.getDefaultDisplay().getMetrics(dimension); + + expandLayout.getViewTreeObserver().addOnPreDrawListener( + new ViewTreeObserver.OnPreDrawListener() { + + + @Override + public boolean onPreDraw() { + expandLayout.getViewTreeObserver().removeOnPreDrawListener(this); + expandLayout.setVisibility(View.GONE); + final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + expandLayout.measure(widthSpec, heightSpec); + mAnimator = slideAnimator(0, expandLayout.getMeasuredHeight()); + return true; + } + }); + + viewMain.setOnClickListener(view -> { + int position = getAdapterPosition(); + Log.d("Magisk", "ReposFragment: CLICK. " + position + " and " + mExpandedList.get(position)); + + if (mExpandedList.get(position)) { + collapse(expandLayout); + } else { + expand(expandLayout); + } + mExpandedList.set(position, !mExpandedList.get(position)); + + }); + if (!Shell.rootAccess()) { + checkBox.setEnabled(false); + delete.setEnabled(false); + } + } + + private void expand(View view) { + + // set Visible + + + Log.d("Magisk", "ReposFragment: Expand anim called " + mMeasuredHeight + " and " + view.getId()); + view.setVisibility(View.VISIBLE); + mAnimator.start(); + } + + private void collapse(View view) { + int finalHeight = view.getHeight(); + ValueAnimator mAnimator = slideAnimator(finalHeight, 0); + Log.d("Magisk", "ReposFragment: Collapse anim called " + finalHeight + " and " + view.getId()); + + mAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationEnd(Animator animator) { + // Height=0, but it set visibility to GONE + view.setVisibility(View.GONE); + } + + @Override + public void onAnimationStart(Animator animator) { + } + + @Override + public void onAnimationCancel(Animator animator) { + } + + @Override + public void onAnimationRepeat(Animator animator) { + } + }); + mAnimator.start(); + } + + private ValueAnimator slideAnimator(int start, int end) { + + ValueAnimator animator = ValueAnimator.ofInt(start, end); + + animator.addUpdateListener(valueAnimator -> { + // Update Height + int value = (Integer) valueAnimator.getAnimatedValue(); + + ViewGroup.LayoutParams layoutParams = expandLayout + .getLayoutParams(); + layoutParams.height = value; + expandLayout.setLayoutParams(layoutParams); + }); + return animator; + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 0354f4184..730d7a220 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -1,147 +1,66 @@ package com.topjohnwu.magisk; -import android.app.Activity; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; +import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; -import android.provider.MediaStore; +import android.preference.PreferenceManager; import android.support.annotation.Nullable; -import android.support.design.widget.FloatingActionButton; -import android.support.design.widget.TabLayout; +import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentPagerAdapter; -import android.support.v4.view.ViewPager; -import android.util.Log; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ProgressBar; -import android.widget.Toast; +import android.widget.CheckBox; +import android.widget.TextView; -import com.ipaulpro.afilechooser.FileInfo; -import com.ipaulpro.afilechooser.utils.FileUtils; import com.topjohnwu.magisk.module.Module; -import com.topjohnwu.magisk.module.RepoHelper; import com.topjohnwu.magisk.utils.Utils; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class ModulesFragment extends Fragment { + @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout; + @BindView(R.id.recyclerView) RecyclerView recyclerView; + @BindView(R.id.empty_rv) TextView emptyTv; - private static final int FETCH_ZIP_CODE = 2; + private SharedPreferences prefs; public static List listModules = new ArrayList<>(); - public static List listModulesCache = new ArrayList<>(); - @BindView(R.id.progressBar) ProgressBar progressBar; - @BindView(R.id.fab) FloatingActionButton fabio; - @BindView(R.id.pager) ViewPager viewPager; - @BindView(R.id.tab_layout) TabLayout tabLayout; - private int viewPagePosition; - private RepoHelper.TaskDelegate mTaskDelegate; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.modules_fragment, container, false); + View viewMain = inflater.inflate(R.layout.modules_fragment, container, false); - ButterKnife.bind(this, view); - fabio.setOnClickListener(v -> { - Intent getContentIntent = FileUtils.createGetContentIntent(null); - getContentIntent.setType("application/zip"); - Intent fileIntent = Intent.createChooser(getContentIntent, "Select a file"); - startActivityForResult(fileIntent, FETCH_ZIP_CODE); + ButterKnife.bind(this, viewMain); + + prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); + mSwipeRefreshLayout.setOnRefreshListener(() -> { + + recyclerView.setVisibility(View.GONE); + new Utils.LoadModules(getActivity()).execute(); + new updateUI().execute(); + prefs.edit().putBoolean("ignoreUpdateAlerts", false).apply(); }); - mTaskDelegate = result -> { - if (result.equals("OK")) { - RefreshUI(); + prefs.registerOnSharedPreferenceChangeListener((sharedPreferences, s) -> { + if (s.contains("updated")) { + viewMain.invalidate(); + viewMain.requestLayout(); + } - }; + }); new updateUI().execute(); - return view; - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (data != null) { - // Get the URI of the selected file - final Uri uri = data.getData(); - Log.i("Magisk", "ModulesFragment: Uri = " + uri.toString() + " or "); - new Utils.FlashZIP(getActivity(),uri).execute(); - try { - // Get the file path from the URI - FileInfo fileInfo = FileUtils.getFileInfo(getActivity(), uri); - Toast.makeText(getActivity(), - "File Selected: " + fileInfo.getDisplayName() + " size: " + fileInfo.getSize(), Toast.LENGTH_LONG).show(); - - if (!fileInfo.isExternal()) { - - } else { - - } - } catch (Exception e) { - Log.e("FileSelectorTestAc...", "File select error", e); - } - } - - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.menu_module, menu); - - } - - private void RefreshUI() { - viewPagePosition = tabLayout.getSelectedTabPosition(); - listModules.clear(); - listModulesCache.clear(); - progressBar.setVisibility(View.VISIBLE); - viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); - tabLayout.setupWithViewPager(viewPager); - viewPager.setCurrentItem(viewPagePosition); - new Utils.LoadModules(getActivity()).execute(); - Collections.sort(listModules, new CustomComparator()); - Collections.sort(listModulesCache, new CustomComparator()); - new updateUI().execute(); - } - - void selectPage(int pageIndex) { - tabLayout.setScrollPosition(pageIndex, 0f, true); - viewPager.setCurrentItem(pageIndex); - } - - public static class NormalModuleFragment extends BaseModuleFragment { - - @Override - protected List listModules() { - return listModules; - } - - } - - public static class CacheModuleFragment extends BaseModuleFragment { - - @Override - protected List listModules() { - return listModulesCache; - } + return viewMain; } private class updateUI extends AsyncTask { @@ -154,53 +73,46 @@ public class ModulesFragment extends Fragment { @Override protected void onPostExecute(Void v) { super.onPostExecute(v); - progressBar.setVisibility(View.GONE); - viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); - tabLayout.setupWithViewPager(viewPager); - selectPage(viewPagePosition); - } - } - - private class TabsAdapter extends FragmentPagerAdapter { - - String[] tabTitles = new String[]{ - getString(R.string.modules), getString(R.string.cache_modules) - }; - - public TabsAdapter(FragmentManager fm) { - super(fm); - } - - @Override - public int getCount() { - return tabTitles.length; - } - - @Override - public String getPageTitle(int position) { - return tabTitles[position]; - } - - @Override - public Fragment getItem(int position) { - if (position == 0) { - NormalModuleFragment nmf = new NormalModuleFragment(); - nmf.SetDelegate(mTaskDelegate); - return nmf; + if (listModules().size() == 0) { + emptyTv.setVisibility(View.VISIBLE); + recyclerView.setVisibility(View.GONE); } else { - CacheModuleFragment cmf = new CacheModuleFragment(); - cmf.SetDelegate(mTaskDelegate); - return cmf; + recyclerView.setVisibility(View.VISIBLE); } + recyclerView.setAdapter(new ModulesAdapter(listModules(), (chk, position) -> { + // On Checkbox change listener + CheckBox chbox = (CheckBox) chk; + + if (!chbox.isChecked()) { + listModules().get(position).createDisableFile(); + Snackbar.make(chk, R.string.disable_file_created, Snackbar.LENGTH_SHORT).show(); + } else { + listModules().get(position).removeDisableFile(); + Snackbar.make(chk, R.string.disable_file_removed, Snackbar.LENGTH_SHORT).show(); + } + }, (deleteBtn, position) -> { + // On delete button click listener + + listModules().get(position).createRemoveFile(); + Snackbar.make(deleteBtn, R.string.remove_file_created, Snackbar.LENGTH_SHORT).show(); + }, (undeleteBtn, position) -> { + // On undelete button click listener + + listModules().get(position).deleteRemoveFile(); + Snackbar.make(undeleteBtn, R.string.remove_file_deleted, Snackbar.LENGTH_SHORT).show(); + })); + + if (mSwipeRefreshLayout.isRefreshing()) + mSwipeRefreshLayout.setRefreshing(false); + } } - public class CustomComparator implements Comparator { - @Override - public int compare(Module o1, Module o2) { - return o1.getName().compareTo(o2.getName()); - } + +// protected abstract List listModules(); + protected List listModules() { + return listModules; } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java index c4c6b8a64..a807f289a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java @@ -1,9 +1,7 @@ package com.topjohnwu.magisk; -import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; -import android.os.AsyncTask; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.Nullable; @@ -50,7 +48,7 @@ public class ReposFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.single_repo_fragment, container, false); + View view = inflater.inflate(R.layout.repos_fragment, container, false); mView = view; ButterKnife.bind(this, view); prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); diff --git a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java index dd3e09d9d..7c9b656e4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java @@ -1,7 +1,6 @@ package com.topjohnwu.magisk; import android.Manifest; -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Module.java b/app/src/main/java/com/topjohnwu/magisk/module/Module.java index f052971be..490056fdc 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -15,8 +15,9 @@ public class Module { private String mName = null; private String mVersion = "(No version provided)"; private String mDescription = "(No description provided)"; - private String mUrl,mSupportUrl,mDonateUrl,mZipUrl,mBaseUrl,mManifestUrl,mAuthor,mLogUrl; - private boolean mEnable, mRemove,mUpdateAvailable, mIsInstalled,mIsCacheModule; + private String mSupportUrl, mDonateUrl, mZipUrl, mAuthor, mLogUrl; + private boolean mEnable = false, mRemove = false, mUpdateAvailable = false, mIsInstalled, + mIsCacheModule = false; private String mId; @@ -38,47 +39,32 @@ public class Module { } switch (props[0]) { - case "versionCode": - this.mVersionCode = Integer.valueOf(props[1]); + case "id": + this.mId = props[1]; break; case "name": this.mName = props[1]; break; - case "author": - this.mAuthor = props[1]; - break; - case "id": - this.mId = props[1]; - break; case "version": this.mVersion = props[1]; break; + case "versionCode": + this.mVersionCode = Integer.parseInt(props[1]); + break; + case "author": + this.mAuthor = props[1]; + break; case "description": this.mDescription = props[1]; break; + case "support": + this.mSupportUrl = props[1]; + break; case "donate": this.mDonateUrl = props[1]; break; case "cacheModule": - this.mIsCacheModule = Boolean.valueOf(props[1]); - break; - case "support": - this.mSupportUrl = props[1]; - break; - case "donateUrl": - this.mDonateUrl = props[1]; - break; - case "zipUrl": - this.mZipUrl = props[1]; - break; - case "baseUrl": - this.mBaseUrl = props[1]; - break; - case "manifestUrl": - this.mManifestUrl = props[1]; - break; - case "logUrl": - this.mLogUrl = props[1]; + this.mIsCacheModule = Boolean.parseBoolean(props[1]); break; default: Log.d("Magisk", "Module: Manifest string not recognized: " + props[0]); @@ -165,18 +151,18 @@ public class Module { } - public Module(Repo repo) { - - mName = repo.getName(); - mVersion = repo.getmVersion(); - mDescription = repo.getDescription(); - mId = repo.getId(); - mVersionCode = repo.getmVersionCode(); - mUrl = repo.getmZipUrl(); - mEnable = true; - mRemove = false; - - } +// public Module(Repo repo) { +// +// mName = repo.getName(); +// mVersion = repo.getmVersion(); +// mDescription = repo.getDescription(); +// mId = repo.getId(); +// mVersionCode = repo.getmVersionCode(); +// mUrl = repo.getmZipUrl(); +// mEnable = true; +// mRemove = false; +// +// } @@ -224,22 +210,24 @@ public class Module { return mRemove; } + public boolean isCache() { + return mIsCacheModule; + } + + public void setCache() { + mIsCacheModule = true; + } + public String getmDonateUrl() { return mDonateUrl; } public String getmZipUrl() { return mZipUrl; } - public String getmManifestUrl() { - return mManifestUrl; - } - public String getmSupportUrl() { return mSupportUrl; } - public boolean isInstalled() {return mIsInstalled; } - public boolean isUpdateAvailable() { return mUpdateAvailable; } } \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java index 74d0babcc..b14c15d3d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -444,7 +444,6 @@ public class Utils { @Override protected Void doInBackground(Void... voids) { ModulesFragment.listModules.clear(); - ModulesFragment.listModulesCache.clear(); List magisk = getModList(MAGISK_PATH); Log.d("Magisk", "Utils: Reload called, loading modules"); List magiskCache = getModList(MAGISK_CACHE_PATH); @@ -456,7 +455,10 @@ public class Utils { for (String mod : magiskCache) { Log.d("Magisk", "Utils: Adding cache module from string " + mod); - ModulesFragment.listModulesCache.add(new Module(mod, mContext)); + Module cacheMod = new Module(mod, mContext); + // Prevent people forgot to change module.prop + cacheMod.setCache(); + ModulesFragment.listModules.add(cacheMod); } return null; diff --git a/app/src/main/res/layout/modules_fragment.xml b/app/src/main/res/layout/modules_fragment.xml index ae6bca833..336fbdb93 100644 --- a/app/src/main/res/layout/modules_fragment.xml +++ b/app/src/main/res/layout/modules_fragment.xml @@ -1,67 +1,31 @@ - + android:layout_height="fill_parent" + android:layout_marginTop="?attr/actionBarSize" + android:orientation="vertical"> - + - + - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/single_repo_fragment.xml b/app/src/main/res/layout/repos_fragment.xml similarity index 100% rename from app/src/main/res/layout/single_repo_fragment.xml rename to app/src/main/res/layout/repos_fragment.xml diff --git a/app/src/main/res/layout/single_module_fragment.xml b/app/src/main/res/layout/single_module_fragment.xml deleted file mode 100644 index 336fbdb93..000000000 --- a/app/src/main/res/layout/single_module_fragment.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - \ No newline at end of file