1 changed files with 511 additions and 0 deletions
@ -0,0 +1,511 @@ |
|||
#!/usr/bin/env python |
|||
# |
|||
# Electrum - lightweight Bitcoin client |
|||
# Copyright (C) 2011 thomasv@gitorious |
|||
# |
|||
# This program is free software: you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation, either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
|
|||
|
|||
import android |
|||
from interface import WalletSynchronizer |
|||
from wallet import Wallet |
|||
from wallet import format_satoshis |
|||
from decimal import Decimal |
|||
|
|||
droid = android.Android() |
|||
wallet = Wallet() |
|||
wallet.set_path("/sdcard/electrum.dat") |
|||
wallet.read() |
|||
|
|||
|
|||
def get_history_layout(n): |
|||
lines = wallet.get_tx_history()[-n:] |
|||
rows = "" |
|||
for line in lines: |
|||
import datetime |
|||
v = line['value'] |
|||
if line.has_key('timestamp'): |
|||
dt = datetime.datetime.fromtimestamp( line['timestamp'] ) |
|||
if dt.date() == dt.today().date(): |
|||
time_str = str( dt.time() ) |
|||
else: |
|||
time_str = str( dt.date() ) |
|||
else: |
|||
time_str = 'pending' |
|||
|
|||
label = line.get('label') |
|||
if not label: label = line['tx_hash'] |
|||
|
|||
rows += """ |
|||
<TableRow> |
|||
<TextView |
|||
android:text="%s" |
|||
android:padding="2px" /> |
|||
<TextView |
|||
android:text="%s" |
|||
android:padding="2px" /> |
|||
<TextView |
|||
android:text="%s" |
|||
android:gravity="right" |
|||
android:padding="2px" /> |
|||
</TableRow>"""%(time_str, ' '+ label[0:10]+ '... ', format_satoshis(v)) |
|||
|
|||
|
|||
output = """ |
|||
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:layout_width="fill_parent" |
|||
android:layout_height="wrap_content" |
|||
android:stretchColumns="*"> |
|||
%s |
|||
</TableLayout> |
|||
"""% rows |
|||
return output |
|||
|
|||
|
|||
|
|||
def show_addresses(): |
|||
droid.dialogCreateAlert("Addresses:") |
|||
l = [] |
|||
for i in range(len(wallet.addresses)): |
|||
addr = wallet.addresses[i] |
|||
l.append( wallet.labels.get(addr,'') + ' ' + addr) |
|||
|
|||
droid.dialogSetItems(l) |
|||
droid.dialogShow() |
|||
response = droid.dialogGetResponse().result |
|||
droid.dialogDismiss() |
|||
|
|||
# show qr code |
|||
print response |
|||
|
|||
|
|||
|
|||
main_layout = """<?xml version="1.0" encoding="utf-8"?> |
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:id="@+id/background" |
|||
android:orientation="vertical" android:layout_width="match_parent" |
|||
android:layout_height="match_parent" android:background="#ff000000"> |
|||
|
|||
<TextView android:id="@+id/historyTextView" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:text="History" |
|||
android:textAppearance="?android:attr/textAppearanceLarge" |
|||
android:gravity="center_vertical|center_horizontal|center"> |
|||
</TextView> |
|||
|
|||
%s |
|||
|
|||
<TextView android:id="@+id/balanceTextView" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:text="TextView" |
|||
android:textAppearance="?android:attr/textAppearanceLarge" |
|||
android:gravity="center_vertical|center_horizontal|center"> |
|||
</TextView> |
|||
|
|||
<LinearLayout android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" android:id="@+id/linearLayout1"> |
|||
<Button android:id="@+id/buttonSend" android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" android:text="Send"></Button> |
|||
<Button android:id="@+id/buttonReceive" android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" android:text="Receive"></Button> |
|||
<Button android:id="@+id/buttonQuit" android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" android:text="Quit"></Button> |
|||
</LinearLayout> |
|||
|
|||
</LinearLayout> |
|||
"""%get_history_layout(10) |
|||
|
|||
|
|||
payto_layout="""<?xml version="1.0" encoding="utf-8"?> |
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:id="@+id/background" |
|||
android:orientation="vertical" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:background="#ff000000"> |
|||
|
|||
<TextView android:id="@+id/recipientTextView" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:text="Pay to:" |
|||
android:textAppearance="?android:attr/textAppearanceLarge" |
|||
android:gravity="left"> |
|||
</TextView> |
|||
|
|||
<EditText android:id="@+id/recipient" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:tag="Tag Me" android:inputType="textCapWords|textPhonetic|number"> |
|||
</EditText> |
|||
|
|||
<TextView android:id="@+id/labelTextView" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:text="Description:" |
|||
android:textAppearance="?android:attr/textAppearanceLarge" |
|||
android:gravity="left"> |
|||
</TextView> |
|||
|
|||
<EditText android:id="@+id/label" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:tag="Tag Me" android:inputType="textCapWords|textPhonetic|number"> |
|||
</EditText> |
|||
|
|||
<TextView android:id="@+id/amountLabelTextView" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:text="Amount:" |
|||
android:textAppearance="?android:attr/textAppearanceLarge" |
|||
android:gravity="left"> |
|||
</TextView> |
|||
|
|||
<EditText android:id="@+id/amount" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:tag="Tag Me" android:inputType="textCapWords|number"> |
|||
</EditText> |
|||
|
|||
<LinearLayout android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" android:id="@+id/linearLayout1"> |
|||
<Button android:id="@+id/buttonContacts" android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" android:text="Contacts"></Button> |
|||
<Button android:id="@+id/buttonPay" android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" android:text="Send"></Button> |
|||
<Button android:id="@+id/buttonCancelSend" android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" android:text="Cancel"></Button> |
|||
</LinearLayout> |
|||
</LinearLayout> |
|||
""" |
|||
|
|||
|
|||
settings_layout = """<?xml version="1.0" encoding="utf-8"?> |
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:id="@+id/background" |
|||
android:orientation="vertical" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:background="#ff000000"> |
|||
|
|||
<TextView android:id="@+id/serverTextView" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:text="Server:" |
|||
android:textAppearance="?android:attr/textAppearanceLarge" |
|||
android:gravity="left"> |
|||
</TextView> |
|||
|
|||
<EditText android:id="@+id/server" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:tag="Tag Me" android:inputType="*"> |
|||
</EditText> |
|||
|
|||
<LinearLayout android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" android:id="@+id/linearLayout1"> |
|||
<Button android:id="@+id/buttonServer" android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" android:text="Server List"></Button> |
|||
<Button android:id="@+id/buttonSave" android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" android:text="Save"></Button> |
|||
<Button android:id="@+id/buttonCancel" android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" android:text="Cancel"></Button> |
|||
</LinearLayout> |
|||
|
|||
</LinearLayout> |
|||
""" |
|||
|
|||
|
|||
|
|||
droid.addOptionsMenuItem("Settings","settings",None,"") |
|||
droid.addOptionsMenuItem("Quit","quit",None,"") |
|||
|
|||
|
|||
def show_balance(): |
|||
c, u = wallet.get_balance() |
|||
droid.fullSetProperty("balanceTextView","text","Balance:"+format_satoshis(c)) |
|||
|
|||
|
|||
def recipient_dialog(): |
|||
title = 'Pay to:' |
|||
message = ('Select recipient') |
|||
droid.dialogCreateAlert(title, message) |
|||
droid.dialogSetItems(wallet.addressbook) |
|||
droid.dialogShow() |
|||
response = droid.dialogGetResponse() |
|||
result = response.result.get('item') |
|||
droid.dialogDismiss() |
|||
if result is not None: |
|||
addr = wallet.addressbook[result] |
|||
return addr |
|||
|
|||
|
|||
def pay_to(recipient, amount, fee, label): |
|||
|
|||
if wallet.use_encryption: |
|||
password = droid.dialogGetPassword('Password').result |
|||
print "password", password |
|||
else: |
|||
password = None |
|||
|
|||
droid.dialogCreateSpinnerProgress("Electrum", "signing transaction...") |
|||
droid.dialogShow() |
|||
tx = wallet.mktx( recipient, amount, label, password, fee) |
|||
print tx |
|||
droid.dialogDismiss() |
|||
|
|||
if tx: |
|||
r, h = wallet.sendtx( tx ) |
|||
droid.dialogCreateAlert('tx sent', h) |
|||
droid.dialogSetPositiveButtonText('OK') |
|||
droid.dialogShow() |
|||
response = droid.dialogGetResponse().result |
|||
droid.dialogDismiss() |
|||
return h |
|||
else: |
|||
return 'error' |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
if not wallet.file_exists: |
|||
droid.dialogCreateAlert("wallet file not found") |
|||
droid.dialogSetPositiveButtonText('OK') |
|||
droid.dialogShow() |
|||
resp = droid.dialogGetResponse().result |
|||
exit(1) |
|||
|
|||
|
|||
|
|||
|
|||
droid.dialogCreateSpinnerProgress("Electrum", "synchronizing") |
|||
droid.dialogShow() |
|||
WalletSynchronizer(wallet,True).start() |
|||
wallet.update() |
|||
wallet.save() |
|||
droid.dialogDismiss() |
|||
droid.vibrate() |
|||
|
|||
|
|||
|
|||
def main_loop(): |
|||
|
|||
droid.fullShow(main_layout) |
|||
show_balance() |
|||
|
|||
out = None |
|||
while out is None: |
|||
|
|||
event = droid.eventWait().result |
|||
print "got event in main loop", event |
|||
|
|||
if event["name"]=="click": |
|||
id=event["data"]["id"] |
|||
if id=="buttonQuit": |
|||
out = 'exit' |
|||
|
|||
elif id=="buttonSend": |
|||
out = 'payto' |
|||
|
|||
elif id=="buttonReceive": |
|||
show_addresses() |
|||
|
|||
elif id=="buttonQuit": |
|||
out = 'quit' |
|||
|
|||
elif event["name"]=="settings": |
|||
out = 'settings' |
|||
|
|||
elif event["name"]=="quit": |
|||
out = 'quit' |
|||
|
|||
#print droid.fullSetProperty("background","backgroundColor","0xff7f0000") |
|||
#elif event["name"]=="screen": |
|||
# if event["data"]=="destroy": |
|||
# out = 'exit' |
|||
|
|||
#droid.fullDismiss() |
|||
return out |
|||
|
|||
def payto_loop(): |
|||
droid.fullShow(payto_layout) |
|||
out = None |
|||
while out is None: |
|||
event = droid.eventWait().result |
|||
print "got event in payto loop", event |
|||
|
|||
if event["name"] == "click": |
|||
id = event["data"]["id"] |
|||
|
|||
if id=="buttonPay": |
|||
|
|||
droid.fullQuery() |
|||
recipient = droid.fullQueryDetail("recipient").result.get('text') |
|||
label = droid.fullQueryDetail("label").result.get('text') |
|||
amount = droid.fullQueryDetail('amount').result.get('text') |
|||
fee = '0.001' |
|||
amount = int( 100000000 * Decimal(amount) ) |
|||
fee = int( 100000000 * Decimal(fee) ) |
|||
result = pay_to(recipient, amount, fee, label) |
|||
|
|||
droid.dialogCreateAlert('result', result) |
|||
droid.dialogSetPositiveButtonText('OK') |
|||
droid.dialogShow() |
|||
droid.dialogGetResponse() |
|||
droid.dialogDismiss() |
|||
out = 'main' |
|||
|
|||
|
|||
elif id=="buttonContacts": |
|||
addr = recipient_dialog() |
|||
droid.fullSetProperty("recipient","text",addr) |
|||
|
|||
elif id=="buttonCancelSend": |
|||
out = 'main' |
|||
|
|||
elif event["name"]=="settings": |
|||
out = 'settings' |
|||
|
|||
elif event["name"]=="quit": |
|||
out = 'quit' |
|||
|
|||
#elif event["name"]=="screen": |
|||
# if event["data"]=="destroy": |
|||
# out = 'main' |
|||
|
|||
#droid.fullDismiss() |
|||
return out |
|||
|
|||
|
|||
def history_loop(): |
|||
layout = get_history_layout() |
|||
droid.fullShow(layout) |
|||
out = None |
|||
while out is None: |
|||
event = droid.eventWait().result |
|||
print "got event in history loop", event |
|||
if event["name"] == "click": |
|||
|
|||
if event["data"]["text"] == "OK": |
|||
out = 'main' |
|||
|
|||
elif event["name"] == "key": |
|||
print repr(event["data"]["key"]) |
|||
if event["data"]["key"] == '4': |
|||
out = 'main' |
|||
|
|||
#elif event["name"]=="screen": |
|||
# if event["data"]=="destroy": |
|||
# out = 'main' |
|||
|
|||
#droid.fullQuery() |
|||
#print "Data entered =",droid.fullQueryDetail("editText1").result |
|||
#droid.fullDismiss() |
|||
return out |
|||
|
|||
def server_dialog(plist): |
|||
droid.dialogCreateAlert("servers") |
|||
droid.dialogSetItems( plist.keys() ) |
|||
droid.dialogShow() |
|||
i = droid.dialogGetResponse().result.get('item') |
|||
droid.dialogDismiss() |
|||
if i is not None: |
|||
response = plist.keys()[i] |
|||
return response |
|||
|
|||
def protocol_dialog(plist): |
|||
options=["TCP","HTTP","native"] |
|||
droid.dialogCreateAlert("Protocol") |
|||
droid.dialogSetSingleChoiceItems(options) |
|||
|
|||
|
|||
|
|||
def settings_loop(): |
|||
droid.fullShow(settings_layout) |
|||
droid.fullSetProperty("server","text",wallet.server) |
|||
|
|||
out = None |
|||
while out is None: |
|||
event = droid.eventWait().result |
|||
if event["name"] == "click": |
|||
|
|||
id = event["data"]["id"] |
|||
|
|||
if id=="buttonServer": |
|||
plist = {} |
|||
for item in wallet.interface.servers: |
|||
host, pp = item |
|||
z = {} |
|||
for item2 in pp: |
|||
protocol, port = item2 |
|||
z[protocol] = port |
|||
plist[host] = z |
|||
|
|||
host = server_dialog(plist) |
|||
p = plist[host] |
|||
port = p['t'] |
|||
srv = host + ':' + port + ':t' |
|||
droid.fullSetProperty("server","text",srv) |
|||
|
|||
elif id=="buttonSave": |
|||
droid.fullQuery() |
|||
srv = droid.fullQueryDetail("server").result.get('text') |
|||
try: |
|||
wallet.set_server(srv) |
|||
out = 'main' |
|||
except: |
|||
droid.dialogCreateAlert('error') |
|||
droid.dialogSetPositiveButtonText('OK') |
|||
droid.dialogShow() |
|||
droid.dialogGetResponse() |
|||
droid.dialogDismiss() |
|||
|
|||
elif id=="buttonCancel": |
|||
out = 'main' |
|||
|
|||
elif event["name"] == "key": |
|||
print repr(event["data"]["key"]) |
|||
if event["data"]["key"] == '4': |
|||
out = 'main' |
|||
|
|||
elif event["name"]=="quit": |
|||
out = 'quit' |
|||
|
|||
return out |
|||
|
|||
|
|||
|
|||
|
|||
s = 'main' |
|||
while True: |
|||
if s == 'main': |
|||
s = main_loop() |
|||
elif s == 'payto': |
|||
s = payto_loop() |
|||
elif s == 'settings': |
|||
s = settings_loop() |
|||
elif s == 'history': |
|||
s = history_loop() |
|||
elif s == 'contacts': |
|||
s = contacts_loop() |
|||
else: |
|||
break |
|||
|
|||
droid.fullDismiss() |
|||
droid.makeToast("Bye!") |
Loading…
Reference in new issue