Skip to content

Instantly share code, notes, and snippets.

@Alvtag
Created February 15, 2023 23:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Alvtag/5bd46a2007e6c4f382d431e43aa96e80 to your computer and use it in GitHub Desktop.
Save Alvtag/5bd46a2007e6c4f382d431e43aa96e80 to your computer and use it in GitHub Desktop.
import Common
import Common.Companion.greyColorProvider
import Common.Companion.whiteColorProvider
import android.content.Context
import android.graphics.Bitmap
import android.util.Log
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.graphics.drawable.toBitmapOrNull
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.preferencesOf
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.glance.*
import androidx.glance.action.Action
import androidx.glance.action.actionParametersOf
import androidx.glance.action.actionStartActivity
import androidx.glance.action.clickable
import androidx.glance.appwidget.*
import androidx.glance.layout.*
import androidx.glance.text.*
import coil.decode.SvgDecoder
import coil.imageLoader
import coil.request.CachePolicy
import coil.request.ErrorResult
import coil.request.ImageRequest
import coil.request.SuccessResult
import com.google.android.glance.appwidget.host.glance.GlanceAppWidgetHostPreview
import com.tribalscale.testwidget.MainActivity
import com.tribalscale.testwidget.R
import java.util.*
class HelloWorldSingleCellWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = HelloWorldSingleCellWidget
}
object HelloWorldSingleCellWidget : GlanceAppWidget() {
val symbolKey: Preferences.Key<String> = stringPreferencesKey(MainActivity.PARAMS_NAME)
override val sizeMode: SizeMode = SizeMode.Exact
@Composable
override fun Content() {
HelloWorldSingleCellWidgetContent()
}
}
@Composable
fun HelloWorldSingleCellWidgetContent() {
val coinSymbol = currentState(HelloWorldSingleCellWidget.symbolKey) ?: "btc"
val coinName = "Bitcoin"
val coinPercentChange = 2.30
val coinPrice = 22432.31
val priceAt = "Price at"
val priceTime = "6:30 PM EST"
val imageSvgUrl =
"${Common.imageUrl}${coinSymbol.lowercase(Locale.ENGLISH)}${Common.imageExtension}"
val context = LocalContext.current
var coinImage by remember(imageSvgUrl) { mutableStateOf<Bitmap?>(null) }
Column(
modifier = GlanceModifier.fillMaxSize()
.background(color = Color(LocalContext.current.getColor(R.color.brandNetcoins)))
.cornerRadius(16.dp)
.padding(18.dp)
.clickable(onClick = actionLaunchActivity(coinSymbol)),
verticalAlignment = Alignment.Top,
horizontalAlignment = Alignment.Start,
) {
// Top row: icons
Row(
verticalAlignment = Alignment.Top,
horizontalAlignment = Alignment.Start,
modifier = GlanceModifier.fillMaxWidth().background(Color(0x00000000))
) {
Log.d("ALVTAG", "BBB+coinImage:${coinImage.toString()}")
if (coinImage != null) {
CoinImage(coinImage!!)
} else {
LaunchedEffect(imageSvgUrl) {
Log.d("ALVTAG", "A1:loadit:+coinImage:${coinImage.toString()}")
Log.d("ALVTAG", "A2:loadit:+imageSvgUrl:${imageSvgUrl.toString()}")
coinImage = context.getNetworkImage(imageSvgUrl)
Log.d("ALVTAG", "A3:loadedIt:+coinImage:${coinImage}")
}
CircularProgressIndicator(modifier = GlanceModifier.size(30.dp))
}
Row(
modifier = GlanceModifier.fillMaxWidth(),
verticalAlignment = Alignment.Top,
horizontalAlignment = Alignment.End
) {
Image(
provider = ImageProvider(R.drawable.netcoins),
contentDescription = LocalContext.current.getString(R.string.content_description_widget_netcoins_image),
modifier = GlanceModifier.size(30.dp, 30.dp)
.clickable(actionLaunchActivity(coinSymbol)),
contentScale = ContentScale.Crop
)
}
}
// Mid row: ticker symbol | % change
// ticker name | 24H
Common.GlanceCoinInfo(coinSymbol, coinName, coinPercentChange)
Column(
modifier = GlanceModifier.clickable(onClick = actionLaunchActivity(coinSymbol))
.fillMaxSize(),
verticalAlignment = Alignment.CenterVertically,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "$${Common.priceFormat.format(coinPrice)}",
style = TextStyle(
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
color = whiteColorProvider(),
fontSize = 24.sp
),
modifier = GlanceModifier.clickable(onClick = actionLaunchActivity(coinSymbol)),
)
Text(
text = "$priceAt $priceTime",
style = TextStyle(
textAlign = TextAlign.Center,
color = greyColorProvider(),
fontSize = 10.sp
),
modifier = GlanceModifier.clickable(onClick = actionLaunchActivity(coinSymbol)),
)
}
}
}
@Composable
private fun CoinImage(coinImage: Bitmap) {
Image(
provider = ImageProvider(coinImage),
contentDescription = stringResource(id = R.string.content_description_widget_coin_logo),
contentScale = ContentScale.FillBounds,
modifier = GlanceModifier.size(30.dp)
)
}
@OptIn(ExperimentalGlanceRemoteViewsApi::class)
@Preview
@Composable
fun HelloWorldSingleCellWidgetPreview() {
// The size of the widget
val displaySize = DpSize(200.dp, 200.dp)
// Provide a state depending on the GlanceAppWidget state definition
val state = preferencesOf(HelloWorldSingleCellWidget.symbolKey to "moo")
GlanceAppWidgetHostPreview(
modifier = Modifier.fillMaxSize(),
glanceAppWidget = HelloWorldSingleCellWidget,
state = state,
displaySize = displaySize,
)
}
fun actionLaunchActivity(symbol: String): Action {
return actionStartActivity(
MainActivity::class.java,
parameters = actionParametersOf(MainActivity.PARAMS_KEY to symbol)
)
}
private suspend fun Context.getNetworkImage(url: String, force: Boolean = false): Bitmap? {
Log.d("ALVGTAG", "AAA url:$url")
val request = ImageRequest.Builder(this)
.data(url)
.decoderFactory(SvgDecoder.Factory())
.apply {
if (force) {
memoryCachePolicy(CachePolicy.DISABLED)
diskCachePolicy(CachePolicy.DISABLED)
}
}.build()
// Request the image to be loaded and throw error if it failed
return when (val result = imageLoader.execute(request)) {
is ErrorResult -> {
Log.d("ALVTAG", "D: failure:"+result.throwable.message)
throw result.throwable
}
is SuccessResult -> {
Log.d("ALVTAG", "D: success:${result.drawable.toBitmapOrNull()}")
result.drawable.toBitmapOrNull()
}
}
}
2023-02-15 17:34:09.710 21044-23067 ALVTAG D BBB+coinImage:null
2023-02-15 17:34:09.712 21044-21079 ALVTAG D BBB+coinImage:null
2023-02-15 17:34:09.722 21044-21078 ALVTAG D A1:loadit:+coinImage:null
2023-02-15 17:34:09.722 21044-21078 ALVTAG D A2:loadit:+imageSvgUrl:https://netcoins.app/images/crypto/btc.svg
2023-02-15 17:34:09.722 21044-21078 ALVGTAG D AAA url:https://netcoins.app/images/crypto/btc.svg
2023-02-15 17:34:09.725 21044-21078 ALVTAG D A1:loadit:+coinImage:null
2023-02-15 17:34:09.725 21044-21078 ALVTAG D A2:loadit:+imageSvgUrl:https://netcoins.app/images/crypto/btc.svg
2023-02-15 17:34:09.725 21044-21078 ALVGTAG D AAA url:https://netcoins.app/images/crypto/btc.svg
2023-02-15 17:34:09.892 21044-21044 cale.testwidge W Class androidx.compose.runtime.snapshots.SnapshotStateList failed lock verification and will run slower.
Common causes for lock verification issues are non-optimized dex code
and incorrect proguard optimizations.
2023-02-15 17:34:10.373 21044-23067 ALVTAG D D: success:android.graphics.Bitmap@4f522e6
2023-02-15 17:34:10.373 21044-23067 ALVTAG D A3:loadedIt:+coinImage:android.graphics.Bitmap@4f522e6
2023-02-15 17:34:10.421 21044-21044 ALVTAG D BBB+coinImage:null
2023-02-15 17:34:10.439 21044-21070 OpenGLRenderer I Davey! duration=716ms; Flags=0, IntendedVsync=68110243727906, Vsync=68110593727892, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=68110600377434, AnimationStart=68110600378850, PerformTraversalsStart=68110665588017, DrawStart=68110666567934, SyncQueued=68110888854184, SyncStart=68110888962017, IssueDrawCommandsStart=68110889027559, SwapBuffers=68110944501267, FrameCompleted=68110960180934, DequeueBufferDuration=20958, QueueBufferDuration=383833, GpuCompleted=12816,
2023-02-15 17:34:10.465 21044-21044 ALVTAG D A1:loadit:+coinImage:null
2023-02-15 17:34:10.465 21044-21044 ALVTAG D A2:loadit:+imageSvgUrl:https://netcoins.app/images/crypto/btc.svg
2023-02-15 17:34:10.465 21044-21044 ALVGTAG D AAA url:https://netcoins.app/images/crypto/btc.svg
2023-02-15 17:34:10.468 21044-21044 ALVTAG D D: success:android.graphics.Bitmap@4f522e6
2023-02-15 17:34:10.468 21044-21044 ALVTAG D A3:loadedIt:+coinImage:android.graphics.Bitmap@4f522e6
2023-02-15 17:34:10.490 21044-21044 GlanceAppWidget W Cannot set the rounded corner of views before Api 31.
2023-02-15 17:34:10.505 21044-23067 ALVTAG D D: success:android.graphics.Bitmap@4f522e6
2023-02-15 17:34:10.506 21044-23067 ALVTAG D A3:loadedIt:+coinImage:android.graphics.Bitmap@4f522e6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment