This commit is contained in:
MM20 2022-06-21 18:37:38 +02:00
parent 26995c1141
commit 96e70da913
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
98 changed files with 61 additions and 891 deletions

View File

@ -9,8 +9,6 @@ import de.mm20.launcher2.owncloud.OwncloudClient
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
interface AccountsRepository {
@ -26,7 +24,7 @@ interface AccountsRepository {
}
internal class AccountsRepositoryImpl(
private val context: Context
context: Context
) : AccountsRepository {
private val scope = CoroutineScope(Job() + Dispatchers.Default)

View File

@ -2,7 +2,6 @@ package de.mm20.launcher2.debug
import android.os.StrictMode
import android.util.Log
import de.mm20.launcher2.BuildConfig
class Debug {
init {

View File

@ -1,4 +1,4 @@
package de.mm20.launcher2.activity;
package de.mm20.launcher2.activity
import android.app.Activity
import android.content.Context

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.applications
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val applicationsModule = module {

View File

@ -4,5 +4,5 @@ import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module
val backupModule = module {
single<BackupManager> { BackupManager(androidContext(), get(), get(), get(), get()) }
single { BackupManager(androidContext(), get(), get(), get(), get()) }
}

View File

@ -1,8 +1,6 @@
package de.mm20.launcher2.badges.providers
import android.util.Log
import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.badges.R
import de.mm20.launcher2.search.data.File
import de.mm20.launcher2.search.data.Searchable
import kotlinx.coroutines.flow.Flow

View File

@ -4,7 +4,6 @@ import de.mm20.launcher2.applications.AppRepository
import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.badges.R
import de.mm20.launcher2.search.data.Application
import de.mm20.launcher2.search.data.LauncherApp
import de.mm20.launcher2.search.data.Searchable
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow

View File

@ -1,50 +0,0 @@
package de.mm20.launcher2.graphics
import android.content.res.ColorStateList
import android.graphics.*
import android.graphics.drawable.Drawable
class TextDrawable(
val text: String,
val color: Int = Color.WHITE,
val height: Int? = null,
val fontSize: Float = 13f,
typeface: Typeface = Typeface.DEFAULT
): Drawable() {
private val paint = Paint()
private val rect = Rect()
init {
paint.textAlign = Paint.Align.CENTER
paint.textSize = fontSize
paint.color = color
paint.isAntiAlias = true
paint.typeface = typeface
paint.style = Paint.Style.FILL
}
override fun draw(canvas: Canvas) {
val bounds = bounds
if (height != null) paint.textSize = fontSize * bounds.height().toFloat() / height.toFloat()
else paint.textSize = fontSize
paint.getTextBounds(text, 0, text.length, rect)
canvas.drawText(text, bounds.exactCenterX(), bounds.exactCenterY() + rect.height() / 2f, paint)
}
override fun setAlpha(alpha: Int) {
paint.alpha = alpha
}
override fun setColorFilter(colorFilter: ColorFilter?) {
paint.colorFilter = colorFilter
}
override fun getOpacity(): Int {
return PixelFormat.TRANSLUCENT
}
override fun setTintList(tint: ColorStateList?) {
paint.color = tint?.defaultColor ?: color
}
}

View File

@ -1,7 +1,5 @@
package de.mm20.launcher2.icons
import android.content.res.Resources
sealed interface LauncherIcon
data class StaticLauncherIcon(

View File

@ -48,7 +48,7 @@ class Calculator(
}
formattedOctString = s.toString()
s = StringBuffer(solution.roundToInt().toString(16).toUpperCase())
s = StringBuffer(solution.roundToInt().toString(16).uppercase(Locale.getDefault()))
while (s.length % 2 != 0) {
s = s.insert(0, '0')
}
@ -62,7 +62,7 @@ class Calculator(
fun getBeatifiedTerm(): String {
if(term.matches(Regex("0x[0-9a-fA-F]+"))) {
return term.substring(2).toUpperCase(Locale.ROOT) + "₁₆"
return term.substring(2).uppercase(Locale.ROOT) + "₁₆"
}
if(term.matches(Regex("0b[01]+"))) {
return term.substring(2) + ""

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.calendar
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val calendarModule = module {

View File

@ -3,16 +3,10 @@ package de.mm20.launcher2.search.data
import android.content.ContentUris
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable
import android.provider.CalendarContract
import de.mm20.launcher2.graphics.TextDrawable
import de.mm20.launcher2.icons.ColorLayer
import de.mm20.launcher2.icons.StaticLauncherIcon
import de.mm20.launcher2.icons.TextLayer
import de.mm20.launcher2.ktx.dp
import palettes.TonalPalette
import java.text.SimpleDateFormat
class CalendarEvent(

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.contacts
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val contactsModule = module {

View File

@ -9,7 +9,6 @@ import android.os.Build;
import android.util.Log;
import java.util.TimeZone;
import java.util.UUID;
import static com.balsikandar.crashreporter.utils.AppUtilsKt.getAppSignature;
@ -68,26 +67,6 @@ public class AppUtils {
return tz.getID();
}
private static String getDeviceId(Context context) {
String androidDeviceId = getAndroidDeviceId(context);
if (androidDeviceId == null)
androidDeviceId = UUID.randomUUID().toString();
return androidDeviceId;
}
private static String getAndroidDeviceId(Context context) {
final String INVALID_ANDROID_ID = "9774d56d682e549c";
final String androidId = android.provider.Settings.Secure.getString(
context.getContentResolver(),
android.provider.Settings.Secure.ANDROID_ID);
if (androidId == null
|| androidId.toLowerCase().equals(INVALID_ANDROID_ID)) {
return null;
}
return androidId;
}
private static int getAppVersionCode(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()

View File

@ -31,7 +31,7 @@ class CurrencyRepository(
toCurrency: String? = null
): List<Pair<String, Double>> {
return withContext<List<Pair<String, Double>>>(Dispatchers.IO) {
return withContext(Dispatchers.IO) {
val dao = AppDatabase.getInstance(context)
.currencyDao()

View File

@ -16,7 +16,7 @@ android {
javaCompileOptions {
annotationProcessorOptions {
arguments.put("room.schemaLocation", "$projectDir/schemas")
arguments["room.schemaLocation"] = "$projectDir/schemas"
}
}
}

View File

@ -1,3 +1,5 @@
@file:Suppress("ClassName")
package de.mm20.launcher2.database
import android.content.Context

View File

@ -1,6 +1,5 @@
package de.mm20.launcher2.database
import android.content.ComponentName
import androidx.lifecycle.LiveData
import androidx.room.*
import de.mm20.launcher2.database.entities.IconEntity

View File

@ -1,10 +1,6 @@
package de.mm20.launcher2.database
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy.REPLACE
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.*
import de.mm20.launcher2.database.entities.ForecastEntity
import kotlinx.coroutines.flow.Flow
@ -13,7 +9,7 @@ interface WeatherDao {
@Query("SELECT * FROM ${ForecastEntity.TABLE_NAME} ORDER BY timestamp ASC")
fun getForecasts(): Flow<List<ForecastEntity>>
@Insert(onConflict = REPLACE)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(forecasts: List<ForecastEntity>)
@Query("DELETE FROM ${ForecastEntity.TABLE_NAME}")

View File

@ -1,12 +1,8 @@
package de.mm20.launcher2.favorites
import android.content.Context
import de.mm20.launcher2.database.entities.FavoritesItemEntity
import de.mm20.launcher2.search.SearchableSerializer
import de.mm20.launcher2.search.data.Searchable
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koin.core.parameter.parametersOf
data class FavoritesItem(
val key: String,

View File

@ -1,19 +1,5 @@
package de.mm20.launcher2.favorites
import de.mm20.launcher2.appshortcuts.AppShortcutDeserializer
import de.mm20.launcher2.appshortcuts.AppShortcutSerializer
import de.mm20.launcher2.calendar.CalendarEventDeserializer
import de.mm20.launcher2.calendar.CalendarEventSerializer
import de.mm20.launcher2.contacts.ContactDeserializer
import de.mm20.launcher2.contacts.ContactSerializer
import de.mm20.launcher2.files.*
import de.mm20.launcher2.search.NullDeserializer
import de.mm20.launcher2.search.NullSerializer
import de.mm20.launcher2.search.data.*
import de.mm20.launcher2.websites.WebsiteDeserializer
import de.mm20.launcher2.websites.WebsiteSerializer
import de.mm20.launcher2.wikipedia.WikipediaDeserializer
import de.mm20.launcher2.wikipedia.WikipediaSerializer
import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.files
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val filesModule = module {

View File

@ -6,7 +6,6 @@ import android.os.Build
import android.os.CancellationSignal
import android.provider.MediaStore
import android.util.Size
import androidx.core.content.ContentResolverCompat
import java.io.File
import java.io.IOException

View File

@ -114,7 +114,7 @@ abstract class File(
}
}
if (resource == R.string.file_type_none && label.matches(Regex(".+\\..+"))) {
val extension = label.substringAfterLast(".").toUpperCase(Locale.getDefault())
val extension = label.substringAfterLast(".").uppercase(Locale.getDefault())
if (extension == "kvaesitso") return context.getString(
R.string.file_type_launcherbackup,
context.getString(R.string.app_name)

View File

@ -4,10 +4,6 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import de.mm20.launcher2.files.R
import de.mm20.launcher2.gservices.DriveFileMeta
import de.mm20.launcher2.gservices.GoogleApiHelper
import de.mm20.launcher2.helper.NetworkUtils
import de.mm20.launcher2.icons.LauncherIcon
class GDriveFile(
val fileId: String,

View File

@ -114,8 +114,8 @@ open class LocalFile(
val icon = withContext(Dispatchers.IO) {
pkgInfo?.applicationInfo?.loadIcon(context.packageManager)
} ?: return null
when {
icon is AdaptiveIconDrawable -> {
when (icon) {
is AdaptiveIconDrawable -> {
return StaticLauncherIcon(
foregroundLayer = icon.foreground?.let {
StaticIconLayer(

View File

@ -3,10 +3,7 @@ package de.mm20.launcher2.search.data
import android.content.Context
import android.content.Intent
import android.net.Uri
import de.mm20.launcher2.msservices.DriveItem
import de.mm20.launcher2.files.R
import de.mm20.launcher2.msservices.MicrosoftGraphApiHelper
import de.mm20.launcher2.icons.LauncherIcon
class OneDriveFile(
val fileId: String,

View File

@ -4,8 +4,6 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import de.mm20.launcher2.files.R
import de.mm20.launcher2.helper.NetworkUtils
import de.mm20.launcher2.owncloud.OwncloudClient
class OwncloudFile(
fileId: Long,

View File

@ -26,7 +26,7 @@ data class DriveFile(
width = file.imageMediaMetadata?.width ?: file.videoMediaMetadata?.width,
height = file.imageMediaMetadata?.height ?: file.videoMediaMetadata?.height
),
directoryColor = file.folderColorRgb?.toLowerCase(Locale.ROOT),
directoryColor = file.folderColorRgb.lowercase(Locale.ROOT),
viewUri = file.webViewLink ?: ""
)
}

View File

@ -69,10 +69,10 @@ class GoogleClockIconProvider(val context: Context) : IconProvider {
}
ClockSublayer(
drawable = drw,
role = when {
it == hourLayer -> ClockSublayerRole.Hour
it == minuteLayer -> ClockSublayerRole.Minute
it == secondLayer -> ClockSublayerRole.Second
role = when (it) {
hourLayer -> ClockSublayerRole.Hour
minuteLayer -> ClockSublayerRole.Minute
secondLayer -> ClockSublayerRole.Second
else -> ClockSublayerRole.Static
}
)

View File

@ -44,8 +44,8 @@ class IconPackIconProvider(
val resId = res.getIdentifier(drawableName, "drawable", iconPack).takeIf { it != 0 }
?: return generateIcon(context, searchable.launcherActivityInfo, size)
val drawable = ResourcesCompat.getDrawable(res, resId, context.theme) ?: return null
return when {
drawable is AdaptiveIconDrawable -> {
return when (drawable) {
is AdaptiveIconDrawable -> {
return StaticLauncherIcon(
foregroundLayer = drawable.foreground?.let {
StaticIconLayer(
@ -135,7 +135,7 @@ class IconPackIconProvider(
}
if (upon != null) {
res.getIdentifier(upon, "drawable", pack).takeIf { it != 0 }?.let {
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)
val maskDrawable = ResourcesCompat.getDrawable(res, it, null) ?: return null
val maskBmp = maskDrawable.toBitmap(size, size)
inBounds = Rect(0, 0, maskBmp.width, maskBmp.height)
@ -145,7 +145,7 @@ class IconPackIconProvider(
}
if (back != null) {
res.getIdentifier(back, "drawable", pack).takeIf { it != 0 }?.let {
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OVER);
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OVER)
val maskDrawable = ResourcesCompat.getDrawable(res, it, null) ?: return null
val maskBmp = maskDrawable.toBitmap(size, size)
inBounds = Rect(0, 0, maskBmp.width, maskBmp.height)

View File

@ -2,7 +2,6 @@ package de.mm20.launcher2.icons.providers
import android.content.Context
import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.search.data.Searchable
class SystemIconProvider(

View File

@ -112,9 +112,9 @@ internal class ThemedIconProvider(
}
ClockSublayer(
drawable = drw,
role = when {
it == hourIndex -> ClockSublayerRole.Hour
it == minuteIndex -> ClockSublayerRole.Minute
role = when (it) {
hourIndex -> ClockSublayerRole.Hour
minuteIndex -> ClockSublayerRole.Minute
else -> ClockSublayerRole.Static
}
)

View File

@ -1,7 +1,5 @@
package de.mm20.launcher2.ktx
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
val Fragment.dp: Float

View File

@ -4,7 +4,6 @@ import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import kotlin.coroutines.CoroutineContext
val View.dp: Float
get() = context.dp

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.music
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val musicModule = module {

View File

@ -51,7 +51,7 @@ interface MusicRepository {
internal class MusicRepositoryImpl(
private val context: Context,
private val notificationRepository: NotificationRepository
notificationRepository: NotificationRepository
) : MusicRepository, KoinComponent {
private val scope = CoroutineScope(Job() + Dispatchers.Default)

View File

@ -31,7 +31,7 @@ interface NotificationRepository {
fun cancelNotification(notification: StatusBarNotification)
}
internal class NotificationRepositoryImpl() : NotificationRepository {
internal class NotificationRepositoryImpl : NotificationRepository {
private val scope = CoroutineScope(Job() + Dispatchers.Default)
override val notifications: MutableStateFlow<List<StatusBarNotification>> = MutableStateFlow(
emptyList()

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.preferences
import android.content.Context
import android.util.Log
import androidx.datastore.core.DataMigration
import androidx.datastore.core.DataStore
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.search
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val searchModule = module {

View File

@ -1,25 +0,0 @@
package de.mm20.launcher2.search
import androidx.lifecycle.MutableLiveData
class SearchRepository {
val isSearching = MutableLiveData<Boolean>(false)
val currentQuery = MutableLiveData<String>()
private var runningSearches = 0
set(value) {
synchronized(runningSearches) {
field = value
isSearching.value = value > 0
}
}
@Synchronized
fun startSearch() {
synchronized(runningSearches) {
runningSearches++
}
}
}

View File

@ -3,7 +3,6 @@ package de.mm20.launcher2.search.data
import android.content.Intent
import android.net.Uri
import de.mm20.launcher2.database.entities.WebsearchEntity
import java.net.URLEncoder
class Websearch(
var urlTemplate: String,

View File

@ -41,7 +41,7 @@ dependencyResolutionManagement {
version("targetSdk", "32")
}
create("libs") {
version("kotlin", "1.7.0")
version("kotlin", "1.6.21")
version("kotlinx.coroutines", "1.6.3")
alias("kotlin.stdlib")
.to("org.jetbrains.kotlin", "kotlin-stdlib")
@ -60,7 +60,7 @@ dependencyResolutionManagement {
listOf("kotlin.stdlib", "kotlinx.coroutines.core", "kotlinx.coroutines.android")
)
version("androidx.compose", "1.2.0-rc01")
version("androidx.compose", "1.2.0-rc02")
alias("androidx.compose.runtime")
.to("androidx.compose.runtime", "runtime")
.versionRef("androidx.compose")
@ -206,7 +206,7 @@ dependencyResolutionManagement {
.to("androidx.datastore", "datastore")
.version("1.0.0")
version("androidx.room", "2.4.2")
version("androidx.room", "2.5.0-alpha02")
alias("androidx.roomruntime")
.to("androidx.room", "room-runtime")
.versionRef("androidx.room")

View File

@ -1,399 +0,0 @@
package de.mm20.launcher2.transition
import android.animation.*
import android.content.Context
import android.graphics.*
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.transition.Transition
import androidx.transition.TransitionValues
/**
* Transitions a TextView from one font size to another. This does not
* do any animation of TextView content and if the text changes, this
* transition will not run.
*
*
* The animation works by capturing a bitmap of the text at the startLegacy
* and end states. It then scales the startLegacy bitmap until it reaches
* a threshold and switches to the scaled end bitmap for the remainder
* of the animation. This keeps the jump in bitmaps in the middle of
* the animation, where it is less noticeable than at the beginning
* or end of the animation. This transition does not work well with
* cropped text. TextResize also does not work with changes in
* TextView gravity.
*/
class TextResize : Transition {
constructor() {
addTarget(TextView::class.java)
}
/**
* Constructor used from XML.
*/
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
addTarget(TextView::class.java)
}
override fun captureStartValues(transitionValues: TransitionValues) {
captureValues(transitionValues)
}
override fun captureEndValues(transitionValues: TransitionValues) {
captureValues(transitionValues)
}
override fun getTransitionProperties(): Array<String> {
return PROPERTIES
}
private fun captureValues(transitionValues: TransitionValues) {
if (transitionValues.view !is TextView) {
return
}
val view = transitionValues.view as TextView
val fontSize = view.textSize
transitionValues.values.put(FONT_SIZE, fontSize)
val data = TextResizeData(view)
transitionValues.values.put(DATA, data)
}
override fun createAnimator(sceneRoot: ViewGroup, startValues: TransitionValues?,
endValues: TransitionValues?): Animator? {
if (startValues == null || endValues == null) {
return null
}
val startData = startValues.values.get(DATA) as TextResizeData
val endData = endValues.values.get(DATA) as TextResizeData
if (startData.gravity != endData.gravity) {
return null // Can't deal with changes in gravity
}
val textView = endValues.view as TextView
var startFontSize = startValues.values.get(FONT_SIZE) as Float
// Capture the startLegacy bitmap -- we need to set the values to the startLegacy values first
setTextViewData(textView, startData, startFontSize)
val startWidth = textView.paint.measureText(textView.text.toString())
val startBitmap = captureTextBitmap(textView)
if (startBitmap == null) {
startFontSize = 0f
}
var endFontSize = endValues.values.get(FONT_SIZE) as Float
// Set the values to the end values
setTextViewData(textView, endData, endFontSize)
val endWidth = textView.paint.measureText(textView.text.toString())
// Capture the end bitmap
val endBitmap = captureTextBitmap(textView)
if (endBitmap == null) {
endFontSize = 0f
}
if (startFontSize == 0f && endFontSize == 0f) {
return null // Can't animate null bitmaps
}
// Set the colors of the TextView so that nothing is drawn.
// Only draw the bitmaps in the overlay.
val textColors = textView.textColors
val hintColors = textView.hintTextColors
val highlightColor = textView.highlightColor
val linkColors = textView.linkTextColors
textView.setTextColor(Color.TRANSPARENT)
textView.setHintTextColor(Color.TRANSPARENT)
textView.highlightColor = Color.TRANSPARENT
textView.setLinkTextColor(Color.TRANSPARENT)
if (startBitmap == null || endBitmap == null) return null
// Create the drawable that will be animated in the TextView's overlay.
// Ensure that it is showing the startLegacy state now.
val drawable = SwitchBitmapDrawable(textView, startData.gravity,
startBitmap, startFontSize, startWidth, endBitmap, endFontSize, endWidth)
textView.overlay.add(drawable)
// Properties: left, top, font size, text color
val leftProp = PropertyValuesHolder.ofFloat("left", startData.paddingLeft.toFloat(), endData.paddingLeft.toFloat())
val topProp = PropertyValuesHolder.ofFloat("top", startData.paddingTop.toFloat(), endData.paddingTop.toFloat())
val rightProp = PropertyValuesHolder.ofFloat("right",
(startData.width - startData.paddingRight).toFloat(), (endData.width - endData.paddingRight).toFloat())
val bottomProp = PropertyValuesHolder.ofFloat("bottom",
(startData.height - startData.paddingBottom).toFloat(), (endData.height - endData.paddingBottom).toFloat())
val fontSizeProp = PropertyValuesHolder.ofFloat("fontSize", startFontSize, endFontSize)
val animator: ObjectAnimator
if (startData.textColor != endData.textColor) {
val textColorProp = PropertyValuesHolder.ofObject("textColor",
ArgbEvaluator(), startData.textColor, endData.textColor)
animator = ObjectAnimator.ofPropertyValuesHolder(drawable,
leftProp, topProp, rightProp, bottomProp, fontSizeProp, textColorProp)
} else {
animator = ObjectAnimator.ofPropertyValuesHolder(drawable,
leftProp, topProp, rightProp, bottomProp, fontSizeProp)
}
val finalFontSize = endFontSize
val listener = object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
textView.overlay.remove(drawable)
textView.setTextColor(textColors)
textView.setHintTextColor(hintColors)
textView.highlightColor = highlightColor
textView.setLinkTextColor(linkColors)
}
override fun onAnimationPause(animation: Animator) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, drawable.fontSize)
val paddingLeft = Math.round(drawable.left)
val paddingTop = Math.round(drawable.top)
val fraction = animator.getAnimatedFraction()
val paddingRight = Math.round(interpolate(startData.paddingRight.toFloat(),
endData.paddingRight.toFloat(), fraction))
val paddingBottom = Math.round(interpolate(startData.paddingBottom.toFloat(),
endData.paddingBottom.toFloat(), fraction))
textView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom)
textView.setTextColor(drawable.textColor)
}
override fun onAnimationResume(animation: Animator) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, finalFontSize)
textView.setPadding(endData.paddingLeft, endData.paddingTop,
endData.paddingRight, endData.paddingBottom)
textView.setTextColor(endData.textColor)
}
}
animator.addListener(listener)
animator.addPauseListener(listener)
return animator
}
/**
* This Drawable is used to scale the startLegacy and end bitmaps and switch between them
* at the appropriate progress.
*/
private class SwitchBitmapDrawable(private val view: TextView, gravity: Int,
private val startBitmap: Bitmap, private val startFontSize: Float, private val startWidth: Float,
private val endBitmap: Bitmap, private val endFontSize: Float, private val endWidth: Float) : Drawable() {
private val horizontalGravity: Int
private val verticalGravity: Int
private val paint = Paint()
/**
* @return The font size of the text in the displayed bitmap.
*/
/**
* Sets the font size that the text should be displayed at.
*
* @param fontSize The font size in pixels of the scaled bitmap text.
*/
var fontSize: Float = 0.toFloat()
set(fontSize) {
field = fontSize
invalidateSelf()
}
/**
* @return The left side of the text.
*/
/**
* Sets the left side of the text. This should be the same as the left padding.
*
* @param left The left side of the text in pixels.
*/
var left: Float = 0.toFloat()
set(left) {
field = left
invalidateSelf()
}
/**
* @return The top of the text.
*/
/**
* Sets the top of the text. This should be the same as the top padding.
*
* @param top The top of the text in pixels.
*/
var top: Float = 0.toFloat()
set(top) {
field = top
invalidateSelf()
}
/**
* @return The right side of the text.
*/
/**
* Sets the right of the drawable.
*
* @param right The right pixel of the drawn area.
*/
var right: Float = 0.toFloat()
set(right) {
field = right
invalidateSelf()
}
/**
* @return The bottom of the text.
*/
/**
* Sets the bottom of the drawable.
*
* @param bottom The bottom pixel of the drawn area.
*/
var bottom: Float = 0.toFloat()
set(bottom) {
field = bottom
invalidateSelf()
}
/**
* @return The color of the text being displayed.
*/
/**
* Sets the color of the text to be displayed.
*
* @param textColor The color of the text to be displayed.
*/
var textColor: Int = 0
set(textColor) {
field = textColor
colorFilter = PorterDuffColorFilter(textColor, PorterDuff.Mode.SRC_IN)
invalidateSelf()
}
override fun getOpacity(): Int {
return PixelFormat.TRANSLUCENT
}
init {
this.horizontalGravity = gravity and Gravity.HORIZONTAL_GRAVITY_MASK
this.verticalGravity = gravity and Gravity.VERTICAL_GRAVITY_MASK
}
override fun invalidateSelf() {
super.invalidateSelf()
view.invalidate()
}
override fun draw(canvas: Canvas) {
val saveCount = canvas.save()
// The threshold changes depending on the target font sizes. Because scaled-up
// fonts look bad, we want to switch when closer to the smaller font size. This
// algorithm ensures that null bitmaps (font size = 0) are never used.
val threshold = startFontSize / (startFontSize + endFontSize)
val fontSize = fontSize
val progress = (fontSize - startFontSize) / (endFontSize - startFontSize)
// The drawn text width is a more accurate scale than font size. This avoids
// jump when switching bitmaps.
val expectedWidth = interpolate(startWidth, endWidth, progress)
if (progress < threshold) {
// draw startLegacy bitmap
val scale = expectedWidth / startWidth
val tx = getTranslationPoint(horizontalGravity, this.left, this.right,
startBitmap.width.toFloat(), scale)
val ty = getTranslationPoint(verticalGravity, this.top, this.bottom,
startBitmap.height.toFloat(), scale)
canvas.translate(tx, ty)
canvas.scale(scale, scale)
canvas.drawBitmap(startBitmap, 0f, 0f, paint)
} else {
// draw end bitmap
val scale = expectedWidth / endWidth
val tx = getTranslationPoint(horizontalGravity, this.left, this.right,
endBitmap.width.toFloat(), scale)
val ty = getTranslationPoint(verticalGravity, this.top, this.bottom,
endBitmap.height.toFloat(), scale)
canvas.translate(tx, ty)
canvas.scale(scale, scale)
canvas.drawBitmap(endBitmap, 0f, 0f, paint)
}
canvas.restoreToCount(saveCount)
}
override fun setAlpha(alpha: Int) {}
override fun setColorFilter(colorFilter: ColorFilter?) {
paint.colorFilter = colorFilter
}
private fun getTranslationPoint(gravity: Int, start: Float, end: Float, dim: Float,
scale: Float): Float {
return when (gravity) {
Gravity.CENTER_HORIZONTAL, Gravity.CENTER_VERTICAL -> (start + end - dim * scale) / 2f
Gravity.RIGHT, Gravity.BOTTOM -> end - dim * scale
Gravity.LEFT, Gravity.TOP -> start
else -> start
}
}
}
/**
* Contains all the non-font-size data used by the TextResize transition.
* None of these values should trigger the transition, so they are not listed
* in PROPERTIES. These are captured together to avoid boxing of all the
* primitives while adding to TransitionValues.
*/
internal class TextResizeData(textView: TextView) {
val paddingLeft = textView.paddingLeft
val paddingTop = textView.paddingTop
val paddingRight = textView.paddingRight
val paddingBottom = textView.paddingBottom
val width = textView.width
val height = textView.height
val gravity = textView.gravity
val textColor = textView.currentTextColor
}
companion object {
private val FONT_SIZE = "TextResize:fontSize"
private val DATA = "TextResize:data"
private val PROPERTIES = arrayOf(
// We only care about FONT_SIZE. If anything else changes, we don't
// want this transition to be called to create an Animator.
FONT_SIZE)
private fun setTextViewData(view: TextView, data: TextResizeData, fontSize: Float) {
view.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize)
view.setPadding(data.paddingLeft, data.paddingTop, data.paddingRight, data.paddingBottom)
view.right = view.left + data.width
view.bottom = view.top + data.height
view.setTextColor(data.textColor)
val widthSpec = View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.EXACTLY)
val heightSpec = View.MeasureSpec.makeMeasureSpec(view.height, View.MeasureSpec.EXACTLY)
view.measure(widthSpec, heightSpec)
view.layout(view.left, view.top, view.right, view.bottom)
}
private fun captureTextBitmap(textView: TextView): Bitmap? {
val background = textView.background
textView.background = null
val width = textView.width - textView.paddingLeft - textView.paddingRight
val height = textView.height - textView.paddingTop - textView.paddingBottom
if (width <= 0 || height <= 0) {
return null
}
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
canvas.translate((-textView.paddingLeft).toFloat(), (-textView.paddingTop).toFloat())
textView.draw(canvas)
textView.background = background
return bitmap
}
private fun interpolate(start: Float, end: Float, fraction: Float): Float {
return start + fraction * (end - start)
}
}
}

View File

@ -3,7 +3,6 @@ package de.mm20.launcher2.ui.animation
import androidx.compose.animation.core.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.ExperimentalUnitApi
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.TextUnitType

View File

@ -27,7 +27,7 @@ import de.mm20.launcher2.ui.component.BottomSheetDialog
import de.mm20.launcher2.ui.component.LargeMessage
import de.mm20.launcher2.ui.component.SmallMessage
@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RestoreBackupSheet(
uri: Uri,

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.ui.component
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable

View File

@ -42,6 +42,7 @@ import de.mm20.launcher2.ui.locals.LocalDarkTheme
import palettes.TonalPalette
import java.time.Instant
import java.time.ZoneId
import kotlin.math.abs
import kotlin.math.pow
import kotlin.math.roundToInt
@ -389,12 +390,12 @@ private val SquircleShape: Shape
for (x in -radius.roundToInt()..radius.roundToInt())
lineTo(
x.toFloat(),
Math.cbrt(radiusToPow - Math.abs(x * x * x)).toFloat()
Math.cbrt(radiusToPow - abs(x * x * x)).toFloat()
)
for (x in radius.roundToInt() downTo -radius.roundToInt())
lineTo(
x.toFloat(),
(-Math.cbrt(radiusToPow - Math.abs(x * x * x))).toFloat()
(-Math.cbrt(radiusToPow - abs(x * x * x))).toFloat()
)
translate(Offset(size.width / 2f, size.height / 2f))
}

View File

@ -3,7 +3,6 @@ package de.mm20.launcher2.ui.component.preferences
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Switch
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.ui.component.preferences
import androidx.compose.material3.Switch
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector

View File

@ -613,6 +613,7 @@ private fun Precipitation(icon: WeatherIcon) {
tint = colorResource(id = R.color.weather_snow)
)
}
else -> {}
}
}
}

View File

@ -181,14 +181,6 @@ class LauncherActivity : BaseActivity() {
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
override fun onResume() {
super.onResume()
/*binding.container.doOnNextLayout {
WallpaperManager.getInstance(this).setWallpaperOffsets(it.windowToken, 0.5f, 0.5f)
}*/
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
val navContract = intent?.let { GestureNavContract.fromIntent(it) }

View File

@ -6,7 +6,7 @@ import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.slideIn
import androidx.compose.animation.slideOut
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.LocalOverScrollConfiguration
import androidx.compose.foundation.LocalOverscrollConfiguration
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
@ -46,8 +46,7 @@ import de.mm20.launcher2.ui.utils.rememberNotificationShadeController
import kotlin.math.roundToInt
@OptIn(
ExperimentalMaterialApi::class,
ExperimentalFoundationApi::class
ExperimentalMaterialApi::class, ExperimentalFoundationApi::class
)
@Composable
fun PagerScaffold(
@ -216,7 +215,7 @@ fun PagerScaffold(
CompositionLocalProvider(
LocalOverScrollConfiguration provides null
LocalOverscrollConfiguration provides null
) {
Row(

View File

@ -7,7 +7,7 @@ import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.slideIn
import androidx.compose.animation.slideOut
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.LocalOverScrollConfiguration
import androidx.compose.foundation.LocalOverscrollConfiguration
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
@ -231,7 +231,7 @@ fun PullDownScaffold(
derivedStateOf { maxHeight }
}
CompositionLocalProvider(
LocalOverScrollConfiguration provides null
LocalOverscrollConfiguration provides null
) {
val offset by animateFloatAsState(if (isSearchOpen) 1f else 0f)
Column(

View File

@ -1,9 +1,6 @@
package de.mm20.launcher2.ui.launcher.modals
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import de.mm20.launcher2.favorites.FavoritesItem
import de.mm20.launcher2.favorites.FavoritesRepository
import org.koin.core.component.KoinComponent

View File

@ -3,19 +3,13 @@ package de.mm20.launcher2.ui.launcher.modals
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.Settings
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource

View File

@ -3,11 +3,7 @@ package de.mm20.launcher2.ui.launcher.modals
import android.content.Context
import android.content.Intent
import androidx.lifecycle.ViewModel
import de.mm20.launcher2.favorites.FavoritesRepository
import de.mm20.launcher2.ui.settings.SettingsActivity
import kotlinx.coroutines.flow.map
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class HiddenItemsSheetVM: ViewModel() {

View File

@ -1,21 +1,9 @@
package de.mm20.launcher2.ui.launcher.search
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.VisibilityOff
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.ui.launcher.LauncherActivityVM
import de.mm20.launcher2.ui.launcher.search.apps.AppResults
import de.mm20.launcher2.ui.launcher.search.appshortcuts.AppShortcutResults
import de.mm20.launcher2.ui.launcher.search.calculator.CalculatorResults
@ -29,7 +17,6 @@ import de.mm20.launcher2.ui.launcher.search.website.WebsiteResults
import de.mm20.launcher2.ui.launcher.search.wikipedia.WikipediaResults
import de.mm20.launcher2.ui.layout.BottomReversed
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SearchColumn(
modifier: Modifier = Modifier,

View File

@ -37,7 +37,6 @@ import kotlin.math.min
import kotlin.math.pow
import kotlin.math.roundToInt
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun AppItem(
modifier: Modifier = Modifier,

View File

@ -1,4 +1,4 @@
package de.mm20.launcher2.ui.search
package de.mm20.launcher2.ui.launcher.search.calculator
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth

View File

@ -11,7 +11,6 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.ui.component.LauncherCard
import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.search.CalculatorItem
@Composable
fun ColumnScope.CalculatorResults(reverse: Boolean = false) {

View File

@ -109,7 +109,7 @@ fun GridItem(modifier: Modifier = Modifier, item: Searchable, showLabels: Boolea
}
}
@OptIn(ExperimentalComposeUiApi::class, ExperimentalAnimationApi::class)
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun ItemPopup(origin: Rect, searchable: Searchable, onDismissRequest: () -> Unit) {
var show by remember { mutableStateOf(false) }

View File

@ -1,19 +1,8 @@
package de.mm20.launcher2.ui.launcher.search.common.grid
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.toAndroidRect
import androidx.core.app.ActivityOptionsCompat
import de.mm20.launcher2.badges.BadgeRepository
import de.mm20.launcher2.favorites.FavoritesRepository
import de.mm20.launcher2.icons.IconRepository
import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.ui.launcher.search.common.SearchableItemVM
import kotlinx.coroutines.flow.Flow
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class GridItemVM(
private val searchable: Searchable
searchable: Searchable
): SearchableItemVM(searchable)

View File

@ -16,7 +16,7 @@ import de.mm20.launcher2.ui.launcher.search.contacts.ContactItem
import de.mm20.launcher2.ui.launcher.search.files.FileItem
import de.mm20.launcher2.ui.launcher.search.shortcut.AppShortcutItem
@OptIn(ExperimentalMaterialApi::class, androidx.compose.foundation.ExperimentalFoundationApi::class)
@OptIn(androidx.compose.foundation.ExperimentalFoundationApi::class)
@Composable
fun ListItem(modifier: Modifier = Modifier, item: Searchable) {
var showDetails by remember { mutableStateOf(false) }

View File

@ -4,6 +4,5 @@ import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.ui.launcher.search.common.SearchableItemVM
class ListItemVM(
private val searchable: Searchable
): SearchableItemVM(searchable) {
}
searchable: Searchable
): SearchableItemVM(searchable)

View File

@ -43,7 +43,6 @@ import de.mm20.launcher2.ui.locals.LocalSnackbarHostState
import de.mm20.launcher2.ui.modifier.scale
import kotlinx.coroutines.launch
@OptIn(ExperimentalUnitApi::class)
@Composable
fun ContactItem(
modifier: Modifier = Modifier,

View File

@ -38,7 +38,6 @@ import kotlinx.coroutines.launch
import java.text.DecimalFormat
import kotlin.math.roundToInt
@OptIn(ExperimentalUnitApi::class)
@Composable
fun FileItem(
modifier: Modifier = Modifier,

View File

@ -40,7 +40,6 @@ import kotlinx.coroutines.launch
import kotlin.math.pow
import kotlin.math.roundToInt
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun AppShortcutItem(
modifier: Modifier = Modifier,

View File

@ -1,9 +1,8 @@
package de.mm20.launcher2.ui.search
package de.mm20.launcher2.ui.launcher.search.unitconverter
import android.icu.text.DateFormat
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.*
import androidx.compose.material3.*
@ -12,11 +11,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import de.mm20.launcher2.search.data.CurrencyUnitConverter
import de.mm20.launcher2.search.data.UnitConverter
import de.mm20.launcher2.ui.R

View File

@ -11,7 +11,6 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.ui.component.LauncherCard
import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.search.UnitConverterItem
@Composable
fun ColumnScope.UnitConverterResults(reverse: Boolean = false) {

View File

@ -1,6 +1,5 @@
package de.mm20.launcher2.ui.launcher.transitions
import android.content.ComponentName
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import com.android.launcher3.GestureNavContract

View File

@ -1,9 +1,6 @@
package de.mm20.launcher2.ui.launcher.transitions
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.toAndroidRectF
import com.android.launcher3.GestureNavContract
import kotlinx.coroutines.flow.MutableSharedFlow

View File

@ -16,7 +16,6 @@ import androidx.compose.foundation.gestures.rememberDraggableState
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Add
import androidx.compose.material3.*
@ -36,7 +35,7 @@ import androidx.compose.ui.window.Dialog
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.ui.ClockWidget
import de.mm20.launcher2.ui.launcher.widgets.clock.ClockWidget
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.ktx.animateTo
import de.mm20.launcher2.ui.launcher.widgets.picker.PickAppWidgetActivity

View File

@ -145,7 +145,7 @@ fun CalendarWidget() {
)
}
val pinnedEvents by viewModel.pinnedCalendarEvents.observeAsState(emptyList())
if (pinnedEvents.size > 0) {
if (pinnedEvents.isNotEmpty()) {
Text(
stringResource(R.string.calendar_widget_pinned_events),
modifier = Modifier.padding(start = 4.dp, end = 4.dp, top = 8.dp, bottom = 4.dp),

View File

@ -1,4 +1,4 @@
package de.mm20.launcher2.ui
package de.mm20.launcher2.ui.launcher.widgets.clock
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@ -19,7 +19,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
import de.mm20.launcher2.ui.base.LocalTime
import de.mm20.launcher2.ui.launcher.widgets.clock.ClockWidgetVM
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.*
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.PartProvider

View File

@ -2,7 +2,6 @@ package de.mm20.launcher2.ui.launcher.widgets.clock.parts
import android.content.Context
import androidx.compose.runtime.Composable
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
import kotlinx.coroutines.flow.Flow

View File

@ -33,7 +33,7 @@ fun AppWidgetList(
modifier = modifier
) {
for (group in widgets) {
item() {
item {
Text(
modifier = Modifier.padding(
top = 16.dp,

View File

@ -10,6 +10,7 @@ import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material3.*
@ -67,7 +68,7 @@ class PickAppWidgetActivity : BaseActivity() {
if (selected == null) {
if (widgets != null) {
AppWidgetList(
modifier = Modifier.fillMaxSize(),
modifier = Modifier.fillMaxSize().padding(it),
widgets = widgets,
onWidgetSelected = {
selectAppWidget(it)
@ -75,7 +76,7 @@ class PickAppWidgetActivity : BaseActivity() {
)
} else {
Box(
modifier = Modifier.fillMaxSize(),
modifier = Modifier.fillMaxSize().padding(it),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator()

View File

@ -39,7 +39,6 @@ import java.text.DecimalFormat
import java.text.SimpleDateFormat
import kotlin.math.roundToInt
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun WeatherWidget() {
val viewModel: WeatherWidgetWM = viewModel()

View File

@ -1,22 +0,0 @@
package de.mm20.launcher2.ui.legacy.helper
import android.graphics.*
import android.util.LruCache
import androidx.annotation.MainThread
/**
* Helper object to store temporary bitmaps to draw on so they don't have to be allocated every
* time and can be reused by different classes and methods.
*/
object BitmapHolder {
private val cache = LruCache<Int, Pair<Bitmap, Canvas>>(8)
@MainThread
fun getBitmapAndCanvas(size: Int): Pair<Bitmap, Canvas> {
return cache[size]?.apply { second.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR) }
?: Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888).let {
Pair(it, Canvas(it)).also { pair -> cache.put(size, pair) }
}
}
}

View File

@ -1,137 +0,0 @@
package de.mm20.launcher2.ui.legacy.view
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.os.BatteryManager
import android.util.AttributeSet
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.*
import de.mm20.launcher2.ktx.dp
import java.util.*
class BatteryChargingView : View, DefaultLifecycleObserver {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleRes: Int) : super(context, attrs, defStyleRes)
private var animating = false
private val activity = context as AppCompatActivity
init {
activity.lifecycle.addObserver(this)
}
private val batteryReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action != Intent.ACTION_BATTERY_CHANGED) return
update(intent, true)
}
}
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
val intent = activity.registerReceiver(batteryReceiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
start()
intent?.let { update(it, true) }
}
override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
stop()
try {
activity.unregisterReceiver(batteryReceiver)
} catch (e: IllegalArgumentException) {
}
}
private fun update(intent: Intent, retryOnZeroCurrent: Boolean = false) {
val status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
val charging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL
if (charging) {
val bm = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val current = bm.getLongProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_NOW)
if (current <= 0) {
intensity = 5
start()
//Workaround for delayed current updates
if (retryOnZeroCurrent) postDelayed({ update(intent) }, 1000)
return
}
intensity = Math.round(current / 100000f).takeIf { it > 0 } ?: 1
start()
} else {
intensity = 0
}
}
var intensity = 0
set(value) {
if (field == 0 && value > 0) start()
if (value == 0) stop()
field = when {
value > 100 -> 100
value < 0 -> 0
else -> value
}
for (i in field until bubbles.size) {
bubbles.pop()
}
for (i in bubbles.size until field) {
bubbles.push(FloatArray(6) { 0f })
}
}
fun start() {
if (animating || intensity == 0) return
animating = true
invalidate()
}
fun stop() {
animating = false
}
/**
* 0: Pos X
* 1: Pos Y
* 2: Delta X
* 3: Delta Y
* 4: Radius
* 5: Lifetime left
*/
private var bubbles = ArrayDeque<FloatArray>()
private val paint = Paint()
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
if (!animating) return
for (b in bubbles) {
if (b[5] <= 0f) {
b[0] = (Math.random() * width).toFloat()
b[1] = height.toFloat()
b[2] = ((Math.random() - 0.5) * width / 120f).toFloat() * dp
b[3] = -(Math.random() * height / 90f).toFloat() * dp
b[4] = (Math.random() * 2 + 2).toFloat() * dp
b[5] = (Math.random() * 80 + 40).toInt().toFloat()
}
paint.color = Color.argb((b[5] / 120f * 120).toInt(), 255, 255, 255)
canvas.drawCircle(b[0], b[1], b[4], paint)
b[0] += b[2]
b[1] += b[3]
b[5]--
}
postInvalidate()
}
}

View File

@ -1,15 +0,0 @@
package de.mm20.launcher2.ui.settings
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class SettingsActivityVM: ViewModel(), KoinComponent {
}

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.ui.settings.accounts
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope

View File

@ -318,7 +318,6 @@ fun SearchBarStylePreference(
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun IconShapePreference(
title: String,

View File

@ -1,6 +1,5 @@
package de.mm20.launcher2.ui.settings.backup
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.*

View File

@ -1,19 +1,9 @@
package de.mm20.launcher2.ui.settings.backup
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.core.content.FileProvider
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.backup.BackupManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.File
class BackupSettingsScreenVM : ViewModel(), KoinComponent {

View File

@ -1,17 +1,12 @@
package de.mm20.launcher2.ui.settings.buildinfo
import android.content.pm.PackageManager
import android.os.Build
import android.util.Base64
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import de.mm20.launcher2.accounts.AccountType
import de.mm20.launcher2.accounts.AccountsRepository
import de.mm20.launcher2.preferences.Settings.WeatherSettings.WeatherProvider
import de.mm20.launcher2.weather.WeatherRepository
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.security.MessageDigest
class BuildInfoSettingsScreenVM : ViewModel(), KoinComponent {
private val accountsRepository: AccountsRepository by inject()

View File

@ -20,7 +20,7 @@ import com.google.accompanist.pager.HorizontalPagerIndicator
import com.google.accompanist.pager.rememberPagerState
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
import de.mm20.launcher2.ui.Clock
import de.mm20.launcher2.ui.launcher.widgets.clock.Clock
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.*

View File

@ -2,7 +2,6 @@ package de.mm20.launcher2.ui.settings.crashreporter
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.crashreporter.BuildConfig
import de.mm20.launcher2.crashreporter.CrashReport

View File

@ -4,8 +4,6 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.preferences.Settings.IconSettings.IconShape
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent

View File

@ -82,7 +82,7 @@ fun HiddenItemsSettingsScreen() {
DropdownMenuItem(
text = { Text(stringResource(R.string.menu_app_info)) },
onClick = {
viewModel.openAppInfo(context, searchable as Application)
viewModel.openAppInfo(context, searchable)
showPopup = false
})

View File

@ -1,17 +1,9 @@
package de.mm20.launcher2.ui.settings.websearch
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.scale
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import coil.imageLoader
import coil.request.ImageRequest
import coil.size.Scale
import de.mm20.launcher2.search.WebsearchRepository
import de.mm20.launcher2.search.data.Websearch
import kotlinx.coroutines.Dispatchers
@ -20,7 +12,6 @@ import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.File
import java.io.FileOutputStream
class WebSearchSettingsScreenVM: ViewModel(), KoinComponent {
private val repository: WebsearchRepository by inject()

View File

@ -2,7 +2,6 @@ package de.mm20.launcher2.unitconverter
import de.mm20.launcher2.currencies.CurrencyRepository
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val unitConverterModule = module {

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.websites
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val websitesModule = module {

View File

@ -94,8 +94,8 @@ internal class WebsiteRepositoryImpl(val context: Context) : WebsiteRepository,
if (favicon.isBlank()) favicon = doc.select("link[rel=icon]").attr("href")
if (favicon.isBlank()) favicon =
doc.head().select("link[href~=.*\\.(ico|png)]").attr("href")
if (!favicon.isBlank()) favicon = resolveUrl(response.request.url, favicon)
if (!image.isBlank()) image = resolveUrl(response.request.url, image)
if (favicon.isNotBlank()) favicon = resolveUrl(response.request.url, favicon)
if (image.isNotBlank()) image = resolveUrl(response.request.url, image)
return@withContext Website(
label = title,
url = url,

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.widgets
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val widgetsModule = module {

View File

@ -7,7 +7,6 @@ import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat
import de.mm20.launcher2.icons.ColorLayer
import de.mm20.launcher2.icons.StaticIconLayer
import de.mm20.launcher2.icons.StaticLauncherIcon
import de.mm20.launcher2.icons.TintedIconLayer
import de.mm20.launcher2.wikipedia.R
@ -43,8 +42,4 @@ class Wikipedia(
intent.intent.data = Uri.parse(uri)
return intent.intent
}
companion object {
}
}

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.wikipedia
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val wikipediaModule = module {