Skip to content

Commit

Permalink
Added wallpaper brightness feature and wallpaper scaling options (fil…
Browse files Browse the repository at this point in the history
…l, stretch, fit)

Enable compiler strong skipping
Updated compose dependencies to 1.7.0-beta01
Added detection for live wallpaper causing wallpaper not to change
Fixed restarting service when opening the app
Fixed content scaling of wallpaper item
Fixed orientation change causing a black screen due to splash screen
Updated translations
  • Loading branch information
Anthonyy232 committed May 18, 2024
1 parent 9a5b40b commit 5d9e87f
Show file tree
Hide file tree
Showing 72 changed files with 2,070 additions and 704 deletions.
41 changes: 24 additions & 17 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ plugins {
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
}

android {
namespace = "com.anthonyla.paperize"
compileSdk = 34
Expand All @@ -17,8 +18,8 @@ android {
applicationId = "com.anthonyla.paperize"
minSdk = 26
targetSdk = 34
versionCode = 11
versionName = "1.2.0"
versionCode = 12
versionName = "1.3.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand All @@ -42,6 +43,7 @@ android {
}
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += strongSkippingConfiguration()
}
buildFeatures {
compose = true
Expand All @@ -65,23 +67,23 @@ androidComponents {

dependencies {
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.0")
implementation("androidx.activity:activity-compose:1.9.0")
implementation(platform("androidx.compose:compose-bom:2024.05.00"))
implementation("androidx.compose.ui:ui:1.7.0-alpha08")
implementation("androidx.compose.ui:ui-graphics:1.7.0-alpha08")
implementation("androidx.compose.ui:ui-tooling-preview:1.7.0-alpha08")
implementation("androidx.compose.material3:material3:1.3.0-alpha06")
implementation("androidx.navigation:navigation-compose:2.8.0-alpha08")
implementation("androidx.compose.material:material:1.7.0-alpha08")
implementation("androidx.compose.ui:ui:1.7.0-beta01")
implementation("androidx.compose.ui:ui-graphics:1.7.0-beta01")
implementation("androidx.compose.ui:ui-tooling-preview:1.7.0-beta01")
implementation("androidx.compose.material3:material3:1.3.0-beta01")
implementation("androidx.navigation:navigation-compose:2.8.0-beta01")
implementation("androidx.compose.material:material:1.7.0-beta01")
implementation("androidx.datastore:datastore:1.1.1")
implementation("androidx.datastore:datastore-preferences:1.1.1")
implementation("androidx.compose.material:material-icons-extended:1.7.0-alpha08")
implementation("androidx.compose.material:material-icons-extended:1.7.0-beta01")
implementation("com.google.accompanist:accompanist-adaptive:0.34.0")
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
implementation("androidx.compose.animation:animation:1.7.0-alpha08")
implementation("androidx.compose.animation:animation:1.7.0-beta01")
implementation("androidx.core:core-splashscreen:1.2.0-alpha01")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.7.0")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.0")
implementation("com.google.code.gson:gson:2.10.1")
implementation("androidx.documentfile:documentfile:1.1.0-alpha01")
implementation("net.engawapg.lib:zoomable:1.7.0-beta02")
Expand All @@ -92,18 +94,23 @@ dependencies {
implementation("com.google.accompanist:accompanist-permissions:0.35.0-alpha")
implementation("com.mikepenz:aboutlibraries-core:11.1.4")
implementation("com.mikepenz:aboutlibraries-compose-m3:11.1.4")
implementation("androidx.compose.foundation:foundation:1.7.0-alpha08")
implementation("androidx.compose.foundation:foundation:1.7.0-beta01")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.0-alpha04")
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.7.0-alpha08")
debugImplementation("androidx.compose.ui:ui-tooling:1.7.0-alpha08")
debugImplementation("androidx.compose.ui:ui-test-manifest:1.7.0-alpha08")
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.7.0-beta01")
debugImplementation("androidx.compose.ui:ui-tooling:1.7.0-beta01")
debugImplementation("androidx.compose.ui:ui-test-manifest:1.7.0-beta01")
implementation("com.google.dagger:hilt-android:2.51.1")
ksp("com.google.dagger:hilt-android-compiler:2.51.1")
implementation("androidx.room:room-runtime:2.6.1")
ksp("androidx.room:room-compiler:2.6.1")
implementation("androidx.room:room-ktx:2.6.1")
implementation("com.lazygeniouz:dfc:1.0.8")
implementation ("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
}
}

private fun strongSkippingConfiguration() = listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:experimentalStrongSkipping=true",
)
10 changes: 8 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<queries>
<intent>
<action android:name="android.service.wallpaper.WallpaperService" />
</intent>
</queries>

<application
android:allowBackup="true"
android:name=".App"
Expand All @@ -26,8 +32,8 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".feature.wallpaper.wallpaperservice.WallpaperService" android:foregroundServiceType="mediaPlayback"/>
<receiver android:name=".feature.wallpaper.wallpaperservice.WallpaperBootReceiver"
<service android:name=".feature.wallpaper.wallpaper_service.WallpaperService" android:foregroundServiceType="mediaPlayback"/>
<receiver android:name=".feature.wallpaper.wallpaper_service.WallpaperBootReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.anthonyla.paperize.core

enum class ScalingConstants {
FIT,
FILL,
STRETCH
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ object SettingsConstants {
const val WALLPAPER_CHANGE_INTERVAL_DEFAULT = 15
const val SET_LOCK_WITH_HOME = "set_lock_with_home"
const val FIRST_LAUNCH = "first_launch"
const val FIRST_ALBUM_SET = "first_album_set"
const val LAST_SET_TIME = "last_set_time"
const val NEXT_SET_TIME = "next_set_time"
const val ENABLE_CHANGER = "enable_changer"
const val DARKEN_PERCENTAGE = "darken_percentage"
const val DARKEN = "darken"
const val WALLPAPER_SCALING = "wallpaper_scaling"
}
118 changes: 118 additions & 0 deletions app/src/main/java/com/anthonyla/paperize/core/WallpaperUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.anthonyla.paperize.core
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.graphics.Paint
import android.net.Uri
import android.util.Log
import android.util.Size
import androidx.compose.ui.util.fastRoundToInt
import androidx.exifinterface.media.ExifInterface

/**
* Get the dimensions of the image from the uri
*/
fun Uri.getImageDimensions(context: Context): Size {
val inputStream = context.contentResolver.openInputStream(this)!!
val exif = ExifInterface(inputStream)
var width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0)
var height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0)
if (width == 0 || height == 0) {
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
BitmapFactory.decodeStream(context.contentResolver.openInputStream(this), null, options)
width = options.outWidth
height = options.outHeight
}
return Size(width, height)
}

/**
* Calculate the inSampleSize for the image
*/
fun calculateInSampleSize(imageSize: Size, width: Int, height: Int): Int {
return if (imageSize.width <= width && imageSize.height <= height) { 1 }
else { (imageSize.width/ width.toFloat()).fastRoundToInt() }
}

/**
* Scale a bitmap using the fit width method
* The bitmap will fit into the given width while maintaining the same aspect ratio
*/
fun fitBitmap(source: Bitmap, width: Int, height: Int): Bitmap {
val aspectRatio = source.height.toFloat() / source.width.toFloat()
val newHeight = (width * aspectRatio).toInt()
val newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(newBitmap)
val bitmap = Bitmap.createScaledBitmap(source, width, newHeight, true)
val top = (height - newHeight) / 2f
canvas.drawBitmap(bitmap, 0f, top, null)
return newBitmap
}

/**
* Scale a bitmap using the fill height method
*/
fun fillBitmap(source: Bitmap, width: Int, height: Int): Bitmap {
try {
val aspectRatio = source.width.toFloat() / source.height.toFloat()
var newWidth = width
var newHeight = (newWidth / aspectRatio).toInt()
if (newHeight < height) {
newHeight = height
newWidth = (newHeight * aspectRatio).toInt()
}
val scaledBitmap = Bitmap.createScaledBitmap(source, newWidth, newHeight, true)
val x = (width - newWidth) / 2f
val y = (height - newHeight) / 2f
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
canvas.drawBitmap(scaledBitmap, x, y, null)
return bitmap
} catch (e: Exception) {
Log.e("WallpaperUtil", "Error filling bitmap: $e")
return source
}
}

/**
* Stretch the bitmap to fit the given width and height
*/
fun stretchBitmap(source: Bitmap, width: Int, height: Int): Bitmap {
try {
val newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(newBitmap)
val bitmap = Bitmap.createScaledBitmap(source, width, height, true)
canvas.drawBitmap(bitmap, 0f, 0f, null)
return newBitmap
} catch (e: Exception) {
Log.e("WallpaperUtil", "Error stretching bitmap: $e")
return source
}
}

/**
* Darken the bitmap by a certain percentage - 0 is darkest, 100 is original
*/
fun darkenBitmap(source: Bitmap, percent: Int, width: Int, height: Int): Bitmap {
try {
val safePercentage = (100 - percent).coerceIn(0, 100)
val factor = 1 - safePercentage / 100f
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
val paint = Paint().apply {
colorFilter = ColorMatrixColorFilter(ColorMatrix().apply {
setScale(factor, factor, factor, 1f)
})
}
canvas.drawBitmap(source, 0f, 0f, paint)
return bitmap
} catch (e: Exception) {
Log.e("WallpaperUtil", "Error darkening bitmap: $e")
return source
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.anthonyla.paperize.feature.wallpaper.presentation
import android.Manifest
import android.animation.ObjectAnimator
import android.app.Activity
import android.app.ActivityManager
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
Expand All @@ -19,16 +20,24 @@ import androidx.core.animation.doOnEnd
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LifecycleEventEffect
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.anthonyla.paperize.core.SettingsConstants
import com.anthonyla.paperize.data.settings.SettingsDataStore
import com.anthonyla.paperize.feature.wallpaper.presentation.settings_screen.SettingsViewModel
import com.anthonyla.paperize.feature.wallpaper.presentation.themes.PaperizeTheme
import com.anthonyla.paperize.feature.wallpaper.presentation.wallpaper_screen.WallpaperScreenViewModel
import com.anthonyla.paperize.feature.wallpaper.wallpaper_service.WallpaperService
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import javax.inject.Inject


@AndroidEntryPoint
class MainActivity : ComponentActivity() {
private val settingsViewModel: SettingsViewModel by viewModels()
Expand All @@ -52,11 +61,11 @@ class MainActivity : ComponentActivity() {
fadeOut.start()
}
}
splashScreen.setKeepOnScreenCondition { settingsViewModel.setKeepOnScreenCondition }

setContent {
val settingsState = settingsViewModel.state.collectAsStateWithLifecycle()
val selectedState = wallpaperScreenViewModel.state.collectAsStateWithLifecycle()
splashScreen.setKeepOnScreenCondition { settingsState.value.isDataLoaded && selectedState.value.isDataLoaded }
val isFirstLaunch = runBlocking { settingsDataStoreImpl.getBoolean(SettingsConstants.FIRST_LAUNCH) } ?: true
if (isFirstLaunch) {
val contentResolver = context.contentResolver
Expand All @@ -65,11 +74,40 @@ class MainActivity : ComponentActivity() {
contentResolver.releasePersistableUriPermission(permission.uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
}
}

LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
lifecycleScope.launch {
val serviceIntent = Intent(this@MainActivity, WallpaperService::class.java)
val isAlreadyRunning = withContext(Dispatchers.IO) {5
val activityManager = getSystemService(ACTIVITY_SERVICE) as? ActivityManager
activityManager?.getRunningServices(Integer.MAX_VALUE)?.any {
it.service == serviceIntent.component
} ?: false
}
if (selectedState.value.selectedAlbum != null && settingsState.value.enableChanger) {
if (!isAlreadyRunning) {
val intent = Intent(context, WallpaperService::class.java).apply {
action = WallpaperService.Actions.START.toString()
}
context.startForegroundService(intent)
}
} else {
if (isAlreadyRunning) {
Intent(context, WallpaperService::class.java).also {
it.action = WallpaperService.Actions.STOP.toString()
context.startForegroundService(it)
}
}
}
}
}

PaperizeTheme(settingsState) {
Surface(tonalElevation = 5.dp) {
PaperizeApp(isFirstLaunch)
}
}

}
}
}
Loading

0 comments on commit 5d9e87f

Please sign in to comment.