Feat: Adds wallet icon/color select (#2917)

This commit is contained in:
Arc 2025-02-04 13:03:35 +00:00 committed by GitHub
parent dd9b217fdf
commit 960c58db87
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 205 additions and 63 deletions

View file

@ -161,4 +161,4 @@ async def get_wallet_for_key(
async def get_total_balance(conn: Optional[Connection] = None):
result = await (conn or db).execute("SELECT SUM(balance) as balance FROM balances")
row = result.mappings().first()
return row.get("balance", 0)
return row.get("balance", 0) or 0

View file

@ -692,3 +692,10 @@ async def m030_add_user_api_tokens_column(db: Connection):
ALTER TABLE accounts ADD COLUMN access_control_list TEXT
"""
)
async def m031_add_color_and_icon_to_wallets(db: Connection):
"""
Adds icon and color columns to wallets.
"""
await db.execute("ALTER TABLE wallets ADD COLUMN extra TEXT")

View file

@ -23,6 +23,11 @@ class BaseWallet(BaseModel):
balance_msat: int
class WalletExtra(BaseModel):
icon: str = "flash_on"
color: str = "primary"
class Wallet(BaseModel):
id: str
user: str
@ -34,6 +39,7 @@ class Wallet(BaseModel):
updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
currency: Optional[str] = None
balance_msat: int = Field(default=0, no_database=True)
extra: WalletExtra = WalletExtra()
@property
def balance(self) -> int:

View file

@ -206,11 +206,29 @@
{% else %}
<div v-if="!mobileSimple" class="col-12 col-md-5 q-gutter-y-md">
<q-card>
<q-card-section>
<h6 class="text-subtitle1 q-mt-none q-mb-sm">
<q-card-section class="q-pb-xs">
<div class="row items-center">
<q-avatar
size="lg"
:icon="g.wallet.extra.icon"
:text-color="$q.dark.isActive ? 'black' : 'grey-3'"
:color="g.wallet.extra.color"
>
</q-avatar>
<q-btn
@click="icon.show = true"
round
color="grey-5"
text-color="black"
size="xs"
icon="add"
style="position: relative; left: -20px; bottom: -10px"
></q-btn>
<div class="text-subtitle1 q-mt-none q-mb-none">
{{ SITE_TITLE }} Wallet:
<strong><em v-text="g.wallet.name"></em></strong>
</h6>
</div>
</div>
</q-card-section>
<q-card-section class="q-pa-none">
<q-separator></q-separator>
@ -388,6 +406,50 @@
</div>
</div>
<q-dialog v-model="icon.show" position="top">
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
<q-form @submit="setIcon" class="q-gutter-md">
<div class="q-gutter-sm q-pa-sm flex flex-wrap justify-center">
<!-- Loop through all icons -->
<q-btn
v-for="(thisIcon, index) in icon.options"
:key="index"
@click="setSelectedIcon(thisIcon)"
round
text-color="black"
:color="icon.data.icon === thisIcon ? icon.data.color || 'primary' : 'grey-5'"
size="md"
:icon="thisIcon"
class="q-mb-sm"
></q-btn>
</div>
<div class="q-pa-sm flex justify-between items-center">
<div class="flex q-pl-lg">
<!-- Color options -->
<q-btn
v-for="(color, index) in icon.colorOptions"
:key="'color-' + index"
@click="setSelectedColor(color)"
round
:color="color"
size="xs"
style="width: 24px; height: 24px; min-width: 24px; padding: 0"
class="q-mr-xs"
></q-btn>
</div>
<q-btn
unelevated
color="primary"
:disable="!icon.data.icon"
type="submit"
>
Save Icon
</q-btn>
</div>
</q-form>
</q-card>
</q-dialog>
<q-dialog
v-model="receive.show"
position="top"

View file

@ -59,6 +59,8 @@ async def api_update_wallet_name(
@wallet_router.patch("")
async def api_update_wallet(
name: Optional[str] = Body(None),
icon: Optional[str] = Body(None),
color: Optional[str] = Body(None),
currency: Optional[str] = Body(None),
key_info: WalletTypeInfo = Depends(require_admin_key),
) -> Wallet:
@ -66,6 +68,8 @@ async def api_update_wallet(
if not wallet:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Wallet not found")
wallet.name = name or wallet.name
wallet.extra.icon = icon or wallet.extra.icon
wallet.extra.color = color or wallet.extra.color
wallet.currency = currency if currency is not None else wallet.currency
await update_wallet(wallet)
return wallet

File diff suppressed because one or more lines are too long

View file

@ -216,7 +216,8 @@ window.LNbits = {
name: data.name,
adminkey: data.adminkey,
inkey: data.inkey,
currency: data.currency
currency: data.currency,
extra: data.extra
}
newWallet.msat = data.balance_msat
newWallet.sat = Math.floor(data.balance_msat / 1000)

View file

@ -44,6 +44,62 @@ window.WalletPageLogic = {
show: false,
location: window.location
},
icon: {
show: false,
data: {},
colorOptions: [
'primary',
'purple',
'orange',
'green',
'brown',
'blue',
'red',
'pink'
],
options: [
'home',
'star',
'bolt',
'paid',
'savings',
'store',
'videocam',
'music_note',
'flight',
'train',
'directions_car',
'school',
'construction',
'science',
'sports_esports',
'sports_tennis',
'theaters',
'water',
'headset_mic',
'videogame_asset',
'person',
'group',
'pets',
'sunny',
'elderly',
'verified',
'snooze',
'mail',
'forum',
'shopping_cart',
'shopping_bag',
'attach_money',
'print_connect',
'dark_mode',
'light_mode',
'android',
'network_wifi',
'shield',
'fitness_center',
'lunch_dining'
]
},
update: {
name: null,
currency: null
@ -149,6 +205,16 @@ window.WalletPageLogic = {
handleBalanceUpdate(value) {
this.g.wallet.sat = this.g.wallet.sat + value
},
setSelectedIcon(selectedIcon) {
this.icon.data.icon = selectedIcon
},
setSelectedColor(selectedColor) {
this.icon.data.color = selectedColor
},
setIcon() {
this.updateWallet(this.icon.data)
this.icon.show = false
},
createInvoice() {
this.receive.status = 'loading'
if (LNBITS_DENOMINATION != 'sats') {

View file

@ -29,6 +29,7 @@
<link async="async" rel="manifest" href="{{ web_manifest }}" />
{% endif %} {% block head_scripts %}{% endblock %}
</head>
<body data-theme="bitcoin">
<div id="vue">
<q-layout view="hHh lpR lfr" v-cloak>
@ -228,19 +229,14 @@
<div class="row items-center">
<q-avatar
size="lg"
:color="
g.wallet && g.wallet.id === wallet.id
? $q.dark.isActive
? 'primary'
: 'primary'
: 'grey-5'
:text-color="$q.dark.isActive ? 'black' : 'grey-3'"
:class="g.wallet && g.wallet.id === wallet.id
? ''
: 'disabled'
"
:color="g.wallet && g.wallet.id === wallet.id ? wallet.extra.color : wallet.extra.color"
:icon="g.wallet && g.wallet.id === wallet.id ? wallet.extra.icon : wallet.extra.icon"
>
<q-icon
name="flash_on"
:size="$q.dark.isActive ? '21px' : '20px'"
:color="$q.dark.isActive ? 'black' : 'grey-3'"
></q-icon>
</q-avatar>
<div
class="text-h6 q-pl-md"

View file

@ -13,20 +13,20 @@
>
<q-item-section side>
<q-avatar
size="md"
size="lg"
:text-color="$q.dark.isActive ? 'black' : 'grey-3'"
:class="g.wallet && g.wallet.id === walletRec.id ? '' : 'disabled'"
:color="
g.wallet && g.wallet.id === walletRec.id
? $q.dark.isActive
? 'primary'
: 'primary'
: 'grey-5'
? walletRec.extra.color
: walletRec.extra.color
"
:icon="
g.wallet && g.wallet.id === walletRec.id
? walletRec.extra.icon
: walletRec.extra.icon
"
>
<q-icon
name="flash_on"
:size="$q.dark.isActive ? '21px' : '20px'"
:color="$q.dark.isActive ? 'blue-grey-10' : 'grey-3'"
></q-icon>
</q-avatar>
</q-item-section>
<q-item-section>