Skip to content

Commit 34e7bd4

Browse files
committed
Added option to show the wallet value of a given bitcoin address.
Removed toast message for clicking on error icon on widgets, as this stopped working. Now show configuration screen with error message.
1 parent ded6ab7 commit 34e7bd4

25 files changed

+446
-97
lines changed

bitcoin/build.gradle.kts

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ android {
1515
applicationId = "com.brentpanther.bitcoinwidget"
1616
minSdk = 23
1717
targetSdk = 35
18-
versionCode = 335
19-
versionName = "8.6.0"
18+
versionCode = 336
19+
versionName = "8.6.1"
2020
}
2121

2222
buildFeatures {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
{
2+
"formatVersion": 1,
3+
"database": {
4+
"version": 6,
5+
"identityHash": "01c616eedee5c021678bbc985446b3ac",
6+
"entities": [
7+
{
8+
"tableName": "Widget",
9+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `widgetId` INTEGER NOT NULL, `widgetType` TEXT NOT NULL, `exchange` TEXT NOT NULL, `coin` TEXT NOT NULL, `currency` TEXT NOT NULL, `coinCustomId` TEXT, `coinCustomName` TEXT, `currencyCustomName` TEXT, `showExchangeLabel` INTEGER NOT NULL, `showCoinLabel` INTEGER NOT NULL, `showIcon` INTEGER NOT NULL, `numDecimals` INTEGER NOT NULL, `currencySymbol` TEXT, `theme` TEXT NOT NULL, `nightMode` TEXT NOT NULL, `coinUnit` TEXT, `currencyUnit` TEXT, `customIcon` TEXT, `portraitTextSize` INTEGER, `landscapeTextSize` INTEGER, `lastValue` TEXT, `amountHeld` REAL, `address` TEXT, `showAmountLabel` INTEGER NOT NULL, `useInverse` INTEGER NOT NULL, `lastUpdated` INTEGER NOT NULL, `state` TEXT NOT NULL)",
10+
"fields": [
11+
{
12+
"fieldPath": "id",
13+
"columnName": "id",
14+
"affinity": "INTEGER",
15+
"notNull": true
16+
},
17+
{
18+
"fieldPath": "widgetId",
19+
"columnName": "widgetId",
20+
"affinity": "INTEGER",
21+
"notNull": true
22+
},
23+
{
24+
"fieldPath": "widgetType",
25+
"columnName": "widgetType",
26+
"affinity": "TEXT",
27+
"notNull": true
28+
},
29+
{
30+
"fieldPath": "exchange",
31+
"columnName": "exchange",
32+
"affinity": "TEXT",
33+
"notNull": true
34+
},
35+
{
36+
"fieldPath": "coin",
37+
"columnName": "coin",
38+
"affinity": "TEXT",
39+
"notNull": true
40+
},
41+
{
42+
"fieldPath": "currency",
43+
"columnName": "currency",
44+
"affinity": "TEXT",
45+
"notNull": true
46+
},
47+
{
48+
"fieldPath": "coinCustomId",
49+
"columnName": "coinCustomId",
50+
"affinity": "TEXT",
51+
"notNull": false
52+
},
53+
{
54+
"fieldPath": "coinCustomName",
55+
"columnName": "coinCustomName",
56+
"affinity": "TEXT",
57+
"notNull": false
58+
},
59+
{
60+
"fieldPath": "currencyCustomName",
61+
"columnName": "currencyCustomName",
62+
"affinity": "TEXT",
63+
"notNull": false
64+
},
65+
{
66+
"fieldPath": "showExchangeLabel",
67+
"columnName": "showExchangeLabel",
68+
"affinity": "INTEGER",
69+
"notNull": true
70+
},
71+
{
72+
"fieldPath": "showCoinLabel",
73+
"columnName": "showCoinLabel",
74+
"affinity": "INTEGER",
75+
"notNull": true
76+
},
77+
{
78+
"fieldPath": "showIcon",
79+
"columnName": "showIcon",
80+
"affinity": "INTEGER",
81+
"notNull": true
82+
},
83+
{
84+
"fieldPath": "numDecimals",
85+
"columnName": "numDecimals",
86+
"affinity": "INTEGER",
87+
"notNull": true
88+
},
89+
{
90+
"fieldPath": "currencySymbol",
91+
"columnName": "currencySymbol",
92+
"affinity": "TEXT",
93+
"notNull": false
94+
},
95+
{
96+
"fieldPath": "theme",
97+
"columnName": "theme",
98+
"affinity": "TEXT",
99+
"notNull": true
100+
},
101+
{
102+
"fieldPath": "nightMode",
103+
"columnName": "nightMode",
104+
"affinity": "TEXT",
105+
"notNull": true
106+
},
107+
{
108+
"fieldPath": "coinUnit",
109+
"columnName": "coinUnit",
110+
"affinity": "TEXT",
111+
"notNull": false
112+
},
113+
{
114+
"fieldPath": "currencyUnit",
115+
"columnName": "currencyUnit",
116+
"affinity": "TEXT",
117+
"notNull": false
118+
},
119+
{
120+
"fieldPath": "customIcon",
121+
"columnName": "customIcon",
122+
"affinity": "TEXT",
123+
"notNull": false
124+
},
125+
{
126+
"fieldPath": "portraitTextSize",
127+
"columnName": "portraitTextSize",
128+
"affinity": "INTEGER",
129+
"notNull": false
130+
},
131+
{
132+
"fieldPath": "landscapeTextSize",
133+
"columnName": "landscapeTextSize",
134+
"affinity": "INTEGER",
135+
"notNull": false
136+
},
137+
{
138+
"fieldPath": "lastValue",
139+
"columnName": "lastValue",
140+
"affinity": "TEXT",
141+
"notNull": false
142+
},
143+
{
144+
"fieldPath": "amountHeld",
145+
"columnName": "amountHeld",
146+
"affinity": "REAL",
147+
"notNull": false
148+
},
149+
{
150+
"fieldPath": "address",
151+
"columnName": "address",
152+
"affinity": "TEXT",
153+
"notNull": false
154+
},
155+
{
156+
"fieldPath": "showAmountLabel",
157+
"columnName": "showAmountLabel",
158+
"affinity": "INTEGER",
159+
"notNull": true
160+
},
161+
{
162+
"fieldPath": "useInverse",
163+
"columnName": "useInverse",
164+
"affinity": "INTEGER",
165+
"notNull": true
166+
},
167+
{
168+
"fieldPath": "lastUpdated",
169+
"columnName": "lastUpdated",
170+
"affinity": "INTEGER",
171+
"notNull": true
172+
},
173+
{
174+
"fieldPath": "state",
175+
"columnName": "state",
176+
"affinity": "TEXT",
177+
"notNull": true
178+
}
179+
],
180+
"primaryKey": {
181+
"autoGenerate": true,
182+
"columnNames": [
183+
"id"
184+
]
185+
},
186+
"indices": [
187+
{
188+
"name": "index_Widget_widgetId",
189+
"unique": true,
190+
"columnNames": [
191+
"widgetId"
192+
],
193+
"orders": [],
194+
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Widget_widgetId` ON `${TABLE_NAME}` (`widgetId`)"
195+
}
196+
],
197+
"foreignKeys": []
198+
},
199+
{
200+
"tableName": "Configuration",
201+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `refresh` INTEGER NOT NULL, `consistentSize` INTEGER NOT NULL, `dataMigrationVersion` INTEGER NOT NULL)",
202+
"fields": [
203+
{
204+
"fieldPath": "id",
205+
"columnName": "id",
206+
"affinity": "INTEGER",
207+
"notNull": true
208+
},
209+
{
210+
"fieldPath": "refresh",
211+
"columnName": "refresh",
212+
"affinity": "INTEGER",
213+
"notNull": true
214+
},
215+
{
216+
"fieldPath": "consistentSize",
217+
"columnName": "consistentSize",
218+
"affinity": "INTEGER",
219+
"notNull": true
220+
},
221+
{
222+
"fieldPath": "dataMigrationVersion",
223+
"columnName": "dataMigrationVersion",
224+
"affinity": "INTEGER",
225+
"notNull": true
226+
}
227+
],
228+
"primaryKey": {
229+
"autoGenerate": true,
230+
"columnNames": [
231+
"id"
232+
]
233+
},
234+
"indices": [],
235+
"foreignKeys": []
236+
}
237+
],
238+
"views": [],
239+
"setupQueries": [
240+
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
241+
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '01c616eedee5c021678bbc985446b3ac')"
242+
]
243+
}
244+
}

bitcoin/src/main/java/com/brentpanther/bitcoinwidget/Enums.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ enum class NightMode {
5757
}
5858

5959
enum class WidgetState {
60-
DRAFT, CURRENT, STALE, RATE_LIMITED, ERROR
60+
DRAFT, CURRENT, STALE, RATE_LIMITED, ERROR, INVALID_ADDRESS
6161
}
6262

6363
enum class WidgetType(@StringRes val widgetName: Int, @StringRes val widgetSummary: Int) {

bitcoin/src/main/java/com/brentpanther/bitcoinwidget/db/Entities.kt

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ data class Widget(
3131
var landscapeTextSize: Int? = null,
3232
var lastValue: String? = null,
3333
var amountHeld: Double? = null,
34+
var address: String? = null,
3435
var showAmountLabel: Boolean,
3536
var useInverse: Boolean,
3637
var lastUpdated: Long,

bitcoin/src/main/java/com/brentpanther/bitcoinwidget/db/WidgetDatabase.kt

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.brentpanther.bitcoinwidget.db
33
import android.content.ContentValues
44
import android.content.Context
55
import android.database.sqlite.SQLiteDatabase
6+
import androidx.room.AutoMigration
67
import androidx.room.Database
78
import androidx.room.Room
89
import androidx.room.RoomDatabase
@@ -11,7 +12,14 @@ import androidx.sqlite.db.SupportSQLiteDatabase
1112
import com.brentpanther.bitcoinwidget.WidgetApplication
1213
import java.io.File
1314

14-
@Database(version = 5, entities = [Widget::class, Configuration::class], exportSchema = true)
15+
@Database(
16+
version = 6,
17+
entities = [Widget::class, Configuration::class],
18+
exportSchema = true,
19+
autoMigrations = [
20+
AutoMigration (from = 5, to = 6)
21+
]
22+
)
1523
abstract class WidgetDatabase : RoomDatabase() {
1624

1725
abstract fun widgetDao(): WidgetDao

bitcoin/src/main/java/com/brentpanther/bitcoinwidget/exchange/ExchangeHelper.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ object ExchangeHelper {
2828

2929
fun getStream(url: String): InputStream? = get(url)?.body?.byteStream()
3030

31-
private fun getString(url: String, headers: Headers? = null) = get(url, headers)?.body?.string() ?: ""
31+
fun getString(url: String, headers: Headers? = null) = get(url, headers)?.body?.string() ?: ""
3232

3333
private fun get(url: String, headers: Headers? = null): Response? {
3434
return try {
@@ -43,7 +43,7 @@ object ExchangeHelper {
4343
throw RateLimitedException()
4444
}
4545
return response
46-
} catch (e: IllegalArgumentException) {
46+
} catch (_: IllegalArgumentException) {
4747
null
4848
}
4949
}

bitcoin/src/main/java/com/brentpanther/bitcoinwidget/receiver/WidgetBroadcastReceiver.kt

-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ class WidgetBroadcastReceiver : BroadcastReceiver() {
1919
override fun onReceive(context: Context, intent: Intent) {
2020
when (intent.action) {
2121
Intent.ACTION_CONFIGURATION_CHANGED -> refreshAllWidgets(context)
22-
"message" -> postMessage(context, intent.getIntExtra("message", 0))
2322
"refresh" -> refreshWidget(context, intent)
2423
}
2524
}
@@ -47,7 +46,4 @@ class WidgetBroadcastReceiver : BroadcastReceiver() {
4746
WidgetUpdater.update(context, intArrayOf(widgetId), manual = true)
4847
}
4948
}
50-
51-
private fun postMessage(context: Context, message: Int) =
52-
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
5349
}

bitcoin/src/main/java/com/brentpanther/bitcoinwidget/strategy/data/PriceWidgetDataStrategy.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ open class PriceWidgetDataStrategy(widgetId: Int) : WidgetDataStrategy(widgetId)
3737
if (widget.state != WidgetState.DRAFT) widget.state = WidgetState.STALE
3838
}
3939
Log.w(TAG, "Error getting value from exchange: ${widget.exchange}.", e)
40-
} catch (e: RateLimitedException) {
40+
} catch (_: RateLimitedException) {
4141
widget.state = WidgetState.RATE_LIMITED
4242
Log.w(TAG, "Exchange is rate limited: ${widget.exchange}.")
4343
} catch (e: Exception) {
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,32 @@
11
package com.brentpanther.bitcoinwidget.strategy.data
22

3+
import com.brentpanther.bitcoinwidget.WidgetState
4+
import com.brentpanther.bitcoinwidget.exchange.ExchangeHelper
5+
36
class ValueWidgetDataStrategy(widgetId: Int) : PriceWidgetDataStrategy(widgetId) {
47

58
override fun setData(value: String) {
69
widget?.apply {
710
val valueDouble = value.toDoubleOrNull() ?: 0.0
8-
val amountHeld = amountHeld ?: 0.0
9-
lastValue = (valueDouble * amountHeld).toString()
11+
val amountHeld = amountHeld
12+
lastValue = when {
13+
amountHeld != null -> (valueDouble * amountHeld).toString()
14+
address != null -> {
15+
val url = "https://blockchain.info/q/addressbalance/$address"
16+
val response = ExchangeHelper.getString(url)
17+
if ("error" in response) {
18+
state = WidgetState.INVALID_ADDRESS
19+
lastValue
20+
}
21+
else {
22+
val balance = response.toDoubleOrNull() ?: throw IllegalStateException()
23+
(valueDouble * balance * .00000001).toString()
24+
}
25+
}
26+
else -> lastValue
27+
}
1028
lastUpdated = System.currentTimeMillis()
1129
}
12-
1330
}
1431

1532
}

0 commit comments

Comments
 (0)