diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index c9d5033..3bf3578 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -6,7 +6,7 @@ open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username +liberapay: sunilpaulmathew issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username custom: ['https://www.paypal.me/menacherry', 'https://play.google.com/store/apps/details?id=com.smartpack.donate'] diff --git a/Credits.md b/Credits.md new file mode 100644 index 0000000..4826bbe --- /dev/null +++ b/Credits.md @@ -0,0 +1,23 @@ +# Credits +Script Manager is, and as always, an open-source project which is ready to accept contributions from others. The application gladly received contributions from a number of people from time to time, mostly with translations. This page provides an incomplete list of people who contributed to this project, directly or indirectly. + +## Code +* [Grarak](https://github.com/Grarak/): Kernel Adiutor, from where some code is taken +* [topjohnwu](https://github.com/topjohnwu): libsu, the library in which Script Manager depending to handle root related tasks +* [Lennoard Silva](https://github.com/Lennoard): contributed code to this project, especially in its early stage of development + +## Icon +* [Toxinpiper](https://t.me/toxinpiper), App Icon + +## Translations +* [Lennoard Silva](https://github.com/Lennoard), Portuguese (Brazilian) Translations +* [SmgKhOaRn](https://github.com/SmgKhOaRn), Korean Translations +* [okta-10](https://github.com/okta-10), Indonesian Translations +* [Mikesew1320](https://github.com/Mikesew1320), Amharic/Russian Translations +* [tsiflimagas](https://github.com/tsiflimagas), Greek Translations +* Hana Shirosaki & Makerye, Chinese (simplified) Translations +* Iphonemuszka, Polish Translations +* InfoZebra & tommynok, Ukrainian Translations +* Many other people contributed via [POEditor](https://poeditor.com/join/project?hash=w47nhsNDL7) + +_If you think I missed your name, please let me know._ \ No newline at end of file diff --git a/README.md b/README.md index 1beefaf..424873d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Script Manager -[![](https://img.shields.io/badge/Script%20Manager-v3.1-green)](https://play.google.com/store/apps/details?id=com.smartpack.scriptmanager) +[![](https://img.shields.io/badge/Script%20Manager-v5.0-green)](https://play.google.com/store/apps/details?id=com.smartpack.scriptmanager) ![](https://img.shields.io/github/languages/top/SmartPack/ScriptManager) ![](https://img.shields.io/github/contributors/smartpack/ScriptManager) ![](https://img.shields.io/github/license/smartpack/SmartPack-Kernel-Manager) @@ -8,20 +8,21 @@ ![Script Manager](https://github.com/SmartPack/ScriptManager/blob/master/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png?raw=true) ### Script Manager is a simple app to create, import, edit and easily execute any properly formatted shell scripts. +_Important Notice: The development of this project is abandoned._ ## Download [](https://play.google.com/store/apps/details?id=com.smartpack.scriptmanager) -[](https://github.com/SmartPack/ScriptManager/blob/master/release/com.smartpack.scriptmanager.apk?raw=true) +[](https://f-droid.org/packages/com.smartpack.scriptmanager) ## Requirements -* ROOT Access +* This app doesn't need ROOT Access for normal use. However, due to the restricted permissions of android eco-system, executing root commands from app won't work without ROOT Access enabled. ## Features -Script Manager is a simple and very basic app, without a settings menu, which can do the following things +Script Manager is a simple and very basic app, with as elegant light/dark UI, which can do the following things * Create, edit, share, and easily execute shell scripts. * Import shell scripts from sdcard. * Apply scripts on boot, either on post-fs or late_service as per user choice (only if rooted with Magisk). @@ -32,28 +33,26 @@ Script Manager is a simple and very basic app, without a settings menu, which ca height="80">](https://t.me/smartpack_kmanager) ## Donations -If you like to appreciate my work, please consider donating to me (either via [PayPal](https://www.paypal.me/menacherry/), or [Ko-fi](https://ko-fi.com/sunilpaulmathew/), or by purchasing the [SmartPack Donation Package](https://play.google.com/store/apps/details?id=com.smartpack.donate) from playstore) as it is helpful to continue my projects more active, although it is not at all necessary. -Please Note: Purchasing [SmartPack Donation Package](https://play.google.com/store/apps/details?id=com.smartpack.donate) will remove Ads on this app. +If you like to appreciate my work, please consider donating to me (either via [Liberapay](https://liberapay.com/sunilpaulmathew/donate), [PayPal](https://www.paypal.me/menacherry/), [Ko-fi](https://ko-fi.com/sunilpaulmathew/), or by purchasing the [SmartPack Donation Package](https://play.google.com/store/apps/details?id=com.smartpack.donate) from playstore) as it is helpful to continue my projects more active, although it is not at all necessary. +[](https://liberapay.com/sunilpaulmathew/donate/) [](https://www.paypal.me/menacherry/) -[](https://play.google.com/store/apps/details?id=com.smartpack.donate) [](https://ko-fi.com/sunilpaulmathew/) +[](https://play.google.com/store/apps/details?id=com.smartpack.donate) + +## Translations +Please help me to translate this application via [POEditor](https://poeditor.com/join/project?hash=w47nhsNDL7). You may also translate after downloading the original language string available [here](app/src/main/res/values/strings.xml). ## Credits -* [Grarak](https://github.com/Grarak), Kernel Adiutor, from where I took a lot of code -* [topjohnwu](https://github.com/topjohnwu), libsu & Magisk -* [Lennoard Silva](https://github.com/Lennoard), Code contributions, Portuguese (Brazilian) Translations -* [SmgKhOaRn](https://github.com/SmgKhOaRn), Korean Translations -* [okta-10](https://github.com/okta-10), Indonesian Translations -* [Mikesew1320](https://github.com/Mikesew1320), Amharic Translations -* [tsiflimagas](https://github.com/tsiflimagas), Greek Translations -* [Toxinpiper](https://t.me/toxinpiper), App Icon +A list of people who contributed to this project is available [here](Credits.md). ## Report a bug or request a feature @@ -61,7 +60,7 @@ You can report a bug or request a feature by [opening an issue](https://github.c ## License - Copyright (C) 2020-2021 sunilpaulmathew + Copyright (C) 2021-2022 sunilpaulmathew Script Manager is a free softwares: you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -74,4 +73,4 @@ You can report a bug or request a feature by [opening an issue](https://github.c for more details. You should have received a copy of the GNU General Public License along - with Script Manager. If not, see . \ No newline at end of file + with Script Manager. If not, see . diff --git a/app/.gitignore b/app/.gitignore index 32fe082..71848ec 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1,5 +1,5 @@ /build /release /src/main/gen -/release +/play *.jks diff --git a/app/build.gradle b/app/build.gradle index b832fcd..2629cb3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,15 +11,15 @@ android { } } - compileSdkVersion 29 - buildToolsVersion '29.0.3' + compileSdkVersion 30 + buildToolsVersion '30.0.3' defaultConfig { applicationId "com.smartpack.scriptmanager" minSdkVersion 23 - targetSdkVersion 29 - versionCode 22 - versionName "3.1" + targetSdkVersion 30 + versionCode 41 + versionName "v5.0" vectorDrawables.useSupportLibrary = true archivesBaseName = "$applicationId-$versionName" testFunctionalTest = false @@ -34,6 +34,17 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + + flavorDimensions "release" + productFlavors { + play { + dimension "release" + } + fdroid { + dimension "release" + } + } + lintOptions { abortOnError false } @@ -48,10 +59,7 @@ repositories { } dependencies { - implementation('com.github.ozodrukh:CircularReveal:1.3.1@aar') { - transitive = true - } - implementation 'com.facebook.android:audience-network-sdk:5.8.0' - implementation "com.github.topjohnwu.libsu:core:2.5.1" - implementation 'com.google.android.material:material:1.2.0-alpha06' + playImplementation 'com.android.billingclient:billing:4.0.0' + implementation "com.github.topjohnwu.libsu:core:3.1.2" + implementation 'com.google.android.material:material:1.4.0' } \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index b39c745..481bb43 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,22 +1,21 @@ # Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /Users/willi/android/sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html -# Add any project specific keep options here: - # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} --keepattributes Signature --keepattributes *Annotation* --keep class com.squareup.okhttp.** { *; } --keep interface com.squareup.okhttp.** { *; } --dontwarn com.squareup.okhttp.** + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/fdroid/java/com/smartpack/scriptmanager/utils/Billing.java b/app/src/fdroid/java/com/smartpack/scriptmanager/utils/Billing.java new file mode 100644 index 0000000..a3b3ec9 --- /dev/null +++ b/app/src/fdroid/java/com/smartpack/scriptmanager/utils/Billing.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2021-2022 sunilpaulmathew + * + * This file is part of Script Manager, an app to create, import, edit + * and easily execute any properly formatted shell scripts. + * + */ + +package com.smartpack.scriptmanager.utils; + +import android.app.Activity; + +/* + * Created by sunilpaulmathew on January 17, 2021 + */ +public class Billing { + + public static void showDonateOption(Activity activity) { + Utils.launchUrl("https://smartpack.github.io/donation/", activity); + } + +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ec96733..35e6ca5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,7 +5,8 @@ - + - - + + + + + - - + \ No newline at end of file diff --git a/app/src/main/assets/update_info.json b/app/src/main/assets/update_info.json index 443185a..4ba87b4 100644 --- a/app/src/main/assets/update_info.json +++ b/app/src/main/assets/update_info.json @@ -1,6 +1,3 @@ { - "releaseNotes": "Change-logs\n - Apply and Test script: Show success message if the output is empty \n - Fixed crashing in no root available situations.\n - Barnd new About & Change-log views.\n - Miscellaneous changes.", - "changelogFull": "v3.1\n - Apply and Test script: Show success message if the output is empty \n - Fixed crashing in no root available situations.\n - Barnd new About & Change-log views.\n - Miscellaneous Changes.\n\nv3.0\n - Removed a bunch of unused code.\n - Removed interstitial ads from app.\n - Replace toast messages with snackbar.\n - Miscellaneous changes.\n\nv2.9\n - Largely improved app user interface.\n - Improved root handling.\n - Added portuguese (brazilian) translations (Credits: @Lennoard).\n - Miscellaneous changes.\n\nv2.8\n - Improved apply & test script options.\n - Miscellaneous changes.\n\nv2.7\n - Migrated to libsu (@Lennoard).\n - Added option to test a script while creating/editing.\n - Brand New applying script view.\n - Allow editing copyright text by long-clicking.\n - Miscellaneous changes.\n\nv2.6\n - Added Greek translations (credits: @tsiflimagas).\n - Miscellaneous changes.\n\nv2.5\n - Added dark & light themes.\n - Added an option to change app language.\n - Fixed creating app folder on Android 10.\n - Added Indonesian (credits: @okta-10) and Amharic (credits: @Mikesew1320) translations.\n - Improved Korean translations (credits: @SmgKhOaRn).\n - Updated build tools & dependencies.\n - Miscellaneous changes.\n\nv2.4\n - res: Added Korean translations (credits @SmgKhOaRn).\n - Main: Updated App UI.\n - Misc: Overall code cleaning and quality improvements.\n\nv2.3\n - Main: Disable Ads if SmartPack Donation Package is installed.\n - Main: App Theme: Make it more Dark.\n - gradle: Update build tools & dependencies.\n - Miscellaneous changes.\n\nv2.2\n - Main: Exit app only after pressing back button twice (prevent accidental closing).\n - Misc: Improved no-root message.\n - gradle: Updated build tools.\n - Miscellaneous changes.\n\nv2.1\n - Main: Improved overall coding style.\n - Miscellaneous Changes.\n\nv2.0\n - Scripts: Import: Updated to work with default Documents UI.\n - res: Brand new icons.\n - Miscellaneous Changes.\n\nv1.8\n - Fixed crashing on some devices.\n - Miscellaneous Changes.\n\nv1.7\n - Preparations for PlayStore release.\n - Misc: Updated example scripts.\n - Main: Added a simple banner Ad view at the bottom.\n - Miscellaneous Changes.\n\nbeta_v6\n - File picking: Support more file manager apps.\n - Main: Slightly updated dark theme.\n - Misc: Overall improvements and bug fixes.\n - Miscellaneous Changes.\n\nbeta_v5\n - Script: Main: Switched to Dark black theme.\n - Miscellaneous Changes.\n\nbeta_v4\n - Script: Added option to directly share scripts.\n - Scripts: Added a helper message, if the item list is empty.\n - Updated targetSdkVersion to 29 (Q).\n - Miscellaneous Changes.\n\nbeta_v3\n - Script Manager: Added a welcome message with examples.\n - App update: fully r-written & switched to json base.\n - Scripts: Import scripts: Fix importing from sdcard root folder.\n - Miscellaneous Changes.\n\nalpha_v2\n - Scripts: On-boot: Add choice to select post-fs or late_service.\n - Script: Edit Script: Show an alert dialog if On-boot is already enabled.\n - Miscellaneous Changes.\n\nalpha_v1\n - The very first public release of Script Manager, an app to create, import, edit and easily execute any properly formatted shell scripts.", - "versionName": "3.1", - "versionCode": 22 -} + "changelogFull": "v5.0\n - Final update + depreciation notice.\n - Updated build tools.\n - Miscellaneous changes.\n\nv4.9\n - More updates for latest Android versions.\n - Improved permission handling.\n - Improved language switch.\n - Miscellaneous changes.\n\nv4.8\n - Overall improved app UI.\n - Updated app to target latest Android versions.\n - Added Chinese (simplified), Ukrainian and Polish translations.\n - Updated build tools.\n - Miscellaneous changes.\n\nv4.7\n - Improved built-in file picker.\n - Improved language switch.\n - Updated build tools.\n - Miscellaneous changes.\n\nv4.6\n - Improved internal file picker to avoid some crashes.\n - Moved popup menu items into a new settings page.\n - Miscellaneous changes.\n\nv4.5\n - Fixed possible crashes on some devices.\n - Temporarily fixed issues on Android 11.\n - Overall improved coding style.\n - Miscellaneous changes.\n\nv4.4\n - Updated build tools and SDK.\n - Added a licence page.\n - Slightly updated app UI.\n - App will now show a supporter badge for those who supported development.\n - Miscellaneous changes.\n\nv4.3\n - Updated app to work with the non-rooted environment (with limited capabilities).\n - App will now show live outputs on applying/testing scripts.\n - Overall improvements in app UI (now using more material elements).\n - App will now use its own file picker for selecting scripts by default (configurable).\n - Added a new option to view script content before importing (by long click).\n - Miscellaneous changes.\n\nv4.2\n - Fixed app crashing when trying to import scripts from some locations.\n - Miscellaneous changes.\n\nv4.1\n - Completely removed Ads from the app.\n - Switched to use Material Alert Dialogs.\n - Added donation option.\n - Miscellaneous changes.\n\nv4.0\n - Re-built from (nearly) scratch.\n - App should be now much more fast.\n - Cleaned a whole lot of unused code.\n - Miscellaneous changes.\n\nv3.5\n - Fixed some issues on Create script.\n - Miscellaneous changes.\n\nv3.4\n - Fixed various issues on Edit, create and apply script.\n - Miscellaneous changes.\n\nv3.7\n - Introduced new page to explain no root status.\n - Miscellaneous changes.\n\nv3.6\n - Improved Ad Layout.\n - Removed unnecessary copyright text.\n - Miscellaneous changes.\n\nv3.5\n - Fixed some issues on Create script.\n - Miscellaneous changes.\n\nv3.4\n - Fixed various issues on Edit, create and apply script.\n - Miscellaneous changes.\n\nv3.3\n - Update script Edit and Details views.\n - Updated libsu to v3.0.2.\n - Update gradle build tools.\n - Miscellaneous changes.\n\nv3.2\n - Update description view (Each and every task on scripts are now more straight forward).\n - Added Russian translation (Credits: Mikesew1320).\n - Add an Auto-Mode to App Theme.\n - Improved About and Change-logs view.\n - Miscellaneous Changes.\n\nv3.1\n - Apply and Test script: Show success message if the output is empty \n - Fixed crashing in no root available situations.\n - Barnd new About & Change-log views.\n - Miscellaneous Changes.\n\nv3.0\n - Removed a bunch of unused code.\n - Removed interstitial ads from app.\n - Replace toast messages with snackbar.\n - Miscellaneous changes.\n\nv2.9\n - Largely improved app user interface.\n - Improved root handling.\n - Added portuguese (brazilian) translations (Credits: @Lennoard).\n - Miscellaneous changes.\n\nv2.8\n - Improved apply & test script options.\n - Miscellaneous changes.\n\nv2.7\n - Migrated to libsu (@Lennoard).\n - Added option to test a script while creating/editing.\n - Brand New applying script view.\n - Allow editing copyright text by long-clicking.\n - Miscellaneous changes.\n\nv2.6\n - Added Greek translations (credits: @tsiflimagas).\n - Miscellaneous changes.\n\nv2.5\n - Added dark & light themes.\n - Added an option to change app language.\n - Fixed creating app folder on Android 10.\n - Added Indonesian (credits: @okta-10) and Amharic (credits: @Mikesew1320) translations.\n - Improved Korean translations (credits: @SmgKhOaRn).\n - Updated build tools & dependencies.\n - Miscellaneous changes.\n\nv2.4\n - res: Added Korean translations (credits @SmgKhOaRn).\n - Main: Updated App UI.\n - Misc: Overall code cleaning and quality improvements.\n\nv2.3\n - Main: Disable Ads if SmartPack Donation Package is installed.\n - Main: App Theme: Make it more Dark.\n - gradle: Update build tools & dependencies.\n - Miscellaneous changes.\n\nv2.2\n - Main: Exit app only after pressing back button twice (prevent accidental closing).\n - Misc: Improved no-root message.\n - gradle: Updated build tools.\n - Miscellaneous changes.\n\nv2.1\n - Main: Improved overall coding style.\n - Miscellaneous Changes.\n\nv2.0\n - Scripts: Import: Updated to work with default Documents UI.\n - res: Brand new icons.\n - Miscellaneous Changes.\n\nv1.8\n - Fixed crashing on some devices.\n - Miscellaneous Changes.\n\nv1.7\n - Preparations for PlayStore release.\n - Misc: Updated example scripts.\n - Main: Added a simple banner Ad view at the bottom.\n - Miscellaneous Changes.\n\nbeta_v6\n - File picking: Support more file manager apps.\n - Main: Slightly updated dark theme.\n - Misc: Overall improvements and bug fixes.\n - Miscellaneous Changes.\n\nbeta_v5\n - Script: Main: Switched to Dark black theme.\n - Miscellaneous Changes.\n\nbeta_v4\n - Script: Added option to directly share scripts.\n - Scripts: Added a helper message, if the item list is empty.\n - Updated targetSdkVersion to 29 (Q).\n - Miscellaneous Changes.\n\nbeta_v3\n - Script Manager: Added a welcome message with examples.\n - App update: fully r-written & switched to json base.\n - Scripts: Import scripts: Fix importing from sdcard root folder.\n - Miscellaneous Changes.\n\nalpha_v2\n - Scripts: On-boot: Add choice to select post-fs or late_service.\n - Script: Edit Script: Show an alert dialog if On-boot is already enabled.\n - Miscellaneous Changes.\n\nalpha_v1\n - The very first public release of Script Manager, an app to create, import, edit and easily execute any properly formatted shell scripts." +} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/MainActivity.java b/app/src/main/java/com/smartpack/scriptmanager/MainActivity.java index cc2ed17..5de149a 100644 --- a/app/src/main/java/com/smartpack/scriptmanager/MainActivity.java +++ b/app/src/main/java/com/smartpack/scriptmanager/MainActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 sunilpaulmathew + * Copyright (C) 2021-2022 sunilpaulmathew * * This file is part of Script Manager, an app to create, import, edit * and easily execute any properly formatted shell scripts. @@ -9,364 +9,151 @@ package com.smartpack.scriptmanager; import android.Manifest; +import android.annotation.SuppressLint; import android.content.Intent; +import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.os.Environment; import android.os.Handler; -import android.view.Menu; -import android.view.SubMenu; -import android.view.View; -import android.widget.LinearLayout; +import android.provider.OpenableColumns; -import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.AppCompatImageButton; -import androidx.appcompat.widget.AppCompatImageView; -import androidx.appcompat.widget.AppCompatTextView; -import androidx.appcompat.widget.PopupMenu; import androidx.core.app.ActivityCompat; -import androidx.viewpager.widget.ViewPager; -import com.facebook.ads.AdSize; -import com.facebook.ads.AdView; -import com.smartpack.scriptmanager.fragments.ScriptsFragment; -import com.smartpack.scriptmanager.utils.PagerAdapter; -import com.smartpack.scriptmanager.utils.Prefs; -import com.smartpack.scriptmanager.utils.UpdateCheck; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.smartpack.scriptmanager.activities.AboutActivity; +import com.smartpack.scriptmanager.activities.SettingsActivity; +import com.smartpack.scriptmanager.utils.Scripts; import com.smartpack.scriptmanager.utils.Utils; -import com.smartpack.scriptmanager.utils.ViewUtils; -import com.smartpack.scriptmanager.utils.root.RootUtils; import java.io.File; +import java.util.Objects; /* * Created by sunilpaulmathew on January 12, 2020 */ - public class MainActivity extends AppCompatActivity { - private AppCompatImageButton mSettings; private boolean mExit; - private Handler mHandler = new Handler(); - private ViewPager mViewPager; + private final Handler mHandler = new Handler(); + private String mPath; @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - // Initialize App Theme & FaceBook Ads + protected void onCreate(Bundle savedInstanceState) { + // Initialize App Theme Utils.initializeAppTheme(this); - Utils.initializeFaceBookAds(this); super.onCreate(savedInstanceState); // Set App Language Utils.setLanguage(this); setContentView(R.layout.activity_main); - mSettings = findViewById(R.id.settings_icon); - mViewPager = findViewById(R.id.viewPagerID); - AppCompatTextView textView = findViewById(R.id.no_root_Text); - AppCompatImageView noroot = findViewById(R.id.no_root_Image); - AppCompatTextView copyRightText = findViewById(R.id.copyright_Text); - Utils.mForegroundCard = findViewById(R.id.foreground_card); - Utils.mBack = findViewById(R.id.back); - Utils.mAppIcon = findViewById(R.id.app_image); - Utils.mCardTitle = findViewById(R.id.card_title); - Utils.mAppName = findViewById(R.id.app_title); - Utils.mAboutApp = findViewById(R.id.about_app); - Utils.mCreditsTitle = findViewById(R.id.credits_title); - Utils.mCredits = findViewById(R.id.credits); - Utils.mForegroundText = findViewById(R.id.foreground_text); - Utils.mCancel = findViewById(R.id.cancel_button); - Utils.mBack.setOnClickListener(v -> { - Utils.closeForeground(); - }); - Utils.mCancel.setOnClickListener(v -> { - Utils.closeForeground(); - }); + Scripts.mRecyclerView = findViewById(R.id.recycler_view); + AppCompatImageButton mSettings = findViewById(R.id.settings_icon); + FloatingActionButton mFab = findViewById(R.id.fab); + AppCompatImageButton mInfo = findViewById(R.id.info_icon); + mSettings.setOnClickListener(v -> { - if (Utils.mForegroundActive) return; - settingsMenu(); + Intent settingsMenu = new Intent(this, SettingsActivity.class); + startActivity(settingsMenu); }); - if (!RootUtils.rootAccess()) { - textView.setText(getString(R.string.no_root)); - noroot.setImageDrawable(Utils.getColoredIcon(R.drawable.ic_help, this)); - Utils.snackbar(mViewPager, getString(R.string.no_root_message)); - return; - } - - if (Prefs.getBoolean("allow_ads", true, this)) { - AdView mAdView = new AdView(this, "804059380003092_804060013336362", AdSize.BANNER_HEIGHT_50); - LinearLayout adContainer = findViewById(R.id.banner_container); - adContainer.addView(mAdView); - mAdView.loadAd(); - } - - PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager()); - adapter.AddFragment(new ScriptsFragment(), getString(R.string.app_name)); - - // Allow changing Copyright Text - if (Utils.existFile(Utils.getInternalDataStorage() + "/copyright") && - Utils.readFile(Utils.getInternalDataStorage() + "/copyright") != null) { - copyRightText.setText(Utils.readFile(Utils.getInternalDataStorage() + "/copyright")); - } else { - copyRightText.setText(R.string.copyright); - } - copyRightText.setOnLongClickListener(item -> { - if (Utils.checkWriteStoragePermission(this)) { - setCopyRightText(); + mFab.setOnClickListener(v -> { + if (Build.VERSION.SDK_INT >= 30) { + Scripts.createScript(this); } else { - ActivityCompat.requestPermissions(this, new String[]{ - Manifest.permission.WRITE_EXTERNAL_STORAGE},1); + if (!Utils.checkWriteStoragePermission(this)) { + ActivityCompat.requestPermissions(this, new String[]{ + Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.permission_denied_write_storage)); + return; + } + Utils.fabMenu(mFab, this); } - return false; }); - mViewPager.setAdapter(adapter); - } - - private void settingsMenu() { - PopupMenu popupMenu = new PopupMenu(this, mSettings); - Menu menu = popupMenu.getMenu(); - if (!Utils.isNotDonated(this)) { - menu.add(Menu.NONE, 0, Menu.NONE, getString(R.string.allow_ads)).setCheckable(true) - .setChecked(Prefs.getBoolean("allow_ads", true, this)); - } - menu.add(Menu.NONE, 1, Menu.NONE, getString(R.string.dark_theme)).setCheckable(true).setChecked( - Prefs.getBoolean("dark_theme", true, this)); - SubMenu language = menu.addSubMenu(Menu.NONE, 2, Menu.NONE, getString(R.string.language, Utils.getLang(this))); - language.add(Menu.NONE, 3, Menu.NONE, getString(R.string.language_default)).setCheckable(true).setChecked( - Utils.languageDefault(this)); - language.add(Menu.NONE, 4, Menu.NONE, getString(R.string.language_en)).setCheckable(true).setChecked( - Prefs.getBoolean("use_en", false, this)); - language.add(Menu.NONE, 5, Menu.NONE, getString(R.string.language_ko)).setCheckable(true) - .setChecked(Prefs.getBoolean("use_ko", false, this)); - language.add(Menu.NONE, 6, Menu.NONE, getString(R.string.language_in)).setCheckable(true).setChecked( - Prefs.getBoolean("use_in", false, this)); - language.add(Menu.NONE, 7, Menu.NONE, getString(R.string.language_am)).setCheckable(true).setChecked( - Prefs.getBoolean("use_am", false, this)); - language.add(Menu.NONE, 14, Menu.NONE, getString(R.string.language_el)).setCheckable(true).setChecked( - Prefs.getBoolean("use_el", false, this)); - language.add(Menu.NONE, 15, Menu.NONE, getString(R.string.language_pt)).setCheckable(true).setChecked( - Prefs.getBoolean("use_pt", false, this)); - SubMenu about = menu.addSubMenu(Menu.NONE, 2, Menu.NONE, getString(R.string.about)); - about.add(Menu.NONE, 13, Menu.NONE, getString(R.string.examples)); - about.add(Menu.NONE, 8, Menu.NONE, getString(R.string.source_code)); - about.add(Menu.NONE, 9, Menu.NONE, getString(R.string.support_group)); - about.add(Menu.NONE, 10, Menu.NONE, getString(R.string.more_apps)); - about.add(Menu.NONE, 11, Menu.NONE, getString(R.string.report_issue)); - about.add(Menu.NONE, 16, Menu.NONE, getString(R.string.change_log)); - about.add(Menu.NONE, 12, Menu.NONE, getString(R.string.about)); - popupMenu.setOnMenuItemClickListener(item -> { - switch (item.getItemId()) { - case 0: - if (Prefs.getBoolean("allow_ads", true, this)) { - Prefs.saveBoolean("allow_ads", false, this); - } else { - Prefs.saveBoolean("allow_ads", true, this); - } - restartApp(); - break; - case 1: - if (Prefs.getBoolean("dark_theme", true, this)) { - Prefs.saveBoolean("dark_theme", false, this); - } else { - Prefs.saveBoolean("dark_theme", true, this); - } - restartApp(); - break; - case 2: - break; - case 3: - if (!Utils.languageDefault(this)) { - Prefs.saveBoolean("use_en", false, this); - Prefs.saveBoolean("use_ko", false, this); - Prefs.saveBoolean("use_in", false, this); - Prefs.saveBoolean("use_am", false, this); - Prefs.saveBoolean("use_el", false, this); - Prefs.saveBoolean("use_pt", false, this); - restartApp(); - } - break; - case 4: - if (!Prefs.getBoolean("use_en", false, this)) { - Prefs.saveBoolean("use_en", true, this); - Prefs.saveBoolean("use_ko", false, this); - Prefs.saveBoolean("use_in", false, this); - Prefs.saveBoolean("use_am", false, this); - Prefs.saveBoolean("use_el", false, this); - Prefs.saveBoolean("use_pt", false, this); - restartApp(); - } - break; - case 5: - if (!Prefs.getBoolean("use_ko", false, this)) { - Prefs.saveBoolean("use_en", false, this); - Prefs.saveBoolean("use_ko", true, this); - Prefs.saveBoolean("use_in", false, this); - Prefs.saveBoolean("use_am", false, this); - Prefs.saveBoolean("use_el", false, this); - Prefs.saveBoolean("use_pt", false, this); - restartApp(); - } - break; - case 6: - if (!Prefs.getBoolean("use_in", false, this)) { - Prefs.saveBoolean("use_en", false, this); - Prefs.saveBoolean("use_ko", false, this); - Prefs.saveBoolean("use_in", true, this); - Prefs.saveBoolean("use_am", false, this); - Prefs.saveBoolean("use_el", false, this); - Prefs.saveBoolean("use_pt", false, this); - restartApp(); - } - break; - case 7: - if (!Prefs.getBoolean("use_am", false, this)) { - Prefs.saveBoolean("use_en", false, this); - Prefs.saveBoolean("use_ko", false, this); - Prefs.saveBoolean("use_in", false, this); - Prefs.saveBoolean("use_am", true, this); - Prefs.saveBoolean("use_el", false, this); - Prefs.saveBoolean("use_pt", false, this); - restartApp(); - } - break; - case 14: - if (!Prefs.getBoolean("use_el", false, this)) { - Prefs.saveBoolean("use_en", false, this); - Prefs.saveBoolean("use_ko", false, this); - Prefs.saveBoolean("use_in", false, this); - Prefs.saveBoolean("use_am", false, this); - Prefs.saveBoolean("use_el", true, this); - Prefs.saveBoolean("use_pt", false, this); - restartApp(); - } - break; - case 15: - if (!Prefs.getBoolean("use_pt", false, this)) { - Prefs.saveBoolean("use_en", false, this); - Prefs.saveBoolean("use_ko", false, this); - Prefs.saveBoolean("use_in", false, this); - Prefs.saveBoolean("use_am", false, this); - Prefs.saveBoolean("use_el", false, this); - Prefs.saveBoolean("use_pt", true, this); - restartApp(); - } - break; - case 8: - launchURL("https://github.com/SmartPack/ScriptManager"); - break; - case 9: - launchURL("https://t.me/smartpack_kmanager"); - break; - case 10: - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse( - "https://play.google.com/store/apps/dev?id=5836199813143882901")); - startActivity(intent); - break; - case 11: - launchURL("https://github.com/SmartPack/ScriptManager/issues/new"); - break; - case 12: - Utils.aboutDialogue(this); - break; - case 13: - launchURL("https://github.com/SmartPack/ScriptManager/tree/master/examples"); - break; - case 16: - Utils.changeLogs(this); - break; - } - return false; + mInfo.setOnClickListener(v -> { + Intent aboutView = new Intent(this, AboutActivity.class); + startActivity(aboutView); }); - popupMenu.show(); - } - public void setCopyRightText() { - String copyright = Utils.getInternalDataStorage() + "/copyright"; - File file = new File(Utils.getInternalDataStorage()); - if (file.exists() && file.isFile()) { - file.delete(); + if (!Utils.getBoolean("depreciation_message", false, this)) { + new MaterialAlertDialogBuilder(this) + .setIcon(R.mipmap.ic_launcher) + .setTitle("Notice") + .setMessage("Please Note: The development of this project is abandoned. Thank you very much to all of you for supporting this project to date.") + .setCancelable(false) + .setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> Utils.saveBoolean("depreciation_message", true, this)).show(); } - file.mkdirs(); - ViewUtils.dialogEditText(Utils.existFile(copyright) ? - Utils.readFile(copyright) : null, - (dialogInterface, i) -> { - }, text -> { - if (text.equals(Utils.readFile(copyright))) return; - if (text.isEmpty()) { - Utils.delete(copyright); - Utils.snackbar(mViewPager, getString(R.string.copyright_default, getString(R.string.copyright))); - return; - } - Utils.create(text, copyright); - Utils.snackbar(mViewPager, getString(R.string.copyright_message, text)); - }, this).setOnDismissListener(dialogInterface -> { - }).show(); - } - private void launchURL(String url) { - if (Utils.isNetworkUnavailable(this)) { - Utils.snackbar(mViewPager, getString(R.string.no_internet)); - } else { - Utils.launchUrl(url, this); - } + Scripts.loadUI(this); } - private void restartApp() { - Intent intent = new Intent(this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - } - - public void androidRooting(View view) { - launchURL("https://www.google.com/search?site=&source=hp&q=android+rooting+magisk"); + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (data == null) return; + if (requestCode == 0) { + Uri uri = data.getData(); + assert uri != null; + File file = new File(Objects.requireNonNull(uri.getPath())); + if (Utils.isDocumentsUI(uri)) { + @SuppressLint("Recycle") Cursor cursor = getContentResolver().query(uri, null, null, null, null); + if (cursor != null && cursor.moveToFirst()) { + mPath = Environment.getExternalStorageDirectory().toString() + "/Download/" + + cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + } + } else { + mPath = Utils.getPath(file); + } + if (!Utils.getExtension(mPath).equals("sh")) { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.wrong_extension, ".sh")); + return; + } + if (!Scripts.isScript(mPath)) { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.wrong_script, file.getName().replace(".sh", ""))); + return; + } + if (Utils.exist(Scripts.scriptExistsCheck(new File(mPath).getName(), this))) { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.script_exists, file.getName())); + return; + } + new MaterialAlertDialogBuilder(this) + .setMessage(getString(R.string.select_question, new File(mPath).getName())) + .setNegativeButton(getString(R.string.cancel), (dialogInterface, i) -> { + }) + .setPositiveButton(getString(R.string.yes), (dialogInterface, i) -> { + Scripts.importScript(mPath, this); + Scripts.reloadUI(this); + }).show(); + } } @Override - public void onStart(){ + public void onStart() { super.onStart(); - if (Prefs.getBoolean("welcomeMessage", true, this)) { - Utils.WelcomeDialog(this); - } - if (!Utils.checkWriteStoragePermission(this)) { - ActivityCompat.requestPermissions(this, new String[]{ - Manifest.permission.WRITE_EXTERNAL_STORAGE},1); - return; - } - if (UpdateCheck.isPlayStoreInstalled(this)) { - return; - } - if (Utils.isNetworkUnavailable(this)) { - return; - } - if (!Utils.isDownloadBinaries()) { - return; - } - if (!UpdateCheck.hasVersionInfo() || (UpdateCheck.lastModified() + 3720000L < System.currentTimeMillis())) { - UpdateCheck.getVersionInfo(); - } - if (UpdateCheck.hasVersionInfo() && BuildConfig.VERSION_CODE < UpdateCheck.versionNumber()) { - UpdateCheck.updateAvailableDialog(this); + if (!Utils.rootAccess() && Utils.getBoolean("no_root_message", true, this)) { + new MaterialAlertDialogBuilder(this) + .setMessage(getString(R.string.root_unavailable)) + .setCancelable(false) + .setPositiveButton(getString(R.string.cancel), (dialogInterface, i) -> { + Utils.saveBoolean("no_root_message", false, this); + }).show(); } } @Override public void onBackPressed() { - if (RootUtils.rootAccess()) { - if (Utils.mForegroundActive) { - Utils.closeForeground(); - } else if (mExit) { - mExit = false; - super.onBackPressed(); - } else { - Utils.snackbar(mViewPager, getString(R.string.press_back)); - mExit = true; - mHandler.postDelayed(() -> mExit = false, 2000); - } - } else { + if (mExit) { + mExit = false; super.onBackPressed(); + } else { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.press_back)); + mExit = true; + mHandler.postDelayed(() -> mExit = false, 2000); } } - } \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/activities/AboutActivity.java b/app/src/main/java/com/smartpack/scriptmanager/activities/AboutActivity.java new file mode 100644 index 0000000..fa9e80c --- /dev/null +++ b/app/src/main/java/com/smartpack/scriptmanager/activities/AboutActivity.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021-2022 sunilpaulmathew + * + * This file is part of Script Manager, an app to create, import, edit + * and easily execute any properly formatted shell scripts. + * + */ + +package com.smartpack.scriptmanager.activities; + +import android.annotation.SuppressLint; +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.AppCompatImageView; + +import com.google.android.material.textview.MaterialTextView; +import com.smartpack.scriptmanager.BuildConfig; +import com.smartpack.scriptmanager.R; +import com.smartpack.scriptmanager.utils.Utils; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Objects; + +/* + * Created by sunilpaulmathew on October 05, 2020 + */ +public class AboutActivity extends AppCompatActivity { + + @SuppressLint("SetTextI18n") + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_about); + + AppCompatImageView mDeveloper = findViewById(R.id.developer); + MaterialTextView mCancelButton = findViewById(R.id.cancel_button); + MaterialTextView mAppTitle = findViewById(R.id.app_title); + MaterialTextView mChangeLog = findViewById(R.id.changelog); + + mDeveloper.setOnClickListener(v -> Utils.launchUrl("https://github.com/sunilpaulmathew", this)); + mAppTitle.setText(getString(R.string.app_name) + (Utils.isProUser(this) ? " Pro " : " ") + BuildConfig.VERSION_NAME); + String change_log = null; + try { + change_log = new JSONObject(Objects.requireNonNull(Utils.readAssetFile( + this, "update_info.json"))).getString("changelogFull"); + } catch (JSONException ignored) { + } + mChangeLog.setText(change_log); + mCancelButton.setOnClickListener(v -> onBackPressed()); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/activities/ApplyScriptActivity.java b/app/src/main/java/com/smartpack/scriptmanager/activities/ApplyScriptActivity.java new file mode 100644 index 0000000..e27080a --- /dev/null +++ b/app/src/main/java/com/smartpack/scriptmanager/activities/ApplyScriptActivity.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2021-2022 sunilpaulmathew + * + * This file is part of Script Manager, an app to create, import, edit + * and easily execute any properly formatted shell scripts. + * + */ + +package com.smartpack.scriptmanager.activities; + +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.widget.NestedScrollView; + +import com.google.android.material.card.MaterialCardView; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.textview.MaterialTextView; +import com.smartpack.scriptmanager.R; +import com.smartpack.scriptmanager.utils.Scripts; +import com.smartpack.scriptmanager.utils.Utils; + +import java.util.ConcurrentModificationException; + +/* + * Created by sunilpaulmathew on April 26, 2020 + */ +public class ApplyScriptActivity extends AppCompatActivity { + + private MaterialTextView mScriptTitle, mOutput; + private MaterialCardView mCancelButton; + private NestedScrollView mScrollView; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_applyscript); + + mCancelButton = findViewById(R.id.cancel_button); + mScriptTitle = findViewById(R.id.script_title); + mOutput = findViewById(R.id.result_text); + mScrollView = findViewById(R.id.scroll_view); + + mCancelButton.setOnClickListener(v -> onBackPressed()); + + mScriptTitle.setText(getString(R.string.applying_script, Scripts.mScriptName)); + + refreshStatus(); + } + + public void refreshStatus() { + new Thread() { + @Override + public void run() { + try { + while (!isInterrupted()) { + Thread.sleep(100); + runOnUiThread(() -> { + try { + mOutput.setText(Utils.getOutput(Scripts.mOutput)); + if (!Scripts.mApplyingScript) { + mCancelButton.setVisibility(View.VISIBLE); + mScriptTitle.setText(getString(R.string.script_applied_success, Scripts.mScriptName)); + } else { + mScriptTitle.setText(getString(R.string.applying_script, Scripts.mScriptName)); + mScrollView.fullScroll(NestedScrollView.FOCUS_DOWN); + } + } catch (ConcurrentModificationException ignored) {} + }); + } + } catch (InterruptedException ignored) {} + } + }.start(); + } + + @Override + public void onBackPressed() { + if (Scripts.mApplyingScript) { + new MaterialAlertDialogBuilder(this) + .setMessage(getString(R.string.script_execute_busy, Scripts.mScriptName)) + .setPositiveButton(getString(R.string.cancel), (dialogInterface, i) -> { + }).show(); + } else { + super.onBackPressed(); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/activities/CreateScriptActivity.java b/app/src/main/java/com/smartpack/scriptmanager/activities/CreateScriptActivity.java new file mode 100644 index 0000000..8fa0b67 --- /dev/null +++ b/app/src/main/java/com/smartpack/scriptmanager/activities/CreateScriptActivity.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2021-2022 sunilpaulmathew + * + * This file is part of Script Manager, an app to create, import, edit + * and easily execute any properly formatted shell scripts. + * + */ + +package com.smartpack.scriptmanager.activities; + +import android.annotation.SuppressLint; +import android.content.pm.ActivityInfo; +import android.os.AsyncTask; +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.AppCompatEditText; +import androidx.appcompat.widget.AppCompatImageButton; +import androidx.core.widget.NestedScrollView; + +import com.google.android.material.card.MaterialCardView; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.textview.MaterialTextView; +import com.smartpack.scriptmanager.R; +import com.smartpack.scriptmanager.utils.Scripts; +import com.smartpack.scriptmanager.utils.Utils; + +import java.io.File; +import java.util.ConcurrentModificationException; +import java.util.Objects; + +/* + * Created by sunilpaulmathew on January 12, 2020 + */ +public class CreateScriptActivity extends AppCompatActivity { + + private AppCompatEditText mEditText; + private MaterialTextView mTestOutput; + private NestedScrollView mScrollView; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_createscript); + + mEditText = findViewById(R.id.edit_text); + mScrollView = findViewById(R.id.scroll_view_testing); + AppCompatImageButton mBack = findViewById(R.id.back_button); + AppCompatImageButton mSave = findViewById(R.id.save_button); + MaterialTextView scriptName = findViewById(R.id.script_name); + MaterialCardView testButton = findViewById(R.id.test_button); + mTestOutput = findViewById(R.id.test_output); + + if (Scripts.mScriptPath == null) { + mEditText.setText("#!/system/bin/sh\n\n"); + } else { + mEditText.setText(Scripts.readScript(Scripts.mScriptPath)); + } + + scriptName.setText(Scripts.mScriptName); + mBack.setOnClickListener(v -> onBackPressed()); + mSave.setOnClickListener(v -> { + Scripts.createScript(Scripts.mScriptPath == null ? new File(Scripts.ScriptFile(this), Scripts.mScriptName).getAbsolutePath() + : Scripts.mScriptPath, Objects.requireNonNull(mEditText.getText()).toString(), this); + if (Scripts.mScriptPath != null) { + if (!Scripts.mScriptPath.startsWith(Scripts.ScriptFile(this).getAbsolutePath())) { + Scripts.createScript(new File(Scripts.ScriptFile(this), Scripts.mScriptName).getAbsolutePath(), + Objects.requireNonNull(mEditText.getText()).toString(), this); + } + if (Scripts.isMgiskPostFS() && Scripts.scriptOnPostBoot(Scripts.mScriptName)) { + Scripts.setScriptOnPostFS(Scripts.mScriptPath, Scripts.mScriptName); + } else if (Scripts.isMgiskServiceD() && Scripts.scriptOnLateBoot(Scripts.mScriptName)) { + Scripts.setScriptOnServiceD(Scripts.mScriptPath, Scripts.mScriptName); + } + } + Scripts.reloadUI(this); + onBackPressed(); + }); + testButton.setOnClickListener(v -> { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); + testCommands(); + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER); + }); + + refreshStatus(); + } + + @SuppressLint("StaticFieldLeak") + private void testCommands() { + new AsyncTask() { + @Override + protected void onPreExecute() { + super.onPreExecute(); + Scripts.mOutput.clear(); + Scripts.mOutput.add(getString(R.string.testing)); + Scripts.mApplyingScript = true; + Utils.delete(getFilesDir().getPath() + "/sm"); + Utils.create(Objects.requireNonNull(mEditText.getText()).toString(),getFilesDir().getPath() + "/sm"); + Scripts.mOutput.add("Checking Output!"); + Scripts.mOutput.add("********************"); + } + @Override + protected Void doInBackground(Void... voids) { + Utils.runCommand("sleep 1"); + Utils.runAndGetLiveOutput("sh " + getFilesDir().getPath() + "/sm", Scripts.mOutput); + return null; + } + @Override + protected void onPostExecute(Void recyclerViewItems) { + super.onPostExecute(recyclerViewItems); + Scripts.mOutput.add("********************"); + Scripts.mOutput.add(getString(R.string.testing_success)); + Utils.delete(getFilesDir().getPath() + "/sm"); + Scripts.mApplyingScript = false; + } + }.execute(); + } + + private void refreshStatus() { + new Thread() { + @Override + public void run() { + try { + while (!isInterrupted()) { + Thread.sleep(100); + runOnUiThread(() -> { + try { + if (mTestOutput != null && Scripts.mOutput != null) { + mTestOutput.setText(Utils.getOutput(Scripts.mOutput)); + } + if (Scripts.mApplyingScript) { + mScrollView.fullScroll(NestedScrollView.FOCUS_DOWN); + } + } catch (ConcurrentModificationException ignored) {} + }); + } + } catch (InterruptedException ignored) {} + } + }.start(); + } + + @Override + public void onBackPressed() { + if (Scripts.mApplyingScript) { + new MaterialAlertDialogBuilder(this) + .setMessage(getString(R.string.script_execute_busy, Scripts.mScriptName)) + .setPositiveButton(getString(R.string.cancel), (dialogInterface, i) -> { + }).show(); + } else { + super.onBackPressed(); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/activities/FilePickerActivity.java b/app/src/main/java/com/smartpack/scriptmanager/activities/FilePickerActivity.java new file mode 100644 index 0000000..1e0f814 --- /dev/null +++ b/app/src/main/java/com/smartpack/scriptmanager/activities/FilePickerActivity.java @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2021-2022 sunilpaulmathew + * + * This file is part of Script Manager, an app to create, import, edit + * and easily execute any properly formatted shell scripts. + * + */ + +package com.smartpack.scriptmanager.activities; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.res.Configuration; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.AppCompatImageButton; +import androidx.appcompat.widget.PopupMenu; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.textview.MaterialTextView; +import com.smartpack.scriptmanager.R; +import com.smartpack.scriptmanager.utils.Scripts; +import com.smartpack.scriptmanager.utils.Utils; + +import java.io.File; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/* + * Created by sunilpaulmathew on December 02, 2020 + */ +public class FilePickerActivity extends AppCompatActivity { + + private AppCompatImageButton mPathIcon; + private AsyncTask> mLoader; + private final Handler mHandler = new Handler(); + private MaterialTextView mTitle; + private RecyclerView mRecyclerView; + private RecycleViewAdapter mRecycleViewAdapter; + private String mPath = Environment.getExternalStorageDirectory().toString() + "/Download"; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_filepicker); + + AppCompatImageButton mBack = findViewById(R.id.back); + mPathIcon = findViewById(R.id.path); + mTitle = findViewById(R.id.title); + mRecyclerView = findViewById(R.id.recycler_view); + mRecyclerView.setLayoutManager(new GridLayoutManager(this, getSpanCount(this))); + mRecycleViewAdapter = new RecycleViewAdapter(getData(this)); + mRecyclerView.setAdapter(mRecycleViewAdapter); + + mTitle.setText(mPath.equals(Environment.getExternalStorageDirectory().toString() + File.separator) ? getString(R.string.path_sdcard) : new File(mPath).getName()); + + mBack.setOnClickListener(v -> super.onBackPressed()); + mPathIcon.setOnClickListener(v -> { + PopupMenu popupMenu = new PopupMenu(this, mPathIcon); + Menu menu = popupMenu.getMenu(); + menu.add(Menu.NONE, 0, Menu.NONE, "A-Z").setCheckable(true) + .setChecked(Utils.getBoolean("az_order", true, this)); + popupMenu.setOnMenuItemClickListener(item -> { + Utils.saveBoolean("az_order", !Utils.getBoolean("az_order", true, this), this); + reload(this); + return false; + }); + popupMenu.show(); + }); + + mRecycleViewAdapter.setOnItemClickListener((position, v) -> { + if (new File(getData(this).get(position)).isDirectory()) { + mPath = getData(this).get(position); + reload(this); + } else { + if (!Utils.getExtension(getData(this).get(position)).equals("sh")) { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.wrong_extension, ".sh")); + return; + } + if (!Scripts.isScript(getData(this).get(position))) { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.wrong_script, new File(getData(this).get(position)).getName())); + return; + } + if (Utils.exist(Scripts.scriptExistsCheck(new File(getData(this).get(position)).getName(), this))) { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.script_exists, new File(getData(this).get(position)).getName())); + return; + } + new MaterialAlertDialogBuilder(this) + .setMessage(getString(R.string.select_question, new File(getData(this).get(position)).getName())) + .setNegativeButton(getString(R.string.cancel), (dialogInterface, i) -> { + }) + .setPositiveButton(getString(R.string.yes), (dialogInterface, i) -> { + Scripts.importScript(getData(this).get(position), this); + Scripts.reloadUI(this); + finish(); + }).show(); + } + }); + } + + private int getSpanCount(Activity activity) { + return Utils.getOrientation(activity) == Configuration.ORIENTATION_LANDSCAPE ? 2 : 1; + } + + private File[] getFilesList() { + if (!mPath.endsWith(File.separator)) { + mPath = mPath + File.separator; + } + if (!new File(mPath).exists()) { + mPath = Environment.getExternalStorageDirectory().toString(); + } + return new File(mPath).listFiles(); + } + + private List getData(Activity activity) { + List mData = new ArrayList<>(), mDir = new ArrayList<>(), mFiles = new ArrayList<>(); + try { + // Add directories + for (File mFile : getFilesList()) { + if (mFile.isDirectory()) { + mDir.add(mFile.getAbsolutePath()); + } + } + Collections.sort(mDir, String.CASE_INSENSITIVE_ORDER); + if (!Utils.getBoolean("az_order", true, activity)) { + Collections.reverse(mDir); + } + mData.addAll(mDir); + // Add files + for (File mFile : getFilesList()) { + if (mFile.isFile() && Utils.getExtension(mFile.getAbsolutePath()).equals("sh")) { + mFiles.add(mFile.getAbsolutePath()); + } + } + Collections.sort(mFiles, String.CASE_INSENSITIVE_ORDER); + if (!Utils.getBoolean("az_order", true, activity)) { + Collections.reverse(mFiles); + } + mData.addAll(mFiles); + } catch (NullPointerException ignored) { + activity.finish(); + } + return mData; + } + + private static String getSize(File file) { + long size = file.length() / 1024; + String timeCreated = DateFormat.getDateTimeInstance().format(System.currentTimeMillis()); + if (size < 1024) { + return timeCreated + ", " + size + " kB"; + } else { + return timeCreated + ", " + size / 1024 + " MB"; + } + } + + private void reload(Activity activity) { + if (mLoader == null) { + mHandler.postDelayed(new Runnable() { + @SuppressLint("StaticFieldLeak") + @Override + public void run() { + mLoader = new AsyncTask>() { + @Override + protected void onPreExecute() { + super.onPreExecute(); + getData(activity).clear(); + mRecyclerView.setVisibility(View.GONE); + } + + @Override + protected List doInBackground(Void... voids) { + mRecycleViewAdapter = new RecycleViewAdapter(getData(activity)); + return null; + } + + @Override + protected void onPostExecute(List recyclerViewItems) { + super.onPostExecute(recyclerViewItems); + mRecyclerView.setAdapter(mRecycleViewAdapter); + mRecycleViewAdapter.notifyDataSetChanged(); + mTitle.setText(mPath.equals(Environment.getExternalStorageDirectory().toString() + File.separator) ? getString(R.string.path_sdcard) + : new File(mPath).getName()); + mRecyclerView.setVisibility(View.VISIBLE); + mLoader = null; + } + }; + mLoader.execute(); + } + }, 250); + } + } + + @Override + public void onStart() { + super.onStart(); + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.use_file_picker_message)); + } + + @Override + public void onBackPressed() { + if (mPath.equals(Environment.getExternalStorageDirectory().toString() + File.separator)) { + super.onBackPressed(); + } else { + mPath = Objects.requireNonNull(new File(mPath).getParentFile()).getPath(); + reload(this); + } + } + + private static class RecycleViewAdapter extends RecyclerView.Adapter { + + private static ClickListener clickListener; + + private final List data; + + public RecycleViewAdapter(List data) { + this.data = data; + } + + @NonNull + @Override + public RecycleViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View rowItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycle_view_filepicker, parent, false); + return new RecycleViewAdapter.ViewHolder(rowItem); + } + + @SuppressLint("UseCompatLoadingForDrawables") + @Override + public void onBindViewHolder(@NonNull RecycleViewAdapter.ViewHolder holder, int position) { + if (new File(this.data.get(position)).isDirectory()) { + holder.mIcon.setImageDrawable(holder.mTitle.getContext().getResources().getDrawable(R.drawable.ic_folder)); + holder.mIcon.setColorFilter(Utils.getThemeAccentColor(holder.mTitle.getContext())); + holder.mDescription.setVisibility(View.GONE); + } else { + if (Utils.getExtension(this.data.get(position)).equals("sh")) { + holder.mDescription.setVisibility(View.VISIBLE); + holder.mIcon.setImageDrawable(holder.mIcon.getContext().getResources().getDrawable(R.drawable.ic_script)); + holder.mLinearLayout.setOnLongClickListener(v -> { + Scripts.mScriptName = new File(this.data.get(position)).getName(); + Scripts.mScriptPath = this.data.get(position); + Scripts.launchCreateScriptActivity(holder.mLinearLayout.getContext()); + return false; + }); + } else { + holder.mIcon.setImageDrawable(holder.mIcon.getContext().getResources().getDrawable(R.drawable.ic_file)); + } + holder.mIcon.setColorFilter(Utils.isDarkTheme(holder.mIcon.getContext()) ? holder.mIcon.getContext() + .getResources().getColor(R.color.white) : holder.mIcon.getContext().getResources().getColor(R.color.black)); + holder.mDescription.setText(getSize(new File(this.data.get(position)))); + } + holder.mTitle.setText(new File(this.data.get(position)).getName()); + } + + @Override + public int getItemCount() { + return this.data.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + private final AppCompatImageButton mIcon; + private final LinearLayout mLinearLayout; + private final MaterialTextView mTitle; + private final MaterialTextView mDescription; + + public ViewHolder(View view) { + super(view); + view.setOnClickListener(this); + this.mIcon = view.findViewById(R.id.icon); + this.mLinearLayout = view.findViewById(R.id.rv_filepicker); + this.mTitle = view.findViewById(R.id.title); + this.mDescription = view.findViewById(R.id.description); + } + + @Override + public void onClick(View view) { + clickListener.onItemClick(getAdapterPosition(), view); + } + } + + public void setOnItemClickListener(ClickListener clickListener) { + RecycleViewAdapter.clickListener = clickListener; + } + + public interface ClickListener { + void onItemClick(int position, View v); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/activities/SettingsActivity.java b/app/src/main/java/com/smartpack/scriptmanager/activities/SettingsActivity.java new file mode 100644 index 0000000..fcd41ec --- /dev/null +++ b/app/src/main/java/com/smartpack/scriptmanager/activities/SettingsActivity.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2021-2022 sunilpaulmathew + * + * This file is part of Script Manager, an app to create, import, edit + * and easily execute any properly formatted shell scripts. + * + */ + +package com.smartpack.scriptmanager.activities; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.graphics.Color; +import android.net.Uri; +import android.os.Bundle; +import android.provider.Settings; +import android.widget.LinearLayout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.AppCompatImageButton; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.textview.MaterialTextView; +import com.smartpack.scriptmanager.BuildConfig; +import com.smartpack.scriptmanager.R; +import com.smartpack.scriptmanager.adapters.RecycleViewSettingsAdapter; +import com.smartpack.scriptmanager.utils.AppSettings; +import com.smartpack.scriptmanager.utils.Billing; +import com.smartpack.scriptmanager.utils.RecycleViewItem; +import com.smartpack.scriptmanager.utils.Utils; + +import java.util.ArrayList; + +/* + * Created by sunilpaulmathew on February 13, 2020 + */ +public class SettingsActivity extends AppCompatActivity { + + private final ArrayList mData = new ArrayList<>(); + + @SuppressLint({"SetTextI18n", "UseCompatLoadingForDrawables"}) + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_settings); + + AppCompatImageButton mBack = findViewById(R.id.back_button); + LinearLayout mAppInfo = findViewById(R.id.app_info); + MaterialTextView mAppTitle = findViewById(R.id.title); + MaterialTextView mAppDescription = findViewById(R.id.description); + RecyclerView mRecyclerView = findViewById(R.id.recycler_view); + + mAppTitle.setText(getString(R.string.app_name) + (Utils.isProUser(this) ? " Pro " : " ") + BuildConfig.VERSION_NAME); + mAppTitle.setTextColor(Utils.isDarkTheme(this) ? Color.WHITE : Color.BLACK); + mAppDescription.setText(BuildConfig.APPLICATION_ID); + + mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); + mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)); + RecycleViewSettingsAdapter mRecycleViewAdapter = new RecycleViewSettingsAdapter(mData); + mRecyclerView.setAdapter(mRecycleViewAdapter); + + mAppInfo.setOnClickListener(v -> { + Intent settings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + settings.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + Uri uri = Uri.fromParts("package", BuildConfig.APPLICATION_ID, null); + settings.setData(uri); + startActivity(settings); + finish(); + }); + + mData.add(new RecycleViewItem(getString(R.string.language), AppSettings.getLanguage(this), getResources().getDrawable(R.drawable.ic_language), null)); + mData.add(new RecycleViewItem(getString(R.string.file_picker), getString(Utils.getBoolean("use_file_picker", true, this) ? R.string.file_picker_inbuilt + : R.string.file_picker_external), getResources().getDrawable(R.drawable.ic_folder), null)); + mData.add(new RecycleViewItem(getString(R.string.dark_theme), AppSettings.getAppThemeDescription(this), getResources().getDrawable(R.drawable.ic_theme), null)); + mData.add(new RecycleViewItem(getString(R.string.source_code), getString(R.string.source_code_summary), getResources().getDrawable( + R.drawable.ic_github), "https://github.com/SmartPack/ScriptManager")); + mData.add(new RecycleViewItem(getString(R.string.support_group), getString(R.string.support_group_summary), getResources().getDrawable(R.drawable.ic_support), + "https://t.me/smartpack_kmanager")); + mData.add(new RecycleViewItem(getString(R.string.report_issue), getString(R.string.report_issue_summary), getResources().getDrawable(R.drawable.ic_issue), + "https://github.com/SmartPack/ScriptManager/issues/new/choose")); + mData.add(new RecycleViewItem(getString(R.string.support_development), null, getResources().getDrawable(R.drawable.ic_donate), null)); + mData.add(new RecycleViewItem(getString(R.string.more_apps), getString(R.string.more_apps_summary), getResources().getDrawable( + R.drawable.ic_playstore), "https://play.google.com/store/apps/dev?id=5836199813143882901")); + mData.add(new RecycleViewItem(getString(R.string.translations), getString(R.string.translations_summary), getResources().getDrawable( + R.drawable.ic_translate), "https://poeditor.com/join/project?hash=w47nhsNDL7")); + mData.add(new RecycleViewItem(getString(R.string.share_app), getString(R.string.share_app_Summary), getResources().getDrawable(R.drawable.ic_share), null)); + mData.add(new RecycleViewItem(getString(R.string.rate_us), getString(R.string.rate_us_Summary), getResources().getDrawable(R.drawable.ic_rate), + "https://play.google.com/store/apps/details?id=com.smartpack.scriptmanager")); + mData.add(new RecycleViewItem(getString(R.string.licence), null, getResources().getDrawable(R.drawable.ic_licence), + "https://www.gnu.org/licenses/gpl-3.0-standalone.html")); + + mRecycleViewAdapter.setOnItemClickListener((position, v) -> { + if (mData.get(position).getUrl() != null) { + Utils.launchUrl(mData.get(position).getUrl(), this); + } else if (position == 0) { + AppSettings.setLanguage(this); + } else if (position == 1) { + new MaterialAlertDialogBuilder(this).setItems(getResources().getStringArray( + R.array.file_picker), (dialogInterface, i) -> { + switch (i) { + case 0: + Utils.saveBoolean("use_file_picker", true, this); + mData.set(position, new RecycleViewItem(getString(R.string.file_picker), getString(R.string.file_picker_inbuilt), + getResources().getDrawable(R.drawable.ic_folder), null)); + mRecycleViewAdapter.notifyItemChanged(position); + break; + case 1: + Utils.saveBoolean("use_file_picker", false, this); + mData.set(position, new RecycleViewItem(getString(R.string.file_picker), getString(R.string.file_picker_external), + getResources().getDrawable(R.drawable.ic_folder), null)); + mRecycleViewAdapter.notifyItemChanged(position); + break; + } + }).setOnDismissListener(dialogInterface -> { + }).show(); + } else if (position == 2) { + AppSettings.setAppTheme(this); + } else if (position == 6) { + Billing.showDonateOption(this); + } else if (position == 9) { + Intent share_app = new Intent(); + share_app.setAction(Intent.ACTION_SEND); + share_app.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.app_name)); + share_app.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_message_app, BuildConfig.VERSION_NAME)); + share_app.setType("text/plain"); + Intent shareIntent = Intent.createChooser(share_app, getString(R.string.share_with)); + startActivity(shareIntent); + } + }); + + mBack.setOnClickListener(v -> onBackPressed()); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/adapters/RecycleViewAdapter.java b/app/src/main/java/com/smartpack/scriptmanager/adapters/RecycleViewAdapter.java new file mode 100644 index 0000000..e12d333 --- /dev/null +++ b/app/src/main/java/com/smartpack/scriptmanager/adapters/RecycleViewAdapter.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2021-2022 sunilpaulmathew + * + * This file is part of Script Manager, an app to create, import, edit + * and easily execute any properly formatted shell scripts. + * + */ + +package com.smartpack.scriptmanager.adapters; + +import android.graphics.Color; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.SubMenu; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatImageButton; +import androidx.appcompat.widget.PopupMenu; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.textview.MaterialTextView; +import com.smartpack.scriptmanager.R; +import com.smartpack.scriptmanager.utils.Scripts; +import com.smartpack.scriptmanager.utils.Utils; + +import java.util.List; + +/* + * Created by sunilpaulmathew on October 05, 2020 + */ +public class RecycleViewAdapter extends RecyclerView.Adapter { + + private final List data; + + public RecycleViewAdapter (List data){ + this.data = data; + } + + @NonNull + @Override + public RecycleViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View rowItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycle_view, parent, false); + return new ViewHolder(rowItem); + } + + @Override + public void onBindViewHolder(@NonNull RecycleViewAdapter.ViewHolder holder, int position) { + holder.scriptTitle.setText(this.data.get(position)); + if (Utils.isDarkTheme(holder.onBootIcon.getContext())) { + holder.onBootIcon.setColorFilter(Color.WHITE); + } else { + holder.onBootIcon.setColorFilter(Color.BLACK); + } + if (Scripts.isMgiskServiceD() && Scripts.scriptOnLateBoot(holder.scriptTitle.getText().toString()) + || Scripts.isMgiskPostFS() && Scripts.scriptOnPostBoot(holder.scriptTitle.getText().toString())) { + holder.onBootIcon.setVisibility(View.VISIBLE); + } else { + holder.onBootIcon.setVisibility(View.GONE); + } + } + + @Override + public int getItemCount() { + return this.data.size(); + } + + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + private final AppCompatImageButton onBootIcon; + private final MaterialTextView scriptTitle; + + public ViewHolder(View view) { + super(view); + view.setOnClickListener(this); + this.scriptTitle = view.findViewById(R.id.script_title); + this.onBootIcon = view.findViewById(R.id.onboot_icon); + } + + @Override + public void onClick(View view) { + Scripts.mScriptName = this.scriptTitle.getText().toString(); + Scripts.mScriptPath = Scripts.ScriptFile(view.getContext()) + "/" + Scripts.mScriptName + ".sh"; + PopupMenu popupMenu = new PopupMenu(view.getContext(), view); + Menu menu = popupMenu.getMenu(); + menu.add(Menu.NONE, 0, Menu.NONE, R.string.apply); + menu.add(Menu.NONE, 1, Menu.NONE, R.string.edit); + menu.add(Menu.NONE, 2, Menu.NONE, R.string.share); + menu.add(Menu.NONE, 3, Menu.NONE, R.string.delete); + if (Utils.rootAccess()) { + SubMenu onBoot = menu.addSubMenu(Menu.NONE, 4, Menu.NONE, R.string.apply_on_boot); + if (Scripts.isMgiskPostFS()) { + onBoot.add(Menu.NONE, 5, Menu.NONE, R.string.post_fs).setCheckable(true) + .setChecked(Scripts.scriptOnPostBoot(Scripts.mScriptName)); + } + if (Scripts.isMgiskServiceD()) { + onBoot.add(Menu.NONE, 6, Menu.NONE, R.string.late_start).setCheckable(true) + .setChecked(Scripts.scriptOnLateBoot(Scripts.mScriptName)); + } + } + popupMenu.setOnMenuItemClickListener(item -> { + switch (item.getItemId()) { + case 0: + new MaterialAlertDialogBuilder(view.getContext()) + .setMessage(view.getContext().getString(R.string.apply_question, Scripts.mScriptName.replace(".sh", ""))) + .setNegativeButton(R.string.cancel, (dialogInterfacei, ii) -> { + }) + .setPositiveButton(R.string.yes, (dialogInterfacei, ii) -> { + if (!Scripts.isScript(Scripts.mScriptPath)) { + Utils.snackbar(view, view.getContext().getString(R.string.wrong_script, Scripts.mScriptName.replace(".sh", ""))); + return; + } + Scripts.applyScript(view.getContext()); + }) + .show(); + break; + case 1: + Scripts.launchCreateScriptActivity(view.getContext()); + break; + case 2: + Scripts.shareScript(view.getContext()); + break; + case 3: + new MaterialAlertDialogBuilder(view.getContext()) + .setMessage(view.getContext().getString(R.string.sure_question, Scripts.mScriptName.replace(".sh", ""))) + .setNegativeButton(R.string.cancel, (dialogInterfacei, ii) -> { + }) + .setPositiveButton(R.string.yes, (dialogInterfacei, ii) -> { + Scripts.deleteScript(Scripts.mScriptPath); + data.remove(getLayoutPosition()); + notifyDataSetChanged(); + }) + .show(); + break; + case 4: + break; + case 5: + if (Scripts.isMgiskPostFS() && Scripts.scriptOnPostBoot(Scripts.mScriptName)) { + Utils.delete(Scripts.MagiskPostFSFile().toString() + "/" + Scripts.mScriptName + ".sh"); + Utils.snackbar(view, view.getContext().getString(R.string.on_boot_message, Scripts.mScriptName)); + } else { + Scripts.setScriptOnPostFS(Scripts.mScriptPath, Scripts.mScriptName); + Utils.delete(Scripts.MagiskServiceFile().toString() + "/" + Scripts.mScriptName + ".sh"); + Utils.snackbar(view, view.getContext().getString(R.string.post_fs_message, Scripts.mScriptName)); + } + notifyItemChanged(getLayoutPosition()); + notifyDataSetChanged(); + break; + case 6: + if (Scripts.isMgiskServiceD() && Scripts.scriptOnLateBoot(Scripts.mScriptName)) { + Utils.delete(Scripts.MagiskServiceFile().toString() + "/" + Scripts.mScriptName + ".sh"); + Utils.snackbar(view, view.getContext().getString(R.string.on_boot_message, Scripts.mScriptName)); + } else { + Scripts.setScriptOnServiceD(Scripts.mScriptPath, Scripts.mScriptName); + Utils.delete(Scripts.MagiskPostFSFile().toString() + "/" + Scripts.mScriptName + ".sh"); + Utils.snackbar(view, view.getContext().getString(R.string.late_start_message, Scripts.mScriptName)); + } + notifyItemChanged(getLayoutPosition()); + notifyDataSetChanged(); + break; + } + return false; + }); + popupMenu.show(); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/adapters/RecycleViewSettingsAdapter.java b/app/src/main/java/com/smartpack/scriptmanager/adapters/RecycleViewSettingsAdapter.java new file mode 100644 index 0000000..7212d62 --- /dev/null +++ b/app/src/main/java/com/smartpack/scriptmanager/adapters/RecycleViewSettingsAdapter.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2021-2022 sunilpaulmathew + * + * This file is part of Script Manager, an app to create, import, edit + * and easily execute any properly formatted shell scripts. + * + */ + +package com.smartpack.scriptmanager.adapters; + +import android.graphics.Color; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.textview.MaterialTextView; +import com.smartpack.scriptmanager.R; +import com.smartpack.scriptmanager.utils.RecycleViewItem; +import com.smartpack.scriptmanager.utils.Utils; + +import java.util.ArrayList; + +/* + * Created by sunilpaulmathew on February 13, 2020 + */ + +public class RecycleViewSettingsAdapter extends RecyclerView.Adapter { + + private final ArrayList data; + + private static ClickListener mClickListener; + + public RecycleViewSettingsAdapter(ArrayList data) { + this.data = data; + } + + @NonNull + @Override + public RecycleViewSettingsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View rowItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycle_view_settings, parent, false); + return new RecycleViewSettingsAdapter.ViewHolder(rowItem); + } + + @Override + public void onBindViewHolder(@NonNull RecycleViewSettingsAdapter.ViewHolder holder, int position) { + if (this.data.get(position).getTitle() != null) { + holder.mTitle.setText(this.data.get(position).getTitle()); + holder.mTitle.setTextColor(Utils.isDarkTheme(holder.mTitle.getContext()) ? Color.WHITE : Color.BLACK); + } + if (this.data.get(position).getDescription() != null) { + holder.mDescription.setText(this.data.get(position).getDescription()); + holder.mDescription.setVisibility(View.VISIBLE); + holder.mDescription.setTextColor(Utils.isDarkTheme(holder.mTitle.getContext()) ? Color.WHITE : Color.BLACK); + } + if (this.data.get(position).getIcon() != null) { + holder.mIcon.setImageDrawable(this.data.get(position).getIcon()); + holder.mIcon.setVisibility(View.VISIBLE); + if (position != 8 && !Utils.isDarkTheme(holder.mIcon.getContext())) { + holder.mIcon.setColorFilter(Color.BLACK); + } + } + } + + @Override + public int getItemCount() { + return this.data.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + private final AppCompatImageView mIcon; + private final MaterialTextView mTitle, mDescription; + + public ViewHolder(View view) { + super(view); + view.setOnClickListener(this); + this.mIcon = view.findViewById(R.id.icon); + this.mTitle = view.findViewById(R.id.title); + this.mDescription = view.findViewById(R.id.description); + } + + @Override + public void onClick(View view) { + mClickListener.onItemClick(getAdapterPosition(), view); + } + } + + public void setOnItemClickListener(ClickListener clickListener) { + RecycleViewSettingsAdapter.mClickListener = clickListener; + } + + public interface ClickListener { + void onItemClick(int position, View v); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/fragments/BaseFragment.java b/app/src/main/java/com/smartpack/scriptmanager/fragments/BaseFragment.java deleted file mode 100644 index c766bae..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/fragments/BaseFragment.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.smartpack.scriptmanager.fragments; - -import android.os.Bundle; - -import android.view.View; -import android.view.ViewTreeObserver; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; - -/** - * Adapted from https://github.com/Grarak/KernelAdiutor by Willi Ye. - */ - -public abstract class BaseFragment extends Fragment { - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - try { - setRetainInstance(true); - } catch (IllegalStateException ignored) { - } - } - - @Override - public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver - .OnGlobalLayoutListener() { - public void onGlobalLayout() { - view.getViewTreeObserver().removeGlobalOnLayoutListener(this); - if (getActivity() == null) return; - onViewFinished(); - } - }); - } - - public void onViewFinished() { - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/fragments/RecyclerViewFragment.java b/app/src/main/java/com/smartpack/scriptmanager/fragments/RecyclerViewFragment.java deleted file mode 100644 index 2f744f4..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/fragments/RecyclerViewFragment.java +++ /dev/null @@ -1,662 +0,0 @@ -package com.smartpack.scriptmanager.fragments; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.app.Activity; -import android.content.res.Configuration; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Handler; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.AnimationUtils; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.widget.Toolbar; -import androidx.core.content.ContextCompat; -import androidx.core.view.ViewCompat; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; -import androidx.fragment.app.FragmentTransaction; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.StaggeredGridLayoutManager; -import androidx.viewpager.widget.ViewPager; - -import com.google.android.material.appbar.AppBarLayout; -import com.google.android.material.floatingactionbutton.FloatingActionButton; -import com.smartpack.scriptmanager.R; -import com.smartpack.scriptmanager.utils.Prefs; -import com.smartpack.scriptmanager.utils.Utils; -import com.smartpack.scriptmanager.utils.ViewUtils; -import com.smartpack.scriptmanager.viewpagerindicator.CirclePageIndicator; -import com.smartpack.scriptmanager.views.dialog.ViewPagerDialog; -import com.smartpack.scriptmanager.views.recyclerview.RecyclerViewAdapter; -import com.smartpack.scriptmanager.views.recyclerview.RecyclerViewItem; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import io.codetail.animation.SupportAnimator; -import io.codetail.animation.ViewAnimationUtils; - -/** - * Adapted from https://github.com/Grarak/KernelAdiutor by Willi Ye. - */ - -public abstract class RecyclerViewFragment extends BaseFragment { - - private Handler mHandler; - private ScheduledThreadPoolExecutor mPoolExecutor; - - private View mRootView; - - private List mItems = new ArrayList<>(); - private RecyclerView mRecyclerView; - private RecyclerView.LayoutManager mLayoutManager; - private RecyclerViewAdapter mRecyclerViewAdapter; - private Scroller mScroller; - - private View mProgress; - - private List mViewPagerFragments; - private View mViewPagerParent; - private ViewPager mViewPager; - private CirclePageIndicator mCirclePageIndicator; - - private FloatingActionButton mTopFab; - private FloatingActionButton mBottomFab; - - private AppBarLayout mAppBarLayout; - private Toolbar mToolBar; - - private AsyncTask> mLoader; - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - mRootView = inflater.inflate(R.layout.fragment_recyclerview, container, false); - mHandler = new Handler(); - - mRecyclerView = mRootView.findViewById(R.id.recyclerview); - - if (mViewPagerFragments != null) { - FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction(); - for (Fragment fragment : mViewPagerFragments) { - fragmentTransaction.remove(fragment); - } - fragmentTransaction.commitAllowingStateLoss(); - mViewPagerFragments.clear(); - } else { - mViewPagerFragments = new ArrayList<>(); - } - mViewPagerParent = mRootView.findViewById(R.id.viewpagerparent); - mViewPager = mRootView.findViewById(R.id.viewpager); - mViewPager.setVisibility(View.INVISIBLE); - mCirclePageIndicator = mRootView.findViewById(R.id.indicator); - mViewPagerParent.setVisibility(View.INVISIBLE); - ViewUtils.dismissDialog(getChildFragmentManager()); - - mProgress = mRootView.findViewById(R.id.progress); - - if (mAppBarLayout != null) { - mAppBarLayout.postDelayed(() -> { - if (mAppBarLayout != null && isAdded() && getActivity() != null) { - ViewCompat.setElevation(mAppBarLayout, showViewPager() ? - 0 : getResources().getDimension(R.dimen.app_bar_elevation)); - } - }, 150); - } - - mTopFab = mRootView.findViewById(R.id.top_fab); - mBottomFab = mRootView.findViewById(R.id.bottom_fab); - - mRecyclerView.clearOnScrollListeners(); - if (showViewPager()) { - mScroller = new Scroller(); - mRecyclerView.addOnScrollListener(mScroller); - } - mRecyclerView.setAdapter(mRecyclerViewAdapter == null ? mRecyclerViewAdapter - = new RecyclerViewAdapter(mItems, () -> getHandler().postDelayed(() -> { - if (isAdded() && getActivity() != null) { - adjustScrollPosition(); - } - }, 250)) : mRecyclerViewAdapter); - mRecyclerView.setLayoutManager(mLayoutManager = getLayoutManager()); - mRecyclerView.setHasFixedSize(true); - - mTopFab.setOnClickListener(v -> onTopFabClick()); - { - Drawable drawable = getTopFabDrawable(); - if (drawable != null) { - mTopFab.setImageDrawable(drawable); - } - } - - mBottomFab.setOnClickListener(v -> onBottomFabClick()); - { - Drawable drawable = getBottomFabDrawable(); - if (drawable != null) { - mBottomFab.setImageDrawable(drawable); - } - } - - if (itemsSize() == 0) { - mLoader = new UILoader(this, savedInstanceState); - mLoader.execute(); - } else { - showProgress(); - init(); - hideProgress(); - postInit(); - adjustScrollPosition(); - - mViewPager.setVisibility(View.VISIBLE); - } - - return mRootView; - } - - private static class UILoader extends AsyncTask> { - - private WeakReference mRefFragment; - private Bundle mSavedInstanceState; - - private UILoader(RecyclerViewFragment fragment, Bundle savedInstanceState) { - mRefFragment = new WeakReference<>(fragment); - mSavedInstanceState = savedInstanceState; - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - RecyclerViewFragment fragment = mRefFragment.get(); - - fragment.showProgress(); - fragment.init(); - } - - @Override - protected List doInBackground(Void... params) { - RecyclerViewFragment fragment = mRefFragment.get(); - - if (fragment.isAdded() && fragment.getActivity() != null) { - List items = new ArrayList<>(); - fragment.addItems(items); - return items; - } - return null; - } - - @Override - protected void onPostExecute(List recyclerViewItems) { - super.onPostExecute(recyclerViewItems); - if (isCancelled() || recyclerViewItems == null) return; - - final RecyclerViewFragment fragment = mRefFragment.get(); - - for (RecyclerViewItem item : recyclerViewItems) { - fragment.addItem(item); - } - fragment.hideProgress(); - fragment.postInit(); - if (mSavedInstanceState == null) { - fragment.mRecyclerView.post(new Runnable() { - @Override - public void run() { - Activity activity = fragment.getActivity(); - if (fragment.isAdded() && activity != null) { - fragment.mRecyclerView.startAnimation(AnimationUtils.loadAnimation( - activity, R.anim.slide_in_bottom)); - - int cx = fragment.mViewPager.getWidth(); - - SupportAnimator animator = ViewAnimationUtils.createCircularReveal( - fragment.mViewPager, cx / 2, 0, 0, cx); - animator.addListener(new SupportAnimator.SimpleAnimatorListener() { - @Override - public void onAnimationStart() { - super.onAnimationStart(); - fragment.mViewPager.setVisibility(View.VISIBLE); - } - - @Override - public void onAnimationEnd() { - super.onAnimationEnd(); - } - }); - animator.setDuration(400); - animator.start(); - } - } - }); - } else { - fragment.mViewPager.setVisibility(View.VISIBLE); - } - fragment.mLoader = null; - } - } - - @Override - public void onViewFinished() { - super.onViewFinished(); - if (showViewPager()) { - ViewPagerAdapter mViewPagerAdapter; - mViewPager.setAdapter(mViewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager(), - mViewPagerFragments)); - mCirclePageIndicator.setViewPager(mViewPager); - - setAppBarLayoutAlpha(0); - adjustScrollPosition(); - } else { - mRecyclerView.setPadding(mRecyclerView.getPaddingLeft(), mToolBar.getHeight(), - mRecyclerView.getPaddingRight(), mRecyclerView.getPaddingBottom()); - mRecyclerView.setClipToPadding(true); - ViewGroup.LayoutParams layoutParams = mViewPagerParent.getLayoutParams(); - layoutParams.height = 0; - mViewPagerParent.requestLayout(); - setAppBarLayoutAlpha(255); - } - } - - protected void init() { - } - - private void postInit() { - if (getActivity() != null && isAdded()) { - for (RecyclerViewItem item : mItems) { - item.onRecyclerViewCreate(getActivity()); - } - } - } - - private void adjustScrollPosition() { - if (mScroller != null) { - mScroller.onScrolled(mRecyclerView, 0, 0); - } - } - - protected abstract void addItems(List items); - - private void setAppBarLayoutAlpha(int alpha) { - Activity activity; - if ((activity = getActivity()) != null && mAppBarLayout != null && mToolBar != null) { - int colorPrimary = ViewUtils.getColorPrimaryColor(activity); - mAppBarLayout.setBackgroundDrawable(new ColorDrawable(Color.argb(alpha, Color.red(colorPrimary), - Color.green(colorPrimary), Color.blue(colorPrimary)))); - mToolBar.setTitleTextColor(Color.argb(alpha, 255, 255, 255)); - } - } - - void addItem(RecyclerViewItem recyclerViewItem) { - mItems.add(recyclerViewItem); - if (mRecyclerViewAdapter != null) { - mRecyclerViewAdapter.notifyItemInserted(mItems.size() - 1); - } - if (mLayoutManager instanceof StaggeredGridLayoutManager) { - ((StaggeredGridLayoutManager) mLayoutManager).setSpanCount(getSpanCount()); - } - } - - private RecyclerView.LayoutManager getLayoutManager() { - return new StaggeredGridLayoutManager(getSpanCount(), StaggeredGridLayoutManager.VERTICAL); - } - - private int getBannerHeight() { - int min = Math.round(getResources().getDimension(R.dimen.banner_min_height)); - int max = Math.round(getResources().getDimension(R.dimen.banner_max_height)); - - int height = Prefs.getInt("banner_size", Math.round(getResources().getDimension( - R.dimen.banner_min_height)), getActivity()); - if (height > max) { - height = max; - Prefs.saveInt("banner_size", max, getActivity()); - } else if (height < min) { - height = min; - Prefs.saveInt("banner_size", min, getActivity()); - } - return height; - } - - void clearItems() { - mItems.clear(); - if (mRecyclerViewAdapter != null) { - mRecyclerViewAdapter.notifyDataSetChanged(); - mRecyclerView.setAdapter(mRecyclerViewAdapter); - mRecyclerView.setLayoutManager(mLayoutManager = getLayoutManager()); - adjustScrollPosition(); - } - } - - public int getSpanCount() { - Activity activity; - if ((activity = getActivity()) != null) { - int span = Utils.isTablet(activity) ? Utils.getOrientation(activity) == - Configuration.ORIENTATION_LANDSCAPE ? 3 : 2 : Utils.getOrientation(activity) == - Configuration.ORIENTATION_LANDSCAPE ? 2 : 1; - if (itemsSize() != 0 && span > itemsSize()) { - span = itemsSize(); - } - return span; - } - return 1; - } - - int itemsSize() { - return mItems.size(); - } - - public static class ViewPagerAdapter extends FragmentPagerAdapter { - - private final List mFragments; - - public ViewPagerAdapter(FragmentManager fragmentManager, List fragments) { - super(fragmentManager); - mFragments = fragments; - } - - @NonNull - @Override - public Fragment getItem(int position) { - return mFragments.get(position); - } - - @Override - public int getCount() { - return mFragments == null ? 0 : mFragments.size(); - } - } - - private class Scroller extends RecyclerView.OnScrollListener { - - private int mScrollDistance; - private int mAppBarLayoutDistance; - private boolean mFade = true; - private ValueAnimator mAlphaAnimator; - - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - View firstItem = mRecyclerView.getChildAt(0); - if (firstItem == null) { - if (mRecyclerViewAdapter != null) { - firstItem = mRecyclerViewAdapter.getFirstItem(); - } - if (firstItem == null) { - return; - } - } - - mScrollDistance = -firstItem.getTop() + mRecyclerView.getPaddingTop(); - - int appBarHeight = 0; - if (mAppBarLayout != null) { - appBarHeight = mAppBarLayout.getHeight(); - } - - if (mScrollDistance > mViewPagerParent.getHeight() - appBarHeight) { - mAppBarLayoutDistance += dy; - fadeAppBarLayout(false); - if (mTopFab != null && showTopFab()) { - mTopFab.hide(); - } - } else { - fadeAppBarLayout(true); - if (mTopFab != null && showTopFab()) { - mTopFab.show(); - } - } - - if (mAppBarLayout != null) { - if (mAppBarLayoutDistance > mAppBarLayout.getHeight()) { - mAppBarLayoutDistance = mAppBarLayout.getHeight(); - } else if (mAppBarLayoutDistance < 0) { - mAppBarLayoutDistance = 0; - } - mAppBarLayout.setTranslationY(-mAppBarLayoutDistance); - } - - mViewPagerParent.setTranslationY(-mScrollDistance); - if (mTopFab != null) { - mTopFab.setTranslationY(-mScrollDistance); - } - - if (showBottomFab() && autoHideBottomFab()) { - if (dy <= 0) { - if (mBottomFab.getVisibility() != View.VISIBLE) { - mBottomFab.show(); - } - } else if (mBottomFab.getVisibility() == View.VISIBLE) { - mBottomFab.hide(); - } - } - } - - private void fadeAppBarLayout(boolean fade) { - if (mFade != fade) { - mFade = fade; - - if (mAlphaAnimator != null) { - mAlphaAnimator.cancel(); - } - - mAlphaAnimator = ValueAnimator.ofFloat(fade ? 1f : 0f, fade ? 0f : 1f); - mAlphaAnimator.addUpdateListener(animation -> setAppBarLayoutAlpha(Math.round(255 * (float) animation.getAnimatedValue()))); - mAlphaAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - mAlphaAnimator = null; - } - }); - mAlphaAnimator.start(); - } - } - - @Override - public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { - super.onScrollStateChanged(recyclerView, newState); - - if (mAppBarLayout == null || newState != 0 || mAppBarLayoutDistance == 0 - || (mAppBarLayoutDistance == mAppBarLayout.getHeight() && mScrollDistance != 0)) { - return; - } - - boolean show = mAppBarLayoutDistance < mAppBarLayout.getHeight() * 0.5f - || mScrollDistance <= mViewPagerParent.getHeight(); - ValueAnimator animator = ValueAnimator.ofInt(mAppBarLayoutDistance, show ? 0 : mAppBarLayout.getHeight()); - animator.addUpdateListener(animation -> { - mAppBarLayoutDistance = (int) animation.getAnimatedValue(); - mAppBarLayout.setTranslationY(-mAppBarLayoutDistance); - }); - animator.start(); - } - } - - void showProgress() { - if (getActivity() != null) { - getActivity().runOnUiThread(() -> { - if (isAdded()) { - mProgress.setVisibility(View.VISIBLE); - mRecyclerView.setVisibility(View.INVISIBLE); - if (mTopFab != null && showTopFab()) { - mTopFab.hide(); - } - if (mBottomFab != null && showBottomFab()) { - mBottomFab.hide(); - } - } - }); - } - } - - void hideProgress() { - mProgress.setVisibility(View.GONE); - mRecyclerView.setVisibility(View.VISIBLE); - mViewPagerParent.setVisibility(View.VISIBLE); - if (mTopFab != null && showTopFab()) { - mTopFab.show(); - } - if (mBottomFab != null && showBottomFab()) { - mBottomFab.show(); - } - adjustScrollPosition(); - } - - @Override - public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - - if (showViewPager()) { - menu.add(0, 0, Menu.NONE, R.string.options) - .setIcon(ContextCompat.getDrawable(requireActivity(), R.drawable.ic_launcher_preview)) - .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM); - } - if (showTopFab()) { - menu.add(0, 1, Menu.NONE, R.string.more) - .setIcon(getTopFabDrawable()) - .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM); - } else if (showBottomFab()) { - menu.add(0, 1, Menu.NONE, R.string.more) - .setIcon(getBottomFabDrawable()) - .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case 0: - ViewUtils.showDialog(getChildFragmentManager(), - ViewPagerDialog.newInstance(getBannerHeight(), mViewPagerFragments)); - return true; - case 1: - if (showTopFab()) { - onTopFabClick(); - } else if (showBottomFab()) { - onBottomFabClick(); - } - return true; - } - return false; - } - - private boolean showViewPager() { - return true; - } - - private boolean showTopFab() { - return false; - } - - private Drawable getTopFabDrawable() { - return null; - } - - private void onTopFabClick() { - } - - protected boolean showBottomFab() { - return false; - } - - protected Drawable getBottomFabDrawable() { - return null; - } - - protected void onBottomFabClick() { - } - - private boolean autoHideBottomFab() { - return true; - } - - protected View getRootView() { - return mRootView; - } - - @Override - public void onResume() { - super.onResume(); - if (mPoolExecutor == null) { - mPoolExecutor = new ScheduledThreadPoolExecutor(1); - mPoolExecutor.scheduleWithFixedDelay(mScheduler, 0, 500, - TimeUnit.MILLISECONDS); - } - for (RecyclerViewItem item : mItems) { - item.onResume(); - } - } - - @Override - public void onPause() { - super.onPause(); - if (mPoolExecutor != null) { - mPoolExecutor.shutdown(); - mPoolExecutor = null; - } - for (RecyclerViewItem item : mItems) { - item.onPause(); - } - } - - private Runnable mScheduler = () -> { - refreshThread(); - - Activity activity = getActivity(); - if (activity == null) return; - activity.runOnUiThread(() -> { - if (getActivity() != null) { - refresh(); - } - }); - }; - - private void refreshThread() { - } - - private void refresh() { - } - - @Override - public void onDestroy() { - super.onDestroy(); - mItems.clear(); - mRecyclerViewAdapter = null; - setAppBarLayoutAlpha(255); - if (mAppBarLayout != null) { - mAppBarLayout.setTranslationY(0); - ViewCompat.setElevation(mAppBarLayout, 0); - } - if (mLoader != null) { - mLoader.cancel(true); - mLoader = null; - } - for (RecyclerViewItem item : mItems) { - item.onDestroy(); - } - } - - Handler getHandler() { - return mHandler; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/fragments/ScriptsFragment.java b/app/src/main/java/com/smartpack/scriptmanager/fragments/ScriptsFragment.java deleted file mode 100644 index 3cd39d7..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/fragments/ScriptsFragment.java +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright (C) 2020-2021 sunilpaulmathew - * - * This file is part of Script Manager, an app to create, import, edit - * and easily execute any properly formatted shell scripts. - * - */ - -package com.smartpack.scriptmanager.fragments; - -import android.Manifest; -import android.annotation.SuppressLint; -import android.content.Intent; -import android.content.res.Configuration; -import android.database.Cursor; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Environment; -import android.provider.OpenableColumns; -import android.view.Menu; -import android.view.MenuItem; -import android.view.SubMenu; - -import androidx.appcompat.widget.PopupMenu; -import androidx.core.app.ActivityCompat; -import androidx.core.content.FileProvider; - -import com.smartpack.scriptmanager.BuildConfig; -import com.smartpack.scriptmanager.R; -import com.smartpack.scriptmanager.utils.ApplyScriptActivity; -import com.smartpack.scriptmanager.utils.EditScriptActivity; -import com.smartpack.scriptmanager.utils.Scripts; -import com.smartpack.scriptmanager.utils.Utils; -import com.smartpack.scriptmanager.utils.ViewUtils; -import com.smartpack.scriptmanager.views.dialog.Dialog; -import com.smartpack.scriptmanager.views.recyclerview.DescriptionView; -import com.smartpack.scriptmanager.views.recyclerview.RecyclerViewItem; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * Created by sunilpaulmathew on January 12, 2020 - */ - -public class ScriptsFragment extends RecyclerViewFragment { - - private AsyncTask> mLoader; - - private boolean mShowCreateNameDialog; - - private Dialog mOptionsDialog; - - private String mCreateName; - private String mEditScript; - private String mPath; - - @Override - protected Drawable getBottomFabDrawable() { - return getResources().getDrawable(R.drawable.ic_add); - } - - @Override - protected boolean showBottomFab() { - return true; - } - - @Override - protected void init() { - super.init(); - - if (mOptionsDialog != null) { - mOptionsDialog.show(); - } - if (mShowCreateNameDialog) { - showCreateDialog(); - } - } - - @Override - public int getSpanCount() { - int span = Utils.isTablet(requireActivity()) ? Utils.getOrientation(getActivity()) == - Configuration.ORIENTATION_LANDSCAPE ? 4 : 3 : Utils.getOrientation(getActivity()) == - Configuration.ORIENTATION_LANDSCAPE ? 3 : 2; - if (itemsSize() != 0 && span > itemsSize()) { - span = itemsSize(); - } - return span; - } - - @Override - protected void addItems(List items) { - if (Utils.checkWriteStoragePermission(requireActivity())) { - reload(); - } else { - ActivityCompat.requestPermissions(requireActivity(), new String[]{ - Manifest.permission.WRITE_EXTERNAL_STORAGE},1); - } - } - - private void reload() { - if (mLoader == null) { - getHandler().postDelayed(new Runnable() { - @SuppressLint("StaticFieldLeak") - @Override - public void run() { - mLoader = new AsyncTask>() { - - @Override - protected void onPreExecute() { - super.onPreExecute(); - showProgress(); - } - - @Override - protected List doInBackground(Void... voids) { - List items = new ArrayList<>(); - load(items); - return items; - } - - @Override - protected void onPostExecute(List recyclerViewItems) { - super.onPostExecute(recyclerViewItems); - if (isAdded()) { - clearItems(); - for (RecyclerViewItem item : recyclerViewItems) { - addItem(item); - } - - hideProgress(); - mLoader = null; - } - } - }; - mLoader.execute(); - } - }, 250); - } - } - - private void load(List items) { - if (!Scripts.ScriptFile().exists()) { - return; - } - for (final String scriptsItems : Scripts.scriptItems()) { - File scripts = new File(Scripts.ScriptFile() + "/" + scriptsItems); - if (Scripts.ScriptFile().length() > 0 && Scripts.isScript(scripts.toString())) { - DescriptionView script = new DescriptionView(); - script.setDrawable(Utils.getColoredIcon(R.drawable.ic_shell, requireActivity())); - script.setMenuIcon(getResources().getDrawable(R.drawable.ic_dots)); - script.setTitle(scripts.getName().replace(".sh", "")); - script.setOnMenuListener(new DescriptionView.OnMenuListener() { - @Override - public void onMenuReady(DescriptionView script, PopupMenu popupMenu) { - Menu menu = popupMenu.getMenu(); - menu.add(Menu.NONE, 0, Menu.NONE, getString(R.string.apply)); - menu.add(Menu.NONE, 1, Menu.NONE, getString(R.string.edit)); - menu.add(Menu.NONE, 2, Menu.NONE, getString(R.string.details)); - menu.add(Menu.NONE, 3, Menu.NONE, getString(R.string.share)); - menu.add(Menu.NONE, 4, Menu.NONE, getString(R.string.delete)); - if (Scripts.isMgiskService()) { - SubMenu onBoot = menu.addSubMenu(Menu.NONE, 5, Menu.NONE, getString(R.string.apply_on_boot)); - onBoot.add(Menu.NONE, 6, Menu.NONE, getString(R.string.post_fs)).setCheckable(true) - .setChecked(Scripts.scriptOnPostBoot(scripts.getName())); - onBoot.add(Menu.NONE, 7, Menu.NONE, getString(R.string.late_start)).setCheckable(true) - .setChecked(Scripts.scriptOnLateBoot(scripts.getName())); - } - popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @SuppressLint({"StaticFieldLeak", "StringFormatInvalid"}) - @Override - public boolean onMenuItemClick(MenuItem item) { - switch (item.getItemId()) { - case 0: - new Dialog(requireActivity()) - .setMessage(getString(R.string.apply_question, scripts.getName().replace(".sh", ""))) - .setNegativeButton(getString(R.string.cancel), (dialogInterfacei, ii) -> { - }) - .setPositiveButton(getString(R.string.yes), (dialogInterfacei, ii) -> { - if (!Scripts.isScript(scripts.toString())) { - Utils.snackbar(getRootView(), getString(R.string.wrong_script, scripts.getName().replace(".sh", ""))); - return; - } - new AsyncTask() { - @Override - protected void onPreExecute() { - super.onPreExecute(); - Scripts.mApplyingScript = true; - if (Scripts.mOutput == null) { - Scripts.mOutput = new StringBuilder(); - } else { - Scripts.mOutput.setLength(0); - } - Scripts.mOutput.append("Executing ").append(scripts.getName()).append("... Please be patient!\n\n"); - Intent applyIntent = new Intent(getActivity(), ApplyScriptActivity.class); - applyIntent.putExtra(ApplyScriptActivity.TITLE_INTENT, scripts.getName()); - startActivityForResult(applyIntent, 3); - } - @Override - protected Void doInBackground(Void... voids) { - Scripts.mOutput.append(Scripts.applyScript(scripts.toString(), getActivity())); - return null; - } - - @Override - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - Scripts.mApplyingScript = false; - } - }.execute(); - }) - .show(); - break; - case 1: - if (Scripts.mOutput == null) { - Scripts.mOutput = new StringBuilder(); - } else { - Scripts.mOutput.setLength(0); - } - if (Scripts.isMgiskService() && (Scripts.scriptOnPostBoot(scripts.getName()) - || Scripts.scriptOnLateBoot(scripts.getName()))) { - Dialog onbootwarning = new Dialog(requireActivity()); - onbootwarning.setMessage(getString(R.string.on_boot_warning, scripts.getName())); - onbootwarning.setNegativeButton(getString(R.string.cancel), (dialogInterface, i) -> { - }); - onbootwarning.setPositiveButton(getString(R.string.edit_anyway), (dialogInterface, i) -> { - showEditDialog(scripts.toString(), scripts.getName()); - }); - onbootwarning.show(); - } else { - showEditDialog(scripts.toString(), scripts.getName()); - } - break; - case 2: - new Dialog(requireActivity()) - .setTitle(scripts.getName().replace(".sh", "")) - .setMessage(Scripts.readScript(scripts.toString())) - .setPositiveButton(getString(R.string.cancel), (dialogInterfacei, ii) -> { - }) - .show(); - break; - case 3: - Uri uriFile = FileProvider.getUriForFile(requireActivity(), - BuildConfig.APPLICATION_ID + ".provider", new File(scripts.toString())); - Intent shareScript = new Intent(Intent.ACTION_SEND); - shareScript.setType("application/sh"); - shareScript.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.shared_by, scripts.getName())); - shareScript.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_message,BuildConfig.VERSION_NAME)); - shareScript.putExtra(Intent.EXTRA_STREAM, uriFile); - shareScript.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - startActivity(Intent.createChooser(shareScript, getString(R.string.share_with))); - break; - case 4: - new Dialog(requireActivity()) - .setMessage(getString(R.string.sure_question, scripts.getName().replace(".sh", ""))) - .setNegativeButton(getString(R.string.cancel), (dialogInterfacei, ii) -> { - }) - .setPositiveButton(getString(R.string.yes), (dialogInterfacei, ii) -> { - Scripts.deleteScript(scripts.toString(), getActivity()); - reload(); - }) - .show(); - break; - case 5: - break; - case 6: - if (Scripts.isMgiskService() && Scripts.scriptOnPostBoot(scripts.getName())) { - Utils.delete(Scripts.MagiskPostFSFile().toString() + "/" + scripts.getName()); - Utils.snackbar(getRootView(), getString(R.string.on_boot_message, scripts.getName())); - } else { - Scripts.setScriptOnPostFS(scripts.toString(), scripts.getName(), getActivity()); - Utils.delete(Scripts.MagiskServiceFile().toString() + "/" + scripts.getName()); - Utils.snackbar(getRootView(), getString(R.string.post_fs_message, scripts.getName())); - } - reload(); - break; - case 7: - if (Scripts.isMgiskService() && Scripts.scriptOnLateBoot(scripts.getName())) { - Utils.delete(Scripts.MagiskServiceFile().toString() + "/" + scripts.getName()); - Utils.snackbar(getRootView(), getString(R.string.on_boot_message, scripts.getName())); - } else { - Scripts.setScriptOnServiceD(scripts.toString(), scripts.getName(), getActivity()); - Utils.delete(Scripts.MagiskPostFSFile().toString() + "/" + scripts.getName()); - Utils.snackbar(getRootView(), getString(R.string.late_start_message, scripts.getName())); - } - reload(); - break; - } - return false; - } - }); - } - }); - - items.add(script); - } - } - if (items.size() == 0) { - DescriptionView info = new DescriptionView(); - info.setDrawable(Utils.getColoredIcon(R.drawable.ic_info, requireActivity())); - info.setSummary(getText(R.string.empty_message)); - info.setFullSpan(true); - info.setOnItemClickListener(item -> { - if (!Utils.checkWriteStoragePermission(requireActivity())) { - ActivityCompat.requestPermissions(requireActivity(), new String[]{ - Manifest.permission.WRITE_EXTERNAL_STORAGE},1); - Utils.snackbar(getRootView(), getString(R.string.permission_denied_write_storage)); - return; - } - - showOptions(); - }); - - items.add(info); - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - if (data == null) return; - if (requestCode == 0) { - Scripts.createScript(mEditScript, Objects.requireNonNull(data.getCharSequenceExtra(EditScriptActivity.TEXT_INTENT)).toString(), getActivity()); - reload(); - } else if (requestCode == 1) { - Uri uri = data.getData(); - assert uri != null; - File file = new File(Objects.requireNonNull(uri.getPath())); - if (Utils.isDocumentsUI(uri)) { - @SuppressLint("Recycle") Cursor cursor = requireActivity().getContentResolver().query(uri, null, null, null, null); - if (cursor != null && cursor.moveToFirst()) { - mPath = Environment.getExternalStorageDirectory().toString() + "/Download/" + - cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); - } - } else { - mPath = Utils.getPath(file); - } - if (!Utils.getExtension(mPath).equals("sh")) { - Utils.snackbar(getRootView(), getString(R.string.wrong_extension, ".sh")); - return; - } - if (!Scripts.isScript(mPath)) { - Utils.snackbar(getRootView(), getString(R.string.wrong_script, file.getName().replace(".sh", ""))); - return; - } - if (Utils.existFile(Scripts.scriptExistsCheck(file.getName()))) { - Utils.snackbar(getRootView(), getString(R.string.script_exists, file.getName())); - return; - } - Dialog selectQuestion = new Dialog(requireActivity()); - selectQuestion.setMessage(getString(R.string.select_question, file.getName().replace("primary:", "") - .replace("file%3A%2F%2F%2F", "").replace("%2F", "/"))); - selectQuestion.setNegativeButton(getString(R.string.cancel), (dialogInterface, i) -> { - }); - selectQuestion.setPositiveButton(getString(R.string.yes), (dialogInterface, i) -> { - Scripts.importScript(mPath, getActivity()); - reload(); - }); - selectQuestion.show(); - } else if (requestCode == 2) { - Scripts.createScript(mCreateName, Objects.requireNonNull(data.getCharSequenceExtra(EditScriptActivity.TEXT_INTENT)).toString(), getActivity()); - mCreateName = null; - reload(); - } - } - - @Override - protected void onBottomFabClick() { - super.onBottomFabClick(); - - if (!Utils.checkWriteStoragePermission(requireActivity())) { - ActivityCompat.requestPermissions(requireActivity(), new String[]{ - Manifest.permission.WRITE_EXTERNAL_STORAGE},1); - Utils.snackbar(getRootView(), getString(R.string.permission_denied_write_storage)); - return; - } - - showOptions(); - } - - private void showOptions() { - mOptionsDialog = new Dialog(requireActivity()).setItems(getResources().getStringArray( - R.array.script_options), (dialogInterface, i) -> { - switch (i) { - case 0: - if (Scripts.mOutput == null) { - Scripts.mOutput = new StringBuilder(); - } else { - Scripts.mOutput.setLength(0); - } - showCreateDialog(); - break; - case 1: - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType("*/*"); - startActivityForResult(intent, 1); - break; - } - }).setOnDismissListener(dialogInterface -> mOptionsDialog = null); - mOptionsDialog.show(); - } - - private void showEditDialog(String string, String name) { - mEditScript = string; - Intent intent = new Intent(getActivity(), EditScriptActivity.class); - intent.putExtra(EditScriptActivity.TITLE_INTENT, name); - intent.putExtra(EditScriptActivity.TEXT_INTENT, Scripts.readScript(string)); - startActivityForResult(intent, 0); - } - - private void showCreateDialog() { - mShowCreateNameDialog = true; - ViewUtils.dialogEditText("", - (dialogInterface, i) -> { - }, text -> { - if (text.isEmpty()) { - Utils.snackbar(getRootView(), getString(R.string.name_empty)); - return; - } - if (!text.endsWith(".sh")) { - text += ".sh"; - } - if (text.contains(" ")) { - text = text.replace(" ", "_"); - } - if (Utils.existFile(Scripts.scriptExistsCheck(text))) { - Utils.snackbar(getRootView(), getString(R.string.script_exists, text)); - return; - } - mCreateName = Utils.getInternalDataStorage() + "/" + text; - Intent intent = new Intent(getActivity(), EditScriptActivity.class); - intent.putExtra(EditScriptActivity.TITLE_INTENT, text); - intent.putExtra(EditScriptActivity.TEXT_INTENT, "#!/system/bin/sh\n\n"); - startActivityForResult(intent, 2); - }, getActivity()).setOnDismissListener(dialogInterface -> mShowCreateNameDialog = false).show(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - if (mLoader != null) { - mLoader.cancel(true); - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/utils/AppSettings.java b/app/src/main/java/com/smartpack/scriptmanager/utils/AppSettings.java new file mode 100644 index 0000000..1eba43b --- /dev/null +++ b/app/src/main/java/com/smartpack/scriptmanager/utils/AppSettings.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2021-2022 sunilpaulmathew + * + * This file is part of Script Manager, an app to create, import, edit + * and easily execute any properly formatted shell scripts. + * + */ + +package com.smartpack.scriptmanager.utils; + +/* + * Created by sunilpaulmathew on February 13, 2020 + */ +import android.content.Context; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.smartpack.scriptmanager.R; + +public class AppSettings { + + public static void setAppTheme(Context context) { + new MaterialAlertDialogBuilder(context).setItems(context.getResources().getStringArray( + R.array.app_theme), (dialogInterface, i) -> { + switch (i) { + case 0: + if (!Utils.getBoolean("theme_auto", true, context)) { + Utils.saveBoolean("dark_theme", false, context); + Utils.saveBoolean("light_theme", false, context); + Utils.saveBoolean("theme_auto", true, context); + Utils.restartApp(context); + } + break; + case 1: + if (!Utils.getBoolean("dark_theme", false, context)) { + Utils.saveBoolean("dark_theme", true, context); + Utils.saveBoolean("light_theme", false, context); + Utils.saveBoolean("theme_auto", false, context); + Utils.restartApp(context); + } + break; + case 2: + if (!Utils.getBoolean("light_theme", false, context)) { + Utils.saveBoolean("dark_theme", false, context); + Utils.saveBoolean("light_theme", true, context); + Utils.saveBoolean("theme_auto", false, context); + Utils.restartApp(context); + } + break; + } + }).setOnDismissListener(dialogInterface -> { + }).show(); + } + + public static String getAppThemeDescription(Context context) { + if (Utils.getBoolean("dark_theme", false, context)) { + return context.getString(R.string.dark_theme_enable); + } else if (Utils.getBoolean("light_theme", false, context)) { + return context.getString(R.string.dark_theme_disable); + } else { + return context.getString(R.string.dark_theme_auto); + } + } + + public static void setLanguage(Context context) { + new MaterialAlertDialogBuilder(context).setItems(context.getResources().getStringArray( + R.array.app_language), (dialogInterface, i) -> { + switch (i) { + case 0: + if (!Utils.getLanguage(context).equals(java.util.Locale.getDefault().getLanguage())) { + Utils.saveString("appLanguage", java.util.Locale.getDefault().getLanguage(), context); + Utils.restartApp(context); + } + break; + case 1: + if (!Utils.getLanguage(context).equals("en_US")) { + Utils.saveString("appLanguage", "en_US", context); + Utils.restartApp(context); + } + break; + case 2: + if (!Utils.getLanguage(context).equals("ko")) { + Utils.saveString("appLanguage", "ko", context); + Utils.restartApp(context); + } + break; + case 3: + if (!Utils.getLanguage(context).equals("am")) { + Utils.saveString("appLanguage", "am", context); + Utils.restartApp(context); + } + break; + case 4: + if (!Utils.getLanguage(context).equals("el")) { + Utils.saveString("appLanguage", "el", context); + Utils.restartApp(context); + } + break; + case 5: + if (!Utils.getLanguage(context).equals("in")) { + Utils.saveString("appLanguage", "in", context); + Utils.restartApp(context); + } + break; + case 6: + if (!Utils.getLanguage(context).equals("pt")) { + Utils.saveString("appLanguage", "pt", context); + Utils.restartApp(context); + } + break; + case 7: + if (!Utils.getLanguage(context).equals("ru")) { + Utils.saveString("appLanguage", "ru", context); + Utils.restartApp(context); + } + break; + case 8: + if (!Utils.getLanguage(context).equals("pl")) { + Utils.saveString("appLanguage", "pl", context); + Utils.restartApp(context); + } + break; + case 9: + if (!Utils.getLanguage(context).equals("zh")) { + Utils.saveString("appLanguage", "zh", context); + Utils.restartApp(context); + } + break; + case 10: + if (!Utils.getLanguage(context).equals("uk")) { + Utils.saveString("appLanguage", "uk", context); + Utils.restartApp(context); + } + break; + } + }).setOnDismissListener(dialogInterface -> { + }).show(); + } + + public static String getLanguage(Context context) { + switch (Utils.getLanguage(context)) { + case "en_US": + return context.getString(R.string.language_en); + case "ko": + return context.getString(R.string.language_ko); + case "am": + return context.getString(R.string.language_am); + case "el": + return context.getString(R.string.language_el); + case "pt": + return context.getString(R.string.language_pt); + case "ru": + return context.getString(R.string.language_ru); + case "in": + return context.getString(R.string.language_in); + case "uk": + return context.getString(R.string.language_uk); + case "zh": + return context.getString(R.string.language_zh); + case "pl": + return context.getString(R.string.language_pl); + default: + return context.getString(R.string.language_default) + " (" + java.util.Locale.getDefault().getLanguage() + ")"; + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/utils/ApplyScriptActivity.java b/app/src/main/java/com/smartpack/scriptmanager/utils/ApplyScriptActivity.java deleted file mode 100644 index 6a60ac6..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/utils/ApplyScriptActivity.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2020-2021 sunilpaulmathew - * - * This file is part of Script Manager, an app to create, import, edit - * and easily execute any properly formatted shell scripts. - * - */ - -package com.smartpack.scriptmanager.utils; - -import android.os.Bundle; -import android.view.View; - -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.AppCompatTextView; - -import com.smartpack.scriptmanager.R; - -/* - * Created by sunilpaulmathew on April 26, 2020 - */ - -public class ApplyScriptActivity extends AppCompatActivity { - - public static final String TITLE_INTENT = "title"; - private static String mTitle; - - private static AppCompatTextView mCancelButton; - private static AppCompatTextView mScriptTitle; - private static AppCompatTextView mOutput; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_editor); - - mCancelButton = findViewById(R.id.cancel_button); - mScriptTitle = findViewById(R.id.script_title); - mTitle = getIntent().getStringExtra(TITLE_INTENT); - if (mTitle != null) { - mScriptTitle.setText(getString(R.string.applying_script, mTitle)); - } - mOutput = findViewById(R.id.result_text); - mCancelButton.setOnClickListener(v -> { - onBackPressed(); - }); - refreshStatus(); - } - - public void refreshStatus() { - new Thread() { - @Override - public void run() { - try { - while (!isInterrupted()) { - Thread.sleep(100); - runOnUiThread(() -> { - if (Scripts.mOutput != null) { - mOutput.setText(Scripts.mOutput.toString()); - mScriptTitle.setVisibility(View.VISIBLE); - mOutput.setVisibility(View.VISIBLE); - if (!Scripts.mApplyingScript) { - mCancelButton.setVisibility(View.VISIBLE); - mScriptTitle.setText(getString(R.string.script_applied, mTitle)); - } - } - }); - } - } catch (InterruptedException ignored) {} - } - }.start(); - } - - @Override - public void onBackPressed() { - if (Scripts.mApplyingScript) return; - super.onBackPressed(); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/utils/EditScriptActivity.java b/app/src/main/java/com/smartpack/scriptmanager/utils/EditScriptActivity.java deleted file mode 100644 index dced492..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/utils/EditScriptActivity.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2020-2021 sunilpaulmathew - * - * This file is part of Script Manager, an app to create, import, edit - * and easily execute any properly formatted shell scripts. - * - */ - -package com.smartpack.scriptmanager.utils; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.os.AsyncTask; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.AppCompatEditText; -import androidx.appcompat.widget.AppCompatTextView; -import androidx.appcompat.widget.Toolbar; -import androidx.core.content.ContextCompat; -import androidx.core.graphics.drawable.DrawableCompat; - -import com.smartpack.scriptmanager.R; -import com.smartpack.scriptmanager.utils.root.RootUtils; - -import java.lang.ref.WeakReference; -import java.util.Objects; - -/* - * Created by sunilpaulmathew on January 12, 2020 - * Based on the original implementation on Kernel Adiutor by - * Willi Ye - */ - -public class EditScriptActivity extends AppCompatActivity { - - public static final String TITLE_INTENT = "title"; - public static final String TEXT_INTENT = "text"; - private static final String EDITTEXT_INTENT = "edittext"; - - private static AppCompatEditText mEditText; - - private static AppCompatTextView mTestOutput; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_editor); - - initToolBar(); - String title = getIntent().getStringExtra(TITLE_INTENT); - if (title != null) { - Objects.requireNonNull(getSupportActionBar()).setTitle(title); - } - - CharSequence text = getIntent().getCharSequenceExtra(TEXT_INTENT); - mEditText = findViewById(R.id.edit_text); - if (text != null) { - mEditText.append(text); - mEditText.setVisibility(View.VISIBLE); - } - AppCompatTextView testButton = findViewById(R.id.test_button); - testButton.setText(R.string.test); - testButton.setVisibility(View.VISIBLE); - testButton.setOnClickListener(v -> { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); - testCommands(new WeakReference<>(this)); - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER); - }); - mTestOutput = findViewById(R.id.test_output); - refreshStatus(); - } - - private static void testCommands(WeakReference activityRef) { - new AsyncTask() { - private ProgressDialog mProgressDialog; - @Override - protected void onPreExecute() { - super.onPreExecute(); - mProgressDialog = new ProgressDialog(activityRef.get()); - mProgressDialog.setMessage(activityRef.get().getString(R.string.testing)); - mProgressDialog.setCancelable(false); - mProgressDialog.show(); - } - @SuppressLint("WrongThread") - @Override - protected Void doInBackground(Void... voids) { - Scripts.mApplyingScript = true; - if (Scripts.mOutput == null) { - Scripts.mOutput = new StringBuilder(); - } else { - Scripts.mOutput.setLength(0); - } - Utils.delete("/data/local/tmp/sm"); - Utils.create(Objects.requireNonNull(mEditText.getText()).toString(),"/data/local/tmp/sm"); - String output = RootUtils.runAndGetError("sh /data/local/tmp/sm"); - if (output.isEmpty()) { - output = activityRef.get().getString(R.string.testing_success); - } - Scripts.mOutput.append(output); - Utils.delete("/data/local/tmp/sm"); - Scripts.mApplyingScript = true; - return null; - } - @Override - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - try { - mProgressDialog.dismiss(); - } catch (IllegalArgumentException ignored) { - } - } - }.execute(); - } - - private void refreshStatus() { - new Thread() { - @Override - public void run() { - try { - while (!isInterrupted()) { - Thread.sleep(100); - runOnUiThread(() -> { - if (mTestOutput != null && Scripts.mOutput != null) { - mTestOutput.setVisibility(View.VISIBLE); - mTestOutput.setText(Scripts.mOutput.toString()); - } - }); - } - } catch (InterruptedException ignored) {} - } - }.start(); - } - - @Override - protected void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - outState.putCharSequence(EDITTEXT_INTENT, mEditText.getText()); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - Drawable drawable = ContextCompat.getDrawable(this, R.drawable.ic_save); - assert drawable != null; - DrawableCompat.setTint(drawable, Color.BLACK); - menu.add(0, Menu.FIRST, Menu.FIRST, getString(R.string.save)).setIcon(drawable) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - Intent intent = new Intent(); - intent.putExtra(TEXT_INTENT, mEditText.getText()); - setResult(0, intent); - finish(); - return super.onOptionsItemSelected(item); - } - - public Toolbar getToolBar() { - return (Toolbar) findViewById(R.id.toolbar); - } - - public void initToolBar() { - Toolbar toolbar = getToolBar(); - if (toolbar != null) { - setSupportActionBar(toolbar); - toolbar.setVisibility(View.VISIBLE); - toolbar.setNavigationOnClickListener(v -> finish()); - Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); - } - } - - @Override - public void onBackPressed() { - if (Scripts.mApplyingScript) return; - super.onBackPressed(); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/utils/PagerAdapter.java b/app/src/main/java/com/smartpack/scriptmanager/utils/PagerAdapter.java deleted file mode 100644 index 2a9bed0..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/utils/PagerAdapter.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2020-2021 sunilpaulmathew - * - * This file is part of Script Manager, an app to create, import, edit - * and easily execute any properly formatted shell scripts. - * - */ - -/** - * Created by sunilpaulmathew on January 12, 2020 - */ - -package com.smartpack.scriptmanager.utils; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; - -import java.util.ArrayList; -import java.util.List; - -public class PagerAdapter extends FragmentPagerAdapter { - - private final List fragmentList = new ArrayList<>(); - private final List fragmentListTitles = new ArrayList<>(); - - public PagerAdapter(FragmentManager fm) { - super(fm); - } - - @Override - @NonNull - public Fragment getItem(int position) { - return fragmentList.get(position); - } - - @Override - public int getCount() { - return fragmentListTitles.size(); - } - - @Override - public CharSequence getPageTitle(int position) { - return fragmentListTitles.get(position); - } - public void AddFragment(Fragment fragment, String title) { - fragmentList.add(fragment); - fragmentListTitles.add(title); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/utils/Prefs.java b/app/src/main/java/com/smartpack/scriptmanager/utils/Prefs.java deleted file mode 100644 index faca119..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/utils/Prefs.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2020-2021 sunilpaulmathew - * - * This file is part of Script Manager, an app to create, import, edit - * and easily execute any properly formatted shell scripts. - * - */ - -package com.smartpack.scriptmanager.utils; - -import android.content.Context; -import android.preference.PreferenceManager; - -/* - * Created by sunilpaulmathew on January 12, 2020 - * Based on the original implementation on Kernel Adiutor by - * Willi Ye - */ - -public class Prefs { - - public static int getInt(String name, int defaults, Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getInt(name, defaults); - } - - public static void saveInt(String name, int value, Context context) { - PreferenceManager.getDefaultSharedPreferences(context).edit().putInt(name, value).apply(); - } - - public static boolean getBoolean(String name, boolean defaults, Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(name, defaults); - } - - public static void saveBoolean(String name, boolean value, Context context) { - PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(name, value).apply(); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/utils/RecycleViewItem.java b/app/src/main/java/com/smartpack/scriptmanager/utils/RecycleViewItem.java new file mode 100644 index 0000000..e0ec708 --- /dev/null +++ b/app/src/main/java/com/smartpack/scriptmanager/utils/RecycleViewItem.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021-2022 sunilpaulmathew + * + * This file is part of Script Manager, an app to create, import, edit + * and easily execute any properly formatted shell scripts. + * + */ + +package com.smartpack.scriptmanager.utils; + +import android.graphics.drawable.Drawable; + +import java.io.Serializable; + +/* + * Created by sunilpaulmathew on February 13, 2020 + */ + +public class RecycleViewItem implements Serializable { + private final String mTitle, mDescription, mUrl; + private final Drawable mIcon; + + public RecycleViewItem(String title, String description, Drawable icon, String url) { + this.mTitle = title; + this.mDescription = description; + this.mIcon = icon; + this.mUrl = url; + } + + public String getTitle() { + return mTitle; + } + + public String getDescription() { + return mDescription; + } + + public Drawable getIcon() { + return mIcon; + } + + public String getUrl() { + return mUrl; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/utils/Scripts.java b/app/src/main/java/com/smartpack/scriptmanager/utils/Scripts.java index 9f8fd83..fcac4a4 100644 --- a/app/src/main/java/com/smartpack/scriptmanager/utils/Scripts.java +++ b/app/src/main/java/com/smartpack/scriptmanager/utils/Scripts.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 sunilpaulmathew + * Copyright (C) 2021-2022 sunilpaulmathew * * This file is part of Script Manager, an app to create, import, edit * and easily execute any properly formatted shell scripts. @@ -8,31 +8,58 @@ package com.smartpack.scriptmanager.utils; +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Environment; +import android.os.Handler; +import androidx.core.app.ActivityCompat; +import androidx.core.content.FileProvider; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.smartpack.scriptmanager.BuildConfig; import com.smartpack.scriptmanager.R; -import com.smartpack.scriptmanager.utils.root.RootFile; -import com.smartpack.scriptmanager.utils.root.RootUtils; +import com.smartpack.scriptmanager.activities.ApplyScriptActivity; +import com.smartpack.scriptmanager.activities.CreateScriptActivity; +import com.smartpack.scriptmanager.adapters.RecycleViewAdapter; import java.io.File; +import java.util.ArrayList; import java.util.List; -/** +/* * Created by sunilpaulmathew on January 12, 2020 */ - public class Scripts { - private static final String SCRIPTS = Utils.getInternalDataStorage(); + private static AsyncTask mLoader; + private static final Handler mHandler = new Handler(); + public static RecyclerView mRecyclerView; + public static RecycleViewAdapter mRecycleViewAdapter; + private static final String MAGISK_SERVICED = "/data/adb/service.d"; private static final String MAGISK_POSTFS = "/data/adb/post-fs-data.d"; - public static StringBuilder mOutput = null; + public static String mScriptName; + public static String mScriptPath; + + public static List mOutput = null; public static boolean mApplyingScript = false; - public static File ScriptFile() { - return new File(SCRIPTS); + public static File ScriptFile(Context context) { + if (Build.VERSION.SDK_INT >= 30) { + return context.getExternalFilesDir(""); + } else { + return new File(Environment.getExternalStorageDirectory(), "scripts"); + } } public static File MagiskServiceFile() { return new File(MAGISK_SERVICED); @@ -41,83 +68,208 @@ public static File MagiskPostFSFile() { return new File(MAGISK_POSTFS); } - public static List scriptItems() { - RootFile file = new RootFile(ScriptFile().toString()); - if (!file.exists()) { - file.mkdir(); + private static File[] getFilesList(Context context) { + if (Utils.exist(ScriptFile(context).toString())) { + makeScriptFolder(context); } - return file.list(); + return new File(ScriptFile(context).toString()).listFiles(); } - private static void makeScriptFolder() { - if (ScriptFile().exists() && ScriptFile().isFile()) { - ScriptFile().delete(); + public static List getData(Context context) { + List mData = new ArrayList<>(); + if (ScriptFile(context).exists()) { + for (File mFile : getFilesList(context)) { + if (isScript(mFile.getPath())) { + mData.add(mFile.getName().replace(".sh", "")); + } + } } - ScriptFile().mkdirs(); + return mData; + } + + private static void makeScriptFolder(Context context) { + if (ScriptFile(context).exists() && ScriptFile(context).isFile()) { + ScriptFile(context).delete(); + } + ScriptFile(context).mkdirs(); } public static void importScript(String string, Context context) { - makeScriptFolder(); - RootUtils.runCommand("cp " + string + " " + SCRIPTS); + makeScriptFolder(context); + Utils.create(Utils.read(string) , new File(ScriptFile(context), new File(string).getName()).getAbsolutePath()); } public static void createScript(String file, String text, Context context) { - makeScriptFolder(); - RootFile f = new RootFile(file); - f.write(text, false); + makeScriptFolder(context); + Utils.create(text, file); + } + + public static void createScript(Activity activity) { + Utils.dialogEditText(null, + (dialogInterface, i) -> { + }, text -> { + if (text.isEmpty()) { + Utils.snackbar(activity.findViewById(android.R.id.content), activity.getString(R.string.name_empty)); + return; + } + if (!text.endsWith(".sh")) { + text += ".sh"; + } + if (text.contains(" ")) { + text = text.replace(" ", "_"); + } + if (Utils.exist(scriptExistsCheck(text, activity))) { + Utils.snackbar(activity.findViewById(android.R.id.content), activity.getString(R.string.script_exists, text)); + return; + } + mScriptName = text; + mScriptPath = null; + launchCreateScriptActivity(activity); + }, activity).setOnDismissListener(dialogInterface -> { + }).show(); } - public static void deleteScript(String path, Context context) { + public static void launchCreateScriptActivity(Context context) { + mOutput = new ArrayList<>(); + Intent intent = new Intent(context, CreateScriptActivity.class); + context.startActivity(intent); + } + + public static void deleteScript(String path) { File file = new File(path); file.delete(); - if (Utils.existFile(MagiskServiceFile() + "/" + file.getName())) { - RootUtils.runCommand("rm -r " + MagiskServiceFile() + "/" + file.getName()); + if (Utils.exist(MagiskServiceFile() + "/" + file.getName())) { + Utils.runCommand("rm -r " + MagiskServiceFile() + "/" + file.getName()); } } - public static String applyScript(String file, Context context) { - RootUtils.runCommand("sleep 1"); - mOutput.append("********************\n Checking Output!\n********************\n\n"); - String output = RootUtils.runAndGetError("sh " + file); - if (output.isEmpty()) { - output = context.getString(R.string.script_applied_success, new File(file).getName()); - } - return output; + private static void applyScript(String file) { + mOutput.add("Checking Output!"); + Utils.runCommand("sleep 1"); + mOutput.add("********************"); + Utils.runAndGetLiveOutput("sh " + file, mOutput); + } + + public static void applyScript(Context context) { + new AsyncTask() { + @Override + protected void onPreExecute() { + super.onPreExecute(); + mApplyingScript = true; + mOutput = new ArrayList<>(); + mOutput.add("Executing " + mScriptName + "... Please be patient!\n\n"); + Intent applyIntent = new Intent(context, ApplyScriptActivity.class); + context.startActivity(applyIntent); + } + + @Override + protected Void doInBackground(Void... voids) { + applyScript(mScriptPath); + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + mOutput.add("********************"); + mOutput.add(context.getString(R.string.script_applied_success, mScriptName)); + mApplyingScript = false; + } + }.execute(); + } + + @SuppressLint("StringFormatInvalid") + public static void shareScript(Context context) { + Uri uriFile = FileProvider.getUriForFile(context, + BuildConfig.APPLICATION_ID + ".provider", new File(mScriptPath)); + Intent shareScript = new Intent(Intent.ACTION_SEND); + shareScript.setType("application/sh"); + shareScript.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_by, mScriptName)); + shareScript.putExtra(Intent.EXTRA_TEXT, context.getString(R.string.share_message) + " " + + context.getString(R.string.share_message_app, "v" + BuildConfig.VERSION_NAME)); + shareScript.putExtra(Intent.EXTRA_STREAM, uriFile); + shareScript.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + context.startActivity(Intent.createChooser(shareScript, context.getString(R.string.share_with))); } public static String readScript(String file) { - return Utils.readFile(file); + return Utils.read(file); } public static boolean isScript(String file) { - return Utils.getExtension(file).equals("sh") && readScript(file).startsWith("#!/system/bin/sh"); + return Utils.getExtension(file).equals("sh") && (readScript(file).startsWith("#!/system/bin/sh") + || readScript(file).startsWith("#!/usr/bin/env bash")); + } + + public static String scriptExistsCheck(String script, Context context) { + return ScriptFile(context).toString() + "/" + script; } - public static String scriptExistsCheck(String script) { - return ScriptFile().toString() + "/" + script; + public static boolean isMgiskServiceD() { + return Utils.exist(MAGISK_SERVICED); } - public static boolean isMgiskService() { - return Utils.existFile(MAGISK_SERVICED) || - Utils.existFile(MAGISK_POSTFS); + public static boolean isMgiskPostFS() { + return Utils.exist(MAGISK_POSTFS); } - public static void setScriptOnServiceD(String string, String name, Context context) { - Utils.copy(string, MAGISK_SERVICED); - Utils.chmod("755", MAGISK_SERVICED + "/" + name); + public static void setScriptOnServiceD(String path, String name) { + Utils.runCommand("cp -r " + path + " " + MAGISK_SERVICED); + Utils.chmod("755", MAGISK_SERVICED + "/" + name + ".sh"); } - public static void setScriptOnPostFS(String string, String name, Context context) { - Utils.copy(string, MAGISK_POSTFS); - Utils.chmod("755", MAGISK_POSTFS + "/" + name); + public static void setScriptOnPostFS(String path, String name) { + Utils.runCommand("cp -r " + path + " " + MAGISK_POSTFS); + Utils.chmod("755", MAGISK_POSTFS + "/" + name + ".sh"); } - public static boolean scriptOnPostBoot(String path) { - return Utils.existFile(MAGISK_POSTFS + "/" + path); + public static boolean scriptOnPostBoot(String name) { + return Utils.exist(MAGISK_POSTFS + "/" + name + ".sh"); } - public static boolean scriptOnLateBoot(String path) { - return Utils.existFile(MAGISK_SERVICED + "/" + path); + public static boolean scriptOnLateBoot(String name) { + return Utils.exist(MAGISK_SERVICED + "/" + name + ".sh"); + } + + public static void loadUI(Activity activity) { + Scripts.mRecyclerView.setLayoutManager(new GridLayoutManager(activity, Utils.getSpanCount(activity))); + try { + Scripts.mRecycleViewAdapter = new RecycleViewAdapter(Scripts.getData(activity)); + } catch (RuntimeException ignored) {} + if (Build.VERSION.SDK_INT >= 30 || Utils.checkWriteStoragePermission(activity)) { + Scripts.mRecyclerView.setAdapter(Scripts.mRecycleViewAdapter); + } else { + ActivityCompat.requestPermissions(activity, new String[] { + Manifest.permission.WRITE_EXTERNAL_STORAGE},1); + Utils.snackbar(activity.findViewById(android.R.id.content), activity.getString(R.string.permission_denied_write_storage)); + } + } + + public static void reloadUI(Activity activity) { + if (mLoader == null) { + mHandler.postDelayed(new Runnable() { + @SuppressLint("StaticFieldLeak") + @Override + public void run() { + mLoader = new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { + mRecycleViewAdapter = new RecycleViewAdapter(getData(activity)); + return null; + } + + @Override + protected void onPostExecute(Void recyclerViewItems) { + super.onPostExecute(recyclerViewItems); + mRecyclerView.setAdapter(mRecycleViewAdapter); + mRecycleViewAdapter.notifyDataSetChanged(); + mLoader = null; + } + }; + mLoader.execute(); + } + }, 250); + } } } \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/utils/UpdateCheck.java b/app/src/main/java/com/smartpack/scriptmanager/utils/UpdateCheck.java deleted file mode 100644 index 632e271..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/utils/UpdateCheck.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2020-2021 sunilpaulmathew - * - * This file is part of Script Manager, an app to create, import, edit - * and easily execute any properly formatted shell scripts. - * - */ - -package com.smartpack.scriptmanager.utils; - -import android.content.Context; -import android.content.pm.PackageManager; - -import com.smartpack.scriptmanager.BuildConfig; -import com.smartpack.scriptmanager.R; -import com.smartpack.scriptmanager.views.dialog.Dialog; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.File; - -/** - * Created by sunilpaulmathew on January 12, 2020 - */ - -public class UpdateCheck { - - private static final String LATEST_VERSION_URL = "https://raw.githubusercontent.com/SmartPack/ScriptManager/master/app/src/main/assets/update_info.json"; - private static final String DOWNLOAD_URL = "https://github.com/SmartPack/ScriptManager/tree/master/release"; - private static final String UPDATE_INFO = Utils.getInternalDataStorage() + "/update_info.json"; - - public static boolean isPlayStoreInstalled(Context context) { - try { - context.getPackageManager().getApplicationInfo("com.android.vending", 0); - return true; - } catch (PackageManager.NameNotFoundException ignored) { - return false; - } - } - - private static void prepareInternalStorage() { - File file = new File(Utils.getInternalDataStorage()); - if (file.exists() && file.isFile()) { - file.delete(); - } - file.mkdirs(); - } - - public static void getVersionInfo() { - prepareInternalStorage(); - Utils.downloadFile(UPDATE_INFO, LATEST_VERSION_URL); - } - - public static int versionNumber() { - try { - JSONObject obj = new JSONObject(Utils.readFile(UPDATE_INFO)); - return (obj.getInt("versionCode")); - } catch (JSONException e) { - return BuildConfig.VERSION_CODE; - } - } - - private static String versionName() { - try { - JSONObject obj = new JSONObject(Utils.readFile(UPDATE_INFO)); - return (obj.getString("versionName")); - } catch (JSONException e) { - return BuildConfig.VERSION_NAME; - } - } - - private static String changelogs() { - try { - JSONObject obj = new JSONObject(Utils.readFile(UPDATE_INFO)); - return (obj.getString("releaseNotes")); - } catch (JSONException e) { - return "Unavailable"; - } - } - - public static boolean hasVersionInfo() { - return Utils.existFile(UPDATE_INFO); - } - - public static long lastModified() { - return new File(UPDATE_INFO).lastModified(); - } - - public static void updateAvailableDialog(Context context) { - new Dialog(context) - .setTitle(context.getString(R.string.update_available, UpdateCheck.versionName())) - .setMessage(context.getString(R.string.update_available_summary, changelogs())) - .setCancelable(false) - .setNegativeButton(context.getString(R.string.cancel), (dialog, id) -> { - }) - .setPositiveButton(context.getString(R.string.get_it), (dialog, id) -> { - Utils.launchUrl(DOWNLOAD_URL, context); - }) - .show(); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/utils/Utils.java b/app/src/main/java/com/smartpack/scriptmanager/utils/Utils.java index 8228cb2..c709627 100644 --- a/app/src/main/java/com/smartpack/scriptmanager/utils/Utils.java +++ b/app/src/main/java/com/smartpack/scriptmanager/utils/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 sunilpaulmathew + * Copyright (C) 2021-2022 sunilpaulmathew * * This file is part of Script Manager, an app to create, import, edit * and easily execute any properly formatted shell scripts. @@ -8,285 +8,327 @@ package com.smartpack.scriptmanager.utils; -import android.annotation.SuppressLint; import android.app.Activity; -import android.app.UiModeManager; import android.content.ActivityNotFoundException; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; -import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.Uri; import android.os.Build; import android.os.Environment; +import android.preference.PreferenceManager; import android.util.DisplayMetrics; -import android.util.Log; +import android.view.Gravity; +import android.view.Menu; import android.view.View; -import android.widget.CheckBox; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatDelegate; -import androidx.appcompat.widget.AppCompatImageButton; -import androidx.appcompat.widget.AppCompatImageView; -import androidx.appcompat.widget.AppCompatTextView; -import androidx.cardview.widget.CardView; +import androidx.appcompat.widget.AppCompatEditText; +import androidx.appcompat.widget.PopupMenu; -import com.facebook.ads.AudienceNetworkAds; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; import com.smartpack.scriptmanager.BuildConfig; +import com.smartpack.scriptmanager.MainActivity; import com.smartpack.scriptmanager.R; -import com.smartpack.scriptmanager.utils.root.RootFile; -import com.smartpack.scriptmanager.utils.root.RootUtils; -import com.smartpack.scriptmanager.views.dialog.Dialog; - -import org.json.JSONException; -import org.json.JSONObject; +import com.smartpack.scriptmanager.activities.FilePickerActivity; +import com.topjohnwu.superuser.Shell; +import com.topjohnwu.superuser.ShellUtils; import java.io.BufferedReader; import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.OutputStream; -import java.math.BigInteger; -import java.net.URL; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import java.util.Objects; /* * Created by sunilpaulmathew on January 12, 2020 - * Based on the original implementation on Kernel Adiutor by - * Willi Ye */ - public class Utils { - public static AppCompatImageButton mBack; - public static AppCompatImageView mAppIcon; - public static AppCompatTextView mCardTitle; - public static AppCompatTextView mAppName; - public static AppCompatTextView mAboutApp; - public static AppCompatTextView mCreditsTitle; - public static AppCompatTextView mCredits; - public static AppCompatTextView mForegroundText; - public static AppCompatTextView mCancel; - public static boolean mForegroundActive = false; - public static CardView mForegroundCard; + static { + Shell.enableVerboseLogging = BuildConfig.DEBUG; + } - private static final String TAG = Utils.class.getSimpleName(); + /* + * The following code is partly taken from https://github.com/SmartPack/SmartPack-Kernel-Manager + * Ref: https://github.com/SmartPack/SmartPack-Kernel-Manager/blob/beta/app/src/main/java/com/smartpack/kernelmanager/utils/root/RootUtils.java + */ + public static boolean rootAccess() { + return Shell.rootAccess(); + } - private static boolean mWelcomeDialog = true; + public static void runCommand(String command) { + Shell.su(command).exec(); + } - public static boolean isNotDonated(Context context) { - if (BuildConfig.DEBUG) return false; + @NonNull + static String runAndGetOutput(String command) { + StringBuilder sb = new StringBuilder(); try { - context.getPackageManager().getApplicationInfo("com.smartpack.donate", 0); - return false; - } catch (PackageManager.NameNotFoundException ignored) { - return true; + List outputs = Shell.su(command).exec().getOut(); + if (ShellUtils.isValidOutput(outputs)) { + for (String output : outputs) { + sb.append(output).append("\n"); + } + } + return removeSuffix(sb.toString()).trim(); + } catch (Exception e) { + return ""; } } - public static void initializeAppTheme(Context context) { - if (Prefs.getBoolean("dark_theme", true, context)) { - AppCompatDelegate.setDefaultNightMode( - AppCompatDelegate.MODE_NIGHT_YES); + public static void runAndGetLiveOutput(String command, List output) { + if (rootAccess()) { + Shell.su(command).to(output, output).exec(); } else { - AppCompatDelegate.setDefaultNightMode( - AppCompatDelegate.MODE_NIGHT_NO); + try { + Process process = Runtime.getRuntime().exec(command); + BufferedReader mInput = new BufferedReader(new InputStreamReader(process.getInputStream())); + BufferedReader mError = new BufferedReader(new InputStreamReader(process.getErrorStream())); + String line; + while ((line = mInput.readLine()) != null) { + output.add(line); + } + while ((line = mError.readLine()) != null) { + output.add(line); + } + } catch (Exception ignored) { + } } } - public static void initializeFaceBookAds(Context context) { - AudienceNetworkAds.initialize(context); + public static String getOutput(List output) { + List mData = new ArrayList<>(); + for (String line : output.toString().substring(1, output.toString().length() - 1).replace( + ", ","\n").replace("ui_print","").split("\\r?\\n")) { + if (!line.startsWith("progress")) { + mData.add(line); + } + } + return mData.toString().substring(1, mData.toString().length() - 1).replace(", ","\n") + .replaceAll("(?m)^[ \t]*\r?\n", ""); } - public static boolean isTv(Context context) { - return ((UiModeManager) Objects.requireNonNull(context.getSystemService(Context.UI_MODE_SERVICE))) - .getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION; + private static String removeSuffix(@Nullable String s) { + if (s != null && s.endsWith("\n")) { + return s.substring(0, s.length() - "\n".length()); + } + return s; } - public static String getInternalDataStorage() { - return Environment.getExternalStorageDirectory().toString() + "/scripts"; - } + /* + * The following code is partly taken from https://github.com/Grarak/KernelAdiutor + * Ref: https://github.com/Grarak/KernelAdiutor/blob/master/app/src/main/java/com/grarak/kerneladiutor/utils/ViewUtils.java + */ - public static void create(String text, String path) { - RootUtils.runCommand("echo '" + text + "' > " + path); + public static int getThemeAccentColor(Context context) { + return context.getResources().getColor(R.color.blue); } - public static void delete(String path) { - if (Utils.existFile(path)) { - RootUtils.runCommand("rm -r " + path); - } + public interface OnDialogEditTextListener { + void onClick(String text); } - static void copy(String source, String dest) { - RootUtils.runCommand("cp -r " + source + " " + dest); + public static MaterialAlertDialogBuilder dialogEditText(String text, final DialogInterface.OnClickListener negativeListener, + final OnDialogEditTextListener onDialogEditTextListener, + Context context) { + return dialogEditText(text, negativeListener, onDialogEditTextListener, -1, context); } - static void chmod(String permission, String path) { - RootUtils.runCommand("chmod " + permission + " " + path); - } + public static MaterialAlertDialogBuilder dialogEditText(String text, final DialogInterface.OnClickListener negativeListener, + final OnDialogEditTextListener onDialogEditTextListener, int inputType, + Context context) { + LinearLayout layout = new LinearLayout(context); + layout.setPadding(75, 75, 75, 75); - // MD5 code from - // https://github.com/CyanogenMod/android_packages_apps_CMUpdater/blob/cm-12.1/src/com/cyanogenmod/updater/utils/MD5.java - public static boolean checkMD5(String md5, File updateFile) { - if (md5 == null || updateFile == null || md5.isEmpty()) { - Log.e(TAG, "MD5 string empty or updateFile null"); - return false; + final AppCompatEditText editText = new AppCompatEditText(context); + editText.setGravity(Gravity.CENTER); + editText.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + if (text != null) { + editText.append(text); } - - String calculatedDigest = calculateMD5(updateFile); - if (calculatedDigest == null) { - Log.e(TAG, "calculatedDigest null"); - return false; + editText.setSingleLine(true); + if (inputType >= 0) { + editText.setInputType(inputType); } - return calculatedDigest.equalsIgnoreCase(md5); - } + layout.addView(editText); - private static String calculateMD5(File updateFile) { - MessageDigest digest; - try { - digest = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - Log.e(TAG, "Exception while getting digest", e); - return null; + MaterialAlertDialogBuilder dialog = new MaterialAlertDialogBuilder(context).setView(layout); + if (negativeListener != null) { + dialog.setNegativeButton(context.getString(R.string.cancel), negativeListener); } - - InputStream is; - try { - is = new FileInputStream(updateFile); - } catch (FileNotFoundException e) { - Log.e(TAG, "Exception while getting FileInputStream", e); - return null; + if (onDialogEditTextListener != null) { + dialog.setPositiveButton(context.getString(R.string.ok), (dialog1, which) + -> onDialogEditTextListener.onClick(Objects.requireNonNull(editText.getText()).toString())) + .setOnDismissListener(dialog1 -> { + if (negativeListener != null) { + negativeListener.onClick(dialog1, 0); + } + }); } + return dialog; + } - byte[] buffer = new byte[8192]; - int read; - try { - while ((read = is.read(buffer)) > 0) { - digest.update(buffer, 0, read); - } - byte[] md5sum = digest.digest(); - BigInteger bigInt = new BigInteger(1, md5sum); - String output = bigInt.toString(16); - // Fill to 32 chars - output = String.format("%32s", output).replace(' ', '0'); - return output; - } catch (IOException e) { - throw new RuntimeException("Unable to process file for MD5", e); - } finally { - try { - is.close(); - } catch (IOException e) { - Log.e(TAG, "Exception on closing MD5 input stream", e); - } - } + /* + * The following code is partly taken from https://github.com/Grarak/KernelAdiutor + * Ref: https://github.com/Grarak/KernelAdiutor/blob/master/app/src/main/java/com/grarak/kerneladiutor/utils/Prefs.java + */ + public static boolean getBoolean(String name, boolean defaults, Context context) { + return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(name, defaults); } - public static boolean isTablet(Context context) { - return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) - >= Configuration.SCREENLAYOUT_SIZE_LARGE; + public static void saveBoolean(String name, boolean value, Context context) { + PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(name, value).apply(); } - public static void snackbar(View view, String message) { - Snackbar snackbar; - snackbar = Snackbar.make(view, message, Snackbar.LENGTH_LONG); - snackbar.show(); + public static String getString(String name, String defaults, Context context) { + return PreferenceManager.getDefaultSharedPreferences(context).getString(name, defaults); } - public static void launchUrl(String url, Context context) { + public static void saveString(String name, String value, Context context) { + PreferenceManager.getDefaultSharedPreferences(context).edit().putString(name, value).apply(); + } + + /* + * The following code is partly taken from https://github.com/Grarak/KernelAdiutor + * Ref: https://github.com/Grarak/KernelAdiutor/blob/master/app/src/main/java/com/grarak/kerneladiutor/utils/Utils.java + */ + public static boolean isNotDonated(Context context) { try { - Intent i = new Intent(Intent.ACTION_VIEW); - i.setData(Uri.parse(url)); - context.startActivity(i); - } catch (ActivityNotFoundException e) { - e.printStackTrace(); + context.getPackageManager().getApplicationInfo("com.smartpack.donate", 0); + return false; + } catch (PackageManager.NameNotFoundException ignored) { + return true; } } - public static Drawable getColoredIcon(int icon, Context context) { - Drawable drawable = context.getResources().getDrawable(icon); - drawable.setTint(ViewUtils.getThemeAccentColor(context)); - return drawable; + public static boolean isProUser(Context context) { + return getBoolean("support_received", false, context) || !isNotDonated(context); } - public static int getOrientation(Activity activity) { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && activity.isInMultiWindowMode() ? - Configuration.ORIENTATION_PORTRAIT : activity.getResources().getConfiguration().orientation; + public static void initializeAppTheme(Context context) { + if (getBoolean("dark_theme", false, context)) { + AppCompatDelegate.setDefaultNightMode( + AppCompatDelegate.MODE_NIGHT_YES); + } else if (getBoolean("light_theme", false, context)) { + AppCompatDelegate.setDefaultNightMode( + AppCompatDelegate.MODE_NIGHT_NO); + } else { + AppCompatDelegate.setDefaultNightMode( + AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM); + } } - public static boolean isDownloadBinaries() { - return Utils.existFile("/system/bin/curl") || Utils.existFile("/system/bin/wget"); + public static boolean isDarkTheme(Context context) { + int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + return currentNightMode == Configuration.UI_MODE_NIGHT_YES; } - static void downloadFile(String path, String url) { - if (isDownloadBinaries()) { - RootUtils.runCommand((Utils.existFile("/system/bin/curl") ? - "curl -L -o " : "wget -O ") + path + " " + url); - } else { - /* - * Based on the following stackoverflow discussion - * Ref: https://stackoverflow.com/questions/15758856/android-how-to-download-file-from-webserver - */ - try (InputStream input = new URL(url).openStream(); - OutputStream output = new FileOutputStream(path)) { - byte[] data = new byte[4096]; - int count; - while ((count = input.read(data)) != -1) { - output.write(data, 0, count); - } + public static void create(String text, String path) { + if (path.startsWith("/storage/") || path.contains(BuildConfig.APPLICATION_ID)) { + try { + File mFile = new File(path); + mFile.createNewFile(); + FileOutputStream fOut = new FileOutputStream(mFile); + OutputStreamWriter myOutWriter = + new OutputStreamWriter(fOut); + myOutWriter.append(text); + myOutWriter.close(); + fOut.close(); } catch (Exception ignored) { } + } else { + runCommand("echo '" + text + "' > " + path); } } - public static String readFile(String file) { - return readFile(file, true); - } - - private static String readFile(String file, boolean root) { - if (root) { - return new RootFile(file).readFile(); + public static void delete(String path) { + if (path.startsWith("/storage/") || path.contains(BuildConfig.APPLICATION_ID)) { + new File(path).delete(); + } else { + runCommand("rm -r " + path); } + } - BufferedReader buf = null; - try { - buf = new BufferedReader(new FileReader(file)); + public static void chmod(String permission, String path) { + runCommand("chmod " + permission + " " + path); + } - StringBuilder stringBuilder = new StringBuilder(); - String line; - while ((line = buf.readLine()) != null) { - stringBuilder.append(line).append("\n"); - } + public static void snackbar(View view, String message) { + Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_LONG); + snackbar.setAction(R.string.dismiss, v -> snackbar.dismiss()); + snackbar.show(); + } - return stringBuilder.toString().trim(); - } catch (IOException ignored) { - } finally { + public static void launchUrl(String url, Activity activity) { + if (isNetworkUnavailable(activity)) { + snackbar(activity.findViewById(android.R.id.content), activity.getString(R.string.no_internet)); + } else { try { - if (buf != null) buf.close(); - } catch (IOException e) { + Intent i = new Intent(Intent.ACTION_VIEW); + i.setData(Uri.parse(url)); + activity.startActivity(i); + } catch (ActivityNotFoundException e) { e.printStackTrace(); } } - return null; } - public static boolean existFile(String file) { - return existFile(file, true); + public static int getOrientation(Activity activity) { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && activity.isInMultiWindowMode() ? + Configuration.ORIENTATION_PORTRAIT : activity.getResources().getConfiguration().orientation; } - private static boolean existFile(String file, boolean root) { - return !root ? new File(file).exists() : new RootFile(file).exists(); + public static boolean isTablet(Context context) { + return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) + >= Configuration.SCREENLAYOUT_SIZE_LARGE; + } + + public static String read(String file) { + if (!file.startsWith("/storage/")) { + return runAndGetOutput("cat '" + file + "'"); + } else { + try(BufferedReader br = new BufferedReader(new FileReader(file))) { + StringBuilder sb = new StringBuilder(); + String line = br.readLine(); + while (line != null) { + sb.append(line); + sb.append(System.lineSeparator()); + line = br.readLine(); + } + return sb.toString(); + } catch (IOException ignored) { + } + return null; + } + } + + public static boolean exist(String file) { + if (!file.startsWith("/storage/")) { + String output = runAndGetOutput("[ -e " + file + " ] && echo true"); + return !output.isEmpty() && output.equals("true"); + } else { + return new File(file).exists(); + } } public static boolean isNetworkUnavailable(Context context) { @@ -342,34 +384,33 @@ public static String getExtension(String string) { return android.webkit.MimeTypeMap.getFileExtensionFromUrl(string); } - /* - * Taken and used almost as such from https://github.com/morogoku/MTweaks-KernelAdiutorMOD/ - * Ref: https://github.com/morogoku/MTweaks-KernelAdiutorMOD/blob/dd5a4c3242d5e1697d55c4cc6412a9b76c8b8e2e/app/src/main/java/com/moro/mtweaks/fragments/kernel/BoefflaWakelockFragment.java#L133 - */ - public static void WelcomeDialog(Context context) { - View checkBoxView = View.inflate(context, R.layout.rv_checkbox, null); - CheckBox checkBox = checkBoxView.findViewById(R.id.checkbox); - checkBox.setChecked(true); - checkBox.setText(context.getString(R.string.always_show)); - checkBox.setOnCheckedChangeListener((buttonView, isChecked) - -> mWelcomeDialog = isChecked); - - new Dialog(Objects.requireNonNull(context)) - .setIcon(R.mipmap.ic_launcher) - .setTitle(context.getString(R.string.app_name)) - .setMessage(context.getText(R.string.welcome_message)) - .setCancelable(false) - .setView(checkBoxView) - .setNeutralButton(context.getString(R.string.examples), (dialog, id) -> { - Utils.launchUrl("https://github.com/SmartPack/ScriptManager/tree/master/examples", context); - }) - .setPositiveButton(context.getString(R.string.got_it), (dialog, id) - -> Prefs.saveBoolean("welcomeMessage", mWelcomeDialog, context)) - - .show(); - } - - private static String readAssetFile(Context context, String file) { + public static void fabMenu(FloatingActionButton button, Activity activity) { + PopupMenu popupMenu = new PopupMenu(activity, button); + Menu menu = popupMenu.getMenu(); + menu.add(Menu.NONE, 0, Menu.NONE, activity.getString(R.string.create)); + menu.add(Menu.NONE, 1, Menu.NONE, activity.getString(R.string.import_item)); + popupMenu.setOnMenuItemClickListener(item -> { + switch (item.getItemId()) { + case 0: + Scripts.createScript(activity); + break; + case 1: + if (Utils.getBoolean("use_file_picker", true, activity)) { + Intent filePicker = new Intent(activity, FilePickerActivity.class); + activity.startActivity(filePicker); + } else { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("*/*"); + activity.startActivityForResult(intent, 0); + } + break; + } + return false; + }); + popupMenu.show(); + } + + public static String readAssetFile(Context context, String file) { InputStream input = null; BufferedReader buf = null; try { @@ -394,87 +435,27 @@ private static String readAssetFile(Context context, String file) { return null; } - @SuppressLint("SetTextI18n") - public static void aboutDialogue(Context context) { - mCardTitle.setText(R.string.about); - mAppName.setText(context.getString(R.string.app_name) + " v" + BuildConfig.VERSION_NAME); - mCredits.setText(context.getString(R.string.credits_summary)); - mCardTitle.setVisibility(View.VISIBLE); - mBack.setVisibility(View.VISIBLE); - mAppIcon.setVisibility(View.VISIBLE); - mAppName.setVisibility(View.VISIBLE); - mAboutApp.setVisibility(View.VISIBLE); - mCreditsTitle.setVisibility(View.VISIBLE); - mCredits.setVisibility(View.VISIBLE); - mCancel.setVisibility(View.VISIBLE); - mForegroundActive = true; - mForegroundCard.setVisibility(View.VISIBLE); - } - - @SuppressLint("SetTextI18n") - public static void changeLogs(Context context) { - String change_log = null; - try { - change_log = new JSONObject(Objects.requireNonNull(readAssetFile( - context, "update_info.json"))).getString("changelogFull"); - } catch (JSONException ignored) { - } - mCardTitle.setText(R.string.change_log); - mAppName.setText(context.getString(R.string.app_name) + " v" + BuildConfig.VERSION_NAME); - mForegroundText.setText(change_log); - mBack.setVisibility(View.VISIBLE); - mCardTitle.setVisibility(View.VISIBLE); - mAppIcon.setVisibility(View.VISIBLE); - mAppName.setVisibility(View.VISIBLE); - mForegroundText.setVisibility(View.VISIBLE); - mCancel.setVisibility(View.VISIBLE); - mForegroundActive = true; - mForegroundCard.setVisibility(View.VISIBLE); - } - - public static void closeForeground() { - mCardTitle.setVisibility(View.GONE); - mBack.setVisibility(View.GONE); - mAppIcon.setVisibility(View.GONE); - mAppName.setVisibility(View.GONE); - mAboutApp.setVisibility(View.GONE); - mCreditsTitle.setVisibility(View.GONE); - mCredits.setVisibility(View.GONE); - mForegroundText.setVisibility(View.GONE); - mCancel.setVisibility(View.GONE); - mForegroundCard.setVisibility(View.GONE); - mForegroundActive = false; - } - - public static boolean languageDefault(Context context) { - return !Prefs.getBoolean("use_en", false, context) - && !Prefs.getBoolean("use_ko", false, context) - && !Prefs.getBoolean("use_in", false, context) - && !Prefs.getBoolean("use_am", false, context) - && !Prefs.getBoolean("use_el", false, context) - && !Prefs.getBoolean("use_pt", false, context); - } - - public static String getLang(Context context) { - if (Prefs.getBoolean("use_en", false, context)) { - return "en_US"; - } else if (Prefs.getBoolean("use_ko", false, context)) { - return "ko"; - } else if (Prefs.getBoolean("use_in", false, context)) { - return "in"; - } else if (Prefs.getBoolean("use_am", false, context)) { - return "am"; - } else if (Prefs.getBoolean("use_el", false, context)) { - return "el"; - } else if (Prefs.getBoolean("use_pt", false, context)) { - return "pt"; - } else { - return java.util.Locale.getDefault().getLanguage(); - } + public static int getSpanCount(Activity activity) { + int span = isTablet(activity) ? getOrientation(activity) == + Configuration.ORIENTATION_LANDSCAPE ? 4 : 3 : getOrientation(activity) == + Configuration.ORIENTATION_LANDSCAPE ? 3 : 2; + return span; + } + + public static void restartApp(Context context) { + Intent intent = new Intent(context, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + context.startActivity(intent); + } + + public static String getLanguage(Context context) { + return getString("appLanguage", java.util.Locale.getDefault().getLanguage(), + context); } public static void setLanguage(Context context) { - Locale myLocale = new Locale(getLang(context)); + Locale myLocale = new Locale(getString("appLanguage", java.util.Locale.getDefault() + .getLanguage(), context)); Resources res = context.getResources(); DisplayMetrics dm = res.getDisplayMetrics(); Configuration conf = res.getConfiguration(); diff --git a/app/src/main/java/com/smartpack/scriptmanager/utils/ViewUtils.java b/app/src/main/java/com/smartpack/scriptmanager/utils/ViewUtils.java deleted file mode 100644 index a7042e9..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/utils/ViewUtils.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2020-2021 sunilpaulmathew - * - * This file is part of Script Manager, an app to create, import, edit - * and easily execute any properly formatted shell scripts. - * - */ - -package com.smartpack.scriptmanager.utils; - -import android.content.Context; -import android.content.DialogInterface; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.ViewGroup; -import android.widget.LinearLayout; - -import androidx.appcompat.widget.AppCompatEditText; -import androidx.fragment.app.DialogFragment; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; - -import com.smartpack.scriptmanager.R; -import com.smartpack.scriptmanager.views.dialog.Dialog; - -/* - * Created by sunilpaulmathew on January 12, 2020 - * Based on the original implementation on Kernel Adiutor by - * Willi Ye - */ - -public class ViewUtils { - - public static Drawable getSelectableBackground(Context context) { - TypedArray typedArray = context.obtainStyledAttributes(new int[]{R.attr.selectableItemBackground}); - Drawable drawable = typedArray.getDrawable(0); - typedArray.recycle(); - return drawable; - } - - public static void showDialog(FragmentManager manager, DialogFragment fragment) { - FragmentTransaction ft = manager.beginTransaction(); - Fragment prev = manager.findFragmentByTag("dialog"); - if (prev != null) { - ft.remove(prev); - } - ft.addToBackStack(null); - - fragment.show(ft, "dialog"); - } - - public static void dismissDialog(FragmentManager manager) { - FragmentTransaction ft = manager.beginTransaction(); - Fragment fragment = manager.findFragmentByTag("dialog"); - if (fragment != null) { - ft.remove(fragment).commit(); - } - } - - public static int getColorPrimaryColor(Context context) { - TypedValue value = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true); - return value.data; - } - - public static int getThemeAccentColor(Context context) { - TypedValue value = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.colorAccent, value, true); - return value.data; - } - - public interface OnDialogEditTextListener { - void onClick(String text); - } - - public static Dialog dialogEditText(String text, final DialogInterface.OnClickListener negativeListener, - final OnDialogEditTextListener onDialogEditTextListener, - Context context) { - return dialogEditText(text, negativeListener, onDialogEditTextListener, -1, context); - } - - public static Dialog dialogEditText(String text, final DialogInterface.OnClickListener negativeListener, - final OnDialogEditTextListener onDialogEditTextListener, int inputType, - Context context) { - LinearLayout layout = new LinearLayout(context); - int padding = (int) context.getResources().getDimension(R.dimen.dialog_padding); - layout.setPadding(padding, padding, padding, padding); - - final AppCompatEditText editText = new AppCompatEditText(context); - editText.setGravity(Gravity.CENTER); - editText.setLayoutParams(new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - if (text != null) { - editText.append(text); - } - editText.setSingleLine(true); - if (inputType >= 0) { - editText.setInputType(inputType); - } - - layout.addView(editText); - - Dialog dialog = new Dialog(context).setView(layout); - if (negativeListener != null) { - dialog.setNegativeButton(context.getString(R.string.cancel), negativeListener); - } - if (onDialogEditTextListener != null) { - dialog.setPositiveButton(context.getString(R.string.ok), (dialog1, which) - -> onDialogEditTextListener.onClick(editText.getText().toString())) - .setOnDismissListener(dialog1 -> { - if (negativeListener != null) { - negativeListener.onClick(dialog1, 0); - } - }); - } - return dialog; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/utils/root/RootFile.java b/app/src/main/java/com/smartpack/scriptmanager/utils/root/RootFile.java deleted file mode 100644 index 68cb68f..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/utils/root/RootFile.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2020-2021 sunilpaulmathew - * - * This file is part of Script Manager, an app to create, import, edit - * and easily execute any properly formatted shell scripts. - * - */ - -package com.smartpack.scriptmanager.utils.root; - -import androidx.annotation.NonNull; - -import com.smartpack.scriptmanager.utils.Utils; -import com.topjohnwu.superuser.Shell; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -/* - * Created by sunilpaulmathew on January 12, 2020 - * Based on the original implementation on Kernel Adiutor by - * Willi Ye - */ - -public class RootFile { - - private final String mFile; - - public RootFile(String file) { - mFile = file; - } - - public String getName() { - return new File(mFile).getName(); - } - - public void mkdir() { - Shell.su("mkdir -p '" + mFile + "'").exec(); - } - - public void write(String text, boolean append) { - String[] array = text.split("\\r?\\n"); - if (!append) delete(); - for (String line : array) { - Shell.su("echo '" + line + "' >> " + mFile).exec(); - } - RootUtils.chmod(mFile, "755"); - } - - public void execute(String... arguments) { - StringBuilder args = new StringBuilder(); - for (String arg : arguments) { - args.append(" \"").append(arg).append("\""); - } - RootUtils.runCommand(mFile + args.toString()); - } - - public void delete() { - Shell.su("rm -r '" + mFile + "'").exec(); - } - - public List list() { - List list = new ArrayList<>(); - String files = RootUtils.runAndGetOutput("ls '" + mFile + "/'"); - if (!files.isEmpty()) { - // Make sure the files exists - for (String file : files.split("\\r?\\n")) { - if (file != null && !file.isEmpty() && Utils.existFile(mFile + "/" + file)) { - list.add(file); - } - } - } - return list; - } - - public boolean exists() { - String output = RootUtils.runAndGetOutput("[ -e " + mFile + " ] && echo true"); - return !output.isEmpty() && output.equals("true"); - } - - public String readFile() { - return RootUtils.runAndGetOutput("cat '" + mFile + "'"); - } - - @NonNull - @Override - public String toString() { - return mFile; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/utils/root/RootUtils.java b/app/src/main/java/com/smartpack/scriptmanager/utils/root/RootUtils.java deleted file mode 100644 index 556b6e4..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/utils/root/RootUtils.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2020-2021 sunilpaulmathew - * - * This file is part of Script Manager, an app to create, import, edit - * and easily execute any properly formatted shell scripts. - * - */ - -package com.smartpack.scriptmanager.utils.root; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.smartpack.scriptmanager.BuildConfig; -import com.topjohnwu.superuser.Shell; -import com.topjohnwu.superuser.ShellUtils; - -import java.util.ArrayList; -import java.util.List; - -/* - * Created by sunilpaulmathew on January 12, 2020 - * Based on the original implementation on Kernel Adiutor by - * Willi Ye - */ - -public class RootUtils { - - static { - /* Shell.Config methods shall be called before any shell is created - * This is the why in this example we call it in a static block - * The followings are some examples, check Javadoc for more details */ - - //Shell.Config.setFlags(Shell.FLAG_REDIRECT_STDERR); (not yet, make it optional cuz it may break current stuff) - Shell.Config.verboseLogging(BuildConfig.DEBUG); - Shell.Config.setTimeout(10); - } - - public static boolean rootAccess() { - return Shell.rootAccess(); - } - - static void chmod(String file, String permission) { - Shell.su("chmod " + permission + " " + file).submit(); - } - - public static void runCommand(String command) { - Shell.su(command).exec(); - } - - @NonNull - static String runAndGetOutput(String command) { - StringBuilder sb = new StringBuilder(); - try { - List outputs = Shell.su(command).exec().getOut(); - if (ShellUtils.isValidOutput(outputs)) { - for (String output : outputs) { - sb.append(output).append("\n"); - } - } - return removeSuffix(sb.toString()).trim(); - } catch (Exception e) { - return ""; - } - } - - @NonNull - public static String runAndGetError(String command) { - StringBuilder sb = new StringBuilder(); - List outputs = new ArrayList<>(); - List stderr = new ArrayList<>(); - try { - Shell.su(command).to(outputs, stderr).exec(); - outputs.addAll(stderr); - if (ShellUtils.isValidOutput(outputs)) { - for (String output : outputs) { - sb.append(output).append("\n"); - } - } - return removeSuffix(sb.toString()).trim(); - } catch (Exception e) { - return ""; - } - } - - private static String removeSuffix(@Nullable String s) { - if (s != null && s.endsWith("\n")) { - return s.substring(0, s.length() - "\n".length()); - } - return s; - } - - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/viewpagerindicator/CirclePageIndicator.java b/app/src/main/java/com/smartpack/scriptmanager/viewpagerindicator/CirclePageIndicator.java deleted file mode 100644 index 21b776a..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/viewpagerindicator/CirclePageIndicator.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright (C) 2011 Patrik Akerfeldt - * Copyright (C) 2011 Jake Wharton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.smartpack.scriptmanager.viewpagerindicator; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Paint.Style; -import android.graphics.drawable.Drawable; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; - -import androidx.core.content.ContextCompat; -import androidx.core.view.MotionEventCompat; -import androidx.core.view.ViewConfigurationCompat; -import androidx.viewpager.widget.ViewPager; - -import com.smartpack.scriptmanager.R; - -import java.util.Objects; - -import static android.graphics.Paint.ANTI_ALIAS_FLAG; -import static android.widget.LinearLayout.HORIZONTAL; -import static android.widget.LinearLayout.VERTICAL; - -/** - * Draws circles (one for each view). The current view position is filled and - * others are only stroked. - */ -public class CirclePageIndicator extends View implements PageIndicator { - private static final int INVALID_POINTER = -1; - - private float mRadius; - private final Paint mPaintPageFill = new Paint(ANTI_ALIAS_FLAG); - private final Paint mPaintStroke = new Paint(ANTI_ALIAS_FLAG); - private final Paint mPaintFill = new Paint(ANTI_ALIAS_FLAG); - private ViewPager mViewPager; - private ViewPager.OnPageChangeListener mListener; - private int mCurrentPage; - private int mSnapPage; - private float mPageOffset; - private int mScrollState; - private int mOrientation; - private boolean mCentered; - private boolean mSnap; - - private int mTouchSlop; - private float mLastMotionX = -1; - private int mActivePointerId = INVALID_POINTER; - private boolean mIsDragging; - private float mExtraSpacing; - - public CirclePageIndicator(Context context) { - this(context, null); - } - - public CirclePageIndicator(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public CirclePageIndicator(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - if (isInEditMode()) return; - - //Load defaults from resources - Resources res = getResources(); - final int defaultPageColor = ContextCompat.getColor(getContext(), R.color.default_circle_indicator_page_color); - final int defaultFillColor = ContextCompat.getColor(getContext(), R.color.default_circle_indicator_fill_color); - final int defaultOrientation = res.getInteger(R.integer.default_circle_indicator_orientation); - final int defaultStrokeColor = ContextCompat.getColor(getContext(), R.color.default_circle_indicator_stroke_color); - final float defaultExtraSpacing = res.getDimension(R.dimen.default_circle_indicator_extra_spacing); - final float defaultStrokeWidth = res.getDimension(R.dimen.default_circle_indicator_stroke_width); - final float defaultRadius = res.getDimension(R.dimen.default_circle_indicator_radius); - final boolean defaultCentered = res.getBoolean(R.bool.default_circle_indicator_centered); - final boolean defaultSnap = res.getBoolean(R.bool.default_circle_indicator_snap); - - //Retrieve styles attributes - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePageIndicator, defStyle, 0); - - mCentered = a.getBoolean(R.styleable.CirclePageIndicator_centered, defaultCentered); - mOrientation = a.getInt(R.styleable.CirclePageIndicator_android_orientation, defaultOrientation); - mPaintPageFill.setStyle(Style.FILL); - mPaintPageFill.setColor(a.getColor(R.styleable.CirclePageIndicator_pageColor, defaultPageColor)); - mPaintStroke.setStyle(Style.STROKE); - mPaintStroke.setColor(a.getColor(R.styleable.CirclePageIndicator_strokeColor, defaultStrokeColor)); - mPaintStroke.setStrokeWidth(a.getDimension(R.styleable.CirclePageIndicator_strokeWidth, defaultStrokeWidth)); - mPaintFill.setStyle(Style.FILL); - mPaintFill.setColor(a.getColor(R.styleable.CirclePageIndicator_fillColor, defaultFillColor)); - mRadius = a.getDimension(R.styleable.CirclePageIndicator_radius, defaultRadius); - mSnap = a.getBoolean(R.styleable.CirclePageIndicator_snap, defaultSnap); - mExtraSpacing = a.getDimension(R.styleable.CirclePageIndicator_extraSpacing, defaultExtraSpacing); - - Drawable background = a.getDrawable(R.styleable.CirclePageIndicator_android_background); - if (background != null) { - setBackgroundDrawable(background); - } - - a.recycle(); - - final ViewConfiguration configuration = ViewConfiguration.get(context); - mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - if (mViewPager == null) { - return; - } - final int count = Objects.requireNonNull(mViewPager.getAdapter()).getCount(); - if (count < 2) { - return; - } - - if (mCurrentPage >= count) { - setCurrentItem(count - 1); - return; - } - - int longSize; - int longPaddingBefore; - int longPaddingAfter; - int shortPaddingBefore; - if (mOrientation == HORIZONTAL) { - longSize = getWidth(); - longPaddingBefore = getPaddingLeft(); - longPaddingAfter = getPaddingRight(); - shortPaddingBefore = getPaddingTop(); - } else { - longSize = getHeight(); - longPaddingBefore = getPaddingTop(); - longPaddingAfter = getPaddingBottom(); - shortPaddingBefore = getPaddingLeft(); - } - - final float threeRadius = mRadius * 2 + mExtraSpacing; - final float shortOffset = shortPaddingBefore + mRadius; - float longOffset = longPaddingBefore + mRadius; - if (mCentered) { - final float circleSize = mRadius * 2; - final float width = count * circleSize + ((count - 1) * mExtraSpacing); - longOffset += ((longSize - longPaddingBefore - longPaddingAfter) / 2.0f) - (width / 2.0f); - } - - float dX; - float dY; - - float pageFillRadius = mRadius; - if (mPaintStroke.getStrokeWidth() > 0) { - pageFillRadius -= mPaintStroke.getStrokeWidth() / 2.0f; - } - - //Draw stroked circles - for (int iLoop = 0; iLoop < count; iLoop++) { - float drawLong = longOffset + (iLoop * threeRadius); - if (mOrientation == HORIZONTAL) { - dX = drawLong; - dY = shortOffset; - } else { - dX = shortOffset; - dY = drawLong; - } - // Only paint fill if not completely transparent - if (mPaintPageFill.getAlpha() > 0) { - canvas.drawCircle(dX, dY, pageFillRadius, mPaintPageFill); - } - - // Only paint stroke if a stroke width was non-zero - if (pageFillRadius != mRadius) { - canvas.drawCircle(dX, dY, mRadius, mPaintFill); - } - } - - //Draw the filled circle according to the current scroll - float cx = (mSnap ? mSnapPage : mCurrentPage) * threeRadius; - if (!mSnap) { - cx += mPageOffset * threeRadius; - } - if (mOrientation == HORIZONTAL) { - dX = longOffset + cx; - dY = shortOffset; - } else { - dX = shortOffset; - dY = longOffset + cx; - } - canvas.drawCircle(dX, dY, mRadius * 1.5f, mPaintFill); - } - - @SuppressLint("ClickableViewAccessibility") - public boolean onTouchEvent(android.view.MotionEvent ev) { - if (super.onTouchEvent(ev)) { - return true; - } - if ((mViewPager == null) || (Objects.requireNonNull(mViewPager.getAdapter()).getCount() == 0)) { - return false; - } - - final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; - switch (action) { - case MotionEvent.ACTION_DOWN: - mActivePointerId = MotionEventCompat.getPointerId(ev, 0); - mLastMotionX = ev.getX(); - break; - - case MotionEvent.ACTION_MOVE: { - final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); - final float x = MotionEventCompat.getX(ev, activePointerIndex); - final float deltaX = x - mLastMotionX; - - if (!mIsDragging) { - if (Math.abs(deltaX) > mTouchSlop) { - mIsDragging = true; - } - } - - if (mIsDragging) { - mLastMotionX = x; - if (mViewPager.isFakeDragging() || mViewPager.beginFakeDrag()) { - mViewPager.fakeDragBy(deltaX); - } - } - - break; - } - - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - if (!mIsDragging) { - final int count = mViewPager.getAdapter().getCount(); - final int width = getWidth(); - final float halfWidth = width / 2f; - final float sixthWidth = width / 6f; - - if ((mCurrentPage > 0) && (ev.getX() < halfWidth - sixthWidth)) { - if (action != MotionEvent.ACTION_CANCEL) { - mViewPager.setCurrentItem(mCurrentPage - 1); - } - return true; - } else if ((mCurrentPage < count - 1) && (ev.getX() > halfWidth + sixthWidth)) { - if (action != MotionEvent.ACTION_CANCEL) { - mViewPager.setCurrentItem(mCurrentPage + 1); - } - return true; - } - } - - mIsDragging = false; - mActivePointerId = INVALID_POINTER; - if (mViewPager.isFakeDragging()) mViewPager.endFakeDrag(); - break; - - case MotionEventCompat.ACTION_POINTER_DOWN: { - final int index = MotionEventCompat.getActionIndex(ev); - mLastMotionX = MotionEventCompat.getX(ev, index); - mActivePointerId = MotionEventCompat.getPointerId(ev, index); - break; - } - - case MotionEventCompat.ACTION_POINTER_UP: - final int pointerIndex = MotionEventCompat.getActionIndex(ev); - final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); - if (pointerId == mActivePointerId) { - final int newPointerIndex = pointerIndex == 0 ? 1 : 0; - mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); - } - mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId)); - break; - } - - return true; - } - - @Override - public void setViewPager(ViewPager view) { - if (mViewPager == view) { - return; - } - if (mViewPager != null) { - mViewPager.removeOnPageChangeListener(this); - } - if (view.getAdapter() == null) { - throw new IllegalStateException("ViewPager does not have adapter instance."); - } - mViewPager = view; - mViewPager.addOnPageChangeListener(this); - invalidate(); - } - - @Override - public void setViewPager(ViewPager view, int initialPosition) { - setViewPager(view); - setCurrentItem(initialPosition); - } - - @Override - public void setCurrentItem(int item) { - if (mViewPager == null) { - throw new IllegalStateException("ViewPager has not been bound."); - } - mViewPager.setCurrentItem(item); - mCurrentPage = item; - invalidate(); - } - - @Override - public void notifyDataSetChanged() { - invalidate(); - } - - @Override - public void onPageScrollStateChanged(int state) { - mScrollState = state; - - if (mListener != null) { - mListener.onPageScrollStateChanged(state); - } - } - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - mCurrentPage = position; - mPageOffset = positionOffset; - invalidate(); - - if (mListener != null) { - mListener.onPageScrolled(position, positionOffset, positionOffsetPixels); - } - } - - @Override - public void onPageSelected(int position) { - if (mSnap || mScrollState == ViewPager.SCROLL_STATE_IDLE) { - mCurrentPage = position; - mSnapPage = position; - invalidate(); - } - - if (mListener != null) { - mListener.onPageSelected(position); - } - } - - @Override - public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { - mListener = listener; - } - - /* - * (non-Javadoc) - * - * @see android.view.View#onMeasure(int, int) - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (mOrientation == HORIZONTAL) { - setMeasuredDimension(measureLong(widthMeasureSpec), measureShort(heightMeasureSpec)); - } else { - setMeasuredDimension(measureShort(widthMeasureSpec), measureLong(heightMeasureSpec)); - } - } - - /** - * Determines the width of this view - * - * @param measureSpec A measureSpec packed into an int - * @return The width of the view, honoring constraints from measureSpec - */ - private int measureLong(int measureSpec) { - int result; - int specMode = MeasureSpec.getMode(measureSpec); - int specSize = MeasureSpec.getSize(measureSpec); - - if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)) { - //We were told how big to be - result = specSize; - } else { - //Calculate the width according the views count - final int count = Objects.requireNonNull(mViewPager.getAdapter()).getCount(); - result = (int) (getPaddingLeft() + getPaddingRight() - + (count * 2 * mRadius) + (count - 1) * (mRadius + mExtraSpacing) + 1); - //Respect AT_MOST value if that was what is called for by measureSpec - if (specMode == MeasureSpec.AT_MOST) { - result = Math.min(result, specSize); - } - } - return result; - } - - /** - * Determines the height of this view - * - * @param measureSpec A measureSpec packed into an int - * @return The height of the view, honoring constraints from measureSpec - */ - private int measureShort(int measureSpec) { - int result; - int specMode = MeasureSpec.getMode(measureSpec); - int specSize = MeasureSpec.getSize(measureSpec); - - if (specMode == MeasureSpec.EXACTLY) { - //We were told how big to be - result = specSize; - } else { - //Measure the height - result = (int) (2 * mRadius + getPaddingTop() + getPaddingBottom() + 1); - //Respect AT_MOST value if that was what is called for by measureSpec - if (specMode == MeasureSpec.AT_MOST) { - result = Math.min(result, specSize); - } - } - return result; - } - - @Override - public void onRestoreInstanceState(Parcelable state) { - SavedState savedState = (SavedState) state; - super.onRestoreInstanceState(savedState.getSuperState()); - mCurrentPage = savedState.currentPage; - mSnapPage = savedState.currentPage; - requestLayout(); - } - - @Override - public Parcelable onSaveInstanceState() { - Parcelable superState = super.onSaveInstanceState(); - SavedState savedState = new SavedState(superState); - savedState.currentPage = mCurrentPage; - return savedState; - } - - static class SavedState extends BaseSavedState { - int currentPage; - - SavedState(Parcelable superState) { - super(superState); - } - - private SavedState(Parcel in) { - super(in); - currentPage = in.readInt(); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeInt(currentPage); - } - - @SuppressWarnings("UnusedDeclaration") - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - @Override - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } - - @Override - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/viewpagerindicator/PageIndicator.java b/app/src/main/java/com/smartpack/scriptmanager/viewpagerindicator/PageIndicator.java deleted file mode 100644 index 7c98c63..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/viewpagerindicator/PageIndicator.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2011 Patrik Akerfeldt - * Copyright (C) 2011 Jake Wharton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.smartpack.scriptmanager.viewpagerindicator; - -import androidx.viewpager.widget.ViewPager; - -/** - * A PageIndicator is responsible to show an visual indicator on the total views - * number and the current visible view. - */ -public interface PageIndicator extends ViewPager.OnPageChangeListener { - /** - * Bind the indicator to a ViewPager. - * - * @param view - */ - void setViewPager(ViewPager view); - - /** - * Bind the indicator to a ViewPager. - * - * @param view - * @param initialPosition - */ - void setViewPager(ViewPager view, int initialPosition); - - /** - *

Set the current page of both the ViewPager and indicator.

- *

- *

This must be used if you need to set the page before - * the views are drawn on screen (e.g., default start page).

- * - * @param item - */ - void setCurrentItem(int item); - - /** - * Set a page change listener which will receive forwarded events. - * - * @param listener - */ - void setOnPageChangeListener(ViewPager.OnPageChangeListener listener); - - /** - * Notify the indicator that the fragment list has changed. - */ - void notifyDataSetChanged(); -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/views/BorderCircleView.java b/app/src/main/java/com/smartpack/scriptmanager/views/BorderCircleView.java deleted file mode 100644 index 6ce298f..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/views/BorderCircleView.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.smartpack.scriptmanager.views; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.util.SparseArray; -import android.widget.FrameLayout; - -import androidx.core.content.ContextCompat; -import androidx.core.graphics.drawable.DrawableCompat; - -import com.smartpack.scriptmanager.R; -import com.smartpack.scriptmanager.utils.ViewUtils; - -/** - * Adapted from https://github.com/Grarak/KernelAdiutor by Willi Ye. - */ - -public class BorderCircleView extends FrameLayout { - - private final Drawable mCheck; - private final Paint mPaint; - private final Paint mPaintBorder; - - public BorderCircleView(Context context) { - this(context, null); - } - - public BorderCircleView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public BorderCircleView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - - if (isClickable()) { - setForeground(ViewUtils.getSelectableBackground(context)); - } - mCheck = ContextCompat.getDrawable(context, R.drawable.ic_done); - DrawableCompat.setTint(mCheck, Color.WHITE); - - mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mPaint.setColor(ViewUtils.getThemeAccentColor(context)); - - mPaintBorder = new Paint(Paint.ANTI_ALIAS_FLAG); - mPaintBorder.setColor(ViewUtils.getColorPrimaryColor(context)); - mPaintBorder.setStrokeWidth((int) getResources().getDimension(R.dimen.circleview_border)); - mPaintBorder.setStyle(Paint.Style.STROKE); - - setWillNotDraw(false); - } - - @Override - public void setBackgroundColor(int color) { - mPaint.setColor(color); - invalidate(); - } - - @Override - public void draw(Canvas canvas) { - super.draw(canvas); - - int width = getMeasuredWidth(); - int height = getMeasuredHeight(); - - float radius = Math.min(width, height) / 2f - 4f; - - canvas.drawCircle(width / 2, height / 2, radius, mPaint); - canvas.drawCircle(width / 2, height / 2, radius, mPaintBorder); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - - float desiredWidth = getResources().getDimension(R.dimen.circleview_width); - float desiredHeight = getResources().getDimension(R.dimen.circleview_height); - - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - float width; - float height; - - if (widthMode == MeasureSpec.EXACTLY) width = widthSize; - else if (widthMode == MeasureSpec.AT_MOST) width = Math.min(desiredWidth, widthSize); - else width = desiredWidth; - - if (heightMode == MeasureSpec.EXACTLY) height = heightSize; - else if (heightMode == MeasureSpec.AT_MOST) height = Math.min(desiredHeight, heightSize); - else height = desiredHeight; - - setMeasuredDimension((int) width, (int) height); - } -} diff --git a/app/src/main/java/com/smartpack/scriptmanager/views/dialog/Dialog.java b/app/src/main/java/com/smartpack/scriptmanager/views/dialog/Dialog.java deleted file mode 100644 index 77fdb62..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/views/dialog/Dialog.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.smartpack.scriptmanager.views.dialog; - -import android.app.AlertDialog; -import android.content.Context; -import android.database.Cursor; -import android.content.DialogInterface; -import android.view.View; -import android.view.WindowManager; - -import androidx.annotation.NonNull; - -/** - * Adapted from https://github.com/Grarak/KernelAdiutor by Willi Ye. - */ - -public class Dialog extends AlertDialog.Builder { - - private DialogInterface.OnDismissListener mOnDismissListener; - - public Dialog(@NonNull Context context) { - super(context); - } - - @Override - public Dialog setTitle(CharSequence title) { - return (Dialog) super.setTitle(title); - } - - @Override - public Dialog setTitle(int titleId) { - return (Dialog) super.setTitle(titleId); - } - - @Override - public Dialog setMessage(CharSequence message) { - return (Dialog) super.setMessage(message); - } - - @Override - public Dialog setMessage(int messageId) { - return (Dialog) super.setMessage(messageId); - } - - @Override - public Dialog setView(int layoutResId) { - return (Dialog) super.setView(layoutResId); - } - - @Override - public Dialog setView(View view) { - return (Dialog) super.setView(view); - } - - @Override - public Dialog setItems(CharSequence[] items, DialogInterface.OnClickListener listener) { - return (Dialog) super.setItems(items, listener); - } - - @Override - public Dialog setItems(int itemsId, DialogInterface.OnClickListener listener) { - return (Dialog) super.setItems(itemsId, listener); - } - - @Override - public Dialog setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) { - return (Dialog) super.setPositiveButton(text, listener); - } - - @Override - public Dialog setPositiveButton(int textId, DialogInterface.OnClickListener listener) { - return (Dialog) super.setPositiveButton(textId, listener); - } - - @Override - public Dialog setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) { - return (Dialog) super.setNegativeButton(text, listener); - } - - @Override - public Dialog setNegativeButton(int textId, DialogInterface.OnClickListener listener) { - return (Dialog) super.setNegativeButton(textId, listener); - } - - @Override - public Dialog setMultiChoiceItems(int itemsId, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener){ - return (Dialog) super.setMultiChoiceItems(itemsId, checkedItems, listener); - } - - @Override - public Dialog setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn, DialogInterface.OnMultiChoiceClickListener listener){ - return (Dialog) super.setMultiChoiceItems(cursor, isCheckedColumn, labelColumn, listener); - } - - @Override - public Dialog - setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener){ - return (Dialog) super.setMultiChoiceItems(items, checkedItems, listener); - } - - public Dialog setOnDismissListener(DialogInterface.OnDismissListener onDismissListener) { - mOnDismissListener = onDismissListener; - setOnCancelListener(dialogInterface -> { - if (mOnDismissListener != null) { - mOnDismissListener.onDismiss(dialogInterface); - } - }); - return this; - } - - @Override - public AlertDialog show() { - try { - AlertDialog dialog = create(); - dialog.setOnDismissListener(mOnDismissListener); - dialog.show(); - return dialog; - } catch (WindowManager.BadTokenException ignored) { - return create(); - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/views/dialog/ViewPagerDialog.java b/app/src/main/java/com/smartpack/scriptmanager/views/dialog/ViewPagerDialog.java deleted file mode 100644 index 2737e17..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/views/dialog/ViewPagerDialog.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.smartpack.scriptmanager.views.dialog; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; - -import androidx.annotation.Nullable; -import androidx.fragment.app.DialogFragment; -import androidx.fragment.app.Fragment; -import androidx.viewpager.widget.ViewPager; - -import com.smartpack.scriptmanager.R; -import com.smartpack.scriptmanager.fragments.RecyclerViewFragment; -import com.smartpack.scriptmanager.viewpagerindicator.CirclePageIndicator; - -import java.util.List; - -/** - * Adapted from https://github.com/Grarak/KernelAdiutor by Willi Ye. - */ - -public class ViewPagerDialog extends DialogFragment { - - public static ViewPagerDialog newInstance(int height, List fragments) { - ViewPagerDialog fragment = new ViewPagerDialog(); - fragment.mHeight = height; - fragment.mFragments = fragments; - return fragment; - } - - private int mHeight; - private List mFragments; - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setStyle(DialogFragment.STYLE_NO_TITLE, 0); - } - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.viewpager_view, container, false); - - ViewPager viewPager = rootView.findViewById(R.id.viewpager); - CirclePageIndicator indicator = rootView.findViewById(R.id.indicator); - viewPager.setAdapter(new RecyclerViewFragment.ViewPagerAdapter(getChildFragmentManager(), mFragments)); - indicator.setViewPager(viewPager); - - return rootView; - } - - @Override - public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver - .OnGlobalLayoutListener() { - public void onGlobalLayout() { - view.getViewTreeObserver().removeGlobalOnLayoutListener(this); - ViewGroup.LayoutParams params = view.getLayoutParams(); - params.height = mHeight; - view.requestLayout(); - } - }); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/views/recyclerview/DescriptionView.java b/app/src/main/java/com/smartpack/scriptmanager/views/recyclerview/DescriptionView.java deleted file mode 100644 index 4f25a74..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/views/recyclerview/DescriptionView.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.smartpack.scriptmanager.views.recyclerview; - -import android.graphics.drawable.Drawable; -import android.view.View; - -import androidx.appcompat.widget.AppCompatImageButton; -import androidx.appcompat.widget.AppCompatImageView; -import androidx.appcompat.widget.AppCompatTextView; -import androidx.appcompat.widget.PopupMenu; - -import com.smartpack.scriptmanager.R; -import com.smartpack.scriptmanager.utils.Utils; - -/** - * Adapted from https://github.com/Grarak/KernelAdiutor by Willi Ye. - */ - -public class DescriptionView extends RecyclerViewItem { - - public interface OnMenuListener { - void onMenuReady(DescriptionView cardView, PopupMenu popupMenu); - } - - private View mRootView; - private AppCompatImageButton mMenuIconView; - private AppCompatImageView mImageView; - private AppCompatTextView mTitleView; - private AppCompatTextView mSummaryView; - - private Drawable mImage; - private Drawable mMenuIcon; - private CharSequence mTitle; - private CharSequence mSummary; - private PopupMenu mPopupMenu; - private OnMenuListener mOnMenuListener; - - @Override - public int getLayoutRes() { - return R.layout.rv_description_view; - } - - @Override - public void onCreateView(View view) { - mRootView = view; - mImageView = view.findViewById(R.id.image); - mTitleView = view.findViewById(R.id.title); - mSummaryView = view.findViewById(R.id.summary); - - if (mTitleView != null) { - mTitleView.setOnFocusChangeListener((v, hasFocus) -> { - if (hasFocus) { - mRootView.requestFocus(); - } - }); - } - if (mSummaryView != null) { - mSummaryView.setOnFocusChangeListener((v, hasFocus) -> { - if (hasFocus) { - mRootView.requestFocus(); - } - }); - } - - mMenuIconView = view.findViewById(R.id.menu_icon); - mMenuIconView.setOnClickListener(v -> { - if (Utils.mForegroundActive) return; - if (mPopupMenu != null) { - mPopupMenu.show(); - } - }); - - super.onCreateView(view); - } - - public void setDrawable(Drawable drawable) { - mImage = drawable; - refresh(); - } - - public void setTitle(CharSequence title) { - mTitle = title; - refresh(); - } - - public void setSummary(CharSequence summary) { - mSummary = summary; - refresh(); - } - - public void setMenuIcon(Drawable menuIcon) { - mMenuIcon = menuIcon; - refresh(); - } - - public void setOnMenuListener(OnMenuListener onMenuListener) { - mOnMenuListener = onMenuListener; - refresh(); - } - - @Override - protected void refresh() { - super.refresh(); - if (mImageView != null && mImage != null) { - mImageView.setImageDrawable(mImage); - mImageView.setVisibility(View.VISIBLE); - } - if (mTitleView != null) { - if (mTitle != null) { - mTitleView.setText(mTitle); - } else { - mTitleView.setVisibility(View.GONE); - } - } - if (mSummaryView != null) { - if (mSummary != null) { - mSummaryView.setText(mSummary); - } else { - mSummaryView.setVisibility(View.GONE); - } - } - if (mMenuIconView != null && mMenuIcon != null && mOnMenuListener != null) { - mMenuIconView.setImageDrawable(mMenuIcon); - mMenuIconView.setVisibility(View.VISIBLE); - mPopupMenu = new PopupMenu(mMenuIconView.getContext(), mMenuIconView); - mOnMenuListener.onMenuReady(this, mPopupMenu); - } - if (mRootView != null && getOnItemClickListener() != null && mTitleView != null - && mSummaryView != null) { - mTitleView.setTextIsSelectable(false); - mSummaryView.setTextIsSelectable(false); - mRootView.setOnClickListener(v -> { - if (getOnItemClickListener() != null) { - getOnItemClickListener().onClick(DescriptionView.this); - } - }); - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/views/recyclerview/RecyclerViewAdapter.java b/app/src/main/java/com/smartpack/scriptmanager/views/recyclerview/RecyclerViewAdapter.java deleted file mode 100644 index ace84bc..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/views/recyclerview/RecyclerViewAdapter.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.smartpack.scriptmanager.views.recyclerview; - -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import com.smartpack.scriptmanager.R; -import com.smartpack.scriptmanager.utils.Prefs; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Adapted from https://github.com/Grarak/KernelAdiutor by Willi Ye. - */ - -public class RecyclerViewAdapter extends RecyclerView.Adapter { - - public interface OnViewChangedListener { - void viewChanged(); - } - - private final List mItems; - private final Map mViews = new HashMap<>(); - private OnViewChangedListener mOnViewChangedListener; - private View mFirstItem; - - public RecyclerViewAdapter(List items, OnViewChangedListener onViewChangedListener) { - mItems = items; - mOnViewChangedListener = onViewChangedListener; - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - RecyclerViewItem item = mItems.get(position); - item.onCreateView(holder.itemView); - } - - @Override - public int getItemCount() { - return mItems.size(); - } - - @Override - @NonNull - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - - RecyclerViewItem item = mItems.get(viewType); - View view; - if (item.cacheable()) { - if (mViews.containsKey(item)) { - view = mViews.get(item); - } else { - mViews.put(item, view = LayoutInflater.from(parent.getContext()) - .inflate(item.getLayoutRes(), parent, false)); - } - } else { - view = LayoutInflater.from(parent.getContext()) - .inflate(item.getLayoutRes(), parent, false); - } - assert view != null; - ViewGroup viewGroup = (ViewGroup) view.getParent(); - if (viewGroup != null) { - viewGroup.removeView(view); - } - if (item.cardCompatible() - && Prefs.getBoolean("forcecards", false, view.getContext())) { - androidx.cardview.widget.CardView cardView = new androidx.cardview.widget.CardView(view.getContext()); - cardView.setRadius(view.getResources().getDimension(R.dimen.cardview_radius)); - cardView.setCardElevation(view.getResources().getDimension(R.dimen.cardview_elevation)); - cardView.setUseCompatPadding(true); - cardView.setFocusable(false); - cardView.addView(view); - view = cardView; - } - if (viewType == item.getLayoutRes()) { - mFirstItem = view; - } - item.setOnViewChangeListener(mOnViewChangedListener); - item.onCreateHolder(); - - return new RecyclerView.ViewHolder(view) { - }; - } - - @Override - public int getItemViewType(int position) { - return position; - } - - public View getFirstItem() { - return mFirstItem; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/smartpack/scriptmanager/views/recyclerview/RecyclerViewItem.java b/app/src/main/java/com/smartpack/scriptmanager/views/recyclerview/RecyclerViewItem.java deleted file mode 100644 index 25233bd..0000000 --- a/app/src/main/java/com/smartpack/scriptmanager/views/recyclerview/RecyclerViewItem.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.smartpack.scriptmanager.views.recyclerview; - -import android.app.Activity; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.LayoutRes; -import androidx.recyclerview.widget.StaggeredGridLayoutManager; - -/** - * Adapted from https://github.com/Grarak/KernelAdiutor by Willi Ye. - */ - -public abstract class RecyclerViewItem { - - private boolean mFullspan; - private View mView; - - public interface OnItemClickListener { - void onClick(RecyclerViewItem item); - } - - private OnItemClickListener mOnItemClickListener; - - public void onCreateView(View view) { - mView = view; - fullSpan(mFullspan); - refresh(); - } - - @LayoutRes - public abstract int getLayoutRes(); - - public void onRecyclerViewCreate(Activity activity) { - } - - void onCreateHolder() { - } - - public void setOnItemClickListener(OnItemClickListener onItemClickListener) { - mOnItemClickListener = onItemClickListener; - } - - OnItemClickListener getOnItemClickListener() { - return mOnItemClickListener; - } - - void setOnViewChangeListener(RecyclerViewAdapter.OnViewChangedListener onViewChangeListener) { - } - - public void setFullSpan(boolean fullspan) { - mFullspan = fullspan; - fullSpan(fullspan); - } - - private void fullSpan(boolean fullspan) { - if (mView != null) { - StaggeredGridLayoutManager.LayoutParams layoutParams = - new StaggeredGridLayoutManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.setFullSpan(fullspan); - mView.setLayoutParams(layoutParams); - } - } - - protected void refresh() { - } - - public void onResume() { - } - - public void onPause() { - } - - public void onDestroy() { - } - - boolean cardCompatible() { - return true; - } - - boolean cacheable() { - return false; - } - -} \ No newline at end of file diff --git a/app/src/main/res/anim/slide_in_bottom.xml b/app/src/main/res/anim/slide_in_bottom.xml deleted file mode 100644 index b0a79f1..0000000 --- a/app/src/main/res/anim/slide_in_bottom.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_back.xml b/app/src/main/res/drawable/ic_back.xml index 827cde0..aabf889 100644 --- a/app/src/main/res/drawable/ic_back.xml +++ b/app/src/main/res/drawable/ic_back.xml @@ -1,9 +1,9 @@ - - + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" > + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_coffee.xml b/app/src/main/res/drawable/ic_coffee.xml new file mode 100644 index 0000000..aec45b0 --- /dev/null +++ b/app/src/main/res/drawable/ic_coffee.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_developer.png b/app/src/main/res/drawable/ic_developer.png new file mode 100644 index 0000000..02d4232 Binary files /dev/null and b/app/src/main/res/drawable/ic_developer.png differ diff --git a/app/src/main/res/drawable/ic_dinner.xml b/app/src/main/res/drawable/ic_dinner.xml new file mode 100644 index 0000000..8946439 --- /dev/null +++ b/app/src/main/res/drawable/ic_dinner.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_donate.xml b/app/src/main/res/drawable/ic_donate.xml new file mode 100644 index 0000000..ae6123d --- /dev/null +++ b/app/src/main/res/drawable/ic_donate.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_donation_app.png b/app/src/main/res/drawable/ic_donation_app.png new file mode 100644 index 0000000..8b6490d Binary files /dev/null and b/app/src/main/res/drawable/ic_donation_app.png differ diff --git a/app/src/main/res/drawable/ic_done.xml b/app/src/main/res/drawable/ic_done.xml deleted file mode 100644 index 1da8ef5..0000000 --- a/app/src/main/res/drawable/ic_done.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_dots.xml b/app/src/main/res/drawable/ic_dots.xml deleted file mode 100644 index 5176d8a..0000000 --- a/app/src/main/res/drawable/ic_dots.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_shell.xml b/app/src/main/res/drawable/ic_file.xml similarity index 100% rename from app/src/main/res/drawable/ic_shell.xml rename to app/src/main/res/drawable/ic_file.xml diff --git a/app/src/main/res/drawable/ic_flash.xml b/app/src/main/res/drawable/ic_flash.xml new file mode 100644 index 0000000..7f67045 --- /dev/null +++ b/app/src/main/res/drawable/ic_flash.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_folder.xml b/app/src/main/res/drawable/ic_folder.xml new file mode 100644 index 0000000..dc6b080 --- /dev/null +++ b/app/src/main/res/drawable/ic_folder.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_github.xml b/app/src/main/res/drawable/ic_github.xml new file mode 100644 index 0000000..0b8e16b --- /dev/null +++ b/app/src/main/res/drawable/ic_github.xml @@ -0,0 +1,6 @@ + + + diff --git a/app/src/main/res/drawable/ic_heart.xml b/app/src/main/res/drawable/ic_heart.xml new file mode 100644 index 0000000..e8a8c6a --- /dev/null +++ b/app/src/main/res/drawable/ic_heart.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_help.xml b/app/src/main/res/drawable/ic_help.xml deleted file mode 100644 index 2bdcfa3..0000000 --- a/app/src/main/res/drawable/ic_help.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_info.xml b/app/src/main/res/drawable/ic_info.xml index f52a15f..9ff8977 100644 --- a/app/src/main/res/drawable/ic_info.xml +++ b/app/src/main/res/drawable/ic_info.xml @@ -1,5 +1,5 @@ - - + + diff --git a/app/src/main/res/drawable/ic_issue.xml b/app/src/main/res/drawable/ic_issue.xml new file mode 100644 index 0000000..7853f61 --- /dev/null +++ b/app/src/main/res/drawable/ic_issue.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_language.xml b/app/src/main/res/drawable/ic_language.xml new file mode 100644 index 0000000..2662398 --- /dev/null +++ b/app/src/main/res/drawable/ic_language.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_preview.png b/app/src/main/res/drawable/ic_launcher_preview.png deleted file mode 100644 index 50e55db..0000000 Binary files a/app/src/main/res/drawable/ic_launcher_preview.png and /dev/null differ diff --git a/app/src/main/res/drawable/ic_licence.xml b/app/src/main/res/drawable/ic_licence.xml new file mode 100644 index 0000000..19fb425 --- /dev/null +++ b/app/src/main/res/drawable/ic_licence.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_meal.xml b/app/src/main/res/drawable/ic_meal.xml new file mode 100644 index 0000000..abbd39e --- /dev/null +++ b/app/src/main/res/drawable/ic_meal.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_path.xml b/app/src/main/res/drawable/ic_path.xml new file mode 100644 index 0000000..454bd7d --- /dev/null +++ b/app/src/main/res/drawable/ic_path.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_playstore.xml b/app/src/main/res/drawable/ic_playstore.xml new file mode 100644 index 0000000..1b54559 --- /dev/null +++ b/app/src/main/res/drawable/ic_playstore.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_rate.xml b/app/src/main/res/drawable/ic_rate.xml new file mode 100644 index 0000000..2f05b2c --- /dev/null +++ b/app/src/main/res/drawable/ic_rate.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_script.xml b/app/src/main/res/drawable/ic_script.xml new file mode 100644 index 0000000..c5874de --- /dev/null +++ b/app/src/main/res/drawable/ic_script.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml index 90be793..62584ed 100644 --- a/app/src/main/res/drawable/ic_settings.xml +++ b/app/src/main/res/drawable/ic_settings.xml @@ -1,5 +1,5 @@ - - + diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 0000000..4f902a1 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_support.xml b/app/src/main/res/drawable/ic_support.xml new file mode 100644 index 0000000..370121b --- /dev/null +++ b/app/src/main/res/drawable/ic_support.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_theme.xml b/app/src/main/res/drawable/ic_theme.xml new file mode 100644 index 0000000..10e1ae1 --- /dev/null +++ b/app/src/main/res/drawable/ic_theme.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_translate.xml b/app/src/main/res/drawable/ic_translate.xml new file mode 100644 index 0000000..191f59f --- /dev/null +++ b/app/src/main/res/drawable/ic_translate.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml new file mode 100644 index 0000000..44b15af --- /dev/null +++ b/app/src/main/res/layout/activity_about.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_applyscript.xml b/app/src/main/res/layout/activity_applyscript.xml new file mode 100644 index 0000000..a773eb6 --- /dev/null +++ b/app/src/main/res/layout/activity_applyscript.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_billing.xml b/app/src/main/res/layout/activity_billing.xml new file mode 100644 index 0000000..870d34f --- /dev/null +++ b/app/src/main/res/layout/activity_billing.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_createscript.xml b/app/src/main/res/layout/activity_createscript.xml new file mode 100644 index 0000000..7b9cf3e --- /dev/null +++ b/app/src/main/res/layout/activity_createscript.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_editor.xml b/app/src/main/res/layout/activity_editor.xml deleted file mode 100644 index f8e9310..0000000 --- a/app/src/main/res/layout/activity_editor.xml +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_filepicker.xml b/app/src/main/res/layout/activity_filepicker.xml new file mode 100644 index 0000000..a4bef63 --- /dev/null +++ b/app/src/main/res/layout/activity_filepicker.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index eb4f982..dd47364 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,115 +1,91 @@ - + android:layout_height="match_parent"> - + android:layout_height="match_parent" + android:orientation="vertical" > - + android:layout_height="wrap_content" + android:background="@color/black" > - + android:gravity="center_horizontal" + android:orientation="vertical" + android:padding="10dp"> - + android:layout_height="wrap_content" > - + android:textColor="?attr/colorAccent" + android:textStyle="bold" + android:textSize="22sp" /> - - - - - - - - + android:layout_gravity="end" + android:background="@null" + android:tint="@color/white" + android:src="@drawable/ic_settings" /> + - + + - + + - - - - + android:layout_height="match_parent" /> + - + android:layout_marginEnd="20dp" + android:orientation="vertical" > + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml new file mode 100644 index 0000000..d3e4a33 --- /dev/null +++ b/app/src/main/res/layout/activity_settings.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml deleted file mode 100644 index e27b32f..0000000 --- a/app/src/main/res/layout/app_bar_main.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - diff --git a/app/src/main/res/layout/fragment_recyclerview.xml b/app/src/main/res/layout/fragment_recyclerview.xml deleted file mode 100644 index e070da8..0000000 --- a/app/src/main/res/layout/fragment_recyclerview.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/recycle_view.xml b/app/src/main/res/layout/recycle_view.xml new file mode 100644 index 0000000..404a27e --- /dev/null +++ b/app/src/main/res/layout/recycle_view.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/recycle_view_donate.xml b/app/src/main/res/layout/recycle_view_donate.xml new file mode 100644 index 0000000..497b368 --- /dev/null +++ b/app/src/main/res/layout/recycle_view_donate.xml @@ -0,0 +1,32 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/recycle_view_filepicker.xml b/app/src/main/res/layout/recycle_view_filepicker.xml new file mode 100644 index 0000000..344b85e --- /dev/null +++ b/app/src/main/res/layout/recycle_view_filepicker.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/recycle_view_settings.xml b/app/src/main/res/layout/recycle_view_settings.xml new file mode 100644 index 0000000..7e9b432 --- /dev/null +++ b/app/src/main/res/layout/recycle_view_settings.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/rv_checkbox.xml b/app/src/main/res/layout/rv_checkbox.xml deleted file mode 100644 index 9cee331..0000000 --- a/app/src/main/res/layout/rv_checkbox.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/rv_description_view.xml b/app/src/main/res/layout/rv_description_view.xml deleted file mode 100644 index 2bf2306..0000000 --- a/app/src/main/res/layout/rv_description_view.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/rv_foreground_view.xml b/app/src/main/res/layout/rv_foreground_view.xml deleted file mode 100644 index 87ea516..0000000 --- a/app/src/main/res/layout/rv_foreground_view.xml +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/viewpager_view.xml b/app/src/main/res/layout/viewpager_view.xml deleted file mode 100644 index 975b3fa..0000000 --- a/app/src/main/res/layout/viewpager_view.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/values-am/strings.xml b/app/src/main/res/values-am/strings.xml index 6dcc7ff..4aef19a 100644 --- a/app/src/main/res/values-am/strings.xml +++ b/app/src/main/res/values-am/strings.xml @@ -1,9 +1,6 @@ - ስለ እኛ - ማስታወቂያዎች እንዲታዩ ፍቀድ - ሁልጊዜ አሳይ የሼል ስክሪፕትን በቀላሉ ለመፍጠር፣ለማስገባት፣ለማስተካከል፣ለማጋራት እና ለማስነሳት የሚያገለግል መተግበሪያ። ተግብር ስልክዎ ጠፍቶ ሲበራ @@ -11,42 +8,24 @@ በመተግበር ላይ %s! ሰርዝ ፍጠር - ምስጋና - Grarak: KernelAdiutor (መነሻ ኮድ)\ntopjohnwu: Magisk (ዳግም ሲበራ አገልግሎት)\nSmgKhOaRn: ኮርያኛ ትርጉም\nOktapra Amtono: ኢንዶኔዥያኛ ትርጉም\nMikesew1320: አማርኛ ትርጉም\nToxinpiper: የመተግበሪያ ምስል ጠቆር ያለ ገፅታ ሰርዝ - ዝርዝር መረጃ አስተካክል - ይሁን አስተካክል - ሼል ስክራፕት ለመፍጠር ወይም ቀድሞ የተዘጋጀ ስክሪፕት ከስልክዎ ለማስገባት ሲፈልጉ እዚህ ጋር ወይም ከታች ያለውን የመደመር ምልክት ይጫኑ። - ምሳሌዎች - አግኝቸዋለሁ - ገብቶኛል አስገባ - ቋንቋ (%s) - አማርኛ + ቋንቋ ነባር - እንግሊዘኛ - ኢንዶኔዥያኛ - ኮርያኛ ወደ ኋላ የመጀመር አሰራር %s ወደ ኋላ በመጀመር አገልግሎት ጊዜ ይነሳል! - ተጨማሪ ከአምራቹ ተጨማሪ መተግበሪያዎች ስክሪፕቱ ግዴታ ስም ሊኖረው ይገባል! በማቋረጥ ላይ እባክዎን የኢንተርኔት አገልግሎት መኖሩን ያረጋግጡ! - ሩት የለም - ይህ መተግበሪያ ያለ ሩት ባልተደረገ ስልክ ላይ አይሰራም! በማቋረጥ ላይ እሺ %s ከ ዳግም ማስጀመሪያ አገልግሎት ተገሏል! - ወደ ኋላ የመጀመር መቼት ቀድሞዉኑ ለ %s በርቷል. በዚህ ስክሪፕት ላይ የሚደረግ ማንኛዉም ለዉጥ እርስዎ ቁልፋን እንደገና እስካላበሩት ድረስ በዳግም ማስጀመር ጊዜ በፍፁም አይተገበርም! - አማራጮች ማከማቻ ላይ የመፃፍ ፍቃድ አልተሰጠም! ፖስት ኤፍኤስ ሞድ %s በ ፖስት ኤፍኤስ ዳታ ጊዜ ይተገበራል! ለመዉጣት ከፈለጉ ወደ ኋላ መመለሻ ቁልፉን ደግመዉ ይጫኑ! ችግር ካለ ለማሳወቅ - አስቀምጥ %s የሚባል ስክሪፕት ቀድሞ አለ! በማቋረጥ ላይ ምረጥ %s? አጋራ @@ -55,10 +34,7 @@ በዚህ አጋራ የቴሌግራም ቤተሰብ ሰርዝ %s? - ስክሪፕት አስተዳዳሪ %s ተገኝቷል! - %s\n\n**ማስታወሻ: እባክዎን መተግበሪያዉን በማውረድ በራስዎ ያሳድጉ!** እባክዎን %s የሆነ ቅጥያ ያለው ፋይል ይምረጡ! - እንኳን በደህና ወደ ስክሪፕት አስተዳዳሪ የአንድሮይድ መተግበሪያ መጡ! የሼል ስክሪፕትን በቀላሉ ለመፍጠር,ለማስገባት,ለማስተካከል,ለማጋራት እና ለማስነሳት የሚያገለግል መተግበሪያ።\n\n*** ማሳሰቢያ ***\nይህ መተግበሪያ በጣም ሀይለኛ ነው። በአግባቡ ካልተጠቀሙበት ስልክዎን ከጥቅም ውጭ ሊያደርገዉ ይችላል! በስልክዎ ላይ የሆነ ነገር ቢፈጠር የዚህ መተግበሪያ አበልፃጊ ሀላፊነቱን አይወስድም! %s ይህ ትክክለኛ ስክሪፕት አይደለም! በማቋረጥ ላይ አዎ \ No newline at end of file diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 3b8c378..1a99f77 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -1,9 +1,6 @@ - Σχετικά με - Επιτρέψτε τις διαφημίσεις - Εμφάνιση πάντα Μια εφαρμογή για να δημιουργήσετε, εισάγετε, τροποποιήσετε, κοινοποίησετε και εύκολα εκτελέσετε σενάρια shell Εφαρμογή Κατά την εκκίνηση @@ -12,41 +9,24 @@ Ακύρωση Λίστα αλλαγών Δημιουργία - Ευχαριστίες - Grarak: KernelAdiutor (βάση κώδικα)\ntopjohnwu: Magisk (υπηρεσία κατά την εκκίνηση)\nSmgKhOaRn: Κορεατική μετάφραση\ntsiflimagas: Ελληνική μετάφραση\nToxinpiper: Εικονίδιο εφαρμογής Σκούρο Θέμα Διαγραφή - Λεπτομέρειες Τροποποίηση - Τροποποίηση ούτως ή άλλως - Πατήστε εδώ, ή το κουμπί προσθήκης στο κάτω μέρος, για να δημιουργήσετε ή να εισάγετε ένα σενάριο shell. - Παραδείγματα - Λήψη - Το κατάλαβα Εισαγωγή - Γλώσσα (%s) - Ελληνικά - Αγγλικά + Γλώσσα Προεπιλογή - Κορεάτικα λειτουργία Late Start %s θα εκτελεστεί στην υπηρεσία late_start! - Περισσότερα Περισσότερα από τον προγραμματιστή Το όνομα του σεναρίου δεν πρέπει να είναι κενό! Διακοπή. Παρακαλώ ελέγξτε τη σύνδεση δικτύου σας! - Απουσία Root - Αυτή η εφαρμογή δε θα λειτουργήσει χωρίς πρόσβαση root! Διακοπή. OK %s έχει εξαιρεθεί από τη διαδικασία εκκίνησης! - Οι ρυθμίσεις κατά την εκκίνηση είναι ήδη ενεργοποιημένες για %s. Επιπλέον αλλαγές σε αυτό το σενάριο δε θα εφαρμοστούν κατά την εκκίνηση, εκτός εάν επανενεργοποιήσετε αυτόν τον διακόπτη! - Επιλογές Απορρίφθηκε η άδεια εγγραφής στον αποθηκευτικό χώρο! λειτουργία Post FS %s θα εκτελεστεί σε λειτουργία post-fs-data! Πατήστε πίσω ξανά για να βγείτε Αναφέρετε κάποιο πρόβλημα - Αποθήκευση Ένα σενάριο με όνομα %s υπάρχει ήδη! Διακοπή. Επιλογή %s? Κοινοποίηση @@ -56,10 +36,7 @@ Πηγαίος Κώδικας Ομάδα Υποστήριξης Διαγραφή %s? - Script Manager %s διαθέσιμο! - %s\n\n**Σημαντικό: Παρακαλώ κατεβάστε και εγκαταστήστε την εφαρμογή χειροκίνητα!** Παρακαλώ επιλέξτε ένα αρχείο με %s προέκταση. - Καλώς ήρθατε στο Script Manager: Μια εφαρμογή για να δημιουργήσετε, εισάγετε, τροποποιήσετε, κοινοποίησετε και εύκολα εκτελέσετε σενάρια shell.\n\n*** ΠΡΟΕΙΔΟΠΟΊΗΣΗ> ***\nΑυτή η εφαρμογή είναι αρκετά ισχυρή ώστε να προκαλέσει προβλήματα στη συσκευή σας. Ο προγραμματιστής αυτής της εφαρμογής δε θα αναλάβει καμία ευθύνη, εάν κατι λάθος συμβεί στη συσκευή σας. %s δεν είναι κατάλληλο αρχείο σεναρίου! Διακοπή. Ναι \ No newline at end of file diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 5e0018a..c5b0bc9 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -1,8 +1,6 @@ - Tentang - Selalu Tampilkan Aplikasi untuk membuat, mengimpor, mengedit, berbagi, dan dengan mudah menjalankan skrip shell Terapkan Terapkan saat boot @@ -10,35 +8,21 @@ Menerapkan %s! Batal Buat Baru - Kontributor - Grarak: KernelAdiutor (Basis Kode)\ntopjohnwu: Magisk (Layanan boot)\nSmgKhOaRn: Terjemahan Korea\nOktapra Amtono: Terjemahan Indonesia\nToxinpiper: Ikon Aplikasi Hapus - Detail Edit - Abaikan dan perbaiki - Untuk membuat atau memuat skrip shell, klik di sini, atau klik tombol add yang terletak di bawah. - Contoh - Dapatkan - Mengerti Impor Mode Lambat %s akan dieksekusi di layanan late_start! - Lainnya Lainnya Dari Pengembang Nama skrip tidak boleh kosong! Batalkan Periksa koneksi internet Anda! - Tidak Ada Akses Root - Aplikasi ini tidak akan berfungsi tanpa Akses Root! Batalkan OK %s dikecualikan saat boot! - Pengaturan saat boot sudah diaktifkan untuk %s. Perubahan lebih lanjut pada skrip ini tidak akan diterapkan Saat boot, kecuali Anda mengaktifkan kembali! - Pilihan Izin menulis ke penyimpanan ditolak! Post FS Mode %s akan dieksekusi di post-fs-data! Tekan kembali untuk keluar Laporkan Masalah - Simpan Skrip dengan nama %s sudah ada! Batalkan Pilih %s? Bagikan @@ -47,10 +31,7 @@ Bagikan Dengan Dukungan Grup Hapus %s? - Script Manager %s tersedia! - %s\n\n**Penting: Silakan unduh dan perbarui aplikasi secara manual!** Pilih berkas dengan format %s. - Selamat Datang di Script Manager: Aplikasi untuk membuat, mengimpor, mengedit, berbagi, dan dengan mudah menjalankan skrip shell.\n\n*** PERINGATAN ***\nAplikasi ini cukup kuat untuk menghancurkan perangkat Anda. Pengembang aplikasi ini tidak bertanggung jawab atas masalah apa pun dengan perangkat Anda. %s bukan berkas skrip yang tepat! Batalkan. Ya \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 6dad949..1dd39c3 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1,9 +1,6 @@ - 정보 - 광고 활성화 - 항상 보이기 쉘 스크립트들을 추가하고, 불러오고, 수정하고, 공유하고, 쉽게 내보내는 어플리케이션 적용 부팅시 적용 @@ -12,42 +9,24 @@ 취소 변경사항 새로 만들기 - 도움을 주신 분들 - Grarak: KernelAdiutor (코드 기반)\ntopjohnwu: Magisk (부팅 서비스)\nSmgKhOaRn: 한국어 번역\nOktapra Amtono: 인도네시아어 번역\nMikesew1320: 에티오피아어 번역\nToxinpiper: 앱 아이콘 다크 테마 제거 - 정보 수정 - 무시하고 수정 - 쉘 스크립트를 만들거나 불러오기 위해서, 여기를 누르거나, 아래에 위치한 추가 버튼을 누르세요. - 예시들 - 알겠습니다 - 이미 알아요 불러오기 - 언어 (%s) - 영어 + 언어 시스템 언어 - 한국어 - 에티오피아어 - 인도네시아어 늦은 시작 모드 %s은(는) 늦은 시작 서비스에서 제거될 것입나다! - 더보기 개발자의 다른 앱들 보기 스크립트 이름이 비어있으면 안됩니다! 취소. 인터넷 연결을 확인해주세요! - 루트 권한 없음 - 이 앱은 루트 권한 없이 작동하지 않습니다! 취소. 확인 %s은(는) 부팅 서비스에서 제거될 것입나다! - %s은(는) 이미 부팅시에 적용됩니다. 이 스크립트에 대한 수정사항들은 스위치를 다시 활성화하지 않는 이상 부팅시에 적용되지 않을 것입니다! - 설정 저장공간 쓰기 권한이 거부되었습니다! Post FS 모드 %s(은)는 post-fs-data에 추출될 것입니다! 나가려면 뒤로가기 버튼을 다시 누르세요 문제 제출하기 - 저장 %s(이)라는 이름의 스크립트는 이미 존재합니다! 취소 %s을(를) 선택하실건가요? 공유 @@ -57,10 +36,7 @@ 소스 코드 지원 받기 %s을(를) 삭제하시겠어요? - 업데이트 가능! - %s\n\n**주의: 앱을 다운로드하고 수동으로 업데이트하세요!** %s 확장자를 가진 파일을 선택해주세요. - Script Manager에 오신 것을 환영합니다: 쉘 스크립트들을 추가하고, 불러오고, 수정하고, 공유하고, 쉽게 내보내는 어플리케이션.\n\n*** 주의 ***\n이 앱은 여러분의 기기를 망가뜨릴 수 있을 정도로 강력합니다. 이 앱의 개발자는 여러분의 기기에 문제가 생기더라도 책임지지 않습니다. %s은(는) 적절한 스크립트가 아닙니다! 취소. \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml new file mode 100644 index 0000000..d8f32f5 --- /dev/null +++ b/app/src/main/res/values-pl/strings.xml @@ -0,0 +1,68 @@ + + + "Aplikacja umożliwiająca tworzenie, importowanie, edycje oraz udostępnianie skryptów shell" + "Zatwierdź" + "Zatwierdź podczas rozruchu" + "Zatwierdzić %s?" + "Zatwierdzanie %s!" + "Błąd podczas łączenia z Google Play!" + "Anuluj" + "dziennik zmian" + "Stwórz" + "Ciemny motyw" + "Auto" + "Wyłącz" + "Włącz" + "Usuń" + "Stworzone przez" + "Anuluj" + "Edytuj" + "Importuj" + "Język" + "Domyślny" + "Opóźniony start" + "Więcej od twórcy" + "Skrypt musi posiadać nazwę! Anulowanie." + "Sprawdź połączenie sieciowe!" + "OK" + "Karta pamięci" + "Brak uprawnień do zapisu w pamieci!" + "Wciśnij cofnij jeszcze raz aby zakończyć" + "Oceń aplikacje" + "Oceń Script Manager w Sklepie Play" + "Zgłoś problem" + "Zgłoś błąd na GitHub" + "%s zatwierdzony pomyślnie!" + "Skrypt o nazwie %s już istnieje! Anulowanie." + "%s jest w trakcie zatwierdzenia! Proszę czekać." + "Wybrać %s?" + "Ustawienia" + "Udostępnij" + "Poleć aplikacje" + "Zaproś znajomych do korzystania ze Script Manager" + "Podziel sie z" + "Kod źródłowy" + "Darowizna" + "Wsparcie techniczne" + "Kup mi obiad" + "Grupa wsparcia" + "Dołącz do grupy na Telegram" + "Kup mi mięso" + "Kup mi kawę" + "Dzięki za twoje wsparcie. Pomagasz nam w dalszym rozwoju projektu! \nW nagrodę otrzymasz odznaczenie, które będzie widnieć na twojej głównej stronie." + "Spróbuj kupić ponownie!" + "Dziekujemy bardzo za twoje wsparcie!" + "Czy usunąć %s?" + "Test" + "Testowanie skryptu… Proszę czekać!" + "Testowanie skryptu zakończone powodzeniem!" + "Tłumaczenie" + "Pomóż w tłumaczeniu aplikacji! Kliknij tutaj aby pobrać oryginalny plik jezykowy" + "Eksplorator plików" + "Zewnętrzny" + "Wbudowany" + "Proszę wybrać plik z rozszerzeniem %s." + "%s nie jest skryptem! Anulowanie." + "Tak" + "Licencja" + \ No newline at end of file diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 97f5c78..5859dbc 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -1,9 +1,6 @@ Script Manager - Sobre - Permitir anúncios - Sempre mostrar Um aplicativo para criar, importar, editar, compartilhar e executar facilmente scripts shell Aplicar Na inicialização @@ -11,46 +8,25 @@ Aplciando %s! Cancelar Mudanças - O texto padrão de direitos autorais, %s, será aplicado na próxima abertura do aplicativo! - O novo texto de direitos autorais, %s, será aplicado na próxima abertura do aplicativo! Criar - Créditos - Grarak: KernelAdiutor (base de código)\ntopjohnwu: libsu e Magisk (serviço de inicialização)\nSmgKhOaRn: traduções Coreanas\nOktapra Amtono: traduções Indinésias\nMikesew1320: traduções Amáricas\ntsiflimagas: traduções Gregas\nLennoard Silva: traduções Portuguesas(br)\nToxinpiper: Ìcone do aplicativo Tema escuro Deletar - Detalhes Editar - Editar mesmo assim - Clique aqui, ou no botão adicionar na parte inferior, para criar ou importar um shell script. - Exemplos - Obter - Entendi Importar - Idioma (%s) - Amárico + Idioma Padrão - Grego - Inglês - Indonésio - Coreano Modo de inicialização tardia %s será executado no serviço late_start! - Mais Mais do desenvolvedor O nome do script não deve estar vazio! Abortando. Por favor, verifique sua conexão à internet! - Sem root - Este aplicativo não funcionará sem acesso root! Abortando. OK %s foi excluído do serviço de inicialização! - As configurações de inicialização já estão ativadas para %s. Quaisquer outras alterações neste script não serão aplicadas na inicialização, a menos que você reative essa opção! - Opções Permissão para modificar o armazenamento negada! Modo pós FS %s será executado no post-fs-data! Pressione voltar novamente para sair Comunicar um problema - Salvar Um script chamado %s já existe! Abortando. Selecionar %s? Compartilhar @@ -59,13 +35,9 @@ Compartilhar com Grupo de suporte Deletar %s? - Script MAnager %s disponível! - %s\n\n** Importante: faça o download e atualize manualmente o aplicativo! ** Por favor, selecione um arquivo com a extensão %s. %s não é um arquivo de script apropriado! Abortando. Sim Código fonte - %s aplicado! Testar - Bem-vindo ao Script Manager: um aplicativo para criar, importar, editar, compartilhar e executar facilmente shell scripts.\n\n***AVISO***\nEste aplicativo é muito poderoso e pode bagunçar o seu dispositivo. O desenvolvedor deste aplicativo não assumirá nenhuma responsabilidade se algo errado acontecer com o seu dispositivo. \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml new file mode 100644 index 0000000..4e5fe35 --- /dev/null +++ b/app/src/main/res/values-ru/strings.xml @@ -0,0 +1,46 @@ + + + + Приложение для создания, импорта, редактирования, обмена и простого выполнения сценариев оболочки + Применять + On-ботинок + Применить%s? + Применяем%s! + Отмена + Изменить бревна + Создайте + Темная тема + удалять + редактировать + Импортировать + Язык + По умолчанию + Режим позднего запуска + %s будет выполняться в сервисе late_start! + Больше от разработчика + Имя скрипта не должно быть пустым! Aborting. + Пожалуйста, проверьте ваше интернет-соединение! + Хорошо + %s исключен из службы загрузки! + В разрешении на запись в хранилище отказано! + Режим Post FS + %s будет выполняться в post-fs-data! + Нажмите еще раз, чтобы выйти + Сообщить о проблеме + %s выполнено успешно! + Сценарий с именем%s уже существует! Aborting. + Выберите%s? + Поделиться + %s/разделен диспетчером скриптов + Чтобы применить этот сценарий, просто загрузите файл и импортируйте его в диспетчер скриптов.\nScript Manager%s можно получить в\nPlayStore: https://play.google.com/store/apps/details?id=com.smartpack.scriptmanager\nGitHub:\nhttps: //github.com/SmartPack/ScriptManager/raw/master/release/com.smartpack.scriptmanager.apk + Поделиться с + Исходный код + Группа поддержки + Удалить%s? + Тестовое задание + "Сценарий тестирования… Пожалуйста, будьте терпеливы!" + "Сценарий тестирования успешно завершен!" + Пожалуйста, выберите файл с расширением%s. + %s не является правильным файлом скрипта! Aborting. + да + \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml new file mode 100644 index 0000000..1685b92 --- /dev/null +++ b/app/src/main/res/values-uk/strings.xml @@ -0,0 +1,62 @@ + + + "Додаток, який дозволяє створювати, імпортувати, редагувати, ділитися та з легкістю виконувати shell-скрипти" + "Виконати" + "Виконати %s?" + "Виконання %s!" + "Скасувати" + "Журнал змін" + "Створити" + "Темна тема" + "Автоматично" + "Вимкнути" + "Увімкнути" + "Видалити" + "Розробник" + "Редагувати" + "Імпортувати" + "Мова" + "За замовчуванням" + "Інші додатки від розробника" + "Перегляньте інші додатки, створені розробником, у Google Play" + "Ім'я скрипта має бути заповненим! Зупинка." + "Перевірте, будь ласка, ваше " + "Ок" + "Не надано дозволу на редагування сховища!" + "Натисніть назад ще раз щоб вийти" + "Оцініть додаток" + "Оцініть або/та залиште відгук про цей додаток в Google Play" + "Повідомити про проблему" + "Відкрити проблему на GitHub" + "На жаль, Root Access для цього додатка або недоступний, або відхилений! Деякі функції цього додатка не працюватимуть на вашому пристрої." + "%s успішно виконано!" + "Скрипт з назвою %s вже існує! Зупинка." + "%s зараз виконується! Будь ласка, почекайте." + "Обрати %s?" + "Параметри" + "Поділитися" + "Поділитися додатком" + "Запросіть своїх друзів використовувати Script Manager" + "Script Manager %s можна завантажити з PlayStore: https://play.google.com/store/apps/details?id=com.smartpack.scriptmanager" + "Поділитися за допомогою" + "Вихідний код" + "Підтримати розробку" + "Група для підтримки" + "Для підтримки приєднайтеся до групи в Telegram" + "Купіть мені їжу" + "Купіть мені каву" + "Дуже дякую за вашу підтримку!" + "Видалити %s?" + "Тестувати" + "Скрипт тестується… Будь ласка, зачекайте!" + "Тестування успішно завершено!" + "Переклад" + "Допоможіть мені перекласти цей додаток! Клацніть тут, щоб отримати оригінальні мовні рядки англійською мовою" + "Засіб вибору файлів" + "Зовнішній" + "Вбудований" + "Виникли проблеми? Вимкніть вбудований засіб вибору файлів у 'Параметрах'!" + "Виберіть файл з розширенням %s." + "Так" + "Ліцензія" + \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000..583f76e --- /dev/null +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,82 @@ + + + "一款用于建立、导入、编辑、执行shell 、脚本的App" + "应用" + "在启动时应用" + "确定应用 %s ?" + "正在应用 %s!" + "无法连接到谷歌计费客户端" + "取消" + "更新日志" + "新建" + "暗黑模式" + "自动切换" + "日间模式" + "夜间模式" + "删除" + "开发者" + "关闭" + "编辑" + "导入" + "语言" + "默认" + "延时启动模式" + "%s 将在late_start模式中启动!" + "关于开发者" + "看看开发者还开发出了哪些应用吧" + "脚本名不能为空!正在中止." + "请检查您的网络连接" + "好的" + "%s已从启动服务中排除" + "SD储存卡" + "未启用存储写入权限!" + "Post FS 模式" + "%s将从Post FS数据中运行!" + "再次点击返回键退出" + "评价支持本软件" + "前往谷歌Play点评Script Manager" + "报告问题" + "前往GitHub报告问题" + "Root 权限不可用或未授予,App的某些功能将无法使用." + "%s已成功运行!" + "%s 已存在!正在中止." + "%s正在运行!请稍后." + "选择%s?" + "设置" + "分享" + "分享此App" + "邀请小伙伴使用 Script Manager吧" + "%s/由Script Manager分享" + "要使用此脚本,只需下载文件并导入Script Manager即可" + "从谷歌Play上下载Script Manager %s 吧: https://play.google.com/store/apps/details?id=com.smartpack.scriptmanager" + "使用以下App分享" + "源码" + "Script Manager是一款开源且接受社区贡献的软件.点击此处获取源码!" + "确认捐赠 \u2665" + "购买捐赠版App" + "支持一下开发者" + "如果你感谢开发者开发完全免费工具的付出,点击下方提供的选项支持一下开发者吧!选购以下一项产品即可获取支持者徽章!" + "支持一份晚餐" + "技术支持群" + "加入电报群" + "投喂我" + "请问喝杯咖啡" + "之前您已经支持过这项这个项目的开发了!" + "感谢您的支持 \u2665\n这将给予我更多动力来更好的维持我的项目!另外,您将获得支持者徽章." + "请重新尝试购买!" + "感谢您的支持!" + "确定删除%s?" + "测试" + "正在测试脚本…请耐心等待!" + "成功完成脚本测试!" + "翻译" + "帮我翻译此App吧!点击此处获取英文原版字符串" + "文件选择" + "外部选择器" + "内置选择器" + "出问题了?请在'设置'菜单中关闭'使用内置选择器'!" + "请使用%s扩展选择一个文件." + "%s不是一个合适的脚本文件!正在中止." + "是" + "许可证" + \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 532ef4b..7242940 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1,7 +1,28 @@ - - @string/create - @string/import_item + + + @string/dark_theme_auto + @string/dark_theme_enable + @string/dark_theme_disable - \ No newline at end of file + + + @string/language_default + @string/language_en + @string/language_ko + @string/language_am + @string/language_el + @string/language_in + @string/language_pt + @string/language_ru + @string/language_pl + @string/language_zh + @string/language_uk + + + + @string/file_picker_inbuilt + @string/file_picker_external + + diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml deleted file mode 100644 index b4662b4..0000000 --- a/app/src/main/res/values/attrs.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 2d9c627..18955ec 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,6 +1,6 @@ - #111111 #000000 + #4285F4 #FFFFFF \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml deleted file mode 100644 index c89828d..0000000 --- a/app/src/main/res/values/dimens.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - 8dp - -48dp - 48dp - - 10dp - - 3dp - 3dp - - 140dp - 280dp - - 50dp - 50dp - 1dp - - 30dp - - diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml deleted file mode 100644 index 3ea04e7..0000000 --- a/app/src/main/res/values/ids.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/app/src/main/res/values/pageindicator.xml b/app/src/main/res/values/pageindicator.xml deleted file mode 100644 index d1cf62f..0000000 --- a/app/src/main/res/values/pageindicator.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - #FFFFFFFF - #00000000 - 0 - 3dp - false - #FFDDDDDD - 1dp - 0dp - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4ec1273..d72432e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,76 +1,93 @@ Script Manager - About - Allow Ads - Always Show An app to create, import, edit, share and easily execute shell scripts Apply On-boot Apply %s? Applying %s! + Failed to connect with Google Play Billing client! Cancel Change-logs - ©SmartPack Projects - Default copyright text, %s, will be applied on next app launch! - New copyright text, %s, will be applied on next app launch! Create - Credits - Grarak: KernelAdiutor (code base)\ntopjohnwu: libsu & Magisk (on-boot service)\nLennoard Silva: Code contributions/pt-Br Translations\nSmgKhOaRn: Korean translations\nOktapra Amtono: Indonesian translations\nMikesew1320: Amharic translations\ntsiflimagas: Greek translations\nToxinpiper: App Icon Dark Theme + Auto + Disable + Enable Delete - Details + Developed By + Dismiss Edit - Edit Anyway - Click here, or the add button at the bottom, to create or import a shell script. - Examples - Get it - Got it Import - Language (%s) - Amharic + Language + አማርኛ Default - Greek - English - Indonesian - Korean - Portuguese + Ελληνικά + English + bahasa Indonesia + 한국어 + Polski + Português + русский + Українська + 中文(简体) Late Start Mode %s will be executed in late_start service! - More + Licence More from Developer + Checkout more applications provided by the developer in Google Play Script name shouldn\'t be empty! Aborting. Please check your internet connection! - No Root - This app won\'t work without Root Access! Aborting. OK %s is excluded from the on boot service! - On-boot settings are already enabled for %s. Any further changes on this script won\'t be applied On-boot, unless you re-enable that switch! - Options + SDCard Permission denied for writing to storage! Post FS Mode %s will be executed in post-fs-data! Press back again to exit + Rate App + Rate or/and Review Script Manager in Google Play Report an Issue - Save - %s Applied! + Raise an issue at GitHub + Unfortunately, Root Access is either unavailable or declined for this app! Some features of this app is, therefore, won\'t work on your device. %s executed successfully! A script named %s is already exists! Aborting. + %s is currently executing! Please wait. Select %s? + Settings Share + Share App + Invite your friends to use Script Manager %s/shared by Script Manager - To apply this script, simply download the file and import into Script Manager.\nScript Manager %s can be obtained from\nPlayStore: https://play.google.com/store/apps/details?id=com.smartpack.scriptmanager\nGitHub: \nhttps://github.com/SmartPack/ScriptManager/raw/master/release/com.smartpack.scriptmanager.apk + To apply this script, simply download the file and import into Script Manager + Script Manager %s can be obtained from PlayStore: https://play.google.com/store/apps/details?id=com.smartpack.scriptmanager Share with Source Code + Script Manager is an open-source application which is ready to accept contributions from the development community. Click here to check out the source code! + Donation Acknowledged \u2665 + Buy Donation App + Support Development + If you like to appreciate the efforts of the developer to provide this tool entirely free, please consider sending a small donation by clicking one among the below-provided options! Buying any of this product will award you a supporter badge here! + Buy me a Dinner Support Group + Join Telegram support group + Buy me a Meal + Buy me a Coffee + You\'re already supported the development with this item before! + Thank you very much for your support \u2665\nIt will motivate me a lot to continue my projects more active! Moreover, you\'ll receive a supporter badge on the top of this page. + Please try purchasing again! + Thank you very much for your support! Delete %s? Test "Testing script… Please be patient!" "Testing script completed successfully!" - Script Manager %s available! - %s\n\n**Important: Please download and manually update the app!** + Translations + Help me to translate this app! Click here to get the original language strings in english + File Picker + External + In-built + Got some issues? Please disable \'Use In-built File Picker\' in \'Settings\' Menu! Please select a file with %s extension. - Welcome to Script Manager: An app to create, import, edit, share and easily execute shell scripts.\n\n*** WARNING> ***\nThis app is too powerful to messed up your device. The developer of this app won\'t take any responsibility, if something wrong happened to your device. %s is not a proper script file! Aborting. Yes \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ad2454f..41e0719 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,11 +1,10 @@ - - \ No newline at end of file diff --git a/app/src/play/AndroidManifest.xml b/app/src/play/AndroidManifest.xml new file mode 100644 index 0000000..b0498b5 --- /dev/null +++ b/app/src/play/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/play/java/com/smartpack/scriptmanager/activities/BillingActivity.java b/app/src/play/java/com/smartpack/scriptmanager/activities/BillingActivity.java new file mode 100644 index 0000000..42a8c21 --- /dev/null +++ b/app/src/play/java/com/smartpack/scriptmanager/activities/BillingActivity.java @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2021-2022 sunilpaulmathew + * + * This file is part of Script Manager, an app to create, import, edit + * and easily execute any properly formatted shell scripts. + * + */ + +package com.smartpack.scriptmanager.activities; + +import android.annotation.SuppressLint; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.AppCompatImageButton; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.android.billingclient.api.BillingClient; +import com.android.billingclient.api.BillingClientStateListener; +import com.android.billingclient.api.BillingFlowParams; +import com.android.billingclient.api.BillingResult; +import com.android.billingclient.api.ConsumeParams; +import com.android.billingclient.api.ConsumeResponseListener; +import com.android.billingclient.api.Purchase; +import com.android.billingclient.api.SkuDetails; +import com.android.billingclient.api.SkuDetailsParams; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.textview.MaterialTextView; +import com.smartpack.scriptmanager.R; +import com.smartpack.scriptmanager.utils.Utils; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/* + * Created by sunilpaulmathew on November 12, 2020 + */ +public class BillingActivity extends AppCompatActivity { + + private final ArrayList mData = new ArrayList<>(); + private BillingClient mBillingClient; + private boolean mClientInitialized = false; + private final List mSkuList = new ArrayList<>(); + + @SuppressLint("UseCompatLoadingForDrawables") + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_billing); + + AppCompatImageButton mBack = findViewById(R.id.back_button); + AppCompatImageButton mSupporterIcon = findViewById(R.id.supporter_button); + MaterialTextView mSupporterMessage = findViewById(R.id.supporter_message); + MaterialTextView mCancel = findViewById(R.id.cancel_button); + + if (Utils.isProUser(this)) { + mSupporterIcon.setVisibility(View.VISIBLE); + mSupporterMessage.setText(getString(R.string.support_status_message)); + } + + mData.add(new RecycleViewItem(getString(R.string.support_app), getResources().getDrawable(R.drawable.ic_donation_app))); + mData.add(new RecycleViewItem(getString(R.string.support_coffee), getResources().getDrawable(R.drawable.ic_coffee))); + mData.add(new RecycleViewItem(getString(R.string.support_meal), getResources().getDrawable(R.drawable.ic_meal))); + mData.add(new RecycleViewItem(getString(R.string.support_dinner), getResources().getDrawable(R.drawable.ic_dinner))); + + RecyclerView mRecyclerView = findViewById(R.id.recycler_view); + mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); + RecycleViewAdapter mRecycleViewAdapter = new RecycleViewAdapter(mData); + mRecyclerView.setAdapter(mRecycleViewAdapter); + mRecyclerView.setVisibility(View.VISIBLE); + + mRecycleViewAdapter.setOnItemClickListener((position, v) -> { + if (position == 0) { + buyDonationApp(); + } else if (position == 1) { + buyMeACoffee(); + } else if (position == 2) { + buyMeAMeal(); + } else if (position == 3) { + buyMeADinner(); + } + }); + + mBack.setOnClickListener(v -> super.onBackPressed()); + mCancel.setOnClickListener(v -> super.onBackPressed()); + + mBillingClient = BillingClient.newBuilder(BillingActivity.this).enablePendingPurchases().setListener((billingResult, list) -> { + if (list != null && billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + for (Purchase purchase : list) { + handlePurchases(purchase); + } + } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.support_retry_message)); + } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.support_already_received_message)); + } + }).build(); + + mBillingClient.startConnection(new BillingClientStateListener() { + @Override + public void onBillingSetupFinished(@NonNull BillingResult billingResult) { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + mClientInitialized = true; + } + } + + @Override + public void onBillingServiceDisconnected() { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.billing_client_disconnected)); + } + }); + } + + private void buyDonationApp() { + if (!Utils.isNotDonated(this)) { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.support_already_received_message)); + return; + } + Utils.launchUrl("https://play.google.com/store/apps/details?id=com.smartpack.donate", this); + } + + private void buyMeACoffee() { + if (!mClientInitialized) { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.billing_client_disconnected)); + return; + } + mSkuList.clear(); + mSkuList.add("donation_coffee"); + final SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); + params.setSkusList(mSkuList).setType(BillingClient.SkuType.INAPP); + + mBillingClient.querySkuDetailsAsync(params.build(), (billingResult, list) -> { + if (list != null && billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + for (final SkuDetails skuDetails : list) { + + BillingFlowParams flowParams = BillingFlowParams.newBuilder() + .setSkuDetails(skuDetails) + .build(); + + mBillingClient.launchBillingFlow(BillingActivity.this, flowParams); + + } + } + }); + } + + private void buyMeADinner() { + if (!mClientInitialized) { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.billing_client_disconnected)); + return; + } + mSkuList.clear(); + mSkuList.add("donation_dinner"); + final SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); + params.setSkusList(mSkuList).setType(BillingClient.SkuType.INAPP); + + mBillingClient.querySkuDetailsAsync(params.build(), (billingResult, list) -> { + if (list != null && billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + for (final SkuDetails skuDetails : list) { + + BillingFlowParams flowParams = BillingFlowParams.newBuilder() + .setSkuDetails(skuDetails) + .build(); + + mBillingClient.launchBillingFlow(BillingActivity.this, flowParams); + + } + } + }); + } + + private void buyMeAMeal() { + if (!mClientInitialized) { + Utils.snackbar(findViewById(android.R.id.content), getString(R.string.billing_client_disconnected)); + return; + } + mSkuList.clear(); + mSkuList.add("donation_meal"); + final SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); + params.setSkusList(mSkuList).setType(BillingClient.SkuType.INAPP); + + mBillingClient.querySkuDetailsAsync(params.build(), (billingResult, list) -> { + if (list != null && billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + for (final SkuDetails skuDetails : list) { + + BillingFlowParams flowParams = BillingFlowParams.newBuilder() + .setSkuDetails(skuDetails) + .build(); + + mBillingClient.launchBillingFlow(BillingActivity.this, flowParams); + + } + } + }); + } + + private void handlePurchases(Purchase purchase) { + try { + if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { + if (purchase.getSkus().contains("donation_coffee") || purchase.getSkus().contains("donation_meal") || purchase.getSkus().contains("donation_dinner")) { + ConsumeParams consumeParams = ConsumeParams.newBuilder() + .setPurchaseToken(purchase.getPurchaseToken()) + .build(); + + ConsumeResponseListener mConsumeResponseListener = (billingResult, s) -> Utils.snackbar(findViewById(android.R.id.content), getString(R.string.support_acknowledged)); + + mBillingClient.consumeAsync(consumeParams, mConsumeResponseListener); + new MaterialAlertDialogBuilder(this) + .setMessage(getString(R.string.support_received_message)) + .setPositiveButton(getString(R.string.cancel), (dialogInterface, i) -> { + }).show(); + + Utils.saveBoolean("support_received", true, this); + } + } + } catch (Exception ignored) {} + } + + private static class RecycleViewAdapter extends RecyclerView.Adapter { + + private final ArrayList data; + + private static ClickListener clickListener; + + public RecycleViewAdapter(ArrayList data) { + this.data = data; + } + + @NonNull + @Override + public RecycleViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View rowItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycle_view_donate, parent, false); + return new ViewHolder(rowItem); + } + + @Override + public void onBindViewHolder(@NonNull RecycleViewAdapter.ViewHolder holder, int position) { + try { + holder.mTitle.setText(this.data.get(position).getTitle()); + holder.mIcon.setImageDrawable(this.data.get(position).getIcon()); + } catch (NullPointerException ignored) {} + } + + @Override + public int getItemCount() { + return this.data.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + private final AppCompatImageView mIcon; + private final MaterialTextView mTitle; + + public ViewHolder(View view) { + super(view); + view.setOnClickListener(this); + this.mIcon = view.findViewById(R.id.icon); + this.mTitle = view.findViewById(R.id.title); + } + + @Override + public void onClick(View view) { + clickListener.onItemClick(getAdapterPosition(), view); + } + } + + public void setOnItemClickListener(ClickListener clickListener) { + RecycleViewAdapter.clickListener = clickListener; + } + + public interface ClickListener { + void onItemClick(int position, View v); + } + + } + + private static class RecycleViewItem implements Serializable { + private final String mTitle; + private final Drawable mIcon; + + public RecycleViewItem(String title, Drawable icon) { + this.mTitle = title; + this.mIcon = icon; + } + + public String getTitle() { + return mTitle; + } + + public Drawable getIcon() { + return mIcon; + } + } + +} \ No newline at end of file diff --git a/app/src/play/java/com/smartpack/scriptmanager/utils/Billing.java b/app/src/play/java/com/smartpack/scriptmanager/utils/Billing.java new file mode 100644 index 0000000..6d08825 --- /dev/null +++ b/app/src/play/java/com/smartpack/scriptmanager/utils/Billing.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021-2022 sunilpaulmathew + * + * This file is part of Script Manager, an app to create, import, edit + * and easily execute any properly formatted shell scripts. + * + */ + +package com.smartpack.scriptmanager.utils; + +import android.app.Activity; +import android.content.Intent; + +import com.smartpack.scriptmanager.activities.BillingActivity; + +/* + * Created by sunilpaulmathew on January 17, 2021 + */ +public class Billing { + + public static void showDonateOption(Activity activity) { + Intent donations = new Intent(activity, BillingActivity.class); + activity.startActivity(donations); + } + +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index a88f843..dbfe549 100644 --- a/build.gradle +++ b/build.gradle @@ -2,22 +2,21 @@ buildscript { repositories { - jcenter() + mavenCentral() google() } dependencies { - classpath 'com.android.tools.build:gradle:3.6.3' - classpath 'com.google.gms:google-services:4.3.3' + classpath 'com.android.tools.build:gradle:4.2.2' } } allprojects { repositories { - jcenter() + mavenCentral() maven { url 'https://maven.google.com' } } } task clean(type: Delete) { delete rootProject.buildDir -} +} \ No newline at end of file diff --git a/change-logs.md b/change-logs.md index 234f66d..db777b8 100644 --- a/change-logs.md +++ b/change-logs.md @@ -1,5 +1,73 @@ # Change-logs +## 41. July 21, 2021 +*Release-tag: 5.0*
+Final update + depreciation notice. Updated build tools. Miscellaneous changes. + +## 40. June 06, 2021 +*Release-tag: 4.9*
+More updates for latest Android versions. Improved permission handling. Improved language switch. Miscellaneous changes. + +## 39. May 31, 2021 +*Release-tag: 4.8*
+Overall improved app UI. Updated app to target latest Android versions. Added Chinese (simplified), Ukrainian and Polish translations. Updated build tools. Miscellaneous changes. + +## 38. March 14, 2021 +*Release-tag: 4.7*
+Improved built-in file picker. Improved language switch. Updated build tools. Miscellaneous changes. + +## 37. February 13, 2021 +*Release-tag: 4.6*
+Improved internal file picker to avoid some crashes. Moved popup menu items into a new settings page. Miscellaneous changes. + +## 36. January 31, 2021 +*Release-tag: 4.5*
+Fixed possible crashes on some devices. Temporarily fixed issues on Android 11. Overall improved coding style. Miscellaneous changes. + +## 35. January 16, 2021 +*Release-tag: 4.4*
+Updated build tools and SDK. Added a licence page. Slightly updated app UI. App will now show a supporter badge for those who supported development. Miscellaneous changes. + +## 34. December 06, 2020 +*Release-tag: 4.3*
+Updated app to work with the non-rooted environment (with limited capabilities). App will now show live outputs on applying/testing scripts. Overall improve app UI (now using more material elements). App will now use its own file picker for selecting scripts by default (configurable). Added a new option to view script content before importing. Miscellaneous changes. + +## 33. November 16, 2020 +*Release-tag: 4.2*
+Fixed app crashing when trying to import scripts from some locations. Miscellaneous changes. + +## 32. November 12, 2020 +*Release-tag: 4.1*
+Completely removed Ads from the app. Switched to use Material Alert Dialogs. Added donation option. Miscellaneous changes. + +## 31. October 6, 2020 +*Release-tag: 4.0*
+Re-built from (nearly) scratch. App should be now much more fast. Cleaned a whole lot of unused code. Miscellaneous changes. + +## 30. September 16, 2020 +*Release-tag: 3.7*
+Introduced new page to explain no root status. Miscellaneous changes. + +## 29. September 08, 2020 +*Release-tag: 3.6*
+Improved Ad Layout. Removed unnecessary copyright text. Miscellaneous changes. + +## 28. September 02, 2020 +*Release-tag: 3.5*
+Fixed some issues on Create script. Miscellaneous changes. + +## 27. August 29, 2020 +*Release-tag: 3.4*
+Fixed various issues on Edit, create and apply script. Miscellaneous changes. + +## 26. August 23, 2020 +*Release-tag: 3.3*
+Update script Edit and Details views. Updated libsu to v3.0.2. Update gradle build tools. Miscellaneous changes. + +## 25. June 14, 2020 +*Release-tag: 3.2*
+Update description view (Each and every task on scripts are now more straight forward). Added Russian translation (Credits: Mikesew1320). Add an Auto-Mode to App Theme. Improved About and Change-logs view. Update gradle build tools. Miscellaneous changes. + ## 24. May 09, 2020 *Release-tag: 3.1*
Apply and Test script: Show success message if the output is empty. Fixed crashing in no root available situations. Barnd new About & Change-log views. Miscellaneous changes. @@ -78,4 +146,4 @@ Scripts: On-boot: Add choice to select post-fs or late_service. Script: Edit Scr ## 1. January 13, 2020 *Release-tag: alpha1*
-The very first public release of Script Manager, an app to create, import, edit and easily execute any properly formatted shell scripts. +The very first public release of Script Manager, an app to create, import, edit and easily execute any properly formatted shell scripts. \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/41.txt b/fastlane/metadata/android/en-US/changelogs/41.txt new file mode 100644 index 0000000..ac62eb6 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/41.txt @@ -0,0 +1,3 @@ +* Final update + depreciation notice. +* Updated build tools. +* Miscellaneous changes. \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt new file mode 100644 index 0000000..3a42e8a --- /dev/null +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -0,0 +1,16 @@ +Script Manager is a simple application to create, import, edit and easily execute any properly formatted shell scripts. + +Please Note + +Script Manager doesn't need ROOT Access for normal use. However, due to the restricted permissions of android eco-system, executing root commands from app won't work without ROOT Access enabled. + +Features + +Script Manager is a simple and very basic app, with a beautifully designed dark/light user interface, which offers the following things +* Create, edit, share, and easily execute shell scripts. +* Import shell scripts from sdcard. +* Apply scripts on boot, either on post-fs or late_service as per user choice (only if rooted with Magisk). + +Translations + +Please help me to translate this application via POEditor. You may also translate after downloading the original language string available GitHub. \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png new file mode 100644 index 0000000..91957ad Binary files /dev/null and b/fastlane/metadata/android/en-US/images/icon.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png new file mode 100644 index 0000000..dd6579a Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png new file mode 100644 index 0000000..a7f10f7 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png new file mode 100644 index 0000000..c82e442 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png new file mode 100644 index 0000000..e016658 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png differ diff --git a/fastlane/metadata/android/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt new file mode 100644 index 0000000..24c5443 --- /dev/null +++ b/fastlane/metadata/android/en-US/short_description.txt @@ -0,0 +1 @@ +An application to manage shell scripts! \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 628670e..c52ac9b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,19 @@ # Project-wide Gradle settings. - -#AndroidX -android.enableJetifier=true +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 88ec5d7..9b6e700 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Feb 28 17:34:20 CET 2020 +#Sun Oct 04 12:48:11 CEST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip diff --git a/local.properties b/local.properties index 895cb48..b9a974a 100644 --- a/local.properties +++ b/local.properties @@ -1,8 +1,10 @@ -## This file must *NOT* be checked into Version Control Systems, +## This file is automatically generated by Android Studio. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file should *NOT* be checked into Version Control Systems, # as it contains information specific to your local configuration. # # Location of the SDK. This is only used by Gradle. # For customization when using a Version Control System, please read the # header note. -#Tue Jan 14 09:40:42 CET 2020 -sdk.dir=C\:\\Users\\HP\\AppData\\Local\\Android\\Sdk +sdk.dir=C\:\\Users\\HP\\AppData\\Local\\Android\\Sdk \ No newline at end of file diff --git a/release/com.smartpack.scriptmanager.apk b/release/com.smartpack.scriptmanager.apk deleted file mode 100644 index af0a722..0000000 Binary files a/release/com.smartpack.scriptmanager.apk and /dev/null differ diff --git a/settings.gradle b/settings.gradle index e7b4def..4b45572 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,2 @@ include ':app' +rootProject.name = "Script Manager" \ No newline at end of file