Skip to content

Commit e3bf36f

Browse files
Work on Nostr client
1 parent faa46fb commit e3bf36f

2 files changed

Lines changed: 176 additions & 445 deletions

File tree

Lines changed: 51 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,43 @@
11
import lvgl as lv
22

3-
from mpos import Activity, Intent, ConnectivityManager, MposKeyboard, pct_of_display_width, pct_of_display_height, SharedPreferences, SettingsActivity
4-
from mpos.ui.anim import WidgetAnimator
5-
6-
from fullscreen_qr import FullscreenQR
3+
from mpos import Activity, Intent, ConnectivityManager, pct_of_display_width, pct_of_display_height, SharedPreferences, SettingsActivity
74

85
class NostrApp(Activity):
96

107
wallet = None
11-
receive_qr_data = None
12-
destination = None
13-
balance_mode = 0 # 0=sats, 1=bits, 2=μBTC, 3=mBTC, 4=BTC
14-
payments_label_current_font = 2
15-
payments_label_fonts = [ lv.font_montserrat_10, lv.font_unscii_8, lv.font_montserrat_16, lv.font_montserrat_24, lv.font_unscii_16, lv.font_montserrat_28_compressed, lv.font_montserrat_40]
8+
events_label_current_font = 2
9+
events_label_fonts = [ lv.font_montserrat_10, lv.font_unscii_8, lv.font_montserrat_16, lv.font_montserrat_24, lv.font_unscii_16, lv.font_montserrat_28_compressed, lv.font_montserrat_40]
1610

1711
# screens:
1812
main_screen = None
1913

2014
# widgets
2115
balance_label = None
22-
receive_qr = None
23-
payments_label = None
24-
25-
# activities
26-
fullscreenqr = FullscreenQR() # need a reference to be able to finish() it
16+
events_label = None
2717

2818
def onCreate(self):
2919
self.prefs = SharedPreferences("com.micropythonos.nostr")
3020
self.main_screen = lv.obj()
3121
self.main_screen.set_style_pad_all(10, 0)
32-
# This line needs to be drawn first, otherwise it's over the balance label and steals all the clicks!
33-
balance_line = lv.line(self.main_screen)
34-
balance_line.set_points([{'x':0,'y':35},{'x':200,'y':35}],2)
35-
balance_line.add_flag(lv.obj.FLAG.CLICKABLE)
22+
# Header line
23+
header_line = lv.line(self.main_screen)
24+
header_line.set_points([{'x':0,'y':35},{'x':200,'y':35}],2)
25+
header_line.add_flag(lv.obj.FLAG.CLICKABLE)
26+
# Header label showing which npub we're following
3627
self.balance_label = lv.label(self.main_screen)
3728
self.balance_label.set_text("")
3829
self.balance_label.align(lv.ALIGN.TOP_LEFT, 0, 0)
3930
self.balance_label.set_style_text_font(lv.font_montserrat_24, 0)
4031
self.balance_label.add_flag(lv.obj.FLAG.CLICKABLE)
41-
self.balance_label.set_width(pct_of_display_width(75)) # 100 - receive_qr
42-
self.balance_label.add_event_cb(self.balance_label_clicked_cb,lv.EVENT.CLICKED,None)
43-
self.receive_qr = lv.qrcode(self.main_screen)
44-
self.receive_qr.set_size(pct_of_display_width(20)) # bigger QR results in simpler code (less error correction?)
45-
self.receive_qr.set_dark_color(lv.color_black())
46-
self.receive_qr.set_light_color(lv.color_white())
47-
self.receive_qr.align(lv.ALIGN.TOP_RIGHT,0,0)
48-
self.receive_qr.set_style_border_color(lv.color_white(), 0)
49-
self.receive_qr.set_style_border_width(1, 0);
50-
self.receive_qr.add_flag(lv.obj.FLAG.CLICKABLE)
51-
self.receive_qr.add_event_cb(self.qr_clicked_cb,lv.EVENT.CLICKED,None)
52-
self.payments_label = lv.label(self.main_screen)
53-
self.payments_label.set_text("")
54-
self.payments_label.align_to(balance_line,lv.ALIGN.OUT_BOTTOM_LEFT,0,10)
55-
self.update_payments_label_font()
56-
self.payments_label.set_width(pct_of_display_width(75)) # 100 - receive_qr
57-
self.payments_label.add_flag(lv.obj.FLAG.CLICKABLE)
58-
self.payments_label.add_event_cb(self.payments_label_clicked,lv.EVENT.CLICKED,None)
32+
self.balance_label.set_width(pct_of_display_width(100))
33+
# Events label
34+
self.events_label = lv.label(self.main_screen)
35+
self.events_label.set_text("")
36+
self.events_label.align_to(header_line,lv.ALIGN.OUT_BOTTOM_LEFT,0,10)
37+
self.update_events_label_font()
38+
self.events_label.set_width(pct_of_display_width(100))
39+
self.events_label.add_flag(lv.obj.FLAG.CLICKABLE)
40+
self.events_label.add_event_cb(self.events_label_clicked,lv.EVENT.CLICKED,None)
5941
settings_button = lv.button(self.main_screen)
6042
settings_button.set_size(lv.pct(20), lv.pct(25))
6143
settings_button.align(lv.ALIGN.BOTTOM_RIGHT, 0, 0)
@@ -64,15 +46,6 @@ def onCreate(self):
6446
settings_label.set_text(lv.SYMBOL.SETTINGS)
6547
settings_label.set_style_text_font(lv.font_montserrat_24, 0)
6648
settings_label.center()
67-
if False: # send button disabled for now, not implemented
68-
send_button = lv.button(self.main_screen)
69-
send_button.set_size(lv.pct(20), lv.pct(25))
70-
send_button.align_to(settings_button, lv.ALIGN.OUT_TOP_MID, 0, -pct_of_display_height(2))
71-
send_button.add_event_cb(self.send_button_tap,lv.EVENT.CLICKED,None)
72-
send_label = lv.label(send_button)
73-
send_label.set_text(lv.SYMBOL.UPLOAD)
74-
send_label.set_style_text_font(lv.font_montserrat_24, 0)
75-
send_label.center()
7649
self.setContentView(self.main_screen)
7750

7851
def onStart(self, main_screen):
@@ -85,9 +58,8 @@ def onResume(self, main_screen):
8558
self.network_changed(cm.is_online())
8659

8760
def onPause(self, main_screen):
88-
if self.wallet and self.destination != FullscreenQR:
89-
self.wallet.stop() # don't stop the wallet for the fullscreen QR activity
90-
self.destination = None
61+
if self.wallet:
62+
self.wallet.stop()
9163
cm = ConnectivityManager.get()
9264
cm.unregister_callback(self.network_changed)
9365

@@ -104,88 +76,52 @@ def went_online(self):
10476
return
10577
try:
10678
from nostr_client import NostrClient
107-
self.wallet = NostrClient(self.prefs.get_string("nostr_nsec"))
108-
self.wallet.follow_npub = self.prefs.get_string("nostr_follow_npub")
109-
self.redraw_static_receive_code_cb()
79+
nsec = self.prefs.get_string("nostr_nsec")
80+
# Generate a random nsec if not configured
81+
if not nsec:
82+
from nostr.key import PrivateKey
83+
random_key = PrivateKey()
84+
nsec = random_key.bech32()
85+
self.prefs.edit().put_string("nostr_nsec", nsec).commit()
86+
print(f"Generated random nsec: {nsec}")
87+
follow_npub = self.prefs.get_string("nostr_follow_npub")
88+
relay = self.prefs.get_string("nostr_relay")
89+
self.wallet = NostrClient(nsec, follow_npub, relay)
11090
except Exception as e:
11191
self.error_cb(f"Couldn't initialize Nostr client because: {e}")
11292
import sys
11393
sys.print_exception(e)
11494
return
115-
self.balance_label.set_text(lv.SYMBOL.REFRESH)
116-
self.payments_label.set_text(f"\nConnecting to backend.\n\nIf this takes too long, it might be down or something's wrong with the settings.")
95+
self.balance_label.set_text("Events from " + self.prefs.get_string("nostr_follow_npub")[:16] + "...")
96+
self.events_label.set_text(f"\nConnecting to relay.\n\nIf this takes too long, the relay might be down or something's wrong with the settings.")
11797
# by now, self.wallet can be assumed
118-
self.wallet.start(self.balance_updated_cb, self.redraw_payments_cb, self.redraw_static_receive_code_cb, self.error_cb)
98+
self.wallet.start(self.redraw_events_cb, self.error_cb)
11999

120100
def went_offline(self):
121101
if self.wallet:
122102
self.wallet.stop() # don't stop the wallet for the fullscreen QR activity
123-
self.payments_label.set_text(f"WiFi is not connected, can't talk to wallet...")
124-
125-
def update_payments_label_font(self):
126-
self.payments_label.set_style_text_font(self.payments_label_fonts[self.payments_label_current_font], 0)
127-
128-
def payments_label_clicked(self, event):
129-
self.payments_label_current_font = (self.payments_label_current_font + 1) % len(self.payments_label_fonts)
130-
self.update_payments_label_font()
131-
132-
def float_to_string(self, value):
133-
# Format float to string with fixed-point notation, up to 6 decimal places
134-
s = "{:.8f}".format(value)
135-
# Remove trailing zeros and decimal point if no decimals remain
136-
return s.rstrip("0").rstrip(".")
137-
138-
def display_balance(self, balance):
139-
#print(f"displaying balance {balance}")
140-
if self.balance_mode == 0: # sats
141-
#balance_text = "丰 " + str(balance) # font doesnt support it
142-
balance_text = str(balance) + " sat"
143-
if balance > 1:
144-
balance_text += "s"
145-
elif self.balance_mode == 1: # bits (1 bit = 100 sats)
146-
balance_bits = balance / 100
147-
balance_text = self.float_to_string(balance_bits) + " bit"
148-
if balance_bits != 1:
149-
balance_text += "s"
150-
elif self.balance_mode == 2: # micro-BTC (1 μBTC = 100 sats)
151-
balance_ubtc = balance / 100
152-
balance_text = self.float_to_string(balance_ubtc) + " micro-BTC"
153-
elif self.balance_mode == 3: # milli-BTC (1 mBTC = 100000 sats)
154-
balance_mbtc = balance / 100000
155-
balance_text = self.float_to_string(balance_mbtc) + " milli-BTC"
156-
elif self.balance_mode == 4: # BTC (1 BTC = 100000000 sats)
157-
balance_btc = balance / 100000000
158-
#balance_text = "₿ " + str(balance) # font doesnt support it - although it should https://fonts.google.com/specimen/Montserrat
159-
balance_text = self.float_to_string(balance_btc) + " BTC"
160-
self.balance_label.set_text(balance_text)
161-
#print("done displaying balance")
162-
163-
def balance_updated_cb(self, sats_added=0):
164-
print(f"balance_updated_cb(sats_added={sats_added})")
165-
if self.fullscreenqr.has_foreground():
166-
self.fullscreenqr.finish()
167-
balance = self.wallet.last_known_balance
168-
print(f"balance: {balance}")
169-
if balance is not None:
170-
WidgetAnimator.change_widget(self.balance_label, anim_type="interpolate", duration=5000, delay=0, begin_value=balance-sats_added, end_value=balance, display_change=self.display_balance)
171-
else:
172-
print("Not drawing balance because it's None")
173-
174-
def redraw_payments_cb(self):
175-
# this gets called from another thread (the wallet) so make sure it happens in the LVGL thread using lv.async_call():
176-
self.payments_label.set_text(str(self.wallet.payment_list))
103+
self.events_label.set_text(f"WiFi is not connected, can't talk to relay...")
177104

178-
def redraw_static_receive_code_cb(self):
105+
def update_events_label_font(self):
106+
self.events_label.set_style_text_font(self.events_label_fonts[self.events_label_current_font], 0)
107+
108+
def events_label_clicked(self, event):
109+
self.events_label_current_font = (self.events_label_current_font + 1) % len(self.events_label_fonts)
110+
self.update_events_label_font()
111+
112+
def redraw_events_cb(self):
179113
# this gets called from another thread (the wallet) so make sure it happens in the LVGL thread using lv.async_call():
180-
self.receive_qr_data = self.wallet.static_receive_code
181-
if self.receive_qr_data:
182-
self.receive_qr.update(self.receive_qr_data, len(self.receive_qr_data))
114+
events_text = ""
115+
if self.wallet.event_list:
116+
for event in self.wallet.event_list:
117+
events_text += f"{event.content}\n\n"
183118
else:
184-
print("Warning: redraw_static_receive_code_cb() was called while self.wallet.static_receive_code is None...")
119+
events_text = "No events yet..."
120+
self.events_label.set_text(events_text)
185121

186122
def error_cb(self, error):
187123
if self.wallet and self.wallet.is_running():
188-
self.payments_label.set_text(str(error))
124+
self.events_label.set_text(str(error))
189125

190126
def should_show_setting(self, setting):
191127
return True
@@ -202,16 +138,4 @@ def settings_button_tap(self, event):
202138

203139
def main_ui_set_defaults(self):
204140
self.balance_label.set_text("Welcome!")
205-
self.payments_label.set_text(lv.SYMBOL.REFRESH)
206-
207-
def balance_label_clicked_cb(self, event):
208-
print("Balance clicked")
209-
self.balance_mode = (self.balance_mode + 1) % 5
210-
self.display_balance(self.wallet.last_known_balance)
211-
212-
def qr_clicked_cb(self, event):
213-
print("QR clicked")
214-
if not self.receive_qr_data:
215-
return
216-
self.destination = FullscreenQR
217-
self.startActivity(Intent(activity_class=self.fullscreenqr).putExtra("receive_qr_data", self.receive_qr_data))
141+
self.events_label.set_text(lv.SYMBOL.REFRESH)

0 commit comments

Comments
 (0)