commit 65ecbf990d712fd152ef6d1f8e5a3a7401839df1
parent d68042e76e3f194c9ec43524a7f79844a4703ce7
Author: ThomasV <thomasv@electrum.org>
Date: Tue, 6 Oct 2015 09:59:29 +0200
kivy: split mainscreen.kv into dynamically loaded .kv files
Diffstat:
15 files changed, 1430 insertions(+), 566 deletions(-)
diff --git a/gui/kivy/main.kv b/gui/kivy/main.kv
@@ -1,4 +1,6 @@
#:import Window kivy.core.window.Window
+#:import Factory kivy.factory.Factory
+#:import _ electrum.i18n._
# Custom Global Widgets
@@ -7,6 +9,79 @@
size_hint: 1, None
height: self.minimum_height
+<LightOptions@SpinnerOption>
+ font_size: '14sp'
+ border: 4, 4, 4, 4
+ color: 0.439, 0.439, 0.439, .8
+ background_normal: 'atlas://gui/kivy/theming/light/action_button_group'
+ background_down: 'atlas://gui/kivy/theming/light/overflow_btn_dn'
+ size_hint_y: None
+ height: '48dp'
+ text_size: self.size[0] - dp(20), self.size[1]
+ halign: 'left'
+ valign: 'middle'
+ shorten: True
+ on_press:
+ ddn = self.parent.parent
+ Factory.Animation(opacity=0, d=.25).start(ddn)
+
+<OppositeDropDown@DropDown>
+ #auto_width: False
+ size_hint: None, None
+ size: self.container.minimum_size if self.container else (0, 0)
+ on_container: if args[1]: self.container.padding = '4dp', '4dp', '4dp', '4dp'
+ canvas.before:
+ Color:
+ rgba: 1, 1, 1, 1
+ BorderImage:
+ pos:self.pos
+ border: 20, 20, 20, 20
+ source: 'atlas://gui/kivy/theming/light/dropdown_background'
+ size: self.size
+
+<OppositeSpinner@CSpinner>
+ dropdown_cls: Factory.OppositeDropDown
+ option_cls: Factory.LightOptions
+ border: 20, 20, 9, 9
+ background_normal: 'atlas://gui/kivy/theming/light/action_group_dark'
+ background_down: self.background_normal
+ values: ('Copy to clipboard', 'Send Payment')
+ size_hint: None, 1
+ width: '12dp'
+ on_release:
+ ddn = self._dropdown
+ ddn.opacity = 0
+ Factory.Animation(opacity=1, d=.25).start(ddn)
+
+
+<BlueSpinner@BoxLayout>
+ foreground_color: 1, 1, 1, 1
+ spacing: '9dp'
+ text: ''
+ values: ('', )
+ icon: ''
+ Image:
+ source: root.icon
+ size_hint: None, None
+ size: '22dp', '22dp'
+ pos_hint: {'center_y': .5}
+ OppositeSpinner:
+ color: root.foreground_color
+ background_normal: 'atlas://gui/kivy/theming/light/action_group_light'
+ markup: False
+ shorten: True
+ font_size: '16dp'
+ size_hint: 1, .7
+ pos_hint: {'center_y': .5}
+ text: root.text
+ text_size: self.size
+ halign: 'left'
+ valign: 'middle'
+ on_text:
+ root.text = args[1]
+ values: root.values
+
+
<IconButton@ButtonBehavior+Image>
allow_stretch: True
size_hint_x: None
@@ -50,39 +125,8 @@
background_normal: 'atlas://gui/kivy/theming/light/textinput_active'
-<CreateAccountButtonBlue@Button>
- canvas.after:
- Color
- rgba: 1, 1, 1, 1 if self.disabled else 0
- Rectangle:
- texture: self.texture
- size: self.size
- pos: self.pos
- Color
- rgba: .5, .5, .5, .5 if self.disabled else 0
- Rectangle:
- texture: self.texture
- size: self.size
- pos: self.x - dp(1), self.y + dp(1)
- border: 15, 5, 5, 5
- background_color: (1, 1, 1, 1) if self.disabled else (.203, .490, .741, 1 if self.state == 'normal' else .75)
- size_hint: 1, None
- height: '48sp'
- text_size: self.size
- halign: 'center'
- valign: 'middle'
- root: None
- background_normal: 'atlas://gui/kivy/theming/light/btn_create_account'
- background_down: 'atlas://gui/kivy/theming/light/btn_create_account'
- background_disabled_normal: 'atlas://gui/kivy/theming/light/btn_create_act_disabled'
- on_press: if self.root: self.root.dispatch('on_press', self)
- on_release: if self.root: self.root.dispatch('on_release', self)
-
-
-<CreateAccountButtonGreen@CreateAccountButtonBlue>
- background_color: (1, 1, 1, 1) if self.disabled else (.415, .717, 0, 1 if self.state == 'normal' else .75)
###########################
-## Gloabal Defaults
+# Global Defaults
###########################
<TextInput>
on_focus: app._focused_widget = root
@@ -127,11 +171,346 @@
size_hint: 1, 1
width: 0 if root.fs else (root.width - img.width)
-StencilView:
- manager: None
+
+
+<WalletActionPrevious@ActionPrevious>
+ app_icon: 'atlas://gui/kivy/theming/light/' + ('wallets' if app.ui_mode[0] != 't' else 'tab_btn')
+ with_previous: False
+ size_hint: None, 1
+ mipmap: True
+ on_release: app.root.children[0].toggle_drawer()
+
+
+<SendReceiveToggle@BoxLayout>
+ padding: '5dp', '5dp'
+ size_hint: 1, None
+ height: '45dp'
+ canvas.before:
+ Color:
+ rgba: 1, 1, 1, 1
+ BorderImage:
+ border: 12, 12, 12, 12
+ source: 'atlas://gui/kivy/theming/light/card'
+ size: self.width + dp(3), self.height
+ pos: self.x - dp(1.5), self.y
+
+<SendReceiveCardTop@GridLayout>
+ canvas.before:
+ BorderImage:
+ border: 9, 9, 9, 9
+ source: 'atlas://gui/kivy/theming/light/card_top'
+ size: self.size
+ pos:self.pos
+ padding: '12dp', '22dp', '12dp', 0
+ cols: 1
+ size_hint: 1, None
+ height: '120dp'
+ spacing: '4dp'
+
+<SendReceiveBlueBottom@GridLayout>
+ canvas.before:
+ Color:
+ rgba: .238, .585, .878, 1
+ BorderImage:
+ border: 9, 9, 9, 9
+ source: 'atlas://gui/kivy/theming/light/card_bottom'
+ size: self.size
+ pos: self.pos
+ Color:
+ rgba: 1, 1, 1, 1
+
+ item_height: dp(42)
+ foreground_color: .843, .914, .972, 1
+ cols: 1
+ padding: '12dp', 0
+
+
+<SendToggle@ToggleButton>
+ source: ''
+ group: 'transfer_type'
+ markup: False
+ bold: True
+ border: 4, 4, 4, 4
+ background_normal: self.background_down
+ color:
+ (.140, .140, .140, 1) if self.state == 'down' else (.796, .796, .796, 1)
+ canvas.after:
+ Color:
+ rgba: 1, 1, 1, 1
+ Image:
+ source: root.source
+ color: root.color
+ size: '30dp', '30dp'
+ center_x: root.center_x - ((root.texture_size[0]/2)+(self.width/1.5))
+ center_y: root.center_y
+
+
+<CardSeparator@Widget>
+ size_hint: 1, None
+ height: dp(1)
+ color: .909, .909, .909, 1
+ canvas:
+ Color:
+ rgba: root.color if root.color else (0, 0, 0, 0)
+ Rectangle:
+ size: self.size
+ pos: self.pos
+
+<AddressSelector@BlueSpinner>
+ icon: 'atlas://gui/kivy/theming/light/globe'
+ values: app.wallet.addresses() if app.wallet else []
+ text: _("Select Your address")
+
+
+<ElectrumScreen>
+ ScrollView:
+ do_scroll_x: False
+ do_scroll_y: False if root.fullscreen else (content.height > root.height - dp(16))
+ AnchorLayout:
+ size_hint_y: None
+ height: root.height if root.fullscreen else max(root.height, content.height)
+ GridLayout:
+ id: content
+ cols: 1
+ spacing: '8dp'
+ padding: '8dp'
+ size_hint: (1, 1) if root.fullscreen else (.8, None)
+ height: self.height if root.fullscreen else self.minimum_height
+
+
+<TabbedCarousel>
+ carousel: carousel
+ do_default_tab: False
+ Carousel:
+ scroll_timeout: 190
+ anim_type: 'out_quart'
+ min_move: .05
+ anim_move_duration: .1
+ anim_cancel_duration: .54
+ scroll_distance: '10dp'
+ on_index: root.on_index(*args)
+ id: carousel
+
+
+<CarouselIndicator@TabbedCarousel>
+ tab_pos: 'bottom_mid'
+ tab_height: '32dp'
+ tab_width: self.tab_height
+ #background_image: 'atlas://data/images/defaulttheme/action_item'
+ strip_border: 0, 0, 0, 0
+
+<CloseButton@IconButton>
+ source: 'atlas://gui/kivy/theming/light/closebutton'
+ opacity: 1 if self.state == 'normal' else .75
+ size_hint: None, None
+ size: '27dp', '27dp'
+
+<-CarouselDialog>
+ header_color: '#707070ff'
+ text_color: 0.701, 0.701, 0.701, 1
+ title_size: '13sp'
+ title: ''
+ separator_color: 0.89, 0.89, 0.89, 1
+ background: 'atlas://gui/kivy/theming/light/tab_btn'
+ carousel_content: carousel_content
canvas.before:
Color:
+ rgba: 0, 0, 0, .9
+ Rectangle:
+ size: Window.size
+ pos: 0, 0
+ Color:
rgba: 1, 1, 1, 1
- Rectangle
+ BorderImage:
+ border: 12, 12, 12, 12
+ source: 'atlas://gui/kivy/theming/light/dialog'
+ size: root.width, root.height - self.carousel_content.tab_height if self.carousel_content else 0
+ pos: root.x, self.y + self.carousel_content.tab_height if self.carousel_content else 10
+ BoxLayout:
+ orientation: 'vertical'
+ GridLayout:
+ cols: 1
+ size_hint: 1, None
+ height: self.minimum_height
+ padding: 0, '7sp'
+ Label:
+ font_size: root.title_size
+ text: u'[color={}]{}[/color]'.format(root.header_color, root.title)
+ text_size: self.width, None
+ halign: 'left'
+ size_hint: 1, None
+ height: self.texture_size[1]
+ CardSeparator:
+ color: root.separator_color
+ height: root.separator_height
+ FloatLayout:
+ size_hint: None, None
+ size: 0, 0
+ CloseButton:
+ id: but_close
+ top: root.top - dp(10)
+ right: root.right - dp(10)
+ on_release: root.dismiss()
+ CarouselIndicator:
+ id: carousel_content
+
+
+<CleanHeader@TabbedPanelHeader>
+ border: 0, 0, 16, 0
+ markup: False
+ text_size: self.size
+ halign: 'center'
+ valign: 'middle'
+ bold: True
+ font_size: '12.5sp'
+ background_normal: 'atlas://gui/kivy/theming/light/tab_btn'
+ background_disabled_normal: 'atlas://gui/kivy/theming/light/tab_btn_disabled'
+ background_down: 'atlas://gui/kivy/theming/light/tab_btn_pressed'
+ #canvas.before:
+ # Color:
+ # rgba: .6, .6, .6, .7
+ # Rectangle:
+ # size: self.size
+ # pos: self.x + 1, self.y - 1
+ # texture: self.texture
+
+
+<ColoredLabel@Label>:
+ font_size: '48sp'
+ color: (.6, .6, .6, 1)
+ canvas.before:
+ Color:
+ rgb: (.9, .9, .9)
+ Rectangle:
+ pos: self.x + sp(2), self.y + sp(2)
+ size: self.width - sp(4), self.height - sp(4)
+
+
+
+<ScreenTabs@Screen>
+ TabbedCarousel:
+ id: panel
+ tab_height: '48dp'
+ default_tab: send_tab
+ strip_border: 0, 0, 0, 0
+
+ HistoryScreen:
+ id: history_screen
+ tab: history_tab
+
+ SendScreen:
+ id: send_screen
+ tab: send_tab
+
+ ReceiveScreen:
+ id: receive_screen
+ tab: receive_tab
+
+ ContactsScreen:
+ id: contacts_screen
+ tab: contacts_tab
+
+ CleanHeader:
+ id: history_tab
+ text: _('History')
+ slide: 0
+ CleanHeader:
+ id: send_tab
+ text: _('Send')
+ slide: 1
+ CleanHeader:
+ id: receive_tab
+ text: _('Receive')
+ slide: 2
+ CleanHeader:
+ id: contacts_tab
+ text: _('Contacts')
+ slide: 3
+
+
+<ActionButton>:
+ border: 4, 0, 0, 0
+ #background_down: 'atlas://gui/kivy/theming/light/overflow_btn_dn'
+
+<OverflowButton@ActionButton>
+ text_size: dp(50), None
+ last: False
+ halign: 'left'
+ valign: 'middle'
+ overflow: None
+ #background_normal:
+ # 'atlas://gui/kivy/theming/light/' +\
+ # ('action_button_group'\
+ # if (self.inside_group and not self.last) else 'tab_btn')
+
+ #on_press:
+ # ddn = self.overflow._dropdown
+ # Factory.Animation.cancel_all(ddn)
+ # anim = Factory.Animation(opacity=0, d=.25)
+ # anim.bind(on_complete=ddn.dismiss)
+ # anim.start(ddn)
+
+BoxLayout:
+
+ orientation: 'vertical'
+
+ canvas.before:
+ Color:
+ rgb: .6, .6, .6
+ Rectangle:
size: self.size
- pos: self.pos-
\ No newline at end of file
+ source: 'gui/kivy/data/background.png'
+
+ ActionBar:
+
+ ActionView:
+ id: av
+
+ ActionPrevious:
+ app_icon: 'atlas://gui/kivy/theming/light/logo'
+ with_previous: False
+ on_release: app.on_back()
+
+ ActionButton:
+ id: action_status
+ important: True
+ size_hint: 1, 1
+ markup: True
+ mipmap: True
+ bold: True
+ markup: True
+ color: 1, 1, 1, 1
+ text:
+ "[color=#777777]{}[/color]"\
+ .format(app.status)
+ font_size: '22dp'
+ minimum_width: '1dp'
+
+ ActionOverflow:
+ id: action_overflow
+ width: '60dp'
+ OverflowButton:
+ text: _('Network')
+ overflow: action_overflow
+ on_release: app.popup_dialog('network')
+ OverflowButton:
+ text: _('Wallet')
+ overflow: action_overflow
+ on_release: app.popup_dialog('wallet')
+ OverflowButton:
+ text: _('Preferences')
+ overflow: action_overflow
+ on_release: app.popup_dialog('settings')
+
+ ScreenManager:
+ id: manager
+ #tabs: Factory.ScreenTabs()
+ ScreenTabs:
+ id: tabs
+ name: "tabs"
+
+ #on_current_screen:
+ #spnr.text = args[1].name
+ #idx = app.screen_names.index(args[1].name)
+ #if idx > -1: app.hierarchy.append(idx)
+ #args
diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
@@ -9,11 +9,6 @@ from electrum.contacts import Contacts
from electrum import bitcoin
from electrum.util import profiler, print_error
-from kivy.config import Config
-Config.set('modules', 'screen', 'droid2')
-Config.set('graphics', 'width', '480')
-Config.set('graphics', 'height', '840')
-
from kivy.app import App
from kivy.core.window import Window
from kivy.logger import Logger
@@ -23,8 +18,7 @@ from kivy.properties import (OptionProperty, AliasProperty, ObjectProperty,
from kivy.cache import Cache
from kivy.clock import Clock
from kivy.factory import Factory
-
-from electrum_gui.kivy.uix.drawer import Drawer
+from kivy.metrics import inch, metrics
# lazy imports for factory so that widgets can be used in kv
Factory.register('InstallWizard',
@@ -34,15 +28,31 @@ Factory.register('ELTextInput', module='electrum_gui.kivy.uix.screens')
# delayed imports: for startup speed on android
-notification = app = Decimal = ref = format_satoshis = Builder = None
-inch = None
+notification = app = ref = format_satoshis = Builder = None
util = False
-re = None
+
+from decimal import Decimal
+import re
# register widget cache for keeping memory down timeout to forever to cache
# the data
Cache.register('electrum_widgets', timeout=0)
+from kivy.uix.screenmanager import Screen
+from kivy.uix.tabbedpanel import TabbedPanel
+
+class ElectrumScreen(Screen):
+ fullscreen = BooleanProperty(False)
+ #def add_widget(self, *args):
+ # if 'content' in self.ids:
+ # return self.ids.content.add_widget(*args)
+ # return super(ElectrumScreen, self).add_widget(*args)
+
+
+Factory.register('TabbedCarousel', module='electrum_gui.kivy.uix.screens')
+
+
+
class ElectrumWindow(App):
def _get_bu(self):
@@ -102,11 +112,9 @@ class ElectrumWindow(App):
:attr:`electrum_config` is a `ObjectProperty`, defaults to None.
'''
- status = StringProperty(_('Uninitialised'))
- '''The status of the connection should show the balance when connected
+ status = StringProperty(_('Not Connected'))
+ balance = StringProperty('')
- :attr:`status` is a `StringProperty` defaults to 'uninitialised'
- '''
def _get_num_zeros(self):
try:
@@ -136,11 +144,8 @@ class ElectrumWindow(App):
return int(p * x)
- navigation_higherarchy = ListProperty([])
- '''This is a list of the current navigation higherarchy of the app used to
- navigate using back button.
-
- :attr:`navigation_higherarchy` is s `ListProperty` defaults to []
+ hierarchy = ListProperty([])
+ '''used to navigate with the back button.
'''
_orientation = OptionProperty('landscape',
@@ -239,6 +244,8 @@ class ElectrumWindow(App):
global Builder
if not Builder:
from kivy.lang import Builder
+
+
return Builder.load_file('gui/kivy/main.kv')
def _pause(self):
@@ -252,6 +259,7 @@ class ElectrumWindow(App):
def on_start(self):
''' This is the start point of the kivy ui
'''
+ Logger.info("dpi: {} {}".format(metrics.dpi, metrics.dpi_rounded))
win = Window
win.bind(size=self.on_size,
on_keyboard=self.on_keyboard)
@@ -299,6 +307,14 @@ class ElectrumWindow(App):
if self.wallet:
self.wallet.stop_threads()
+ def on_back(self):
+ try:
+ self.hierarchy.pop()()
+ except IndexError:
+ # capture back button and pause app.
+ self._pause()
+
+
def on_keyboard_height(self, window, height):
win = window
active_widg = win.children[0]
@@ -351,6 +367,12 @@ class ElectrumWindow(App):
self.init_ui()
self.load_wallet(wallet)
+ def popup_dialog(self, name):
+ popup = Builder.load_file('gui/kivy/uix/ui_screens/'+name+'.kv')
+ popup.open()
+
+
+
@profiler
def init_ui(self):
''' Initialize The Ux part of electrum. This function performs the basic
@@ -366,13 +388,15 @@ class ElectrumWindow(App):
self.completions = []
# setup UX
- self.screens = ['mainscreen',]
+ self.screens = {}
#setup lazy imports for mainscreen
Factory.register('AnimatedPopup',
module='electrum_gui.kivy.uix.dialogs')
- Factory.register('TabbedCarousel',
- module='electrum_gui.kivy.uix.screens')
+
+ #Factory.register('TabbedCarousel',
+ # module='electrum_gui.kivy.uix.screens')
+
Factory.register('ScreenDashboard',
module='electrum_gui.kivy.uix.screens')
#Factory.register('EffectWidget',
@@ -386,17 +410,26 @@ class ElectrumWindow(App):
# preload widgets. Remove this if you want to load the widgets on demand
Cache.append('electrum_widgets', 'AnimatedPopup', Factory.AnimatedPopup())
- Cache.append('electrum_widgets', 'TabbedCarousel', Factory.TabbedCarousel())
+
+ #Cache.append('electrum_widgets', 'TabbedCarousel', Factory.TabbedCarousel())
+
Cache.append('electrum_widgets', 'QRCodeWidget', Factory.QRCodeWidget())
Cache.append('electrum_widgets', 'CSpinner', Factory.CSpinner())
# load and focus the ui
#Load mainscreen
- dr = Builder.load_file('gui/kivy/uix/ui_screens/mainscreen.kv')
- self.root.add_widget(dr)
- self.root.manager = manager = dr.ids.manager
- self.root.main_screen = m = manager.screens[0]
- self.tabs = m.ids.tabs
+
+ #dr = Builder.load_file('gui/kivy/uix/ui_screens/mainscreen.kv')
+ #self.root.add_widget(dr)
+ #self.root.manager = manager = dr.ids.manager
+ #self.root.main_screen = m = manager.screens[0]
+ #self.tabs = m.ids.tabs
+
+ self.root.manager = self.root.ids['manager']
+ self.recent_activity_card = None
+ self.history_screen = None
+ self.contacts_screen = None
+ self.wallet_screen = None
#TODO
# load left_menu
@@ -411,6 +444,7 @@ class ElectrumWindow(App):
self.wallet = None
+
def create_quote_text(self, btc_balance, mode='normal'):
'''
'''
@@ -473,10 +507,6 @@ class ElectrumWindow(App):
if not self.wallet:
return
- global Decimal
- if not Decimal:
- from decimal import Decimal
-
unconfirmed = ''
quote_text = ''
@@ -487,34 +517,38 @@ class ElectrumWindow(App):
server_height = self.network.get_server_height()
server_lag = self.network.get_local_height() - server_height
if not self.wallet.up_to_date or server_height == 0:
- text = _("Synchronizing...")
+ self.status = _("Synchronizing...")
elif server_lag > 1:
- text = _("Server is lagging (%d blocks)"%server_lag)
+ self.status = _("Server lagging (%d blocks)"%server_lag)
else:
c, u, x = self.wallet.get_account_balance(self.current_account)
text = self.format_amount(c)
+ self.balance = text
if u:
unconfirmed = " [%s unconfirmed]" %( self.format_amount(u, True).strip())
if x:
unmatured = " [%s unmatured]"%(self.format_amount(x, True).strip())
+ self.balance = text.strip()
quote_text = self.create_quote_text(Decimal(c+u+x)/100000000, mode='symbol') or ''
+ self.status = self.balance
else:
- text = _("Not connected")
- try:
- status_card = self.root.main_screen.ids.tabs.ids.\
- screen_dashboard.ids.status_card
- except AttributeError:
- return
- self.status = text.strip()
+ self.status = _("Not connected")
+
+ return
+
+ print self.root.manager.ids
+
+ #try:
+ status_card = self.root.main_screen.ids.tabs.ids.\
+ screen_dashboard.ids.status_card
+ #except AttributeError:
+ # return
+
status_card.quote_text = quote_text.strip()
status_card.uncomfirmed = unconfirmed.strip()
def format_amount(self, x, is_diff=False, whitespaces=False):
- '''
- '''
- global format_satoshis
- if not format_satoshis:
- from electrum.util import format_satoshis
+ from electrum.util import format_satoshis
return format_satoshis(x, is_diff, self.num_zeros,
self.decimal_point, whitespaces)
@@ -532,116 +566,16 @@ class ElectrumWindow(App):
self.update_history_tab()
self.update_contacts_tab()
- def parse_histories(self, items):
- for item in items:
- tx_hash, conf, value, timestamp, balance = item
- time_str = _("unknown")
- if conf > 0:
- try:
- time_str = datetime.datetime.fromtimestamp(
- timestamp).isoformat(' ')[:-3]
- except Exception:
- time_str = _("error")
-
- if conf == -1:
- time_str = _('unverified')
- icon = "atlas://gui/kivy/theming/light/close"
- elif conf == 0:
- time_str = _('pending')
- icon = "atlas://gui/kivy/theming/light/unconfirmed"
- elif conf < 6:
- time_str = '' # add new to fix error when conf < 0
- conf = max(1, conf)
- icon = "atlas://gui/kivy/theming/light/clock{}".format(conf)
- else:
- icon = "atlas://gui/kivy/theming/light/confirmed"
-
- if value is not None:
- v_str = self.format_amount(value, True).replace(',','.')
- else:
- v_str = '--'
-
- balance_str = self.format_amount(balance).replace(',','.')
-
- if tx_hash:
- label, is_default_label = self.wallet.get_label(tx_hash)
- else:
- label = _('Pruned transaction outputs')
- is_default_label = False
-
- yield (conf, icon, time_str, label, v_str, balance_str, tx_hash)
@profiler
def update_history_tab(self, see_all=False):
- try:
- history_card = self.root.main_screen.ids.tabs.ids.\
- screen_dashboard.ids.recent_activity_card
- except AttributeError:
- return
- histories = self.parse_histories(reversed(
- self.wallet.get_history(self.current_account)))
-
- # repopulate History Card
- last_widget = history_card.ids.content.children[-1]
- history_card.ids.content.clear_widgets()
- history_add = history_card.ids.content.add_widget
- history_add(last_widget)
- RecentActivityItem = Factory.RecentActivityItem
- global Decimal, ref
- if not ref:
- from weakref import ref
- if not Decimal:
- from decimal import Decimal
-
- get_history_rate = self.get_history_rate
- count = 0
- for items in histories:
- count += 1
- conf, icon, date_time, address, amount, balance, tx = items
- ri = RecentActivityItem()
- ri.icon = icon
- ri.date = date_time
- mintimestr = date_time.split()[0]
- ri.address = address
- ri.amount = amount
- ri.quote_text = get_history_rate(ref(ri),
- Decimal(amount),
- mintimestr)
- ri.balance = balance
- ri.confirmations = conf
- ri.tx_hash = tx
- history_add(ri)
- if count == 8 and not see_all:
- break
-
- history_card.ids.btn_see_all.opacity = (0 if count < 8 else 1)
-
+ if self.history_screen:
+ self.history_screen.update(see_all)
def update_contacts_tab(self):
- contact_list = self.root.main_screen.ids.tabs.ids.\
- screen_contacts.ids.contact_container
- #contact_list.clear_widgets()
+ if self.contacts_screen:
+ self.contacts_screen.update()
- child = -1
- children = contact_list.children
-
- for key in sorted(self.contacts.keys()):
- _type, address = self.contacts[key]
- label = self.wallet.labels.get(address, '')
- child += 1
- try:
- if children[child].label == label:
- continue
- except IndexError:
- pass
- tx = self.wallet.get_num_tx(address)
- ci = Factory.ContactItem()
- ci.address = address
- ci.label = label
- ci.tx_amount = tx
- contact_list.add_widget(ci)
-
- #self.run_hook('update_contacts_tab')
def do_send(self):
app = App.get_running_app()
@@ -650,9 +584,6 @@ class ElectrumWindow(App):
label = unicode(scrn.message_e.text)
r = unicode(scrn.payto_e.text).strip()
# label or alias, with address in brackets
- global re
- if not re:
- import re
m = re.match('(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>', r)
to_address = m.group(2) if m else r
@@ -774,46 +705,23 @@ class ElectrumWindow(App):
def on_size(self, instance, value):
width, height = value
self._orientation = 'landscape' if width > height else 'portrait'
-
- global inch
- if not inch:
- from kivy.metrics import inch
-
self._ui_mode = 'tablet' if min(width, height) > inch(3.51) else 'phone'
- Logger.debug('orientation: {} ui_mode: {}'.format(self._orientation,
- self._ui_mode))
-
- def load_screen(self, index=0, direction='left', manager=None, switch=True):
- ''' Load the appropriate screen as mentioned in the parameters.
- '''
+ #Logger.info("size: {} {}".format(width, height))
+ #Logger.info('orientation: {}'.format(self._orientation))
+ #Logger.info('ui_mode: {}'.format(self._ui_mode))
+
+ def load_screen(self, name, direction='left', manager=None):
+ screen = self.screens.get(name)
+ if screen is None:
+ screen = Builder.load_file('gui/kivy/uix/ui_screens/' + name + '.kv')
+ screen.name = name
+ self.screens[name] = screen
manager = manager or self.root.manager
- screen = Builder.load_file('gui/kivy/uix/ui_screens/'\
- + self.screens[index] + '.kv')
- screen.name = self.screens[index]
- if switch:
- manager.switch_to(screen, direction=direction)
- return screen
-
- def load_next_screen(self):
- '''
- '''
- manager = root.manager
- try:
- self.load_screen(self.screens.index(manager.current_screen.name)+1,
- manager=manager)
- except IndexError:
- self.load_screen()
+ manager.switch_to(screen, direction=direction)
- def load_previous_screen(self):
- ''' Load the previous screen from disk.
- '''
- manager = root.manager
- try:
- self.load_screen(self.screens.index(manager.current_screen.name)-1,
- direction='right',
- manager=manager)
- except IndexError:
- pass
+ def load_history(self):
+ #Builder.load_file('gui/kivy/uix/ui_screens/history.kv')
+ print "load history", self.root.manager.ids.history
def save_new_contact(self, address, label):
address = unicode(address)
diff --git a/gui/kivy/theming/light-0.png b/gui/kivy/theming/light-0.png
Binary files differ.
diff --git a/gui/kivy/theming/light.atlas b/gui/kivy/theming/light.atlas
@@ -1 +1 @@
-{"light-0.png": {"closebutton": [641, 591, 60, 43], "card_top": [901, 792, 32, 16], "tab_btn_disabled": [867, 483, 32, 32], "tab_btn_pressed": [901, 483, 32, 32], "bit_logo": [589, 728, 44, 51], "globe": [686, 267, 72, 72], "btn_send_nfc": [955, 793, 18, 15], "shadow_right": [975, 803, 32, 5], "logo_atom_dull": [773, 517, 64, 64], "create_act_text_active": [995, 638, 22, 10], "action_group_light": [431, 344, 33, 48], "tab": [390, 715, 64, 64], "logo": [296, 211, 128, 128], "qrcode": [2, 194, 145, 145], "close": [834, 810, 88, 88], "btn_create_act_disabled": [985, 911, 32, 32], "white_bg_round_top": [834, 788, 31, 20], "card_bottom": [867, 792, 32, 16], "confirmed": [839, 636, 64, 64], "overflow_btn_dn": [989, 520, 16, 10], "carousel_deselected": [760, 275, 64, 64], "network": [692, 467, 48, 48], "blue_bg_round_rb": [935, 495, 31, 20], "dropdown_background": [765, 599, 29, 35], "action_bar": [795, 479, 36, 36], "pen": [905, 517, 64, 64], "overflow_background": [796, 599, 29, 35], "arrow_back": [971, 650, 50, 50], "clock3": [641, 636, 64, 64], "contact": [971, 532, 49, 49], "star_big_inactive": [426, 211, 128, 128], "lightblue_bg_round_lb": [968, 495, 31, 20], "manualentry": [149, 205, 145, 134], "stepper_restore_password": [247, 464, 392, 117], "tab_disabled": [752, 233, 96, 32], "mail_icon": [522, 725, 65, 54], "tab_strip": [850, 233, 96, 32], "tab_btn": [833, 483, 32, 32], "btn_create_account": [948, 233, 64, 32], "btn_send_address": [935, 793, 18, 15], "add_contact": [742, 472, 51, 43], "gear": [2, 33, 105, 159], "wallets": [703, 594, 60, 40], "stepper_left": [247, 583, 392, 117], "nfc_stage_one": [324, 900, 489, 122], "nfc_clock": [2, 460, 243, 240], "btn_nfc": [752, 219, 13, 12], "textinput_active": [718, 784, 114, 114], "clock2": [958, 275, 64, 64], "nfc_phone": [556, 213, 128, 126], "clock4": [707, 636, 64, 64], "paste_icon": [945, 945, 75, 77], "shadow": [324, 715, 64, 64], "carousel_selected": [826, 275, 64, 64], "card": [686, 216, 64, 49], "unconfirmed": [456, 715, 64, 64], "info": [707, 517, 64, 64], "electrum_icon640": [2, 702, 320, 320], "action_button_group": [971, 520, 16, 10], "action_group_dark": [396, 344, 33, 48], "nfc": [839, 517, 64, 64], "contact_avatar": [641, 466, 49, 49], "clock1": [892, 275, 64, 64], "create_act_text": [971, 638, 22, 10], "icon_border": [641, 517, 64, 64], "stepper_full": [324, 781, 392, 117], "card_btn": [945, 911, 38, 32], "wallet": [635, 735, 49, 44], "important": [924, 810, 88, 88], "dialog": [1001, 495, 18, 20], "error": [815, 908, 128, 114], "stepper_restore_seed": [2, 341, 392, 117], "contact_overlay": [905, 636, 64, 64], "settings": [396, 394, 54, 64], "clock5": [773, 636, 64, 64]}}-
\ No newline at end of file
+{"light-0.png": {"closebutton": [964, 855, 60, 43], "card_top": [964, 786, 32, 16], "tab_btn_disabled": [788, 483, 32, 32], "tab_btn_pressed": [856, 483, 32, 32], "bit_logo": [396, 407, 44, 51], "globe": [821, 628, 72, 72], "btn_send_nfc": [755, 290, 18, 15], "shadow_right": [895, 629, 32, 5], "logo_atom_dull": [654, 715, 64, 64], "action_group_light": [396, 357, 33, 48], "tab": [918, 715, 64, 64], "logo": [815, 906, 128, 116], "qrcode": [2, 194, 145, 145], "close": [641, 612, 88, 88], "btn_create_act_disabled": [754, 483, 32, 32], "white_bg_round_top": [956, 495, 31, 20], "card_bottom": [989, 499, 32, 16], "confirmed": [390, 715, 64, 64], "overflow_btn_dn": [995, 519, 16, 10], "carousel_deselected": [895, 636, 64, 64], "network": [556, 225, 48, 48], "blue_bg_round_rb": [890, 495, 31, 20], "dropdown_background": [659, 238, 29, 35], "action_bar": [945, 907, 36, 36], "pen": [786, 715, 64, 64], "overflow_background": [690, 238, 29, 35], "arrow_back": [971, 531, 50, 50], "clock3": [839, 517, 64, 64], "contact": [641, 466, 49, 49], "star_big_inactive": [296, 211, 128, 128], "lightblue_bg_round_lb": [923, 495, 31, 20], "manualentry": [149, 205, 145, 134], "stepper_restore_password": [247, 464, 392, 117], "tab_disabled": [755, 307, 96, 32], "mail_icon": [622, 285, 65, 54], "tab_strip": [853, 307, 96, 32], "tab_btn": [822, 483, 32, 32], "btn_create_account": [951, 307, 64, 32], "btn_send_address": [998, 787, 18, 15], "add_contact": [606, 230, 51, 43], "gear": [2, 33, 105, 159], "wallets": [692, 475, 60, 40], "stepper_left": [247, 583, 392, 117], "nfc_stage_one": [324, 900, 489, 122], "nfc_clock": [2, 460, 243, 240], "btn_nfc": [821, 614, 13, 12], "textinput_active": [848, 784, 114, 114], "clock2": [773, 517, 64, 64], "nfc_phone": [426, 213, 128, 126], "clock4": [905, 517, 64, 64], "paste_icon": [945, 945, 75, 77], "shadow": [852, 715, 64, 64], "carousel_selected": [641, 517, 64, 64], "card": [689, 290, 64, 49], "unconfirmed": [556, 275, 64, 64], "info": [588, 715, 64, 64], "electrum_icon640": [2, 702, 320, 320], "action_button_group": [1008, 719, 16, 10], "action_group_dark": [984, 731, 33, 48], "nfc": [720, 715, 64, 64], "contact_avatar": [964, 804, 49, 49], "clock1": [707, 517, 64, 64], "create_act_text_active": [984, 719, 22, 10], "icon_border": [522, 715, 64, 64], "stepper_full": [324, 781, 392, 117], "card_btn": [983, 911, 38, 32], "wallet": [442, 414, 49, 44], "important": [731, 612, 88, 88], "dialog": [641, 590, 18, 20], "error": [718, 784, 128, 114], "stepper_restore_seed": [2, 341, 392, 117], "contact_overlay": [456, 715, 64, 64], "settings": [961, 636, 54, 64], "create_act_text": [971, 519, 22, 10], "clock5": [324, 715, 64, 64]}}+
\ No newline at end of file
diff --git a/gui/kivy/theming/light/logo.png b/gui/kivy/theming/light/logo.png
Binary files differ.
diff --git a/gui/kivy/uix/console.py b/gui/kivy/uix/console.py
@@ -1,319 +0,0 @@
-# source: http://stackoverflow.com/questions/2758159/how-to-embed-a-python-interpreter-in-a-pyqt-widget
-
-import sys, os, re
-import traceback, platform
-from kivy.core.window import Keyboard
-from kivy.uix.textinput import TextInput
-from kivy.properties import StringProperty, ListProperty, DictProperty
-from kivy.clock import Clock
-
-from electrum import util
-
-
-if platform.system() == 'Windows':
- MONOSPACE_FONT = 'Lucida Console'
-elif platform.system() == 'Darwin':
- MONOSPACE_FONT = 'Monaco'
-else:
- MONOSPACE_FONT = 'monospace'
-
-
-class Console(TextInput):
-
- prompt = StringProperty('>> ')
- '''String representing the Prompt message'''
-
- startup_message = StringProperty('')
- '''Startup Message to be displayed in the Console if any'''
-
- history = ListProperty([])
- '''History of the console'''
-
- namespace = DictProperty({})
- '''Dict representing the current namespace of the console'''
-
- def __init__(self, **kwargs):
- super(Console, self).__init__(**kwargs)
- self.construct = []
- self.showMessage(self.startup_message)
- self.updateNamespace({'run':self.run_script})
- self.set_json(False)
-
- def set_json(self, b):
- self.is_json = b
-
- def run_script(self, filename):
- with open(filename) as f:
- script = f.read()
- result = eval(script, self.namespace, self.namespace)
-
- def updateNamespace(self, namespace):
- self.namespace.update(namespace)
-
- def showMessage(self, message):
- self.appendPlainText(message)
- self.newPrompt()
-
- def clear(self):
- self.setPlainText('')
- self.newPrompt()
-
- def newPrompt(self):
- if self.construct:
- prompt = '.' * len(self.prompt)
- else:
- prompt = self.prompt
-
- self.completions_pos = self.cursor_index()
- self.completions_visible = False
-
- self.appendPlainText(prompt)
- self.move_cursor_to('end')
-
- def getCommand(self):
- curr_line = self._lines[-1]
- curr_line = curr_line.rstrip()
- curr_line = curr_line[len(self.prompt):]
- return curr_line
-
- def setCommand(self, command):
- if self.getCommand() == command:
- return
- curr_line = self._lines[-1]
- last_pos = len(self.text)
- self.select_text(last_pos - len(curr_line) + len(self.prompt), last_pos)
- self.delete_selection()
- self.insert_text(command)
-
- def show_completions(self, completions):
- if self.completions_visible:
- self.hide_completions()
-
- self.move_cursor_to(self.completions_pos)
-
- completions = map(lambda x: x.split('.')[-1], completions)
- t = '\n' + ' '.join(completions)
- if len(t) > 500:
- t = t[:500] + '...'
- self.insert_text(t)
- self.completions_end = self.cursor_index()
-
- self.move_cursor_to('end')
- self.completions_visible = True
-
-
- def hide_completions(self):
- if not self.completions_visible:
- return
- self.move_cursor_to(self.completions_pos)
- l = self.completions_end - self.completions_pos
- for x in range(l):
- self.move_cursor_to('cursor_right')
- self.do_backspace()
-
- self.move_cursor_to('end')
- self.completions_visible = False
-
- def getConstruct(self, command):
- if self.construct:
- prev_command = self.construct[-1]
- self.construct.append(command)
- if not prev_command and not command:
- ret_val = '\n'.join(self.construct)
- self.construct = []
- return ret_val
- else:
- return ''
- else:
- if command and command[-1] == (':'):
- self.construct.append(command)
- return ''
- else:
- return command
-
- def getHistory(self):
- return self.history
-
- def setHisory(self, history):
- self.history = history
-
- def addToHistory(self, command):
- if command and (not self.history or self.history[-1] != command):
- self.history.append(command)
- self.history_index = len(self.history)
-
- def getPrevHistoryEntry(self):
- if self.history:
- self.history_index = max(0, self.history_index - 1)
- return self.history[self.history_index]
- return ''
-
- def getNextHistoryEntry(self):
- if self.history:
- hist_len = len(self.history)
- self.history_index = min(hist_len, self.history_index + 1)
- if self.history_index < hist_len:
- return self.history[self.history_index]
- return ''
-
- def getCursorPosition(self):
- return self.cursor[0] - len(self.prompt)
-
- def setCursorPosition(self, position):
- self.cursor = (len(self.prompt) + position, self.cursor[1])
-
- def register_command(self, c, func):
- methods = { c: func}
- self.updateNamespace(methods)
-
-
- def runCommand(self):
- command = self.getCommand()
- self.addToHistory(command)
-
- command = self.getConstruct(command)
-
- if command:
- tmp_stdout = sys.stdout
-
- class stdoutProxy():
- def __init__(self, write_func):
- self.write_func = write_func
- self.skip = False
-
- def flush(self):
- pass
-
- def write(self, text):
- if not self.skip:
- stripped_text = text.rstrip('\n')
- self.write_func(stripped_text)
- self.skip = not self.skip
-
- if type(self.namespace.get(command)) == type(lambda:None):
- self.appendPlainText("'%s' is a function. Type '%s()' to use it in the Python console."%(command, command))
- self.newPrompt()
- return
-
- sys.stdout = stdoutProxy(self.appendPlainText)
- try:
- try:
- result = eval(command, self.namespace, self.namespace)
- if result != None:
- if self.is_json:
- util.print_json(result)
- else:
- self.appendPlainText(repr(result))
- except SyntaxError:
- exec command in self.namespace
- except SystemExit:
- pass
- except:
- traceback_lines = traceback.format_exc().split('\n')
- # Remove traceback mentioning this file, and a linebreak
- for i in (3,2,1,-1):
- traceback_lines.pop(i)
- self.appendPlainText('\n'.join(traceback_lines))
- sys.stdout = tmp_stdout
- self.newPrompt()
- self.set_json(False)
-
- def _keyboard_on_key_down(self, window, keycode, text, modifiers):
- self._hide_cut_copy_paste()
- is_osx = sys.platform == 'darwin'
- # Keycodes on OSX:
- ctrl, cmd = 64, 1024
- key, key_str = keycode
-
- if key == Keyboard.keycodes['tab']:
- self.completions()
- return
-
- self.hide_completions()
-
- if key == Keyboard.keycodes['enter']:
- self.runCommand()
- return
- if key == Keyboard.keycodes['home']:
- self.setCursorPosition(0)
- return
- if key == Keyboard.keycodes['pageup']:
- return
- elif key in (Keyboard.keycodes['left'], Keyboard.keycodes['backspace']):
- if self.getCursorPosition() == 0:
- return
- elif key == Keyboard.keycodes['up']:
- self.setCommand(self.getPrevHistoryEntry())
- return
- elif key == Keyboard.keycodes['down']:
- self.setCommand(self.getNextHistoryEntry())
- return
- elif key == Keyboard.keycodes['l'] and modifiers == ['ctrl']:
- self.clear()
-
- super(Console, self)._keyboard_on_key_down(window, keycode, text, modifiers)
-
- def completions(self):
- cmd = self.getCommand()
- lastword = re.split(' |\(|\)',cmd)[-1]
- beginning = cmd[0:-len(lastword)]
-
- path = lastword.split('.')
- ns = self.namespace.keys()
-
- if len(path) == 1:
- ns = ns
- prefix = ''
- else:
- obj = self.namespace.get(path[0])
- prefix = path[0] + '.'
- ns = dir(obj)
-
-
- completions = []
- for x in ns:
- if x[0] == '_':continue
- xx = prefix + x
- if xx.startswith(lastword):
- completions.append(xx)
- completions.sort()
-
- if not completions:
- self.hide_completions()
- elif len(completions) == 1:
- self.hide_completions()
- self.setCommand(beginning + completions[0])
- else:
- # find common prefix
- p = os.path.commonprefix(completions)
- if len(p)>len(lastword):
- self.hide_completions()
- self.setCommand(beginning + p)
- else:
- self.show_completions(completions)
-
- # NEW
- def setPlainText(self, message):
- """Equivalent to QT version"""
- self.text = message
-
- # NEW
- def appendPlainText(self, message):
- """Equivalent to QT version"""
- if len(self.text) == 0:
- self.text = message
- else:
- if message:
- self.text += '\n' + message
-
- # NEW
- def move_cursor_to(self, pos):
- """Aggregate all cursor moving functions"""
- if isinstance(pos, int):
- self.cursor = self.get_cursor_from_index(pos)
- elif pos in ('end', 'pgend', 'pageend'):
- def updt_cursor(*l):
- self.cursor = self.get_cursor_from_index(self.text)
- Clock.schedule_once(updt_cursor)
- else: # cursor_home, cursor_end, ... (see docs)
- self.do_cursor_movement(pos)
diff --git a/gui/kivy/uix/dialogs/carousel_dialog.py b/gui/kivy/uix/dialogs/carousel_dialog.py
@@ -91,9 +91,10 @@ class RecentActivityDialog(CarouselDialog):
'''
'''
def on_activate(self):
+
# animate to first slide
- carousel = self.carousel_content.carousel
- carousel.load_slide(carousel.slides[0])
+ #carousel = self.carousel_content.carousel
+ #carousel.load_slide(carousel.slides[0])
item = self.item
try:
diff --git a/gui/kivy/uix/screens.py b/gui/kivy/uix/screens.py
@@ -7,6 +7,7 @@ from kivy.properties import (ObjectProperty, DictProperty, NumericProperty,
from kivy.lang import Builder
from kivy.factory import Factory
+from electrum.i18n import _
# Delayed imports
app = None
@@ -17,6 +18,9 @@ class CScreen(Factory.Screen):
__events__ = ('on_activate', 'on_deactivate', 'on_enter', 'on_leave')
action_view = ObjectProperty(None)
+ loaded = False
+ kvname = None
+ app = App.get_running_app()
def _change_action_view(self):
app = App.get_running_app()
@@ -31,26 +35,43 @@ class CScreen(Factory.Screen):
def on_enter(self):
# FIXME: use a proper event don't use animation time of screen
Clock.schedule_once(lambda dt: self.dispatch('on_activate'), .25)
+ pass
+
+ def update(self):
+ pass
def on_activate(self):
- Clock.schedule_once(lambda dt: self._change_action_view())
+
+ if self.kvname and not self.loaded:
+ print "loading:" + self.kvname
+ self.screen = Builder.load_file('gui/kivy/uix/ui_screens/' + self.kvname + '.kv')
+ self.add_widget(self.screen)
+ self.loaded = True
+ self.update()
+ setattr(self.app, self.kvname + '_screen', self)
+
+ #app.history_screen = screen
+ #app.recent_activity_card = screen.ids.recent_activity_card
+ #app.update_history_tab()
+
+ #Clock.schedule_once(lambda dt: self._change_action_view())
def on_leave(self):
self.dispatch('on_deactivate')
def on_deactivate(self):
- Clock.schedule_once(lambda dt: self._change_action_view())
+ pass
+ #Clock.schedule_once(lambda dt: self._change_action_view())
-class ScreenDashboard(CScreen):
- ''' Dashboard screen: Used to display the main dashboard.
- '''
+class HistoryScreen(CScreen):
tab = ObjectProperty(None)
+ kvname = 'history'
def __init__(self, **kwargs):
self.ra_dialog = None
- super(ScreenDashboard, self).__init__(**kwargs)
+ super(HistoryScreen, self).__init__(**kwargs)
def show_tx_details(self, item):
ra_dialog = Cache.get('electrum_widgets', 'RecentActivityDialog')
@@ -64,6 +85,83 @@ class ScreenDashboard(CScreen):
ra_dialog.item = item
ra_dialog.open()
+ def parse_histories(self, items):
+ for item in items:
+ tx_hash, conf, value, timestamp, balance = item
+ time_str = _("unknown")
+ if conf > 0:
+ try:
+ time_str = datetime.datetime.fromtimestamp(
+ timestamp).isoformat(' ')[:-3]
+ except Exception:
+ time_str = _("error")
+
+ if conf == -1:
+ time_str = _('unverified')
+ icon = "atlas://gui/kivy/theming/light/close"
+ elif conf == 0:
+ time_str = _('pending')
+ icon = "atlas://gui/kivy/theming/light/unconfirmed"
+ elif conf < 6:
+ time_str = '' # add new to fix error when conf < 0
+ conf = max(1, conf)
+ icon = "atlas://gui/kivy/theming/light/clock{}".format(conf)
+ else:
+ icon = "atlas://gui/kivy/theming/light/confirmed"
+
+ if value is not None:
+ v_str = self.app.format_amount(value, True).replace(',','.')
+ else:
+ v_str = '--'
+
+ balance_str = self.app.format_amount(balance).replace(',','.')
+
+ if tx_hash:
+ label, is_default_label = self.app.wallet.get_label(tx_hash)
+ else:
+ label = _('Pruned transaction outputs')
+ is_default_label = False
+
+ yield (conf, icon, time_str, label, v_str, balance_str, tx_hash)
+
+ def update(self, see_all=False):
+
+ history_card = self.screen.ids.recent_activity_card
+ histories = self.parse_histories(reversed(
+ self.app.wallet.get_history(self.app.current_account)))
+ # repopulate History Card
+ last_widget = history_card.ids.content.children[-1]
+ history_card.ids.content.clear_widgets()
+ history_add = history_card.ids.content.add_widget
+ history_add(last_widget)
+ RecentActivityItem = Factory.RecentActivityItem
+
+ from weakref import ref
+ from decimal import Decimal
+
+ get_history_rate = self.app.get_history_rate
+ count = 0
+ for items in histories:
+ count += 1
+ conf, icon, date_time, address, amount, balance, tx = items
+ ri = RecentActivityItem()
+ ri.icon = icon
+ ri.date = date_time
+ mintimestr = date_time.split()[0]
+ ri.address = address
+ ri.amount = amount
+ ri.quote_text = get_history_rate(ref(ri),
+ Decimal(amount),
+ mintimestr)
+ ri.balance = balance
+ ri.confirmations = conf
+ ri.tx_hash = tx
+ history_add(ri)
+ if count == 8 and not see_all:
+ break
+
+ history_card.ids.btn_see_all.opacity = (0 if count < 8 else 1)
+
class ScreenAddress(CScreen):
'''This is the dialog that shows a carousel of the currently available
@@ -95,22 +193,19 @@ class ScreenPassword(Factory.Screen):
pass
-class MainScreen(Factory.Screen):
- pass
-
-
-class ScreenSend(CScreen):
+class SendScreen(CScreen):
+ kvname = 'send'
def set_qr_data(self, uri):
self.ids.payto_e.text = uri.get('address', '')
self.ids.message_e.text = uri.get('message', '')
self.ids.amount_e.text = uri.get('amount', '')
-class ScreenReceive(CScreen):
- pass
+class ReceiveScreen(CScreen):
+ kvname = 'receive'
-
-class ScreenContacts(CScreen):
+class ContactsScreen(CScreen):
+ kvname = 'contacts'
def add_new_contact(self):
dlg = Cache.get('electrum_widgets', 'NewContactDialog')
@@ -119,6 +214,25 @@ class ScreenContacts(CScreen):
Cache.append('electrum_widgets', 'NewContactDialog', dlg)
dlg.open()
+ def update(self):
+ contact_list = self.screen.ids.contact_container
+ contact_list.clear_widgets()
+ child = -1
+ children = contact_list.children
+ for key in sorted(self.app.contacts.keys()):
+ _type, value = self.app.contacts[key]
+ child += 1
+ try:
+ if children[child].label == value:
+ continue
+ except IndexError:
+ pass
+ ci = Factory.ContactItem()
+ ci.address = key
+ ci.label = value
+ contact_list.add_widget(ci)
+
+
class CSpinner(Factory.Spinner):
'''CustomDropDown that allows fading out the dropdown
@@ -139,7 +253,7 @@ class CSpinner(Factory.Spinner):
class TabbedCarousel(Factory.TabbedPanel):
- '''Custom TabbedOanel using a carousel used in the Main Screen
+ '''Custom TabbedPanel using a carousel used in the Main Screen
'''
carousel = ObjectProperty(None)
diff --git a/gui/kivy/uix/ui_screens/contacts.kv b/gui/kivy/uix/ui_screens/contacts.kv
@@ -0,0 +1,93 @@
+<ContactImage@Widget>:
+ source: 'atlas://gui/kivy/theming/light/contact_avatar'
+ size_hint_x: None
+ width: self.height
+ canvas:
+ Color:
+ rgba: 1, 1, 1, 1
+ Ellipse:
+ source: root.source
+ size: self.width + dp(6), self.height + dp(6)
+ pos: self.x - dp(3), self.y - dp(3)
+ Ellipse:
+ source: 'atlas://gui/kivy/theming/light/contact_overlay'
+ size: self.width + dp(11), self.height + dp(11)
+ pos: self.x - dp(5.5), self.y - dp(5.5)
+
+<ContactLabel@Label>
+ color: .305, .309, .309, 1
+ text_size: self.size
+ halign: 'left'
+ valign: 'middle'
+
+<ContactSeperator@Widget>
+ canvas.before:
+ Color:
+ rgba: .890, .890, .890, 1
+ Rectangle:
+ size: self.size
+ pos: self.x, self.y + dp(9)
+ size_hint: None, None
+ size: '1dp', '22dp'
+ pos_hint_y: .5
+
+<ContactTextInput@TextInput>
+ background_normal: self.background_down
+ background_down: 'atlas://gui/kivy/theming/light/tab_btn'
+ size_hint_y: None
+ height: '22dp'
+
+<ContactBitLogo@Image>
+ source: 'atlas://gui/kivy/theming/light/bit_logo'
+ size_hint_x: None
+ width: '32dp'
+
+<ContactItem@BoxLayout>
+ address: ''
+ label: ''
+ tx_amt: 0
+ size_hint_y: None
+ height: '65dp'
+ padding: dp(12)
+ spacing: dp(5)
+ canvas.before:
+ #Color:
+ # rgba: 1, 1, 1, 1
+ Rectangle:
+ size: self.size
+ pos: self.pos
+ ContactImage:
+ id: contact_image
+ Widget:
+ size_hint_x: None
+ width: '9dp'
+ ContactLabel:
+ id: contact_address
+ text: root.address
+ ContactSeperator:
+ ContactLabel:
+ text: root.label
+ #ContactBitLogo:
+
+ContactsScreen:
+ name: 'contacts'
+ on_activate:
+ if not self.action_view:\
+ self.action_view = app.root.main_screen.ids.tabs.ids.screen_dashboard.action_view
+ BoxLayout:
+ orientation: 'vertical'
+ spacing: '1dp'
+ ContactTextInput:
+ ScrollView:
+ canvas.before:
+ #Color:
+ # rgba: .8901, .8901, .8901, 1
+ Rectangle:
+ size: self.size
+ pos: self.pos
+ GridLayout:
+ cols: 1
+ id: contact_container
+ size_hint_y: None
+ height: self.minimum_height
+ spacing: '1dp'
diff --git a/gui/kivy/uix/ui_screens/history.kv b/gui/kivy/uix/ui_screens/history.kv
@@ -0,0 +1,224 @@
+#:import _ electrum.i18n._
+#:import Factory kivy.factory.Factory
+#:set font_light 'data/fonts/Roboto-Condensed.ttf'
+#:set btc_symbol unichr(171)
+#:set mbtc_symbol unichr(187)
+
+
+<Card@GridLayout>
+ cols: 1
+ padding: '12dp' , '22dp', '12dp' , '12dp'
+ spacing: '12dp'
+ size_hint: 1, None
+ height: max(100, self.minimum_height)
+ canvas.before:
+ Color:
+ rgba: 1, 1, 1, 1
+ BorderImage:
+ border: 18, 18, 18, 18
+ source: 'atlas://gui/kivy/theming/light/card'
+ size: self.size
+ pos: self.pos
+
+<CardLabel@Label>
+ color: 0.45, 0.45, 0.45, 1
+ size_hint: 1, None
+ text: ''
+ text_size: self.width, None
+ height: self.texture_size[1]
+ halign: 'left'
+ valign: 'top'
+
+<CardButton@Button>
+ background_normal: 'atlas://gui/kivy/theming/light/card_btn'
+ bold: True
+ font_size: '10sp'
+ color: 0.699, 0.699, 0.699, 1
+ size_hint: None, None
+ size: self.texture_size[0] + dp(32), self.texture_size[1] + dp(7)
+
+
+<CardItem@ButtonBehavior+GridLayout>
+ canvas.before:
+ Color:
+ rgba: 0.192, .498, 0.745, 1 if self.state == 'down' else 0
+ Rectangle
+ size: self.size
+ pos: self.x, self.y + dp(5)
+ cols: 1
+ padding: '2dp', '2dp'
+ spacing: '2dp'
+ size_hint: 1, None
+ height: self.minimum_height
+
+<RecentActivityItem@CardItem>
+ icon: 'atlas://gui/kivy/theming/light/important'
+ address:'no address set'
+ amount: '+0.00'
+ balance: 'xyz'# balance_after
+ amount_color: '#DB3627' if float(self.amount) < 0 else '#2EA442'
+ confirmations: 0
+ date: '0/0/0'
+ quote_text: '.'
+
+ spacing: '9dp'
+ on_release:
+ app.history_screen.show_tx_details(root)
+ BoxLayout:
+ size_hint: 1, None
+ spacing: '8dp'
+ height: '32dp'
+ Image:
+ id: icon
+ source: root.icon
+ size_hint: None, 1
+ width: self.height *.54
+ mipmap: True
+ BoxLayout:
+ orientation: 'vertical'
+ Widget
+ CardLabel:
+ shorten: True
+ text: root.address
+ markup: False
+ text_size: self.size
+ CardLabel:
+ color: .699, .699, .699, 1
+ text: root.date
+ font_size: '12sp'
+ Widget
+ CardLabel:
+ halign: 'right'
+ font_size: '13sp'
+ size_hint: None, 1
+ width: '90sp'
+ markup: True
+ font_name: font_light
+ text:
+ u'[color={amount_color}]{sign}{symbol}{amount}[/color]\n'\
+ u'[color=#B2B3B3][size=12sp]{qt}[/size]'\
+ u'[/color]'.format(amount_color=root.amount_color,\
+ amount=root.amount[1:], qt=root.quote_text, sign=root.amount[0],\
+ symbol=btc_symbol if app.base_unit == 'BTC' else mbtc_symbol)
+ CardSeparator
+
+<CardRecentActivity@Card>
+ BoxLayout:
+ size_hint: 1, None
+ height: lbl.height
+ CardLabel:
+ id: lbl
+ text: _('RECENT ACTIVITY')
+ CardButton:
+ id: btn_see_all
+ disabled: True if not self.opacity else False
+ text: _('SEE ALL')
+ font_size: '12sp'
+ on_release: app.update_history_tab(see_all=True)
+ GridLayout:
+ id: content
+ spacing: '7dp'
+ cols: 1
+ size_hint: 1, None
+ height: self.minimum_height
+ CardSeparator
+
+<CardPaymentRequest@Card>
+ CardLabel:
+ text: _('PAYMENT REQUEST')
+ CardSeparator:
+
+<CardStatusInfo@Card>
+ padding: '12dp' , '12dp'
+ status: app.status
+ quote_text: ''
+ unconfirmed: ''
+ cols: 2
+ FloatLayout
+ anchor_x: 'left'
+ size_hint: 1, None
+ height: '82dp'
+ IconButton:
+ mipmap: True
+ pos_hint: {'x': 0, 'center_y': .45}
+ color: .90, .90, .90, 1
+ source: 'atlas://gui/kivy/theming/light/qrcode'
+ size_hint: None, .85
+ width: self.height
+ on_release:
+ dlg = Cache.get('electrum_widgets', 'WalletAddressesDialog')
+
+ if not dlg:\
+ Factory.register('WalletAddressesDialog', module='electrum_gui.kivy.uix.dialogs.carousel_dialog');\
+ dlg = Factory.WalletAddressesDialog();\
+ Cache.append('electrum_widgets', 'WalletAddressesDialog', dlg)
+
+ dlg.open()
+ CardLabel:
+ id: top_label
+ halign: 'right'
+ valign: 'top'
+ bold: True
+ pos_hint: {'top': 1, 'right': 1}
+ font_name: font_light
+ #balance_in_numbers: bool(ord(root.status[0]) not in range(ord('A'), ord('z')))
+ balance_in_numbers: True
+ font_size: '50sp' if self.balance_in_numbers else '30sp'
+ text_size: self.width, root.height/2
+ text:
+ u'[color=#4E4F4F]{}{}[/color]'\
+ .format('' if not self.balance_in_numbers else\
+ (btc_symbol if app.base_unit == 'BTC' else mbtc_symbol), root.status)
+ BoxLayout
+ pos_hint: {'y': 0, 'right': 1}
+ spacing: '5dp'
+ CardLabel
+ halign: 'right'
+ markup: True
+ font_size: '22dp'
+ font_name: font_light
+ text: u'[color=#c3c3c3]{}[/color]'.format(root.quote_text)
+ IconButton
+ color: .698, .698, .698, 1
+ source: 'atlas://gui/kivy/theming/light/gear'
+ size_hint_y: None
+ height: '28dp'
+ opacity: .5 if self.state == 'down' else 1
+ on_release:
+ dlg = Cache.get('electrum_widgets', 'CurrencySelectionDialog')
+
+ if not dlg:\
+ Factory.register('SelectionDialog', module='electrum_gui.kivy.uix.dialogs');\
+ dlg = Factory.CurrencySelectionDialog();\
+ Cache.append('electrum_widgets', 'CurrencySelectionDialog', dlg)
+
+ dlg.open()
+
+
+
+HistoryScreen:
+ name: 'history'
+ content: content
+ ScrollView:
+ id: content
+ do_scroll_x: False
+ GridLayout
+ id: grid
+ cols: 1 #if root.width < root.height else 2
+ size_hint: 1, None
+ height: self.minimum_height
+ padding: '12dp'
+ spacing: '12dp'
+ #GridLayout:
+ # cols: 1
+ # size_hint: 1, None
+ # height: self.minimum_height
+ # spacing: '12dp'
+ # orientation: 'vertical'
+ # CardStatusInfo:
+ # id: status_card
+ # CardPaymentRequest:
+ # id: payment_card
+ CardRecentActivity:
+ id: recent_activity_card
+
diff --git a/gui/kivy/uix/ui_screens/network.kv b/gui/kivy/uix/ui_screens/network.kv
@@ -0,0 +1,10 @@
+Popup:
+ id: network
+ title: _('Network')
+ BoxLayout:
+
+ Button:
+ size_hint_y: None
+ height: '48dp'
+ text: 'close'
+ on_release: network.dismiss()
diff --git a/gui/kivy/uix/ui_screens/receive.kv b/gui/kivy/uix/ui_screens/receive.kv
@@ -0,0 +1,171 @@
+#:import _ electrum.i18n._
+#:import Decimal decimal.Decimal
+#:set btc_symbol unichr(171)
+#:set mbtc_symbol unichr(187)
+#:set font_light 'data/fonts/Roboto-Condensed.ttf'
+
+
+
+ReceiveScreen:
+ name: 'receive'
+ mode: 'qr'
+ on_mode: if args[1] == 'nfc': from electrum_gui.kivy.nfc_scanner import NFCScanner
+ action_view: Factory.ReceiveActionView()
+
+ #on_activate:
+ # self.ids.toggle_qr.state = 'down'
+ # first_address = app.wallet.addresses()[0]
+ # qr.data = app.encode_uri(first_address,
+ # amount=amount_e.text,
+ # label=app.wallet.labels.get(first_address, first_address),
+ # message='') if app.wallet and app.wallet.addresses() else ''
+ #on_deactivate:
+ # self.ids.amount_e.focus = False
+
+ BoxLayout
+ padding: '12dp', '12dp', '12dp', '12dp'
+ spacing: '12dp'
+ mode: 'qr'
+ orientation: 'vertical'
+ SendReceiveToggle
+ SendToggle:
+ id: toggle_qr
+ text: 'QR'
+ state: 'down' if root.mode == 'qr' else 'normal'
+ source: 'atlas://gui/kivy/theming/light/qrcode'
+ background_down: 'atlas://gui/kivy/theming/light/btn_send_address'
+ on_release:
+ if root.mode == 'qr': root.mode = 'nr'
+ root.mode = 'qr'
+ SendToggle:
+ id: toggle_nfc
+ text: 'NFC'
+ state: 'down' if root.mode == 'nfc' else 'normal'
+ source: 'atlas://gui/kivy/theming/light/nfc'
+ background_down: 'atlas://gui/kivy/theming/light/btn_send_nfc'
+ on_release:
+ if root.mode == 'nfc': root.mode = 'nr'
+ root.mode = 'nfc'
+ GridLayout:
+ id: grid
+ cols: 1
+ #size_hint: 1, None
+ #height: self.minimum_height
+ SendReceiveCardTop
+ height: '110dp'
+ BoxLayout:
+ size_hint: 1, None
+ height: '42dp'
+ rows: 1
+ Label:
+ color: amount_e.foreground_color
+ bold: True
+ text_size: self.size
+ valign: 'bottom'
+ font_size: '22sp'
+ text:
+ u'[font={fnt}]{smbl}[/font]'.\
+ format(smbl=btc_symbol if app.base_unit == 'BTC' else mbtc_symbol, fnt=font_light)
+ size_hint_x: .25
+ ELTextInput:
+ id: amount_e
+ input_type: 'number'
+ multiline: False
+ bold: True
+ font_size: '50sp'
+ foreground_color: .308, .308, .308, 1
+ background_normal: 'atlas://gui/kivy/theming/light/tab_btn'
+ pos_hint: {'top': 1.5}
+ size_hint: .7, None
+ height: '67dp'
+ hint_text: 'Amount'
+ text: '0.0'
+ CardSeparator
+ BoxLayout:
+ size_hint: 1, None
+ height: '32dp'
+ spacing: '5dp'
+ Label:
+ color: lbl_quote.color
+ font_size: '12dp'
+ text: 'Ask to scan the QR below'
+ text_size: self.size
+ halign: 'left'
+ valign: 'middle'
+ Label:
+ id: lbl_quote
+ font_size: '12dp'
+ size_hint: .5, 1
+ color: .761, .761, .761, 1
+ text: u'= {}'.format(app.create_quote_text(Decimal(float(amount_e.text)), mode='symbol')) if amount_e.text else u'0'
+ text_size: self.size
+ halign: 'right'
+ valign: 'middle'
+ SendReceiveBlueBottom
+ id: blue_bottom
+ padding: '12dp', 0, '12dp', '12dp'
+ AddressSelector:
+ id: address_selection
+ foreground_color: blue_bottom.foreground_color
+ opacity: 1 if app.expert_mode else 0
+ size_hint: 1, None
+ height: blue_bottom.item_height if app.expert_mode else 0
+ on_text:
+ if not args[1].startswith('Select'):\
+ qr.data = app.encode_uri(args[1],\
+ amount=amount_e.text,\
+ label=app.wallet.labels.get(args[1], args[1]),\
+ message='')
+ CardSeparator
+ opacity: address_selection.opacity
+ color: blue_bottom.foreground_color
+ Widget:
+ size_hint_y: None
+ height: dp(10)
+ FloatLayout
+ id: bl
+ QRCodeWidget:
+ id: qr
+ size_hint: None, 1
+ width: min(self.height, bl.width)
+ pos_hint: {'center': (.5, .5)}
+ on_touch_down:
+ if self.collide_point(*args[1].pos):\
+ app.show_info_bubble(icon=self.ids.qrimage.texture, text='texture')
+ Button:
+ background_color: (1, 1, 1, 1) if self.disabled else ((.258, .80, .388, 1) if self.state == 'normal' else (.203, .490, .741, 1))
+ text: _('Goto next step') if app.wallet and app.wallet.seed else _('Create unsigned transaction')
+ size_hint_y: None
+ height: '38dp'
+ #disabled: True if wallet_selection.opacity == 0 else False
+ on_release:
+ message = 'sending {} {} to {}'.format(\
+ app.base_unit, amount_e.text, payto_e.text)
+ app.gui.main_gui.do_send(self, message=message)
+
+<ReceiveActionView@ActionView>
+ WalletActionPrevious:
+ id: action_previous
+ width: '32dp'
+ ActionButton:
+ id: action_logo
+ important: True
+ size_hint: 1, 1
+ markup: True
+ mipmap: True
+ bold: True
+ markup: True
+ color: 1, 1, 1, 1
+ text:
+ "[color=#777777][sub] [sup][size=9dp]{}[/size][/sup][/sub]{}[/color]"\
+ .format(app.base_unit, app.status)
+ font_size: '22dp'
+ minimum_width: '1dp'
+ Butt_star:
+ id: but_star
+ on_release:
+ if self.state == 'down':\
+ app.show_info_bubble(\
+ text='[b]Expert mode on[/b]\n you can now select your address',\
+ icon='atlas://gui/kivy/theming/light/star_big_inactive',\
+ duration=1, arrow_pos='', width='250dp')
diff --git a/gui/kivy/uix/ui_screens/send.kv b/gui/kivy/uix/ui_screens/send.kv
@@ -0,0 +1,243 @@
+#:import _ electrum.i18n._
+#:import Decimal decimal.Decimal
+
+#:import Factory kivy.factory.Factory
+#:set btc_symbol unichr(171)
+#:set mbtc_symbol unichr(187)
+#:set font_light 'data/fonts/Roboto-Condensed.ttf'
+
+<SendActionView@ActionView>
+ foreground_color: (.466, .466, .466, 1)
+ color_active: (0.235, .588, .89, 1)
+ WalletActionPrevious:
+ id: action_previous
+ width: but_star.width
+ ActionButton:
+ id: action_logo
+ important: True
+ size_hint: 1, 1
+ markup: True
+ mipmap: True
+ bold: True
+ markup: True
+ color: 1, 1, 1, 1
+ text:
+ "[color=#777777][sub] [sup][size=9dp]{}[/size][/sup][/sub]{}[/color]"\
+ .format(app.base_unit, app.status)
+ font_size: '22dp'
+ minimum_width: '1dp'
+ Butt_star:
+ id: but_star
+ on_release:
+ if self.state == 'down':\
+ app.show_info_bubble(\
+ text='[b]Expert mode on[/b]\n you can now select your address',\
+ icon='atlas://gui/kivy/theming/light/star_big_inactive',\
+ duration=1, arrow_pos='', width='250dp')
+
+
+
+
+<TextInputSendBlue@TextInput>
+ padding: '5dp'
+ size_hint: 1, None
+ height: '27dp'
+ pos_hint: {'center_y':.5}
+ multiline: False
+ hint_text_color: self.foreground_color
+ foreground_color: .843, .914, .972, 1
+ background_color: 1, 1, 1, 1
+ background_normal: 'atlas://gui/kivy/theming/light/tab_btn'
+ background_active: 'atlas://gui/kivy/theming/light/textinput_active'
+
+
+SendScreen:
+
+ mode: 'address'
+ name: 'send'
+ action_view: Factory.SendActionView()
+ #on_deactivate:
+ # self.ids.amount_e.focus = False
+ # self.ids.payto_e.focus = False
+ # self.ids.message_e.focus = False
+ BoxLayout
+ padding: '12dp', '12dp', '12dp', '12dp'
+ spacing: '12dp'
+ orientation: 'vertical'
+ mode: 'address'
+ SendReceiveToggle:
+ SendToggle:
+ id: toggle_address
+ text: 'ADDRESS'
+ group: 'send_type'
+ state: 'down' if root.mode == 'address' else 'normal'
+ source: 'atlas://gui/kivy/theming/light/globe'
+ background_down: 'atlas://gui/kivy/theming/light/btn_send_address'
+ on_release:
+ if root.mode == 'address': root.mode = 'fc'
+ root.mode = 'address'
+ SendToggle:
+ id: toggle_nfc
+ text: 'NFC'
+ group: 'send_type'
+ state: 'down' if root.mode == 'nfc' else 'normal'
+ source: 'atlas://gui/kivy/theming/light/nfc'
+ background_down: 'atlas://gui/kivy/theming/light/btn_send_nfc'
+ on_release:
+ if root.mode == 'nfc': root.mode = 'str'
+ root.mode = 'nfc'
+ GridLayout:
+ id: grid
+ cols: 1
+ size_hint: 1, None
+ height: self.minimum_height
+ SendReceiveCardTop
+ id: card_address
+ BoxLayout
+ size_hint: 1, None
+ height: '42dp'
+ rows: 1
+ Label
+ id: lbl_symbl
+ bold: True
+ color: amount_e.foreground_color
+ text_size: self.size
+ valign: 'bottom'
+ halign: 'left'
+ font_size: '22sp'
+ text:
+ u'[font={fnt}]{smbl}[/font]'.\
+ format(smbl=btc_symbol if app.base_unit == 'BTC' else mbtc_symbol, fnt=font_light)
+ size_hint_x: .25
+ ELTextInput:
+ id: amount_e
+ input_type: 'number'
+ multiline: False
+ bold: True
+ font_size: '50sp'
+ foreground_color: .308, .308, .308, 1
+ background_normal: 'atlas://gui/kivy/theming/light/tab_btn'
+ pos_hint: {'top': 1.5}
+ size_hint: .7, None
+ height: '67dp'
+ hint_text: 'Amount'
+ text: '0.0'
+ on_text_validate: payto_e.focus = True
+ CardSeparator
+ BoxLayout:
+ size_hint: 1, None
+ height: '42dp'
+ spacing: '5dp'
+ Label:
+ id: fee_e
+ color: .761, .761, .761, 1
+ font_size: '12dp'
+ amt: app.format_amount(app.wallet.fee_per_kb(app.gui_object.config)) if app.wallet else 0
+ text:
+ u'[b]{sign}{symbl}{amt}[/b] of fee'.\
+ format(symbl=lbl_symbl.text,\
+ sign='+' if self.amt > 0 else '-', amt=self.amt)
+ size_hint_x: None
+ width: self.texture_size[0]
+ halign: 'left'
+ valign: 'middle'
+ IconButton:
+ color: 0.694, 0.694, 0.694, 1
+ source: 'atlas://gui/kivy/theming/light/gear'
+ pos_hint: {'center_y': .5}
+ size_hint: None, None
+ size: '22dp', '22dp'
+ on_release:
+ dlg = Cache.get('electrum_widgets', 'TransactionFeeDialog')
+
+ if not dlg:\
+ Factory.register('SelectionDialog', module='electrum_gui.kivy.uix.dialogs');\
+ dlg = Factory.TransactionFeeDialog();\
+ Cache.append('electrum_widgets', 'TransactionDialog', dlg)
+
+ dlg.return_obj = fee_e
+ dlg.open()
+ Label:
+ font_size: '12dp'
+ color: fee_e.color
+ text: u'= {}'.format(app.create_quote_text(Decimal(float(amount_e.text)), mode='symbol')) if amount_e.text else u'0'
+ text_size: self.size
+ halign: 'right'
+ valign: 'middle'
+ SendReceiveBlueBottom:
+ id: blue_bottom
+ size_hint: 1, None
+ height: self.minimum_height
+ BoxLayout
+ size_hint: 1, None
+ height: blue_bottom.item_height
+ spacing: '5dp'
+ Image:
+ source: 'atlas://gui/kivy/theming/light/contact'
+ size_hint: None, None
+ size: '22dp', '22dp'
+ pos_hint: {'center_y': .5}
+ TextInputSendBlue:
+ id: payto_e
+ hint_text: "Enter Contact or adress"
+ on_text_validate:
+ Factory.Animation(opacity=1,\
+ height=blue_bottom.item_height)\
+ .start(message_selection)
+ message_e.focus = True
+ Widget:
+ size_hint: None, None
+ width: dp(2)
+ height: qr.height
+ pos_hint: {'center_y':.5}
+ canvas.after:
+ Rectangle:
+ size: self.size
+ pos: self.pos
+ IconButton:
+ id: qr
+ source: 'atlas://gui/kivy/theming/light/qrcode'
+ pos_hint: {'center_y': .5}
+ size_hint: None, None
+ size: '22dp', '22dp'
+ on_release: app.scan_qr(on_complete=root.set_qr_data)
+ CardSeparator
+ opacity: message_selection.opacity
+ color: blue_bottom.foreground_color
+ BoxLayout:
+ id: message_selection
+ opacity: 1 if app.expert_mode else 0
+ size_hint: 1, None
+ height: blue_bottom.item_height if app.expert_mode else 0
+ spacing: '5dp'
+ Image:
+ source: 'atlas://gui/kivy/theming/light/pen'
+ size_hint: None, None
+ size: '22dp', '22dp'
+ pos_hint: {'center_y': .5}
+ TextInputSendBlue:
+ id: message_e
+ hint_text: 'Enter description here'
+ on_text_validate:
+ anim = Factory.Animation(opacity=1, height=blue_bottom.item_height)
+ anim.start(wallet_selection)
+ #anim.start(address_selection)
+ CardSeparator
+ opacity: address_selection.opacity
+ color: blue_bottom.foreground_color
+ AddressSelector:
+ id: address_selection
+ foreground_color: blue_bottom.foreground_color
+ opacity: 1 if app.expert_mode else 0
+ size_hint: 1, None
+ height: blue_bottom.item_height if app.expert_mode else 0
+ Button:
+ #background_color: (1, 1, 1, 1) if self.disabled else ((.258, .80, .388, 1) if self.state == 'normal' else (.203, .490, .741, 1))
+ text: _('Send')
+ size_hint_y: None
+ height: '38dp'
+ disabled: False
+ on_release: app.do_send()
+ Widget
+
+
diff --git a/gui/kivy/uix/ui_screens/settings.kv b/gui/kivy/uix/ui_screens/settings.kv
@@ -0,0 +1,27 @@
+Popup:
+ id: settings
+ title: _('Settings')
+ BoxLayout:
+
+ Button:
+ size_hint_y: None
+ height: '48dp'
+ text: 'Button normal'
+
+ Button:
+ size_hint_y: None
+ height: '48dp'
+ text: 'Button down'
+ state: 'down'
+
+ Button:
+ size_hint_y: None
+ height: '48dp'
+ text: 'Button disabled'
+ disabled: True
+
+ Button:
+ size_hint_y: None
+ height: '48dp'
+ text: 'close'
+ on_release: settings.dismiss()
diff --git a/gui/kivy/uix/ui_screens/wallet.kv b/gui/kivy/uix/ui_screens/wallet.kv
@@ -0,0 +1,14 @@
+
+
+<WalletSelector@BlueSpinner>
+ icon: 'atlas://gui/kivy/theming/light/wallet'
+ values: ('default Wallet',)
+ text: _('Select your wallet')
+
+
+ElectrumScreen:
+
+ WalletSelector:
+ id: wallet_selection
+ size_hint: 1, None
+ height: blue_bottom.item_height if app.expert_mode else 0