Added the shadow to the icons

This commit is contained in:
Tommaso Berlose 2020-10-16 18:04:30 +02:00
parent e2719b6445
commit 331d5772af
10 changed files with 295 additions and 149 deletions

Binary file not shown.

View File

@ -28,6 +28,8 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField("String", "GOOGLE_API_KEY", apikeyProperties['GOOGLE_API_KEY'])
renderscriptSupportModeEnabled true
}
buildTypes {

View File

@ -0,0 +1,84 @@
package com.tommasoberlose.anotherwidget.helpers
import android.content.Context
import android.graphics.*
import android.renderscript.*
import android.util.TypedValue
import android.widget.ImageView
import androidx.core.graphics.drawable.toBitmap
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
import java.util.prefs.Preferences
import kotlin.math.min
object ImageHelper {
fun ImageView.applyShadow(originalView: ImageView, factor: Float = 1f) {
clearColorFilter()
val cElevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, when (if (context.isDarkTheme()) com.tommasoberlose.anotherwidget.global.Preferences.textShadowDark else com.tommasoberlose.anotherwidget.global.Preferences.textShadow) {
0 -> 0f * factor
1 -> 8f * factor
2 -> 16f * factor
else -> 0f * factor
}, resources.displayMetrics)
if (originalView.drawable != null) {
val btm = originalView.drawable.toBitmap().copy(Bitmap.Config.ARGB_8888, true)
val comb = Bitmap.createBitmap(btm)
val shadowBitmap = generateShadowBitmap(context, cElevation, btm, factor)
shadowBitmap?.let {
val canvas = Canvas(comb)
canvas.drawColor(Color.TRANSPARENT)
canvas.save()
val rect = Rect()
val bounds = originalView.drawable.copyBounds()
canvas.getClipBounds(rect)
rect.inset(-2 * getBlurRadius(context, cElevation).toInt(), -2 * getBlurRadius(context, cElevation).toInt())
canvas.save()
canvas.clipRect(rect)
canvas.drawBitmap(shadowBitmap, 0f, 2f, null)
canvas.restore()
setImageBitmap(comb)
}
}
}
private fun generateShadowBitmap(context: Context, cElevation: Float, bitmap: Bitmap?, factor: Float): Bitmap? {
val rs: RenderScript = RenderScript.create(context)
val element = Element.U8_4(rs)
val blurScript: ScriptIntrinsicBlur = ScriptIntrinsicBlur.create(rs, element)
val colorMatrixScript: ScriptIntrinsicColorMatrix = ScriptIntrinsicColorMatrix.create(rs)
val allocationIn = Allocation.createFromBitmap(rs, bitmap)
val allocationOut = Allocation.createTyped(rs, allocationIn.type)
val matrix = Matrix4f(floatArrayOf(
0f, 0f, 0f, 0f,
0f, 0f, 0f, 0f,
0f, 0f, 0f, 0f,
0f, 0f, 0f, when (if (context.isDarkTheme()) com.tommasoberlose.anotherwidget.global.Preferences.textShadowDark else com.tommasoberlose.anotherwidget.global.Preferences.textShadow) {
0 -> 0f * factor
1 -> 0.8f * factor
2 -> 1f * factor
else -> 0f
}))
colorMatrixScript.setColorMatrix(matrix)
colorMatrixScript.forEach(allocationIn, allocationOut)
blurScript.setRadius(getBlurRadius(context, cElevation))
blurScript.setInput(allocationOut)
blurScript.forEach(allocationIn)
allocationIn.copyTo(bitmap)
allocationIn.destroy()
allocationOut.destroy()
return bitmap
}
private fun getBlurRadius(context: Context, customElevation: Float): Float {
val maxElevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24f, context.resources.displayMetrics)
return min(25f * (customElevation / maxElevation), 25f)
}
}

View File

@ -66,6 +66,10 @@ class WeatherProviderActivity : AppCompatActivity() {
injector
.text(R.id.text, WeatherHelper.getProviderName(this, provider))
.clicked(R.id.item) {
if (Preferences.weatherProvider != provider.value) {
Preferences.weatherProviderError = "-"
Preferences.weatherProviderLocationError = ""
}
val oldValue = Preferences.weatherProvider
Preferences.weatherProvider = provider.value
updateListItem(oldValue)
@ -77,6 +81,10 @@ class WeatherProviderActivity : AppCompatActivity() {
}
}
.clicked(R.id.radioButton) {
if (Preferences.weatherProvider != provider.value) {
Preferences.weatherProviderError = "-"
Preferences.weatherProviderLocationError = ""
}
val oldValue = Preferences.weatherProvider
Preferences.weatherProvider = provider.value
updateListItem(oldValue)

View File

@ -354,6 +354,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION
) != true)
|| (Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-")
|| (Preferences.weatherProviderLocationError != "")
} else {
false
}

View File

@ -42,6 +42,8 @@ import com.tommasoberlose.anotherwidget.ui.activities.WeatherProviderActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.collapse
import com.tommasoberlose.anotherwidget.utils.expand
import kotlinx.android.synthetic.main.fragment_weather_settings.*
import kotlinx.android.synthetic.main.fragment_weather_settings.scrollView
import kotlinx.coroutines.delay
@ -87,11 +89,6 @@ class WeatherTabFragment : Fragment() {
) {
binding.isWeatherVisible = Preferences.showWeather
viewModel.showWeatherWarning.observe(viewLifecycleOwner, Observer {
weather_warning?.isVisible = it
checkLocationPermission()
})
viewModel.showWeather.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_weather_label?.text =
@ -100,6 +97,7 @@ class WeatherTabFragment : Fragment() {
binding.isWeatherVisible = it
}
checkLocationPermission()
checkWeatherProviderConfig()
})
viewModel.weatherProvider.observe(viewLifecycleOwner, Observer {
@ -174,7 +172,7 @@ class WeatherTabFragment : Fragment() {
WeatherReceiver.setUpdates(requireContext())
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
location_permission_alert?.isVisible = true
background_location_warning.isVisible = false
background_location_warning.isVisible = true
location_permission_alert?.setOnClickListener {
MaterialBottomSheetDialog(requireContext(), message = getString(R.string.background_location_warning))
.setPositiveButton(getString(android.R.string.ok)) {
@ -188,18 +186,22 @@ class WeatherTabFragment : Fragment() {
}
private fun checkWeatherProviderConfig() {
weather_provider_error.isVisible = Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-"
if (Preferences.showWeather && Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-" && !location_permission_alert.isVisible) {
weather_provider_error.expand()
} else {
weather_provider_error.collapse()
}
weather_provider_error?.text = Preferences.weatherProviderError
weather_provider_location_error.isVisible = Preferences.weatherProviderLocationError != ""
if (Preferences.showWeather && Preferences.weatherProviderLocationError != "" && !location_permission_alert.isVisible) {
weather_provider_location_error.expand()
} else {
weather_provider_location_error.collapse()
}
weather_provider_location_error?.text = Preferences.weatherProviderLocationError
}
private fun setupListener() {
action_hide_weather_warning.setOnClickListener {
Preferences.showWeatherWarning = false
}
action_show_weather.setOnClickListener {
Preferences.showWeather = !Preferences.showWeather
}

View File

@ -29,6 +29,7 @@ import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.*
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
import com.tommasoberlose.anotherwidget.helpers.ImageHelper.applyShadow
import com.tommasoberlose.anotherwidget.receivers.*
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
@ -715,7 +716,6 @@ class MainWidget : AppWidgetProvider() {
if (Preferences.customNotes.isNotEmpty()) {
v.second_row_icon.isVisible = false
v.next_event_date.text = Preferences.customNotes
v.next_event_date.gravity
v.next_event_date.maxLines = 2
showSomething = true
break@loop
@ -804,9 +804,9 @@ class MainWidget : AppWidgetProvider() {
}
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.value) {
listOf<ImageView>(v.second_row_icon)
listOf<ImageView>(v.second_row_icon, v.second_row_icon_shadow)
} else {
listOf<ImageView>(v.second_row_icon, v.weather_icon)
listOf<ImageView>(v.second_row_icon, v.weather_icon, v.second_row_icon_shadow)
}.forEach {
it.setColorFilter(ColorHelper.getSecondaryFontColorRgb(context.applicationContext.isDarkTheme()))
it.alpha =
@ -889,6 +889,38 @@ class MainWidget : AppWidgetProvider() {
it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
}
// Icons shadow
listOf(
Pair(v.second_row_icon, v.second_row_icon_shadow),
).forEach {
if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) {
it.second.isVisible = false
} else {
it.second.isVisible = it.first.isVisible
it.second.scaleX = it.first.scaleX
it.second.scaleY = it.first.scaleY
it.second.applyShadow(it.first)
}
}
listOf(
Pair(v.action_next, v.action_next_shadow),
Pair(v.action_previous, v.action_previous_shadow),
).forEach {
if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) {
it.second.isVisible = false
} else {
it.second.isVisible = it.first.isVisible
it.second.scaleX = it.first.scaleX
it.second.scaleY = it.first.scaleY
it.second.applyShadow(it.first, 0.6f)
}
}
v.action_previous.scaleX = v.action_previous.scaleX * -1
v.action_previous_shadow.scaleX = v.action_previous_shadow.scaleX * -1
// Custom Font
if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) {
val googleSans: Typeface = when (Preferences.customFontVariant) {

View File

@ -1,12 +1,11 @@
package com.tommasoberlose.anotherwidget.utils
import android.animation.*
import android.content.pm.PackageManager
import android.view.Gravity
import android.view.View
import android.view.ViewAnimationUtils
import android.widget.Toast
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.app.Activity
import android.app.WallpaperManager
import android.content.*
@ -23,10 +22,20 @@ import android.content.res.Resources
import android.graphics.drawable.Drawable
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.ViewPropertyAnimator
import android.view.animation.Animation
import android.view.animation.Transformation
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.core.animation.addListener
import androidx.core.animation.doOnEnd
import androidx.core.animation.doOnStart
import androidx.core.view.isVisible
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
import kotlinx.android.synthetic.main.fragment_app_main.*
import kotlinx.android.synthetic.main.the_widget_sans.*
import java.util.*
@ -68,55 +77,72 @@ fun View.reveal(initialX: Int? = null, initialY: Int? = null) {
}
fun View.expand() {
if (visibility != View.VISIBLE) {
measure(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
val targetHeight = measuredHeight
fun View.expand(duration: Long = 500L) {
clearAnimation()
try {
val animator = (tag as ValueAnimator)
animator.removeAllListeners()
animator.cancel()
} catch (ex: java.lang.Exception) {}
layoutParams.height = 0
visibility = View.VISIBLE
val a = object : Animation() {
protected override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
layoutParams.height = if (interpolatedTime == 1f)
LinearLayout.LayoutParams.WRAP_CONTENT
else
(targetHeight * interpolatedTime).toInt()
translationY = 0f
requestLayout()
}
override fun willChangeBounds(): Boolean {
return true
}
}
a.duration = 500L
startAnimation(a)
layoutParams = layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
measure(0, 0)
val initialHeight = measuredHeight
val anim = ValueAnimator.ofFloat(
alpha,
1f
).apply {
this.duration = duration
addUpdateListener {
val animatedValue = animatedValue as Float
layoutParams = layoutParams.apply {
height = (initialHeight * animatedValue).toInt()
}
translationY = (initialHeight * animatedValue - initialHeight)
alpha = animatedValue
}
addListener(
onStart = {
isVisible = true
}
)
}
tag = anim
anim.start()
}
fun View.collapse(duration: Long = 500L) {
if (visibility != View.GONE) {
val initialHeight = measuredHeight
val a = object : Animation() {
protected override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
if (interpolatedTime == 1f) {
visibility = View.GONE
} else {
layoutParams.height = initialHeight - (initialHeight * interpolatedTime).toInt()
requestLayout()
}
}
override fun willChangeBounds(): Boolean {
return true
clearAnimation()
try {
val animator = (tag as ValueAnimator)
animator.removeAllListeners()
animator.cancel()
} catch (ex: java.lang.Exception) {}
val initialHeight = measuredHeight
val anim = ValueAnimator.ofFloat(
alpha,
0f
).apply {
this.duration = duration
addUpdateListener {
val animatedValue = animatedValue as Float
layoutParams = layoutParams.apply {
height = (initialHeight * animatedValue).toInt()
}
translationY = (initialHeight * animatedValue - initialHeight)
alpha = animatedValue
}
a.duration = duration //(initialHeight / v.context.resources.displayMetrics.density).toLong()
startAnimation(a)
addListener(
onEnd = {
isVisible = false
}
)
}
tag = anim
anim.start()
}
fun Context.openURI(url: String) {

View File

@ -21,45 +21,6 @@
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
app:cardElevation="0dp"
app:cardCornerRadius="9dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:id="@+id/weather_warning"
android:backgroundTint="@color/disabledButtonBackground"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:duplicateParentState="true"
android:id="@+id/label"
android:textSize="16sp"
android:text="@string/weather_warning"
android:textColor="@color/colorPrimaryText"
android:letterSpacing="0"
android:textAppearance="@style/AnotherWidget.Settings.Title"
app:textAllCaps="false" />
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:text="@android:string/ok"
android:id="@+id/action_hide_weather_warning"
android:textColor="@color/colorPrimaryText"
android:layout_gravity="end" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -215,24 +176,21 @@
android:layout_height="wrap_content"
android:id="@+id/label_custom_location"
style="@style/AnotherWidget.Settings.Subtitle"/>
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="36dp"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:letterSpacing="0"
android:textAllCaps="false"
android:clickable="true"
android:layout_marginStart="-8dp"
android:layout_marginBottom="-8dp"
android:paddingBottom="0dp"
android:paddingTop="0dp"
android:focusable="true"
android:visibility="gone"
android:id="@+id/location_permission_alert"
android:textColor="@color/errorColorText"
android:text="@string/action_grant_permission"/>
</LinearLayout>
</LinearLayout>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:duplicateParentState="true"
android:textSize="14sp"
android:id="@+id/weather_provider_location_error"
android:textColor="@color/errorColorText"
android:letterSpacing="0"
android:fontFamily="@font/google_sans_bold"
android:textStyle="bold"
android:layout_marginStart="64dp"
android:textAppearance="@style/TextAppearance.MaterialComponents.Button"
app:textAllCaps="false" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -247,22 +205,22 @@
android:fontFamily="@font/google_sans"
android:textAppearance="@style/AnotherWidget.Settings.Subtitle"
app:textAllCaps="false" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:duplicateParentState="true"
android:textSize="14sp"
android:paddingStart="64dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:visibility="gone"
android:id="@+id/weather_provider_location_error"
android:textColor="@color/errorColorText"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:letterSpacing="0"
android:fontFamily="@font/google_sans_bold"
android:textStyle="bold"
android:textAppearance="@style/TextAppearance.MaterialComponents.Button"
app:textAllCaps="false" />
android:textAllCaps="false"
android:clickable="true"
android:focusable="true"
android:layout_marginTop="8dp"
android:layout_marginStart="64dp"
app:rippleColor="@color/errorColorText_op10"
app:backgroundTint="@color/errorColorText_op10"
android:id="@+id/location_permission_alert"
android:textColor="@color/errorColorText"
android:visibility="gone"
android:text="@string/action_grant_permission"/>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -78,12 +78,21 @@
android:layout_height="wrap_content"
android:layoutDirection="locale"
android:orientation="horizontal">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center_vertical"
android:id="@+id/action_previous"
android:src="@drawable/round_chevron_left" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/action_previous_shadow"
android:src="@drawable/round_chevron_right" />
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/action_previous"
android:src="@drawable/round_chevron_right" />
</RelativeLayout>
<TextView
android:id="@+id/next_event"
android:layout_width="0dp"
@ -107,12 +116,21 @@
android:includeFontPadding="false"
style="@style/AnotherWidget.Widget.Title" />
</LinearLayout>
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center_vertical"
android:id="@+id/action_next"
android:src="@drawable/round_chevron_right" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/action_next_shadow"
android:src="@drawable/round_chevron_right" />
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/action_next"
android:src="@drawable/round_chevron_right" />
</RelativeLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
@ -134,8 +152,8 @@
android:layout_height="28dp"
android:paddingEnd="4dp"
android:paddingStart="4dp"
android:id="@+id/special_weather_icon"
android:layout_marginEnd="4dp"/>
android:layout_marginEnd="4dp"
android:id="@+id/special_weather_icon"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -178,13 +196,28 @@
android:gravity="center_vertical"
android:id="@+id/second_row"
android:orientation="horizontal">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:cropToPadding="false"
android:clipChildren="false"
android:layout_marginEnd="4dp"
android:layout_marginStart="4dp"
android:id="@+id/second_row_icon"
android:src="@drawable/round_today"/>
android:layout_marginStart="4dp">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:cropToPadding="false"
android:clipChildren="false"
android:id="@+id/second_row_icon_shadow"
android:src="@drawable/round_today"/>
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:cropToPadding="false"
android:clipChildren="false"
android:id="@+id/second_row_icon"
android:src="@drawable/round_today"/>
</RelativeLayout>
<TextView
android:id="@+id/next_event_date"
android:layout_width="wrap_content"
@ -217,11 +250,11 @@
android:layout_width="18dp"
android:layout_height="18dp"
android:id="@+id/weather_icon"
android:layout_marginEnd="4dp"
android:clipChildren="false"
android:clipToPadding="false"
android:adjustViewBounds="true"
android:layout_marginStart="4dp"
android:layout_marginEnd="2dp"
android:layout_marginStart="2dp"
android:src="@drawable/clear_night"/>
<TextView
android:layout_width="wrap_content"