Initial commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,48 @@
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("kotlin-android")
|
||||
id("kotlin-android-extensions")
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = sdk.versions.compileSdk.get().toInt()
|
||||
|
||||
defaultConfig {
|
||||
minSdk = sdk.versions.minSdk.get().toInt()
|
||||
targetSdk = sdk.versions.targetSdk.get().toInt()
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.bundles.kotlin)
|
||||
implementation(libs.androidx.core)
|
||||
implementation(libs.androidx.appcompat)
|
||||
|
||||
implementation(libs.bundles.androidx.lifecycle)
|
||||
|
||||
implementation(project(":ktx"))
|
||||
implementation(project(":preferences"))
|
||||
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.kts.kts.kts.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# 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 *;
|
||||
#}
|
||||
|
||||
# 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
|
||||
@@ -0,0 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="de.mm20.launcher2.badges">
|
||||
|
||||
/
|
||||
</manifest>
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.mm20.launcher2.badges
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
|
||||
data class Badge(
|
||||
var number: Int? = null,
|
||||
var progress: Float? = null,
|
||||
var iconRes: Int? = null,
|
||||
var icon: Drawable? = null
|
||||
)
|
||||
@@ -0,0 +1,150 @@
|
||||
package de.mm20.launcher2.badges
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.LauncherApps
|
||||
import android.os.Build
|
||||
import android.os.Process
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import de.mm20.launcher2.ktx.getSerialNumber
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.preferences.LauncherPreferences
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
class BadgeProvider private constructor(val context: Context) {
|
||||
|
||||
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
|
||||
private val badges = mutableMapOf<String, MutableLiveData<Badge>>()
|
||||
|
||||
init {
|
||||
if (LauncherPreferences.instance.cloudBadges) {
|
||||
addCloudBadges()
|
||||
}
|
||||
if (LauncherPreferences.instance.suspendBadges) {
|
||||
addSuspendBadges()
|
||||
}
|
||||
if (LauncherPreferences.instance.profileBadges && isAtLeastApiLevel(Build.VERSION_CODES.O)) {
|
||||
addProfileBadges()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun setBadge(key: String, badge: Badge) {
|
||||
if (badges.containsKey(key)) {
|
||||
badges[key]?.postValue(badge)
|
||||
return
|
||||
}
|
||||
badges[key] = MutableLiveData(badge)
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a badge with all set values of another badge but keeps all other values
|
||||
*/
|
||||
fun updateBadge(key: String,
|
||||
badge: Badge) {
|
||||
if (badges.containsKey(key)) {
|
||||
badges[key]?.run {
|
||||
val updatedBadge = value?.also {
|
||||
if (badge.number != null) it.number = badge.number
|
||||
if (badge.progress != null) it.progress = badge.progress
|
||||
if (badge.iconRes != null) it.iconRes = badge.iconRes
|
||||
if (badge.icon != null) it.icon = badge.icon
|
||||
}
|
||||
postValue(updatedBadge)
|
||||
}
|
||||
} else {
|
||||
badges[key] = MutableLiveData(badge)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeBadge(key: String) {
|
||||
badges[key]?.postValue(Badge())
|
||||
}
|
||||
|
||||
fun getBadge(key: String): Badge? {
|
||||
return badges[key]?.value
|
||||
}
|
||||
|
||||
fun getLiveBadge(key: String): LiveData<Badge> {
|
||||
return badges[key] ?: MutableLiveData<Badge>(Badge()).also { badges[key] = it }
|
||||
}
|
||||
|
||||
fun removeNotificationBadges() {
|
||||
for (k in badges.keys) {
|
||||
if (k.startsWith("app://")) {
|
||||
val badge = getBadge(k) ?: continue
|
||||
badge.number = null
|
||||
badge.progress = null
|
||||
updateBadge(k, badge)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun removeSuspendBadges() {
|
||||
for ((k, v) in badges) {
|
||||
if (k.startsWith("app://") && v.value?.iconRes == R.drawable.ic_badge_suspended) {
|
||||
val badge = getBadge(k) ?: continue
|
||||
badge.iconRes = null
|
||||
updateBadge(k, badge)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addSuspendBadges() {
|
||||
scope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val apps = context.packageManager.getInstalledApplications(0)
|
||||
for (app in apps) {
|
||||
if (app.flags and ApplicationInfo.FLAG_SUSPENDED != 0) {
|
||||
setBadge("app://${app.packageName}", Badge(iconRes = R.drawable.ic_badge_suspended))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addCloudBadges() {
|
||||
setBadge("gdrive://", Badge(iconRes = R.drawable.ic_badge_gdrive))
|
||||
setBadge("onedrive://", Badge(iconRes = R.drawable.ic_badge_onedrive))
|
||||
setBadge("nextcloud://", Badge(iconRes = R.drawable.ic_badge_nextcloud))
|
||||
setBadge("owncloud://", Badge(iconRes = R.drawable.ic_badge_owncloud))
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
fun addProfileBadges() {
|
||||
val profiles = (context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps).profiles
|
||||
for (p in profiles) {
|
||||
if (p == Process.myUserHandle()) continue
|
||||
setBadge("profile://${p.getSerialNumber(context)}", Badge(
|
||||
iconRes = R.drawable.ic_badge_workprofile
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fun removeCloudBadges() {
|
||||
removeBadge("gdrive://")
|
||||
removeBadge("onedrive://")
|
||||
removeBadge("nextcloud://")
|
||||
removeBadge("owncloud://")
|
||||
}
|
||||
|
||||
fun removeShortcutBadges() {
|
||||
for (k in badges.keys) {
|
||||
if (k.startsWith("shortcut://")) {
|
||||
removeBadge(k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private lateinit var instance: BadgeProvider
|
||||
|
||||
fun getInstance(context: Context): BadgeProvider {
|
||||
if (!::instance.isInitialized) instance = BadgeProvider(context.applicationContext)
|
||||
return instance
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="12dp"
|
||||
android:height="12dp"
|
||||
android:viewportWidth="12"
|
||||
android:viewportHeight="12">
|
||||
<path
|
||||
android:pathData="M6,3.9609C5.0708,3.9609 4.2897,4.5951 4.0469,5.4492 3.8356,4.9971 3.382,4.6777 2.8535,4.6777 2.1275,4.6777 1.5313,5.274 1.5313,6 1.5313,6.726 2.1275,7.3223 2.8535,7.3223 3.382,7.3223 3.8356,7.0029 4.0469,6.5508 4.2897,7.4049 5.0708,8.0391 6,8.0391 6.9292,8.0391 7.7103,7.4049 7.9531,6.5508 8.1644,7.0029 8.618,7.3223 9.1465,7.3223 9.8725,7.3223 10.4688,6.726 10.4688,6 10.4688,5.274 9.8725,4.6777 9.1465,4.6777 8.618,4.6777 8.1644,4.9971 7.9531,5.4492 7.7103,4.5951 6.9292,3.9609 6,3.9609ZM6,4.748C6.6958,4.748 7.252,5.3042 7.252,6 7.252,6.6958 6.6958,7.252 6,7.252 5.3042,7.252 4.748,6.6958 4.748,6 4.748,5.3042 5.3042,4.748 6,4.748ZM2.8535,5.4629C3.1544,5.4629 3.3906,5.6991 3.3906,6 3.3906,6.3009 3.1544,6.5371 2.8535,6.5371 2.5526,6.5371 2.3164,6.3009 2.3164,6 2.3164,5.6991 2.5526,5.4629 2.8535,5.4629ZM9.1465,5.4629C9.4474,5.4629 9.6836,5.6991 9.6836,6 9.6836,6.3009 9.4474,6.5371 9.1465,6.5371 8.8456,6.5371 8.6094,6.3009 8.6094,6 8.6094,5.6991 8.8456,5.4629 9.1465,5.4629Z"
|
||||
android:fillColor="#0082c9"
|
||||
android:fillAlpha="1"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,7 @@
|
||||
<vector android:height="12dp" android:viewportHeight="32"
|
||||
android:viewportWidth="32" android:width="12dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#0364b8" android:pathData="M12.9264,12.0618L12.9264,12.061L18.3634,15.3177 21.6031,13.954A5.242,5.242 0,0 1,23.6887 13.5243C23.8085,13.5243 23.9266,13.53 24.044,13.5372A8.0932,8.0932 77.497,0 0,9.443 11.0988L9.5256,11.0963A6.4422,6.4422 0,0 1,12.9264 12.0618Z"/>
|
||||
<path android:fillColor="#0078d4" android:pathData="M12.9272,12.061A6.4422,6.4422 45,0 0,9.5256 11.0963L9.443,11.0988A6.4721,6.4721 0,0 0,4.2148 21.2719L9.0076,19.2543 11.1394,18.3575 15.8844,16.3601 18.3626,15.3177Z"/>
|
||||
<path android:fillColor="#1490df" android:pathData="M24.044,13.5372A5.3229,5.3229 0,0 0,23.6887 13.5243,5.242 5.242,135 0,0 21.6039,13.9548L18.3634,15.3177 19.303,15.8802 22.3824,17.7247 23.7259,18.5291 28.3204,21.2808A5.2606,5.2606 0,0 0,24.044 13.5372Z"/>
|
||||
<path android:fillColor="#28a8ea" android:pathData="M23.7259,18.5291 L22.3824,17.7247 19.303,15.8794 18.3642,15.3177 15.8852,16.3601 11.1402,18.3575 9.0076,19.2543 4.2132,21.2719A6.4657,6.4657 45,0 0,9.5256 24.0454L23.6887,24.0454A5.259,5.259 45,0 0,28.3204 21.2808Z"/>
|
||||
</vector>
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<group
|
||||
android:pivotX="12"
|
||||
android:pivotY="12"
|
||||
android:scaleX="0.75"
|
||||
android:scaleY="0.75">
|
||||
<path
|
||||
android:fillColor="@color/badge_text"
|
||||
android:pathData="M 6.0001504,1.9998779 C 6.0001398,4.0032011 6.0001647,6.0065239 6.0001504,8.009847 7.3334024,9.3398262 8.6666543,10.669805 9.9999063,11.999784 8.668341,13.338163 7.3234967,14.663325 6.0001504,16.009875 6.0001504,18.006653 6.0001504,20.00343 6.0001504,22.000207 10.000079,22.000207 14.000006,22.000207 17.999935,22.000207 17.999945,20.000157 17.99992,18.000107 17.999935,16.000057 16.666683,14.666633 15.333431,13.333208 14.000179,11.999784 15.331753,10.664856 16.676576,9.343147 17.999935,8.0000283 17.999935,5.9999781 17.999935,3.9999282 17.999935,1.9998779 14.000006,1.9998779 10.000079,1.9998779 6.0001504,1.9998779 Z M 8.0000283,3.9997559 C 10.666704,3.9997559 13.333381,3.9997559 16.000057,3.9997559 16.000057,5.1664375 16.000057,6.333119 16.000057,7.4998005 14.666633,8.8332248 13.333208,10.166649 11.999784,11.500073 10.666532,10.166649 9.3332804,8.8332248 8.0000283,7.4998005 8.0000283,6.333119 8.0000283,5.1664375 8.0000283,3.9997559 Z" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<group
|
||||
android:pivotX="12"
|
||||
android:pivotY="12"
|
||||
android:scaleX="0.75"
|
||||
android:scaleY="0.75">
|
||||
<path
|
||||
android:fillColor="@color/badge_text"
|
||||
android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2z" />
|
||||
</group>
|
||||
</vector>
|
||||
Reference in New Issue
Block a user