diff --git a/app/src/main/java/com/topjohnwu/magisk/di/ApplicationModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/ApplicationModule.kt index 09fd26d68..dd5e7bebc 100644 --- a/app/src/main/java/com/topjohnwu/magisk/di/ApplicationModule.kt +++ b/app/src/main/java/com/topjohnwu/magisk/di/ApplicationModule.kt @@ -2,10 +2,12 @@ package com.topjohnwu.magisk.di import android.content.Context import com.skoumal.teanity.rxbus.RxBus +import com.topjohnwu.magisk.App import org.koin.dsl.module val applicationModule = module { single { RxBus() } single { get().resources } + single { get() as App } } diff --git a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt index 523a7bdfc..e4df34487 100644 --- a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt +++ b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt @@ -1,10 +1,12 @@ package com.topjohnwu.magisk.di import com.topjohnwu.magisk.ui.MainViewModel +import com.topjohnwu.magisk.ui.home.HomeViewModel import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.module val viewModelModules = module { viewModel { MainViewModel() } + viewModel { HomeViewModel(get(), get()) } } diff --git a/app/src/main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt b/app/src/main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt new file mode 100644 index 000000000..bf405b0b3 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt @@ -0,0 +1,14 @@ +package com.topjohnwu.magisk.model.events + +import com.skoumal.teanity.viewevents.ViewEvent + + +data class OpenLinkEvent(val url: String) : ViewEvent() + +object ManagerInstallEvent : ViewEvent() +object MagiskInstallEvent : ViewEvent() + +object ManagerChangelogEvent : ViewEvent() +object MagiskChangelogEvent : ViewEvent() + +object UninstallEvent : ViewEvent() diff --git a/app/src/main/java/com/topjohnwu/magisk/model/observer/Observer.kt b/app/src/main/java/com/topjohnwu/magisk/model/observer/Observer.kt new file mode 100644 index 000000000..3f675dded --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/model/observer/Observer.kt @@ -0,0 +1,31 @@ +package com.topjohnwu.magisk.model.observer + +import androidx.databinding.Observable +import androidx.databinding.ObservableField +import java.io.Serializable + + +class Observer(vararg dependencies: Observable, private val observer: () -> T) : + ObservableField(*dependencies), Serializable { + + val value: T get() = observer() + + @Deprecated( + message = "Use KObservableField.value syntax from code", + replaceWith = ReplaceWith("value") + ) + override fun get(): T { + return value + } + + @Deprecated( + message = "Observer cannot be set", + level = DeprecationLevel.HIDDEN + ) + override fun set(newValue: T) { + } + + override fun toString(): String { + return "Observer(value=$value)" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt index f93e766e0..d9b0a8c16 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt @@ -1,8 +1,14 @@ package com.topjohnwu.magisk.ui.base +import androidx.core.net.toUri import androidx.databinding.ViewDataBinding import com.skoumal.teanity.view.TeanityActivity +import com.topjohnwu.magisk.utils.Utils abstract class MagiskActivity : - TeanityActivity() + TeanityActivity() { + + fun openUrl(url: String) = Utils.openLink(this, url.toUri()) + +} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskFragment.kt index 024b00492..8d186a228 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskFragment.kt @@ -5,4 +5,12 @@ import com.skoumal.teanity.view.TeanityFragment abstract class MagiskFragment : - TeanityFragment() + TeanityFragment() { + + protected val magiskActivity get() = activity as MagiskActivity<*, *> + + fun openLink(url: String) { + magiskActivity.openUrl(url) + } + +} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskViewModel.kt index ca82d4039..c6f6ad86e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskViewModel.kt @@ -1,6 +1,6 @@ package com.topjohnwu.magisk.ui.base -import com.skoumal.teanity.viewmodel.TeanityViewModel +import com.skoumal.teanity.viewmodel.LoadingViewModel -abstract class MagiskViewModel : TeanityViewModel() +abstract class MagiskViewModel : LoadingViewModel() diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt new file mode 100644 index 000000000..f223c1087 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt @@ -0,0 +1,91 @@ +package com.topjohnwu.magisk.ui.home + +import android.content.res.Resources +import com.skoumal.teanity.util.KObservableField +import com.topjohnwu.magisk.App +import com.topjohnwu.magisk.Config +import com.topjohnwu.magisk.Const +import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.model.events.* +import com.topjohnwu.magisk.model.observer.Observer +import com.topjohnwu.magisk.ui.base.MagiskViewModel +import com.topjohnwu.magisk.utils.toggle + + +class HomeViewModel( + private val resources: Resources, + private val app: App +) : MagiskViewModel() { + + val isAdvancedExpanded = KObservableField(false) + + val isForceEncryption = KObservableField(false /*todo*/) + val isKeepVerity = KObservableField(false /*todo*/) + + private val prefsObserver = Observer(isForceEncryption, isKeepVerity) { + Config.keepEnc = isForceEncryption.value + Config.keepVerity = isKeepVerity.value + } + + val magiskState = KObservableField(MagiskState.LOADING) + val magiskStateText = Observer(magiskState) { + @Suppress("WhenWithOnlyElse") + when (magiskState.value) { + MagiskState.NO_ROOT -> TODO() + MagiskState.NOT_INSTALLED -> TODO() + MagiskState.UP_TO_DATE -> TODO() + MagiskState.LOADING -> TODO() + MagiskState.OBSOLETE -> TODO() + } + } + val magiskCurrentVersion = KObservableField("") + val magiskLatestVersion = KObservableField("") + val magiskAdditionalInfo = Observer(magiskState) { + if (Config.get(Config.Key.COREONLY)) + resources.getString(R.string.core_only_enabled) + else + "" + } + + val managerState = KObservableField(MagiskState.LOADING) + val managerStateText = Observer(managerState) { + @Suppress("WhenWithOnlyElse") + when (managerState.value) { + MagiskState.NO_ROOT -> TODO() + MagiskState.NOT_INSTALLED -> TODO() + MagiskState.UP_TO_DATE -> TODO() + MagiskState.LOADING -> TODO() + MagiskState.OBSOLETE -> TODO() + } + } + val managerCurrentVersion = KObservableField("") + val managerLatestVersion = KObservableField("") + val managerAdditionalInfo = Observer(managerState) { + if (app.packageName != BuildConfig.APPLICATION_ID) + "(${app.packageName})" + else + "" + } + + fun paypalPressed() = OpenLinkEvent(Const.Url.PAYPAL_URL).publish() + fun patreonPressed() = OpenLinkEvent(Const.Url.PATREON_URL).publish() + fun twitterPressed() = OpenLinkEvent(Const.Url.TWITTER_URL).publish() + fun githubPressed() = OpenLinkEvent(Const.Url.REPO_URL).publish() + fun xdaPressed() = OpenLinkEvent(Const.Url.XDA_THREAD).publish() + fun uninstallPressed() = UninstallEvent.publish() + + fun refresh() {} + + fun advancedPressed() = isAdvancedExpanded.toggle() + + fun installPressed(item: MagiskItem) = when (item) { + MagiskItem.MANAGER -> ManagerInstallEvent.publish() + MagiskItem.MAGISK -> MagiskInstallEvent.publish() + } + + fun cardPressed(item: MagiskItem) = when (item) { + MagiskItem.MANAGER -> ManagerChangelogEvent.publish() + MagiskItem.MAGISK -> MagiskChangelogEvent.publish() + } + +} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.java b/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.java deleted file mode 100644 index 4a1864214..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.java +++ /dev/null @@ -1,332 +0,0 @@ -package com.topjohnwu.magisk.ui.home; - -import android.net.Uri; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.ImageView; -import android.widget.LinearLayout; - -import com.topjohnwu.magisk.BuildConfig; -import com.topjohnwu.magisk.Config; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.tasks.CheckUpdates; -import com.topjohnwu.magisk.ui.MainActivity; -import com.topjohnwu.magisk.ui.base.BaseActivity; -import com.topjohnwu.magisk.ui.base.BaseFragment; -import com.topjohnwu.magisk.utils.Event; -import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.magisk.view.ArrowExpandable; -import com.topjohnwu.magisk.view.Expandable; -import com.topjohnwu.magisk.view.ExpandableViewHolder; -import com.topjohnwu.magisk.view.MarkDownWindow; -import com.topjohnwu.magisk.view.SafetyNet; -import com.topjohnwu.magisk.view.UpdateCardHolder; -import com.topjohnwu.magisk.view.dialogs.EnvFixDialog; -import com.topjohnwu.magisk.view.dialogs.MagiskInstallDialog; -import com.topjohnwu.magisk.view.dialogs.ManagerInstallDialog; -import com.topjohnwu.magisk.view.dialogs.UninstallDialog; -import com.topjohnwu.net.Networking; -import com.topjohnwu.superuser.Shell; - -import java.util.Locale; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.cardview.widget.CardView; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import androidx.transition.ChangeBounds; -import androidx.transition.Fade; -import androidx.transition.Transition; -import androidx.transition.TransitionManager; -import androidx.transition.TransitionSet; -import butterknife.BindColor; -import butterknife.BindView; -import butterknife.OnClick; - -public class MagiskFragment extends BaseFragment implements SwipeRefreshLayout.OnRefreshListener { - - private static boolean shownDialog = false; - - @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout; - @BindView(R.id.linearLayout) LinearLayout root; - - @BindView(R.id.install_option_card) CardView installOptionCard; - @BindView(R.id.keep_force_enc) CheckBox keepEncChkbox; - @BindView(R.id.keep_verity) CheckBox keepVerityChkbox; - @BindView(R.id.install_option_expand) ViewGroup optionExpandLayout; - @BindView(R.id.arrow) ImageView arrow; - - @BindView(R.id.uninstall_button) CardView uninstallButton; - - @BindColor(R.color.red500) int colorBad; - @BindColor(R.color.green500) int colorOK; - @BindColor(R.color.yellow500) int colorWarn; - @BindColor(R.color.green500) int colorNeutral; - @BindColor(R.color.blue500) int colorInfo; - - private UpdateCardHolder magisk; - private UpdateCardHolder manager; - private SafetyNet safetyNet; - private Transition transition; - private Expandable optionExpand; - - private void magiskInstall(View v) { - // Show Manager update first - if (Config.remoteManagerVersionCode > BuildConfig.VERSION_CODE) { - new ManagerInstallDialog(requireActivity()).show(); - return; - } - new MagiskInstallDialog((BaseActivity) requireActivity()).show(); - } - - private void managerInstall(View v) { - new ManagerInstallDialog(requireActivity()).show(); - } - - private void openLink(String url) { - Utils.openLink(requireActivity(), Uri.parse(url)); - } - - @OnClick(R.id.paypal) - void paypal() { - openLink(Const.Url.PAYPAL_URL); - } - - @OnClick(R.id.patreon) - void patreon() { - openLink(Const.Url.PATREON_URL); - } - - @OnClick(R.id.twitter) - void twitter() { - openLink(Const.Url.TWITTER_URL); - } - - @OnClick(R.id.github) - void github() { - openLink(Const.Url.SOURCE_CODE_URL); - } - - @OnClick(R.id.xda) - void xda() { - openLink(Const.Url.XDA_THREAD); - } - - @OnClick(R.id.uninstall_button) - void uninstall() { - new UninstallDialog(requireActivity()).show(); - } - - @OnClick(R.id.arrow) - void expandOptions() { - if (optionExpand.isExpanded()) - optionExpand.collapse(); - else optionExpand.expand(); - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_magisk, container, false); - unbinder = new MagiskFragment_ViewBinding(this, v); - requireActivity().setTitle(R.string.magisk); - - optionExpand = new ArrowExpandable(new ExpandableViewHolder(optionExpandLayout), arrow); - safetyNet = new SafetyNet(v); - magisk = new UpdateCardHolder(inflater, root); - manager = new UpdateCardHolder(inflater, root); - manager.setClickable(vv -> - MarkDownWindow.show(requireActivity(), null, - getResources().openRawResource(R.raw.changelog))); - root.addView(magisk.itemView, 1); - root.addView(manager.itemView, 2); - - keepVerityChkbox.setChecked(Config.keepVerity); - keepVerityChkbox.setOnCheckedChangeListener((view, checked) -> Config.keepVerity = checked); - keepEncChkbox.setChecked(Config.keepEnc); - keepEncChkbox.setOnCheckedChangeListener((view, checked) -> Config.keepEnc = checked); - - mSwipeRefreshLayout.setOnRefreshListener(this); - - magisk.install.setOnClickListener(this::magiskInstall); - manager.install.setOnClickListener(this::managerInstall); - if (Config.get(Config.Key.COREONLY)) { - magisk.additional.setText(R.string.core_only_enabled); - magisk.additional.setVisibility(View.VISIBLE); - } - if (!app.getPackageName().equals(BuildConfig.APPLICATION_ID)) { - manager.additional.setText("(" + app.getPackageName() + ")"); - manager.additional.setVisibility(View.VISIBLE); - } - - transition = new TransitionSet() - .setOrdering(TransitionSet.ORDERING_TOGETHER) - .addTransition(new Fade(Fade.OUT)) - .addTransition(new ChangeBounds()) - .addTransition(new Fade(Fade.IN)); - - updateUI(); - return v; - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - safetyNet.unbinder.unbind(); - magisk.unbinder.unbind(); - manager.unbinder.unbind(); - } - - @Override - public void onRefresh() { - mSwipeRefreshLayout.setRefreshing(false); - TransitionManager.beginDelayedTransition(root, transition); - safetyNet.reset(); - magisk.reset(); - manager.reset(); - - Config.loadMagiskInfo(); - updateUI(); - - Event.reset(this); - Config.remoteMagiskVersionString = null; - Config.remoteMagiskVersionCode = -1; - - shownDialog = false; - - // Trigger state check - if (Networking.checkNetworkStatus(app)) { - CheckUpdates.check(); - } - } - - @Override - public int[] getListeningEvents() { - return new int[] {Event.UPDATE_CHECK_DONE}; - } - - @Override - public void onEvent(int event) { - updateCheckUI(); - } - - private void updateUI() { - ((MainActivity) requireActivity()).checkHideSection(); - int image, color; - String status; - if (Config.magiskVersionCode < 0) { - color = colorBad; - image = R.drawable.ic_cancel; - status = getString(R.string.magisk_version_error); - magisk.status.setText(status); - magisk.currentVersion.setVisibility(View.GONE); - } else { - color = colorOK; - image = R.drawable.ic_check_circle; - status = getString(R.string.magisk); - magisk.currentVersion.setText(getString(R.string.current_installed, - String.format(Locale.US, "v%s (%d)", - Config.magiskVersionString, Config.magiskVersionCode))); - } - magisk.statusIcon.setColorFilter(color); - magisk.statusIcon.setImageResource(image); - - manager.statusIcon.setColorFilter(colorOK); - manager.statusIcon.setImageResource(R.drawable.ic_check_circle); - manager.currentVersion.setText(getString(R.string.current_installed, - String.format(Locale.US, "v%s (%d)", - BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE))); - - if (!Networking.checkNetworkStatus(app)) { - // No network, updateCheckUI will not be triggered - magisk.status.setText(status); - manager.status.setText(R.string.app_name); - magisk.setValid(false); - manager.setValid(false); - } - } - - private void updateCheckUI() { - int image, color; - String status, button = ""; - - TransitionManager.beginDelayedTransition(root, transition); - - if (Config.remoteMagiskVersionCode < 0) { - color = colorNeutral; - image = R.drawable.ic_help; - status = getString(R.string.invalid_update_channel); - } else { - magisk.latestVersion.setText(getString(R.string.latest_version, - String.format(Locale.US, "v%s (%d)", - Config.remoteMagiskVersionString, Config.remoteMagiskVersionCode))); - if (Config.remoteMagiskVersionCode > Config.magiskVersionCode) { - color = colorInfo; - image = R.drawable.ic_update; - status = getString(R.string.magisk_update_title); - button = getString(R.string.update); - } else { - color = colorOK; - image = R.drawable.ic_check_circle; - status = getString(R.string.magisk_up_to_date); - button = getString(R.string.install); - } - } - if (Config.magiskVersionCode > 0) { - // Only override status if Magisk is installed - magisk.statusIcon.setImageResource(image); - magisk.statusIcon.setColorFilter(color); - magisk.status.setText(status); - magisk.install.setText(button); - } - - if (Config.remoteManagerVersionCode < 0) { - color = colorNeutral; - image = R.drawable.ic_help; - status = getString(R.string.invalid_update_channel); - } else { - manager.latestVersion.setText(getString(R.string.latest_version, - String.format(Locale.US, "v%s (%d)", - Config.remoteManagerVersionString, Config.remoteManagerVersionCode))); - if (Config.remoteManagerVersionCode > BuildConfig.VERSION_CODE) { - color = colorInfo; - image = R.drawable.ic_update; - status = getString(R.string.manager_update_title); - manager.install.setText(R.string.update); - } else { - color = colorOK; - image = R.drawable.ic_check_circle; - status = getString(R.string.manager_up_to_date); - manager.install.setText(R.string.install); - } - } - manager.statusIcon.setImageResource(image); - manager.statusIcon.setColorFilter(color); - manager.status.setText(status); - - magisk.setValid(Config.remoteMagiskVersionCode > 0); - manager.setValid(Config.remoteManagerVersionCode > 0); - - if (Config.remoteMagiskVersionCode < 0) { - // Hide install related components - installOptionCard.setVisibility(View.GONE); - uninstallButton.setVisibility(View.GONE); - } else { - // Show install related components - installOptionCard.setVisibility(View.VISIBLE); - uninstallButton.setVisibility(Shell.rootAccess() ? View.VISIBLE : View.GONE); - } - - if (!shownDialog && Config.magiskVersionCode > 0 && - !Shell.su("env_check").exec().isSuccess()) { - shownDialog = true; - new EnvFixDialog(requireActivity()).show(); - } - } -} - diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.kt new file mode 100644 index 000000000..77f435eea --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.kt @@ -0,0 +1,279 @@ +package com.topjohnwu.magisk.ui.home + +import com.skoumal.teanity.viewevents.ViewEvent +import com.topjohnwu.magisk.Config +import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.model.events.MagiskInstallEvent +import com.topjohnwu.magisk.model.events.ManagerInstallEvent +import com.topjohnwu.magisk.model.events.OpenLinkEvent +import com.topjohnwu.magisk.model.events.UninstallEvent +import com.topjohnwu.magisk.utils.Event +import com.topjohnwu.magisk.view.MarkDownWindow +import com.topjohnwu.magisk.view.dialogs.ManagerInstallDialog +import com.topjohnwu.magisk.view.dialogs.UninstallDialog +import org.koin.androidx.viewmodel.ext.android.viewModel +import com.topjohnwu.magisk.ui.base.MagiskFragment as NewMagiskFragment + +class MagiskFragment : NewMagiskFragment() { + + /*@BindView(R.id.swipeRefreshLayout) + internal var mSwipeRefreshLayout: SwipeRefreshLayout? = null + @BindView(R.id.linearLayout) + internal var root: LinearLayout? = null + + @BindView(R.id.install_option_card) + internal var installOptionCard: CardView? = null + @BindView(R.id.keep_force_enc) + internal var keepEncChkbox: CheckBox? = null + @BindView(R.id.keep_verity) + internal var keepVerityChkbox: CheckBox? = null + @BindView(R.id.install_option_expand) + internal var optionExpandLayout: ViewGroup? = null + @BindView(R.id.arrow) + internal var arrow: ImageView? = null + + @BindView(R.id.uninstall_button) + internal var uninstallButton: CardView? = null + + @BindColor(R.color.red500) + internal var colorBad: Int = 0 + @BindColor(R.color.green500) + internal var colorOK: Int = 0 + @BindColor(R.color.yellow500) + internal var colorWarn: Int = 0 + @BindColor(R.color.green500) + internal var colorNeutral: Int = 0 + @BindColor(R.color.blue500) + internal var colorInfo: Int = 0*/ + + /*private var magisk: UpdateCardHolder? = null + private var manager: UpdateCardHolder? = null + private var safetyNet: SafetyNet? = null + private var transition: Transition? = null + private var optionExpand: Expandable? = null*/ + + override val layoutRes: Int = R.layout.fragment_magisk + override val viewModel: HomeViewModel by viewModel() + + override fun onEventDispatched(event: ViewEvent) { + super.onEventDispatched(event) + when (event) { + is OpenLinkEvent -> openLink(event.url) + is ManagerInstallEvent -> installManager() + is MagiskInstallEvent -> installMagisk() + is UninstallEvent -> uninstall() + } + } + + private fun installMagisk() { + // Show Manager update first + if (Config.remoteManagerVersionCode > BuildConfig.VERSION_CODE) { + ManagerInstallDialog(requireActivity()).show() + return + } + //FIXME dialog requires old base + //MagiskInstallDialog(requireActivity()).show() + } + + private fun installManager() = ManagerInstallDialog(requireActivity()).show() + + private fun uninstall() { + UninstallDialog(requireActivity()).show() + } + + private fun changelogManager() { + MarkDownWindow.show( + requireActivity(), null, + resources.openRawResource(R.raw.changelog) + ) + } + + /*override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val v = inflater.inflate(R.layout.fragment_magisk, container, false) + requireActivity().setTitle(R.string.magisk) + + //safetyNet = SafetyNet(v) + + *//*transition = TransitionSet() + .setOrdering(TransitionSet.ORDERING_TOGETHER) + .addTransition(Fade(Fade.OUT)) + .addTransition(ChangeBounds()) + .addTransition(Fade(Fade.IN))*//* + + updateUI() + return v + }*/ + + private fun onRefresh() { + /*mSwipeRefreshLayout!!.isRefreshing = false + TransitionManager.beginDelayedTransition(root!!, transition) + safetyNet!!.reset() + magisk!!.reset() + manager!!.reset()*/ + + Config.loadMagiskInfo() + updateUI() + + //FIXME requires old base + /*Event.reset(this) + Config.remoteMagiskVersionString = null + Config.remoteMagiskVersionCode = -1*/ + + shownDialog = false + + // Trigger state check + /*if (Networking.checkNetworkStatus(app)) { + CheckUpdates.check() + }*/ + } + + private fun getListeningEvents(): IntArray { + return intArrayOf(Event.UPDATE_CHECK_DONE) + } + + private fun onEvent(event: Int) { + updateCheckUI() + } + + private fun updateUI() { + /*(requireActivity() as MainActivity).checkHideSection() + val image: Int + val color: Int + val status: String + if (Config.magiskVersionCode < 0) { + color = colorBad + image = R.drawable.ic_cancel + status = getString(R.string.magisk_version_error) + magisk!!.status.text = status + magisk!!.currentVersion.visibility = View.GONE + } else { + color = colorOK + image = R.drawable.ic_check_circle + status = getString(R.string.magisk) + magisk!!.currentVersion.text = getString( + R.string.current_installed, + String.format( + Locale.US, "v%s (%d)", + Config.magiskVersionString, Config.magiskVersionCode + ) + ) + } + magisk!!.statusIcon.setColorFilter(color) + magisk!!.statusIcon.setImageResource(image) + + manager!!.statusIcon.setColorFilter(colorOK) + manager!!.statusIcon.setImageResource(R.drawable.ic_check_circle) + manager!!.currentVersion.text = getString( + R.string.current_installed, + String.format( + Locale.US, "v%s (%d)", + BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE + ) + ) + + if (!Networking.checkNetworkStatus(app)) { + // No network, updateCheckUI will not be triggered + magisk!!.status.text = status + manager!!.status.setText(R.string.app_name) + magisk!!.setValid(false) + manager!!.setValid(false) + }*/ + } + + private fun updateCheckUI() { + /*var image: Int + var color: Int + var status: String + var button = "" + + + if (Config.remoteMagiskVersionCode < 0) { + color = colorNeutral + image = R.drawable.ic_help + status = getString(R.string.invalid_update_channel) + } else { + magisk!!.latestVersion.text = getString( + R.string.latest_version, + String.format( + Locale.US, "v%s (%d)", + Config.remoteMagiskVersionString, Config.remoteMagiskVersionCode + ) + ) + if (Config.remoteMagiskVersionCode > Config.magiskVersionCode) { + color = colorInfo + image = R.drawable.ic_update + status = getString(R.string.magisk_update_title) + button = getString(R.string.update) + } else { + color = colorOK + image = R.drawable.ic_check_circle + status = getString(R.string.magisk_up_to_date) + button = getString(R.string.install) + } + } + if (Config.magiskVersionCode > 0) { + // Only override status if Magisk is installed + magisk!!.statusIcon.setImageResource(image) + magisk!!.statusIcon.setColorFilter(color) + magisk!!.status.text = status + magisk!!.install.text = button + } + + if (Config.remoteManagerVersionCode < 0) { + color = colorNeutral + image = R.drawable.ic_help + status = getString(R.string.invalid_update_channel) + } else { + manager!!.latestVersion.text = getString( + R.string.latest_version, + String.format( + Locale.US, "v%s (%d)", + Config.remoteManagerVersionString, Config.remoteManagerVersionCode + ) + ) + if (Config.remoteManagerVersionCode > BuildConfig.VERSION_CODE) { + color = colorInfo + image = R.drawable.ic_update + status = getString(R.string.manager_update_title) + manager!!.install.setText(R.string.update) + } else { + color = colorOK + image = R.drawable.ic_check_circle + status = getString(R.string.manager_up_to_date) + manager!!.install.setText(R.string.install) + } + } + manager!!.statusIcon.setImageResource(image) + manager!!.statusIcon.setColorFilter(color) + manager!!.status.text = status + + magisk!!.setValid(Config.remoteMagiskVersionCode > 0) + manager!!.setValid(Config.remoteManagerVersionCode > 0) + + if (Config.remoteMagiskVersionCode < 0) { + // Hide install related components + installOptionCard!!.visibility = View.GONE + uninstallButton!!.visibility = View.GONE + } else { + // Show install related components + installOptionCard!!.visibility = View.VISIBLE + uninstallButton!!.visibility = if (Shell.rootAccess()) View.VISIBLE else View.GONE + } + + if (!shownDialog && Config.magiskVersionCode > 0 && + !Shell.su("env_check").exec().isSuccess + ) { + shownDialog = true + EnvFixDialog(requireActivity()).show() + }*/ + } + + companion object { + + private var shownDialog = false + } +} + diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskItem.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskItem.kt new file mode 100644 index 000000000..8f26b0c1d --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskItem.kt @@ -0,0 +1,6 @@ +package com.topjohnwu.magisk.ui.home + + +enum class MagiskItem { + MANAGER, MAGISK +} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskState.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskState.kt new file mode 100644 index 000000000..8d880001d --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskState.kt @@ -0,0 +1,6 @@ +package com.topjohnwu.magisk.ui.home + + +enum class MagiskState { + NO_ROOT, NOT_INSTALLED, UP_TO_DATE, OBSOLETE, LOADING +} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/DataBindingAdapters.kt b/app/src/main/java/com/topjohnwu/magisk/utils/DataBindingAdapters.kt index f160e46ba..61d27118b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/DataBindingAdapters.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/DataBindingAdapters.kt @@ -1,6 +1,8 @@ package com.topjohnwu.magisk.utils import android.view.View +import androidx.annotation.DrawableRes +import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.Toolbar import androidx.databinding.BindingAdapter @@ -9,3 +11,8 @@ import androidx.databinding.BindingAdapter fun setOnNavigationClickedListener(view: Toolbar, listener: View.OnClickListener) { view.setNavigationOnClickListener(listener) } + +@BindingAdapter("srcCompat") +fun setImageResource(view: AppCompatImageView, @DrawableRes resId: Int) { + view.setImageResource(resId) +} diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/XBinding.kt b/app/src/main/java/com/topjohnwu/magisk/utils/XBinding.kt new file mode 100644 index 000000000..ff9307a9e --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/XBinding.kt @@ -0,0 +1,8 @@ +package com.topjohnwu.magisk.utils + +import com.skoumal.teanity.util.KObservableField + + +fun KObservableField.toggle() { + value = !value +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_magisk.xml b/app/src/main/res/layout/fragment_magisk.xml index a83e96333..10c6dd845 100644 --- a/app/src/main/res/layout/fragment_magisk.xml +++ b/app/src/main/res/layout/fragment_magisk.xml @@ -1,472 +1,520 @@ - + - + + + + + + + + + + + android:layout_height="fill_parent" + android:orientation="vertical" + app:onRefreshListener="@{() -> viewModel.refresh()}" + app:refreshing="@{viewModel.loading}"> - - - - - - - - - - - - - - + android:orientation="vertical"> - + - - + android:layout_height="wrap_content" + android:layout_marginTop="5dp" + android:layout_marginBottom="5dp"> + + + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintStart_toEndOf="@+id/icon" + app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + android:layout_height="wrap_content"> - + + + + + + + + + + + + + + + android:paddingBottom="10dp"> + + + + + + + + + + + - - + - - - + android:layout_height="match_parent" + android:layout_marginStart="5dp" + android:layout_marginTop="4dp" + android:layout_marginEnd="5dp" + android:layout_marginBottom="4dp" + app:cardCornerRadius="@dimen/card_corner_radius" + app:cardElevation="@dimen/card_elevation"> - - - - - - - - - - - - - - - - - - - - - + app:layout_constraintTop_toBottomOf="@+id/paypal"> - + + + + + + + + + + + app:layout_constraintStart_toEndOf="@id/github"> + + + + + + + + + + + + + + + + + - + - - - - - + android:layout_height="match_parent" + android:layout_gravity="center" + android:layout_marginStart="5dp" + android:layout_marginTop="4dp" + android:layout_marginEnd="5dp" + android:layout_marginBottom="4dp" + android:clickable="true" + android:focusable="true" + android:foreground="?android:attr/selectableItemBackground" + android:onClick="@{() -> viewModel.uninstallPressed()}" + app:cardCornerRadius="@dimen/card_corner_radius" + app:cardElevation="@dimen/card_elevation"> - + android:layout_marginTop="10dp" + android:layout_marginBottom="10dp" + android:ems="10" + android:fontFamily="sans-serif" + android:gravity="center" + android:text="@string/uninstall" + android:textAllCaps="false" + android:textSize="20sp" + android:textStyle="bold" /> - + - - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/app/src/main/res/layout/include_update_card.xml b/app/src/main/res/layout/include_update_card.xml new file mode 100644 index 000000000..03a6d003f --- /dev/null +++ b/app/src/main/res/layout/include_update_card.xml @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/update_card.xml b/app/src/main/res/layout/update_card.xml index 103f62725..2fd143493 100644 --- a/app/src/main/res/layout/update_card.xml +++ b/app/src/main/res/layout/update_card.xml @@ -75,7 +75,6 @@ android:layout_height="wrap_content" android:maxLines="1" android:text="@string/checking_for_updates" - android:visibility="gone" app:autoSizeMinTextSize="1sp" app:autoSizeTextType="uniform" app:layout_constraintEnd_toEndOf="@+id/status" @@ -87,7 +86,6 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:maxLines="1" - android:visibility="gone" app:autoSizeMinTextSize="1sp" app:autoSizeTextType="uniform" app:layout_constraintEnd_toEndOf="@+id/status" @@ -101,7 +99,6 @@ android:layout_marginEnd="8dp" android:maxLines="1" android:text="@string/install" - android:visibility="gone" app:autoSizeMaxTextSize="14sp" app:autoSizeTextType="uniform" app:layout_constraintBottom_toBottomOf="parent"