Compare commits
25 commits
Author | SHA1 | Date | |
---|---|---|---|
49b9eb30ae | |||
fb8fdc363c | |||
49627608b0 | |||
|
6cdb5c365a | ||
8efb67cae8 | |||
ae54ac906f | |||
4f823c5b80 | |||
7fd2ee8c3a | |||
1b837b1b15 | |||
1d8ab21c7e | |||
44018f0aaf | |||
e945565a97 | |||
3d3c219c7a | |||
27d02805c1 | |||
4a9f1ad3ba | |||
f6936ee05c | |||
4284123185 | |||
d3972142f9 | |||
d4e2d5e04a | |||
1b3cb334ee | |||
83bd139347 | |||
c5fc622d8c | |||
ce6dca5363 | |||
f0a570e23d | |||
705880d5de |
1
.gitattributes
vendored
|
@ -1 +0,0 @@
|
|||
*.webp filter=lfs diff=lfs merge=lfs -text
|
10
.gitignore
vendored
|
@ -1,12 +1,7 @@
|
|||
*.iml
|
||||
.gradle
|
||||
/.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
/.idea
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
|
@ -14,3 +9,4 @@
|
|||
.cxx
|
||||
local.properties
|
||||
*:Zone.Identifier
|
||||
app/release/
|
||||
|
|
3
.idea/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="11" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="deploymentTargetDropDown">
|
||||
<targetSelectedWithDropDown>
|
||||
<Target>
|
||||
<type value="QUICK_BOOT_TARGET" />
|
||||
<deviceKey>
|
||||
<Key>
|
||||
<type value="VIRTUAL_DEVICE_PATH" />
|
||||
<value value="C:\Users\anri\.android\avd\Mi_Note_10_Lite_API_30.avd" />
|
||||
</Key>
|
||||
</deviceKey>
|
||||
</Target>
|
||||
</targetSelectedWithDropDown>
|
||||
<timeTargetWasSelectedWithDropDown value="2021-09-03T21:19:00.040945900Z" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,20 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
|
@ -1,6 +0,0 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="AndroidElementNotAllowed" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
|
@ -1,34 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DesignSurface">
|
||||
<option name="filePathToZoomLevelMap">
|
||||
<map>
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.3402777777777778" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/drawable/ic_launcher_background.xml" value="0.3402777777777778" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/drawable/ic_launcher_foreground_test.xml" value="0.3402777777777778" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/drawable/ic_plus.xml" value="0.20337837837837838" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/drawable/ic_return.xml" value="0.3402777777777778" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/drawable/ic_settings.xml" value="0.3402777777777778" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/drawable/shadow.xml" value="0.3277777777777778" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/layout/activity_app_infos.xml" value="0.5" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/layout/activity_app_list.xml" value="0.3015625" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/layout/activity_login.xml" value="0.25" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/layout/activity_main.xml" value="0.22" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/layout/activity_settings.xml" value="0.25" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/layout/activity_showInfos.xml" value="0.2171875" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/layout/list_item_view.xml" value="0.29739583333333336" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/layout/list_item_view_app_download.xml" value="0.75" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/layout/list_item_view_app_list.xml" value="0.25729166666666664" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/menu/menu_main.xml" value="0.33" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.3402777777777778" />
|
||||
<entry key="..\:/Users/anri/AndroidStudioProjects/MobiDL/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.3402777777777778" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
14
README.md
|
@ -1,4 +1,12 @@
|
|||
# Disclaimer
|
||||
This branch corresponds to the scraper written in Kotlin *for Android*, check [this branch](https://gitlab.com/Mylloon/mobilismScrap/-/tree/python) for the one written in Python.
|
||||
# MobiDL
|
||||
## Disclaimer
|
||||
This branch corresponds to the scraper written in Kotlin *for Android*, check [this branch](https://git.kennel.ml/Anri/mobilismScrap/src/branch/python) for the one written in Python.<br>
|
||||
|
||||
Using Git LFS for the `.webp` files
|
||||
## Download
|
||||
You can download the app in the [release page](https://git.kennel.ml/Anri/mobilismScrap/releases).
|
||||
|
||||
Application compatible with Android 12.
|
||||
|
||||
### Requirements
|
||||
Minimum: Android 6.0 (Marshmallow) <br>
|
||||
Recommended: Android 8.0 (Oreo)
|
||||
|
|
|
@ -11,7 +11,7 @@ android {
|
|||
minSdk 23
|
||||
targetSdk 31
|
||||
versionCode 1
|
||||
versionName "1.1"
|
||||
versionName "1.2.2"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
@ -32,11 +32,12 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.core:core-ktx:1.6.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation 'com.google.android.material:material:1.5.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||
implementation 'com.github.kittinunf.fuel:fuel:2.3.1'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1'
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'androidx.work:work-runtime-ktx:2.7.1'
|
||||
}
|
|
@ -1,7 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.mylloon.mobidl" >
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
@ -23,6 +27,16 @@
|
|||
<meta-data
|
||||
android:name="preloaded_fonts"
|
||||
android:resource="@array/preloaded_fonts" />
|
||||
|
||||
<receiver
|
||||
android:name="BootReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
|
||||
</manifest>
|
4
app/src/main/assets/appNames.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"tiktok": "musically",
|
||||
"twitch livestream multiplayer": "twitch"
|
||||
}
|
Before Width: | Height: | Size: 42 KiB |
|
@ -4,6 +4,7 @@ package com.mylloon.mobidl
|
|||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AlertDialog
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
|
@ -16,20 +17,73 @@ import android.os.Looper
|
|||
import android.text.Editable
|
||||
import android.text.InputType
|
||||
import android.text.TextWatcher
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.*
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.work.*
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import kotlinx.coroutines.*
|
||||
import java.util.*
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.util.DisplayMetrics
|
||||
import java.util.concurrent.ExecutionException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
private fun isWorkScheduled(context: Context): Boolean {
|
||||
val instance = WorkManager.getInstance(context)
|
||||
val statuses = instance.getWorkInfosByTag("com.mylloon.mobidl.BackgroundUpdateCheck")
|
||||
return try {
|
||||
var running = false
|
||||
val workInfoList = statuses.get()
|
||||
for (workInfo in workInfoList) {
|
||||
val state = workInfo.state
|
||||
running = (state == WorkInfo.State.RUNNING) or (state == WorkInfo.State.ENQUEUED)
|
||||
}
|
||||
running
|
||||
} catch (e: ExecutionException) {
|
||||
e.printStackTrace()
|
||||
println("No job already running")
|
||||
false
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
println("No job already running")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun newJob(context: Context) {
|
||||
val myConstraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED) //checks whether device should have Network Connection
|
||||
.build()
|
||||
val job = PeriodicWorkRequestBuilder<BackgroundUpdateCheck>(1, TimeUnit.DAYS)
|
||||
.setConstraints(myConstraints)
|
||||
.build()
|
||||
WorkManager.getInstance(context).enqueue(job)
|
||||
}
|
||||
|
||||
class BootReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (!isWorkScheduled(context)) {
|
||||
println("Create a update check job in background...")
|
||||
when (intent.action) {
|
||||
Intent.ACTION_DATE_CHANGED -> {
|
||||
newJob(context)
|
||||
}
|
||||
Intent.ACTION_BOOT_COMPLETED -> {
|
||||
val sharedPref = context.getSharedPreferences("com.mylloon.MobiDL",
|
||||
AppCompatActivity.MODE_PRIVATE)
|
||||
sharedPref.edit().putInt("notifID", 0).apply()
|
||||
newJob(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private var settingsButton: Menu? = null // before starting the app there is no settings button
|
||||
|
@ -37,8 +91,8 @@ class MainActivity : AppCompatActivity() {
|
|||
private var inSettings: Boolean = false // by default your not in settings page
|
||||
private var inAppList: Boolean = false // by default your not in app list page
|
||||
private var inAppInfo: Boolean = false // by default your not in app info page
|
||||
private var prefs: SharedPreferences? = null // first run detection
|
||||
private val sharedPref = "com.mylloon.MobiDL" // shared pref name
|
||||
private var sharedPref: SharedPreferences? = null // first run detection
|
||||
private val sharedPrefName = "com.mylloon.MobiDL" // shared pref name
|
||||
private var timeOfLastToast: Long = System.currentTimeMillis() - 2000
|
||||
private var listInfos: MutableList<Map<String, String?>>? = null
|
||||
private var appMobilismInfos: Map<String, String?>? = null
|
||||
|
@ -64,15 +118,54 @@ class MainActivity : AppCompatActivity() {
|
|||
val context = applicationContext() // get app context
|
||||
|
||||
// read apps from the app preference
|
||||
val sharedPref = context.getSharedPreferences(sharedPref, MODE_PRIVATE)
|
||||
val sharedPref = context.getSharedPreferences(sharedPrefName, MODE_PRIVATE)
|
||||
val data: Set<String>? = sharedPref.getStringSet("apps", null)
|
||||
|
||||
return data?.toMutableList() ?: mutableListOf()
|
||||
}
|
||||
|
||||
|
||||
private fun getValuesAppNeedToBeUpdated(): MutableMap<String, Boolean> { // list of the apps (from the storage if exists)
|
||||
val context = applicationContext() // get app context
|
||||
|
||||
// read apps from the app preference
|
||||
val sharedPref = context.getSharedPreferences(sharedPrefName, MODE_PRIVATE)
|
||||
val dataApp: Set<String>? = sharedPref.getStringSet("appsUpdate", null)
|
||||
val dataBool: Set<String>? = sharedPref.getStringSet("boolUpdate", null)
|
||||
val dataAppList = dataApp?.toList()
|
||||
val dataBoolList = dataBool?.toList()
|
||||
|
||||
val finalMap = mutableMapOf<String, Boolean>()
|
||||
if ((dataAppList != null) and (dataBoolList != null)) {
|
||||
for (i in dataAppList!!.indices) {
|
||||
if (i in dataBoolList!!.indices) {
|
||||
finalMap[dataAppList[i]] =
|
||||
dataBoolList[i].substring(i.toString().length).toBoolean()
|
||||
}
|
||||
}
|
||||
}
|
||||
return finalMap
|
||||
}
|
||||
|
||||
private fun storeValuesAppNeedToBeUpdated(updateApps: MutableMap<String, Boolean>) {
|
||||
val updateAppsName: Set<String> = updateApps.keys
|
||||
val updateAppsBool: MutableCollection<Boolean> = updateApps.values
|
||||
val updateAppsBoolList: List<Boolean> = updateAppsBool.toList()
|
||||
val updateAppsBoolSet: MutableList<String> = mutableListOf()
|
||||
for (i in updateAppsBoolList.indices) {
|
||||
updateAppsBoolSet.add(i.toString() + updateAppsBoolList[i].toString())
|
||||
}
|
||||
|
||||
with(applicationContext().getSharedPreferences(sharedPrefName, MODE_PRIVATE).edit()) {
|
||||
this?.putStringSet("appsUpdate", updateAppsName)
|
||||
this?.putStringSet("boolUpdate", updateAppsBoolSet.toSet())
|
||||
this?.apply()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) { // Main function
|
||||
super.onCreate(savedInstanceState)
|
||||
prefs = getSharedPreferences("com.mylloon.MobiDL", MODE_PRIVATE)
|
||||
sharedPref = getSharedPreferences(sharedPrefName, MODE_PRIVATE)
|
||||
|
||||
try {
|
||||
if (Credentials().get(0) == null) { // test if credentials have already been registered
|
||||
|
@ -128,6 +221,7 @@ class MainActivity : AppCompatActivity() {
|
|||
private fun mainPage(toDelete: String? = null) {
|
||||
if (toDelete == null) {
|
||||
setContentView(R.layout.activity_main) // display main page
|
||||
if (!isWorkScheduled(applicationContext)) newJob(applicationContext) // run background job if not already running
|
||||
if (!settingsButtonVisible) { // check if the settings button isn't already showed
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
toggleSettingsButtonVisibility()
|
||||
|
@ -137,6 +231,7 @@ class MainActivity : AppCompatActivity() {
|
|||
val user = Credentials().get(0).toString()
|
||||
this.title = "${getString(R.string.app_name)} (${getString(R.string.connected_as)} $user)"
|
||||
val valuesRecyclerView = getValuesRecyclerView() // list of all the element in the main page
|
||||
val checkedItemListOfApps = getValuesAppNeedToBeUpdated()
|
||||
|
||||
class Adapter(private val values: List<String>) :
|
||||
RecyclerView.Adapter<Adapter.ViewHolder>() {
|
||||
|
@ -163,20 +258,30 @@ class MainActivity : AppCompatActivity() {
|
|||
button?.setOnLongClickListener {
|
||||
val builder: AlertDialog.Builder =
|
||||
AlertDialog.Builder(instance)
|
||||
builder.setTitle("${getString(R.string.remove)} ${button?.text} ?")
|
||||
builder.setTitle("${getString(R.string.config)} ${button?.text} ?")
|
||||
builder.setPositiveButton(R.string.remove) { _, _ ->
|
||||
instance?.mainPage(
|
||||
button?.text.toString()
|
||||
)
|
||||
checkedItemListOfApps[button?.text.toString()] = false
|
||||
storeValuesAppNeedToBeUpdated(checkedItemListOfApps)
|
||||
}
|
||||
val appInstalled = isItAnInstalledApp(button?.text.toString())
|
||||
if (appInstalled != null) {
|
||||
val checkedItems = booleanArrayOf(
|
||||
false // get this info from the app files somewhere
|
||||
checkedItemListOfApps[button?.text.toString()] == true
|
||||
)
|
||||
builder.setMultiChoiceItems(
|
||||
arrayOf(getString(R.string.updateCheck)),
|
||||
checkedItems
|
||||
) { _, _, isChecked ->
|
||||
println("Update for ${button?.text.toString()}: " + if (isChecked) "enabled" else "disabled" + "")
|
||||
checkedItemListOfApps[button?.text.toString()] = isChecked
|
||||
storeValuesAppNeedToBeUpdated(checkedItemListOfApps)
|
||||
}
|
||||
builder.setNegativeButton(R.string.forceUpdate) { _, _ ->
|
||||
Notif().work(applicationContext,
|
||||
button?.text.toString())
|
||||
}
|
||||
}
|
||||
builder.setNeutralButton(R.string.cancel) { dialog, _ -> dialog.cancel() }
|
||||
builder.show()
|
||||
|
@ -205,11 +310,8 @@ class MainActivity : AppCompatActivity() {
|
|||
if (toDelete != null) {
|
||||
valuesRecyclerView.remove(toDelete)
|
||||
|
||||
val context = applicationContext() // get app context
|
||||
|
||||
// read apps from the app preference
|
||||
val sharedPref = context.getSharedPreferences(sharedPref, MODE_PRIVATE)
|
||||
sharedPref.edit().putStringSet("apps", valuesRecyclerView.toSet()).apply()
|
||||
sharedPref!!.edit().putStringSet("apps", valuesRecyclerView.toSet()).apply()
|
||||
recyclerView.adapter = Adapter(valuesRecyclerView)
|
||||
}
|
||||
recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
|
@ -219,11 +321,8 @@ class MainActivity : AppCompatActivity() {
|
|||
fun addApp(app: String) {
|
||||
valuesRecyclerView.add(app)
|
||||
|
||||
val context = applicationContext() // get app context
|
||||
|
||||
// read apps from the app preference
|
||||
val sharedPref = context.getSharedPreferences(sharedPref, MODE_PRIVATE)
|
||||
sharedPref.edit().putStringSet("apps", valuesRecyclerView.toSet()).apply()
|
||||
sharedPref!!.edit().putStringSet("apps", valuesRecyclerView.toSet()).apply()
|
||||
recyclerView.adapter = Adapter(valuesRecyclerView)
|
||||
|
||||
}
|
||||
|
@ -249,6 +348,21 @@ class MainActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
fun isItAnInstalledApp(app: String): String? {
|
||||
var appName = app
|
||||
val registeredAnswered: Map<String, String> = Gson().fromJson(
|
||||
assets.open("appNames.json").bufferedReader()
|
||||
.use { it.readText() },
|
||||
object : TypeToken<Map<String, String>>() {}.type
|
||||
)
|
||||
for ((key, value) in registeredAnswered) appName =
|
||||
if (Regex(appName.lowercase()).containsMatchIn(key)) value else appName.lowercase()
|
||||
for (packageInfo in packageManager.getInstalledPackages(PackageManager.GET_META_DATA)) {
|
||||
if (Regex(appName).containsMatchIn(packageInfo.packageName)) return packageInfo.versionName
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun callScrapper(
|
||||
user: String,
|
||||
password: String,
|
||||
|
@ -470,9 +584,13 @@ class MainActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
val title = findViewById<TextView>(R.id.textViewAppName)
|
||||
title.text = appMobilismInfos!!["title"]
|
||||
title.setOnClickListener { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://forum.mobilism.org$link"))) }
|
||||
title.setOnClickListener {
|
||||
startActivity(Intent(Intent.ACTION_VIEW,
|
||||
Uri.parse("https://forum.mobilism.org$link")))
|
||||
}
|
||||
findViewById<TextView>(R.id.textViewAppAuthor).text = appMobilismInfos!!["author"]
|
||||
findViewById<TextView>(R.id.textViewAppDate).text = appMobilismInfos!!["date"]
|
||||
val changelogs = findViewById<TextView>(R.id.textViewAppChangelogs)
|
||||
|
@ -527,9 +645,9 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (prefs!!.getBoolean("firstrun", true)) {
|
||||
if (sharedPref!!.getBoolean("firstrun", true)) {
|
||||
Credentials().generateKey() // Generate RSA keys
|
||||
prefs!!.edit().putBoolean("firstrun", false)
|
||||
sharedPref!!.edit().putBoolean("firstrun", false)
|
||||
.apply() // first run done, now the next ones won't be "first".
|
||||
}
|
||||
}
|
||||
|
|
169
app/src/main/java/com/mylloon/mobidl/Notification.kt
Normal file
|
@ -0,0 +1,169 @@
|
|||
package com.mylloon.mobidl
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
|
||||
var sharedPrefName = "com.mylloon.MobiDL" // shared pref name
|
||||
|
||||
class BackgroundUpdateCheck(appContext: Context, workerParams: WorkerParameters) :
|
||||
Worker(appContext, workerParams) {
|
||||
private val ctx = appContext
|
||||
|
||||
override fun doWork(): Result {
|
||||
fun getValuesAppNeedToBeUpdated(): MutableMap<String, Boolean> { // list of the apps (from the storage if exists)
|
||||
val context = MainActivity.applicationContext() // get app context
|
||||
|
||||
// read apps from the app preference
|
||||
val sharedPref = context.getSharedPreferences(sharedPrefName,
|
||||
AppCompatActivity.MODE_PRIVATE)
|
||||
val dataApp: Set<String>? = sharedPref.getStringSet("appsUpdate", null)
|
||||
val dataBool: Set<String>? = sharedPref.getStringSet("boolUpdate", null)
|
||||
val dataAppList = dataApp?.toList()
|
||||
val dataBoolList = dataBool?.toList()
|
||||
|
||||
val finalMap = mutableMapOf<String, Boolean>()
|
||||
if ((dataAppList != null) and (dataBoolList != null)) {
|
||||
for (i in dataAppList!!.indices) {
|
||||
if (i in dataBoolList!!.indices) {
|
||||
finalMap[dataAppList[i]] =
|
||||
dataBoolList[i].substring(i.toString().length).toBoolean()
|
||||
}
|
||||
}
|
||||
}
|
||||
return finalMap
|
||||
}
|
||||
val apps = getValuesAppNeedToBeUpdated()
|
||||
for (app in apps.keys) {
|
||||
if (apps[app] == true) {
|
||||
println("Checking update for $app...")
|
||||
Notif().work(ctx, app)
|
||||
}
|
||||
}
|
||||
println("Update check: Done.")
|
||||
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
|
||||
class Notif {
|
||||
private lateinit var notificationManager: NotificationManager
|
||||
private lateinit var notificationChannel: NotificationChannel
|
||||
private lateinit var builder: Notification.Builder
|
||||
private val channelId = "i.apps.notifications"
|
||||
private val description = R.string.descriptionNotification
|
||||
|
||||
@SuppressLint("UnspecifiedImmutableFlag")
|
||||
fun newNotification(
|
||||
context: Context,
|
||||
notificationID: Int,
|
||||
appName: String,
|
||||
version: String,
|
||||
url: String,
|
||||
) {
|
||||
notificationManager = context.getSystemService(NotificationManager::class.java)
|
||||
val pendingIntent = PendingIntent.getActivity(context,
|
||||
notificationID,
|
||||
Intent(Intent.ACTION_VIEW, Uri.parse(url)),
|
||||
(PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // checking if android version is greater than oreo(API 26) or not
|
||||
notificationChannel = NotificationChannel(channelId,
|
||||
context.getString(description),
|
||||
NotificationManager.IMPORTANCE_LOW)
|
||||
notificationChannel.enableLights(true)
|
||||
notificationChannel.lightColor = Color.GREEN
|
||||
notificationChannel.enableVibration(false)
|
||||
notificationManager.createNotificationChannel(notificationChannel)
|
||||
|
||||
builder = Notification.Builder(context, channelId)
|
||||
.setContentTitle("${context.getString(R.string.newUpdateTitleNotification)} $appName")
|
||||
.setContentText("${context.getString(R.string.newUpdateVersionNotification)} $version ${
|
||||
context.getString(R.string.newUpdateAvailableNotification)
|
||||
}")
|
||||
.setSmallIcon(R.drawable.download)
|
||||
.setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher))
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true)
|
||||
} else {
|
||||
builder = Notification.Builder(context)
|
||||
.setContentTitle("${context.getString(R.string.newUpdateTitleNotification)} $appName")
|
||||
.setContentText("${context.getString(R.string.newUpdateVersionNotification)} $version ${
|
||||
context.getString(R.string.newUpdateAvailableNotification)
|
||||
}")
|
||||
.setSmallIcon(R.drawable.download)
|
||||
.setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher))
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true)
|
||||
}
|
||||
notificationManager.notify(notificationID, builder.build())
|
||||
val sharedPref =
|
||||
context.getSharedPreferences(sharedPrefName, AppCompatActivity.MODE_PRIVATE)
|
||||
sharedPref.edit().putInt("notifID", notificationID + 1).apply()
|
||||
}
|
||||
|
||||
fun work(context: Context, app: String) {
|
||||
var appName = app
|
||||
val registeredAnswered: Map<String, String> = Gson().fromJson(
|
||||
context.assets.open("appNames.json").bufferedReader()
|
||||
.use { it.readText() },
|
||||
object : TypeToken<Map<String, String>>() {}.type
|
||||
)
|
||||
for ((key, value) in registeredAnswered) appName =
|
||||
if (Regex(appName.lowercase()).containsMatchIn(key)) value else appName.lowercase()
|
||||
var installedAppVersion: String? = null
|
||||
for (packageInfo in context.packageManager.getInstalledPackages(PackageManager.GET_META_DATA)) {
|
||||
if (Regex(appName).containsMatchIn(packageInfo.packageName)) installedAppVersion =
|
||||
packageInfo.versionName
|
||||
}
|
||||
if (installedAppVersion == null) return
|
||||
else {
|
||||
try {
|
||||
val res =
|
||||
Scraper(Credentials().get(0), Credentials().get(1), app).search() ?: return
|
||||
if (res[0].containsKey("gotResults")) {
|
||||
var latestVersion = res[1]["title"]!!
|
||||
latestVersion = Regex("""(?<=v?)\d+\.\d+(\.\d+)?""").findAll(latestVersion)
|
||||
.map { it.groupValues[0] }.toList()[0]
|
||||
val arrayInstalledVersion: MutableList<String> =
|
||||
installedAppVersion.split(".") as MutableList<String>
|
||||
val arrayLatestVersion: MutableList<String> =
|
||||
latestVersion.split(".") as MutableList<String>
|
||||
while (arrayInstalledVersion.size > arrayLatestVersion.size) arrayLatestVersion.add(
|
||||
"0")
|
||||
while (arrayInstalledVersion.size < arrayLatestVersion.size) arrayInstalledVersion.add(
|
||||
"0")
|
||||
var needUpdate = false
|
||||
for (i in arrayInstalledVersion.indices) {
|
||||
if (arrayLatestVersion[i].toInt() > arrayInstalledVersion[i].toInt()) needUpdate =
|
||||
true
|
||||
}
|
||||
if (needUpdate) {
|
||||
val sharedPref = context.getSharedPreferences(sharedPrefName,
|
||||
AppCompatActivity.MODE_PRIVATE)
|
||||
return newNotification(context,
|
||||
sharedPref.getInt("notifID", 0),
|
||||
app,
|
||||
latestVersion,
|
||||
"https://forum.mobilism.org${res[1]["link"]}")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -197,7 +197,7 @@ class Scraper(
|
|||
}
|
||||
elements["downloadLinks"] = try {
|
||||
htmlPage = htmlPage.replace(Regex("Download Instructions:</span>(.*?)?<br />"),
|
||||
"Download Instructions:</span><br /><s")
|
||||
"Download Instructions:</span><br />")
|
||||
var tmp =
|
||||
Regex("""Download Instructions:</span> ?<br />(.*|[\s\S]*)<br /><br />Trouble downloading|</a></div>""").findAll(
|
||||
htmlPage)
|
||||
|
|
5
app/src/main/res/drawable/download.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="#8E44AD"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M5,20h14v-2H5V20zM19,9h-4V3H9v6H5l7,7L19,9z"/>
|
||||
</vector>
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:19994ee5e957b8d8f6a2fbef8e00b35d608d3e4d7a68911e67ca07047f5cf6ba
|
||||
size 3360
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c24a8e75ece7af2ac1671c9882d635c2986eaf5172984e7fcb77576bfe398865
|
||||
size 5042
|
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 12 KiB |
|
@ -32,4 +32,11 @@
|
|||
<string name="changelogs">Changements</string>
|
||||
<string name="downloads">Téléchargements</string>
|
||||
<string name="noLinkFound">Aucun lien trouvé</string>
|
||||
<string name="descriptionNotification">Mise à jour des applications</string>
|
||||
<string name="newUpdateTitleNotification">Nouvelle version pour</string>
|
||||
<string name="newUpdateVersionNotification">Version</string>
|
||||
<string name="newUpdateAvailableNotification">disponible</string>
|
||||
<string name="forceUpdate">Force recherche de MàJ</string>
|
||||
<string name="rename">Renommer</string>
|
||||
<string name="config">Configurer</string>
|
||||
</resources>
|
|
@ -13,11 +13,20 @@
|
|||
<string name="newAppDialogTitle">New app name</string>
|
||||
<string name="validate">Validate</string>
|
||||
<string name="remove">Remove</string>
|
||||
<string name="config">Config</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="forceUpdate">Force update search</string>
|
||||
<string name="rename">Rename</string>
|
||||
<string name="updateCheck">Update check</string>
|
||||
<string name="notConnected">You are not logged in, redirection to the login page</string>
|
||||
<string name="dropBro">drop bro</string>
|
||||
|
||||
<!-- Notifications -->
|
||||
<string name="descriptionNotification">Application Update</string>
|
||||
<string name="newUpdateTitleNotification">New version for</string>
|
||||
<string name="newUpdateVersionNotification">Version</string>
|
||||
<string name="newUpdateAvailableNotification">available</string>
|
||||
|
||||
<!-- Settings page -->
|
||||
<string name="titleSettings">Settings</string>
|
||||
<string name="changeCredentials">Change credentials</string>
|
||||
|
|
|
@ -5,7 +5,7 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.0.2'
|
||||
classpath 'com.android.tools.build:gradle:7.1.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
#Wed Aug 25 01:29:46 CEST 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|