Skip to content

Commit

Permalink
add: pie chart for installer packages
Browse files Browse the repository at this point in the history
  • Loading branch information
Hamza417 committed Jan 1, 2025
1 parent fc9ef8e commit da705a5
Show file tree
Hide file tree
Showing 19 changed files with 493 additions and 48 deletions.
7 changes: 7 additions & 0 deletions .idea/dictionaries/Hamza.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ android {
minSdkVersion 23
targetSdkVersion 35
versionCode 10101
versionName "Build101.0.1"
versionName "Build102.0.0"
vectorDrawables.useSupportLibrary = true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

Expand Down
10 changes: 9 additions & 1 deletion app/src/main/assets/html/changelogs.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ <h1>Change Logs</h1>

<!-- Write change logs here -->
<sub>(Current Version)</sub>
<h2>Build102.0.1</h2>
<h2>Build102.0.0</h2>

<h4>User Interface</h4>

Expand Down Expand Up @@ -56,6 +56,14 @@ <h4>Improvements</h4>
</li>
</ul>

<h4>Analytics</h4>

<ul>
<li>Added new pie chart for <i>Installer of Apps</i> to show a graph for apps are installer
sources of apps.
</li>
</ul>

<br/>

<!-- //////////////////////////////////////////////////////////// Older Versions //////////////////////////////////////////////////////////// -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package app.simple.inure.adapters.analytics

import android.annotation.SuppressLint
import android.content.res.ColorStateList
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import app.simple.inure.R
import app.simple.inure.constants.InstallerColors
import app.simple.inure.decorations.corners.DynamicCornerAccentColor
import app.simple.inure.decorations.ripple.DynamicRippleLegendLinearLayout
import app.simple.inure.decorations.typeface.TypeFaceTextView
import app.simple.inure.util.ColorUtils
import app.simple.inure.util.NullSafety.isNotNull
import com.github.mikephil.charting.data.PieEntry

class AdapterInstallerLegend(private val pieEntries: ArrayList<PieEntry>,
private val colors: ArrayList<Int>,
val labels: HashMap<String, String>,
private val function: ((PieEntry, Boolean) -> Unit)? = null) : RecyclerView.Adapter<AdapterInstallerLegend.Holder>() {

private var highLightedEntry: PieEntry? = null
private var lastHighlightedEntry: PieEntry? = null

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
return Holder(LayoutInflater.from(parent.context)
.inflate(R.layout.adapter_legend, parent, false))
}

override fun onBindViewHolder(holder: Holder, position: Int) {
val color = InstallerColors.getInstallerColorMap().get(pieEntries[position].label) ?: colors[position]
holder.color.backgroundTintList = ColorStateList.valueOf(color)
holder.label.text = labels[pieEntries[position].label]

holder.container.setOnClickListener {
function?.invoke(pieEntries[position], false)
}

holder.container.setOnLongClickListener {
function?.invoke(pieEntries[position], true)
true
}

if (highLightedEntry != null && highLightedEntry!!.label == pieEntries[position].label) {
holder.container.highlight(ColorUtils.lightenColor(color, 0.2F))
} else {
holder.container.setRippleColor(ColorUtils.lightenColor(color, 0.2F))
holder.container.unHighlight()
}
}

override fun getItemCount(): Int {
return pieEntries.size
}

@SuppressLint("NotifyDataSetChanged")
fun highlightEntry(e: PieEntry?) {
highLightedEntry = e
if (e.isNotNull()) {
for (i in pieEntries.indices) {
if (pieEntries[i].label == e?.label) {
lastHighlightedEntry = e
notifyItemChanged(i)
break
}
}
} else {
for (i in pieEntries.indices) {
if (pieEntries[i].label == lastHighlightedEntry?.label) {
lastHighlightedEntry = null
notifyItemChanged(i)
break
}
}
}
}

inner class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val color: DynamicCornerAccentColor = itemView.findViewById(R.id.legend_color)
val label: TypeFaceTextView = itemView.findViewById(R.id.legend_text)
val container: DynamicRippleLegendLinearLayout = itemView.findViewById(R.id.container)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ class AdapterInstallerChanges(private val list: ArrayList<Triple<String, String,
}

override fun onBindViewHolder(holder: Holder, position: Int) {
holder.title.text = list[position].first
holder.added.text = list[position].second
holder.removed.text = list[position].third
holder.title.text = list[position].first()
holder.added.text = list[position].second()
holder.removed.text = list[position].third()
}
}
4 changes: 3 additions & 1 deletion app/src/main/java/app/simple/inure/apk/utils/MetaUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,9 @@ object MetaUtils {
val unapprovedDomains = userState?.hostToStateMap
?.filterValues { it == DomainVerificationUserState.DOMAIN_STATE_NONE }

return listOf(verifiedDomains, selectedDomains, unapprovedDomains).any { it?.isNotEmpty() == true }
return listOf(verifiedDomains, selectedDomains, unapprovedDomains).any {
it?.isNotEmpty() == true
}
}.getOrElse {
it.printStackTrace()
return false
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/java/app/simple/inure/apk/utils/PackageUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -555,4 +555,17 @@ object PackageUtils {
fun getIntentFilter(s: String): Intent {
return Intent(s)
}

fun getInstallerPackageName(context: Context, packageName: String): String? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
context.packageManager.getInstallSourceInfo(packageName).installingPackageName
} else {
@Suppress("DEPRECATION")
context.packageManager.getInstallerPackageName(packageName)
}
}

fun PackageInfo.getInstallerPackageName(context: Context): String? {
return getInstallerPackageName(context, this.packageName)
}
}
50 changes: 50 additions & 0 deletions app/src/main/java/app/simple/inure/constants/InstallerColors.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package app.simple.inure.constants

object InstallerColors {

const val UNKNOWN = 0xFF6D7291.toInt()

private val colors: ArrayList<Int> by lazy {
arrayListOf(
0xFFEA4335.toInt(), // Play Store
0xFFFFB401.toInt(), // Aurora Store
0xFF217AD3.toInt(), // F-Droid
0xFFFFA967.toInt(), // Inure
0xFF4CAF50.toInt(), // APKMirror
0xFF9E9E9E.toInt(), // System
0xFF673AB7.toInt(), // Aptoide
0xFF00C4F7.toInt(), // Amazon Appstore
0xFF2196F3.toInt(), // APKPure
0xFF3F51B5.toInt(), // Samsung Galaxy Store
0xFFF65C5B.toInt(), // Huawei AppGallery
0xFFE91E63.toInt(), // SlideME
)
}

private val colorMap = mapOf(
"com.android.vending" to 0xFFEA4335.toInt(),
"com.google.android.packageinstaller" to 0xFFEA4335.toInt(),
"com.aurora.store" to 0xFFFFB401.toInt(),
"org.fdroid.fdroid" to 0xFF217AD3.toInt(),
"app.simple.inure" to 0xFFFFA967.toInt(),
"com.apkmirror" to 0xFF4CAF50.toInt(),
"system" to 0xFF9E9E9E.toInt(),
"com.android.shell" to 0xFF9E9E9E.toInt(),
"com.aptoide.pt" to 0xFF673AB7.toInt(),
"com.amazon.venezia" to 0xFF00C4F7.toInt(),
"com.apkpure.aegon" to 0xFF2196F3.toInt(),
"com.sec.android.app.samsungapps" to 0xFF3F51B5.toInt(),
"com.huawei.appmarket" to 0xFFF65C5B.toInt(),
"com.slideme.sam.manager" to 0xFFE91E63.toInt(),
"com.xiaomi.market" to 0xFFE173E5.toInt(),
"com.xiaomi.discover" to 0xFF3B56E5.toInt(),
)

fun getInstallerColors(): ArrayList<Int> {
return colors
}

fun getInstallerColorMap(): Map<String, Int> {
return colorMap
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,22 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import app.simple.inure.viewmodels.subviewers.AnalyticsDataViewModel
import app.simple.inure.viewmodels.subviewers.AnalyticsInstallerViewModel
import com.github.mikephil.charting.data.Entry

class AnalyticsSDKViewModelFactory(private val entry: Entry) : ViewModelProvider.Factory {
class AnalyticsViewModelFactory(private val entry: Entry) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
val application = extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY]!!

@Suppress("LiftReturnOrAssignment")
when {
modelClass.isAssignableFrom(AnalyticsDataViewModel::class.java) -> {
return AnalyticsDataViewModel(application, entry) as T
}
modelClass.isAssignableFrom(AnalyticsInstallerViewModel::class.java) -> {
return AnalyticsInstallerViewModel(application, entry) as T
}
else -> {
throw IllegalArgumentException("Nope, Wrong Viewmodel!!")
}
Expand Down
26 changes: 4 additions & 22 deletions app/src/main/java/app/simple/inure/models/Triple.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,7 @@
package app.simple.inure.models;

public class Triple <T, U, V> {
private final T first;
private final U second;
private final V third;

public Triple(T first, U second, V third) {
this.first = first;
this.second = second;
this.third = third;
}

public T getFirst() {
return first;
}

public U getSecond() {
return second;
}

public V getThird() {
return third;
}
public record Triple <T, U, V>(
T first,
U second,
V third) {
}
20 changes: 10 additions & 10 deletions app/src/main/java/app/simple/inure/models/Tuple.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,34 @@

public class Tuple <T, K> {

private T mObjectOne;
private K mObjectTwo;
private T one;
private K two;

public Tuple(T param1, K param2) {
mObjectOne = param1;
mObjectTwo = param2;
one = param1;
two = param2;
}

public T getFirst() {
return mObjectOne;
return one;
}

public K getSecond() {
return mObjectTwo;
return two;
}

public void setFirst(T t) {
mObjectOne = t;
one = t;
}

public void setSecond(K k) {
mObjectTwo = k;
two = k;
}

public int compareTo(Tuple tt) {
int i = mObjectOne.toString().toLowerCase().compareTo(tt.getFirst().toString().toLowerCase());
int i = one.toString().toLowerCase().compareTo(tt.getFirst().toString().toLowerCase());
if (i == 0) {
return mObjectTwo.toString().toLowerCase().compareTo(tt.getSecond().toString().toLowerCase());
return two.toString().toLowerCase().compareTo(tt.getSecond().toString().toLowerCase());
}
else if (i < 0) {
return -1;
Expand Down
Loading

0 comments on commit da705a5

Please sign in to comment.