URI: 
       tMerge branch 'kivy_new' - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit a87f3fe887fce7c7ff00166504a599868591b48c
   DIR parent 646044b43122e6523253fabc2702b41101bfc5d7
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Tue,  6 Mar 2018 19:38:21 +0100
       
       Merge branch 'kivy_new'
       
       Diffstat:
         M gui/kivy/main.kv                    |      20 +++-----------------
         M gui/kivy/main_window.py             |      29 ++++++++++++++++++++++++++++-
         A gui/kivy/theming/light/share.png    |       0 
         M gui/kivy/uix/context_menu.py        |       1 -
         A gui/kivy/uix/dialogs/addresses.py   |     212 ++++++++++++++++++++++++++++++
         A gui/kivy/uix/dialogs/invoices.py    |     169 +++++++++++++++++++++++++++++++
         A gui/kivy/uix/dialogs/requests.py    |     157 +++++++++++++++++++++++++++++++
         M gui/kivy/uix/screens.py             |     204 +------------------------------
         D gui/kivy/uix/ui_screens/address.kv  |      90 -------------------------------
         D gui/kivy/uix/ui_screens/invoices.kv |      66 -------------------------------
         M gui/kivy/uix/ui_screens/receive.kv  |      23 +++++++++++++++++++----
         D gui/kivy/uix/ui_screens/requests.kv |      66 -------------------------------
         M gui/kivy/uix/ui_screens/send.kv     |      23 ++++++++++++++---------
       
       13 files changed, 605 insertions(+), 455 deletions(-)
       ---
   DIR diff --git a/gui/kivy/main.kv b/gui/kivy/main.kv
       t@@ -372,9 +372,6 @@
                tab_height: '48dp'
                tab_width: panel.width/3
                strip_border: 0, 0, 0, 0
       -        InvoicesScreen:
       -            id: invoices_screen
       -            tab: invoices_tab
                SendScreen:
                    id: send_screen
                    tab: send_tab
       t@@ -384,29 +381,18 @@
                ReceiveScreen:
                    id: receive_screen
                    tab: receive_tab
       -        AddressScreen:
       -            id: address_screen
       -            tab: address_tab
       -        CleanHeader:
       -            id: invoices_tab
       -            text: _('Invoices')
       -            slide: 0
                CleanHeader:
                    id: send_tab
                    text: _('Send')
       -            slide: 1
       +            slide: 0
                CleanHeader:
                    id: history_tab
                    text: _('Balance')
       -            slide: 2
       +            slide: 1
                CleanHeader:
                    id: receive_tab
                    text: _('Receive')
       -            slide: 3
       -        CleanHeader:
       -            id: address_tab
       -            text: _('Addresses')
       -            slide: 4
       +            slide: 2
        
        
        <ActionOvrButton@ActionButton>
   DIR diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
       t@@ -824,7 +824,6 @@ class ElectrumWindow(App):
                d = LabelDialog(_('Enter description'), text, callback)
                d.open()
        
       -    @profiler
            def amount_dialog(self, screen, show_max):
                from .uix.dialogs.amount_dialog import AmountDialog
                amount = screen.amount
       t@@ -836,6 +835,34 @@ class ElectrumWindow(App):
                popup = AmountDialog(show_max, amount, cb)
                popup.open()
        
       +    def invoices_dialog(self, screen):
       +        from .uix.dialogs.invoices import InvoicesDialog
       +        if len(self.wallet.invoices.sorted_list()) == 0:
       +            self.show_info(' '.join([
       +                _('No saved invoices.'),
       +                _('Signed invoices are saved automatically when you scan them.'),
       +                _('You may also save unsigned requests or contact addresses using the save button.')
       +            ]))
       +            return
       +        popup = InvoicesDialog(self, screen, None)
       +        popup.update()
       +        popup.open()
       +
       +    def requests_dialog(self, screen):
       +        from .uix.dialogs.requests import RequestsDialog
       +        if len(self.wallet.get_sorted_requests(self.electrum_config)) == 0:
       +            self.show_info(_('No saved requests.'))
       +            return
       +        popup = RequestsDialog(self, screen, None)
       +        popup.update()
       +        popup.open()
       +
       +    def addresses_dialog(self, screen):
       +        from .uix.dialogs.addresses import AddressesDialog
       +        popup = AddressesDialog(self, screen, None)
       +        popup.update()
       +        popup.open()
       +
            def fee_dialog(self, label, dt):
                from .uix.dialogs.fee_dialog import FeeDialog
                def cb():
   DIR diff --git a/gui/kivy/theming/light/share.png b/gui/kivy/theming/light/share.png
       Binary files differ.
   DIR diff --git a/gui/kivy/uix/context_menu.py b/gui/kivy/uix/context_menu.py
       t@@ -47,7 +47,6 @@ class ContextMenu(Bubble):
                    l = MenuItem()
                    l.text = _(k)
                    def func(f=v):
       -                Clock.schedule_once(lambda dt: self.hide(), 0.1)
                        Clock.schedule_once(lambda dt: f(obj), 0.15)
                    l.on_release = func
                    self.ids.buttons.add_widget(l)
   DIR diff --git a/gui/kivy/uix/dialogs/addresses.py b/gui/kivy/uix/dialogs/addresses.py
       t@@ -0,0 +1,212 @@
       +from kivy.app import App
       +from kivy.factory import Factory
       +from kivy.properties import ObjectProperty
       +from kivy.lang import Builder
       +from decimal import Decimal
       +
       +Builder.load_string('''
       +<AddressLabel@Label>
       +    text_size: self.width, None
       +    halign: 'left'
       +    valign: 'top'
       +
       +<AddressItem@CardItem>
       +    address: ''
       +    memo: ''
       +    amount: ''
       +    status: ''
       +    BoxLayout:
       +        spacing: '8dp'
       +        height: '32dp'
       +        orientation: 'vertical'
       +        Widget
       +        AddressLabel:
       +            text: root.address
       +            shorten: True
       +        Widget
       +        AddressLabel:
       +            text: (root.amount if root.status == 'Funded' else root.status) + '     ' + root.memo
       +            color: .699, .699, .699, 1
       +            font_size: '13sp'
       +            shorten: True
       +        Widget
       +
       +<AddressesDialog@Popup>
       +    id: popup
       +    title: _('Addresses')
       +    message: ''
       +    pr_status: 'Pending'
       +    show_change: 0
       +    show_used: 0
       +    on_message:
       +        self.parent.update()
       +    BoxLayout:
       +        id:box
       +        padding: '12dp', '70dp', '12dp', '12dp'
       +        spacing: '12dp'
       +        orientation: 'vertical'
       +        size_hint: 1, 1.1
       +        BoxLayout:
       +            spacing: '6dp'
       +            size_hint: 1, None
       +            orientation: 'horizontal'
       +            AddressFilter:
       +                opacity: 1
       +                size_hint: 1, None
       +                height: self.minimum_height
       +                spacing: '5dp'
       +                AddressButton:
       +                    id: search
       +                    text: {0:_('Receiving'), 1:_('Change'), 2:_('All')}[root.show_change]
       +                    on_release:
       +                        root.show_change = (root.show_change + 1) % 3
       +                        Clock.schedule_once(lambda dt: root.update())
       +            AddressFilter:
       +                opacity: 1
       +                size_hint: 1, None
       +                height: self.minimum_height
       +                spacing: '5dp'
       +                AddressButton:
       +                    id: search
       +                    text: {0:_('All'), 1:_('Unused'), 2:_('Funded'), 3:_('Used')}[root.show_used]
       +                    on_release:
       +                        root.show_used = (root.show_used + 1) % 4
       +                        Clock.schedule_once(lambda dt: root.update())
       +            AddressFilter:
       +                opacity: 1
       +                size_hint: 1, None
       +                height: self.minimum_height
       +                spacing: '5dp'
       +                canvas.before:
       +                    Color:
       +                        rgba: 0.9, 0.9, 0.9, 1
       +                AddressButton:
       +                    id: change
       +                    text: root.message if root.message else _('Search')
       +                    on_release: Clock.schedule_once(lambda dt: app.description_dialog(addr_screen))
       +        ScrollView:
       +            GridLayout:
       +                cols: 1
       +                id: search_container
       +                size_hint_y: None
       +                height: self.minimum_height
       +''')
       +
       +
       +from electrum_gui.kivy.i18n import _
       +from electrum_gui.kivy.uix.context_menu import ContextMenu
       +
       +
       +class AddressesDialog(Factory.Popup):
       +
       +    def __init__(self, app, screen, callback):
       +        Factory.Popup.__init__(self)
       +        self.app = app
       +        self.screen = screen
       +        self.callback = callback
       +        self.cards = {}
       +        self.context_menu = None
       +
       +    def get_card(self, addr, balance, is_used, label):
       +        ci = self.cards.get(addr)
       +        if ci is None:
       +            ci = Factory.AddressItem()
       +            ci.screen = self
       +            ci.address = addr
       +            self.cards[addr] = ci
       +
       +        ci.memo = label
       +        ci.amount = self.app.format_amount_and_units(balance)
       +        request = self.app.wallet.get_payment_request(addr, self.app.electrum_config)
       +        if is_used:
       +            ci.status = _('Used')
       +        else:
       +            ci.status = _('Funded') if balance > 0 else _('Unused')
       +        return ci
       +
       +
       +    def update(self):
       +        self.menu_actions = [(_('Use'), self.do_show), (_('Details'), self.do_view)]
       +        wallet = self.app.wallet
       +        if self.show_change == 0:
       +            _list = wallet.get_receiving_addresses()
       +        elif self.show_change == 1:
       +            _list = wallet.get_change_addresses()
       +        else:
       +            _list = wallet.get_addresses()
       +        search = self.screen.message
       +        container = self.ids.search_container
       +        container.clear_widgets()
       +        n = 0
       +        for address in _list:
       +            label = wallet.labels.get(address, '')
       +            balance = sum(wallet.get_addr_balance(address))
       +            is_used = wallet.is_used(address)
       +            if self.show_used == 1 and (balance or is_used):
       +                continue
       +            if self.show_used == 2 and balance == 0:
       +                continue
       +            if self.show_used == 3 and not is_used:
       +                continue
       +            card = self.get_card(address, balance, is_used, label)
       +            if search and not self.ext_search(card, search):
       +                continue
       +            container.add_widget(card)
       +            n += 1
       +        if not n:
       +            msg = _('No address matching your search')
       +            container.add_widget(EmptyLabel(text=msg))
       +
       +    def do_show(self, obj):
       +        self.hide_menu()
       +        self.dismiss()
       +        self.app.show_request(obj.address)
       +
       +    def do_view(self, obj):
       +        req = self.app.wallet.get_payment_request(obj.address, self.app.electrum_config)
       +        if req:
       +            c, u, x = self.app.wallet.get_addr_balance(obj.address)
       +            balance = c + u + x
       +            if balance > 0:
       +                req['fund'] = balance
       +            status = req.get('status')
       +            amount = req.get('amount')
       +            address = req['address']
       +            if amount:
       +                status = req.get('status')
       +                status = request_text[status]
       +            else:
       +                received_amount = self.app.wallet.get_addr_received(address)
       +                status = self.app.format_amount_and_units(received_amount)
       +            self.app.show_pr_details(req, status, False)
       +
       +        else:
       +            req = { 'address': obj.address, 'status' : obj.status }
       +            status = obj.status
       +            c, u, x = self.app.wallet.get_addr_balance(obj.address)
       +            balance = c + u + x
       +            if balance > 0:
       +                req['fund'] = balance
       +            self.app.show_addr_details(req, status)
       +
       +    def do_delete(self, obj):
       +        from .dialogs.question import Question
       +        def cb(result):
       +            if result:
       +                self.app.wallet.remove_payment_request(obj.address, self.app.electrum_config)
       +                self.update()
       +        d = Question(_('Delete request?'), cb)
       +        d.open()
       +
       +    def ext_search(self, card, search):
       +        return card.memo.find(search) >= 0 or card.amount.find(search) >= 0
       +        
       +    def show_menu(self, obj):
       +        self.hide_menu()
       +        self.context_menu = ContextMenu(obj, self.menu_actions)
       +        self.ids.box.add_widget(self.context_menu)
       +
       +    def hide_menu(self):
       +        if self.context_menu is not None:
       +            self.ids.box.remove_widget(self.context_menu)
       +            self.context_menu = None
   DIR diff --git a/gui/kivy/uix/dialogs/invoices.py b/gui/kivy/uix/dialogs/invoices.py
       t@@ -0,0 +1,169 @@
       +from kivy.app import App
       +from kivy.factory import Factory
       +from kivy.properties import ObjectProperty
       +from kivy.lang import Builder
       +from decimal import Decimal
       +
       +Builder.load_string('''
       +<InvoicesLabel@Label>
       +    #color: .305, .309, .309, 1
       +    text_size: self.width, None
       +    halign: 'left'
       +    valign: 'top'
       +
       +<InvoiceItem@CardItem>
       +    requestor: ''
       +    memo: ''
       +    amount: ''
       +    status: ''
       +    date: ''
       +    icon: 'atlas://gui/kivy/theming/light/important'
       +    Image:
       +        id: icon
       +        source: root.icon
       +        size_hint: None, 1
       +        width: self.height *.54
       +        mipmap: True
       +    BoxLayout:
       +        spacing: '8dp'
       +        height: '32dp'
       +        orientation: 'vertical'
       +        Widget
       +        InvoicesLabel:
       +            text: root.requestor
       +            shorten: True
       +        Widget
       +        InvoicesLabel:
       +            text: root.memo
       +            color: .699, .699, .699, 1
       +            font_size: '13sp'
       +            shorten: True
       +        Widget
       +    BoxLayout:
       +        spacing: '8dp'
       +        height: '32dp'
       +        orientation: 'vertical'
       +        Widget
       +        InvoicesLabel:
       +            text: root.amount
       +            font_size: '15sp'
       +            halign: 'right'
       +            width: '110sp'
       +        Widget
       +        InvoicesLabel:
       +            text: root.status
       +            font_size: '13sp'
       +            halign: 'right'
       +            color: .699, .699, .699, 1
       +        Widget
       +
       +
       +<InvoicesDialog@Popup>
       +    id: popup
       +    title: _('Invoices')
       +    BoxLayout:
       +        id: box
       +        orientation: 'vertical'
       +        spacing: '1dp'
       +        ScrollView:
       +            GridLayout:
       +                cols: 1
       +                id: invoices_container
       +                size_hint: 1, None
       +                height: self.minimum_height
       +                spacing: '2dp'
       +                padding: '12dp'
       +''')
       +
       +from kivy.properties import BooleanProperty
       +from electrum_gui.kivy.i18n import _
       +from electrum.util import format_time
       +from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
       +from electrum_gui.kivy.uix.context_menu import ContextMenu
       +
       +invoice_text = {
       +    PR_UNPAID:_('Pending'),
       +    PR_UNKNOWN:_('Unknown'),
       +    PR_PAID:_('Paid'),
       +    PR_EXPIRED:_('Expired')
       +}
       +pr_icon = {
       +    PR_UNPAID: 'atlas://gui/kivy/theming/light/important',
       +    PR_UNKNOWN: 'atlas://gui/kivy/theming/light/important',
       +    PR_PAID: 'atlas://gui/kivy/theming/light/confirmed',
       +    PR_EXPIRED: 'atlas://gui/kivy/theming/light/close'
       +}
       +
       +
       +class InvoicesDialog(Factory.Popup):
       +
       +    def __init__(self, app, screen, callback):
       +        Factory.Popup.__init__(self)
       +        self.app = app
       +        self.screen = screen
       +        self.callback = callback
       +        self.cards = {}
       +        self.context_menu = None
       +
       +    def get_card(self, pr):
       +        key = pr.get_id()
       +        ci = self.cards.get(key)
       +        if ci is None:
       +            ci = Factory.InvoiceItem()
       +            ci.key = key
       +            ci.screen = self
       +            self.cards[key] = ci
       +        ci.requestor = pr.get_requestor()
       +        ci.memo = pr.get_memo()
       +        amount = pr.get_amount()
       +        if amount:
       +            ci.amount = self.app.format_amount_and_units(amount)
       +            status = self.app.wallet.invoices.get_status(ci.key)
       +            ci.status = invoice_text[status]
       +            ci.icon = pr_icon[status]
       +        else:
       +            ci.amount = _('No Amount')
       +            ci.status = ''
       +        exp = pr.get_expiration_date()
       +        ci.date = format_time(exp) if exp else _('Never')
       +        return ci
       +
       +    def update(self):
       +        self.menu_actions = [('Pay', self.do_pay), ('Details', self.do_view), ('Delete', self.do_delete)]
       +        invoices_list = self.ids.invoices_container
       +        invoices_list.clear_widgets()
       +        _list = self.app.wallet.invoices.sorted_list()
       +        for pr in _list:
       +            ci = self.get_card(pr)
       +            invoices_list.add_widget(ci)
       +
       +    def do_pay(self, obj):
       +        self.hide_menu()
       +        self.dismiss()
       +        pr = self.app.wallet.invoices.get(obj.key)
       +        self.app.on_pr(pr)
       +
       +    def do_view(self, obj):
       +        pr = self.app.wallet.invoices.get(obj.key)
       +        pr.verify(self.app.wallet.contacts)
       +        self.app.show_pr_details(pr.get_dict(), obj.status, True)
       +
       +    def do_delete(self, obj):
       +        from .question import Question
       +        def cb(result):
       +            if result:
       +                self.app.wallet.invoices.remove(obj.key)
       +            self.hide_menu()
       +            self.update()
       +        d = Question(_('Delete invoice?'), cb)
       +        d.open()
       +
       +    def show_menu(self, obj):
       +        self.hide_menu()
       +        self.context_menu = ContextMenu(obj, self.menu_actions)
       +        self.ids.box.add_widget(self.context_menu)
       +
       +    def hide_menu(self):
       +        if self.context_menu is not None:
       +            self.ids.box.remove_widget(self.context_menu)
       +            self.context_menu = None
   DIR diff --git a/gui/kivy/uix/dialogs/requests.py b/gui/kivy/uix/dialogs/requests.py
       t@@ -0,0 +1,157 @@
       +from kivy.app import App
       +from kivy.factory import Factory
       +from kivy.properties import ObjectProperty
       +from kivy.lang import Builder
       +from decimal import Decimal
       +
       +Builder.load_string('''
       +<RequestLabel@Label>
       +    #color: .305, .309, .309, 1
       +    text_size: self.width, None
       +    halign: 'left'
       +    valign: 'top'
       +
       +<RequestItem@CardItem>
       +    address: ''
       +    memo: ''
       +    amount: ''
       +    status: ''
       +    date: ''
       +    icon: 'atlas://gui/kivy/theming/light/important'
       +    Image:
       +        id: icon
       +        source: root.icon
       +        size_hint: None, 1
       +        width: self.height *.54
       +        mipmap: True
       +    BoxLayout:
       +        spacing: '8dp'
       +        height: '32dp'
       +        orientation: 'vertical'
       +        Widget
       +        RequestLabel:
       +            text: root.address
       +            shorten: True
       +        Widget
       +        RequestLabel:
       +            text: root.memo
       +            color: .699, .699, .699, 1
       +            font_size: '13sp'
       +            shorten: True
       +        Widget
       +    BoxLayout:
       +        spacing: '8dp'
       +        height: '32dp'
       +        orientation: 'vertical'
       +        Widget
       +        RequestLabel:
       +            text: root.amount
       +            halign: 'right'
       +            font_size: '15sp'
       +        Widget
       +        RequestLabel:
       +            text: root.status
       +            halign: 'right'
       +            font_size: '13sp'
       +            color: .699, .699, .699, 1
       +        Widget
       +
       +<RequestsDialog@Popup>
       +    id: popup
       +    title: _('Requests')
       +    BoxLayout:
       +        id:box
       +        orientation: 'vertical'
       +        spacing: '1dp'
       +        ScrollView:
       +            GridLayout:
       +                cols: 1
       +                id: requests_container
       +                size_hint: 1, None
       +                height: self.minimum_height
       +                spacing: '2dp'
       +                padding: '12dp'
       +''')
       +
       +from kivy.properties import BooleanProperty
       +from electrum_gui.kivy.i18n import _
       +from electrum.util import format_time
       +from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
       +from electrum_gui.kivy.uix.context_menu import ContextMenu
       +
       +pr_icon = {
       +    PR_UNPAID: 'atlas://gui/kivy/theming/light/important',
       +    PR_UNKNOWN: 'atlas://gui/kivy/theming/light/important',
       +    PR_PAID: 'atlas://gui/kivy/theming/light/confirmed',
       +    PR_EXPIRED: 'atlas://gui/kivy/theming/light/close'
       +}
       +request_text = {
       +    PR_UNPAID: _('Pending'),
       +    PR_UNKNOWN: _('Unknown'),
       +    PR_PAID: _('Received'),
       +    PR_EXPIRED: _('Expired')
       +}
       +
       +
       +class RequestsDialog(Factory.Popup):
       +
       +    def __init__(self, app, screen, callback):
       +        Factory.Popup.__init__(self)
       +        self.app = app
       +        self.screen = screen
       +        self.callback = callback
       +        self.cards = {}
       +        self.context_menu = None
       +
       +    def get_card(self, req):
       +        address = req['address']
       +        ci = self.cards.get(address)
       +        if ci is None:
       +            ci = Factory.RequestItem()
       +            ci.address = address
       +            ci.screen = self
       +            self.cards[address] = ci
       +
       +        amount = req.get('amount')
       +        ci.amount = self.app.format_amount_and_units(amount) if amount else ''
       +        ci.memo = req.get('memo', '')
       +        status, conf = self.app.wallet.get_request_status(address)
       +        ci.status = request_text[status]
       +        ci.icon = pr_icon[status]
       +        #exp = pr.get_expiration_date()
       +        #ci.date = format_time(exp) if exp else _('Never')
       +        return ci
       +
       +    def update(self):
       +        self.menu_actions = [(_('Show'), self.do_show), (_('Delete'), self.do_delete)]
       +        requests_list = self.ids.requests_container
       +        requests_list.clear_widgets()
       +        _list = self.app.wallet.get_sorted_requests(self.app.electrum_config)
       +        for pr in _list:
       +            ci = self.get_card(pr)
       +            requests_list.add_widget(ci)
       +
       +    def do_show(self, obj):
       +        self.hide_menu()
       +        self.dismiss()
       +        self.app.show_request(obj.address)
       +
       +    def do_delete(self, req):
       +        from .question import Question
       +        def cb(result):
       +            if result:
       +                self.app.wallet.remove_payment_request(req.address, self.app.electrum_config)
       +                self.hide_menu()
       +                self.update()
       +        d = Question(_('Delete request'), cb)
       +        d.open()
       +
       +    def show_menu(self, obj):
       +        self.hide_menu()
       +        self.context_menu = ContextMenu(obj, self.menu_actions)
       +        self.ids.box.add_widget(self.context_menu)
       +
       +    def hide_menu(self):
       +        if self.context_menu is not None:
       +            self.ids.box.remove_widget(self.context_menu)
       +            self.context_menu = None
   DIR diff --git a/gui/kivy/uix/screens.py b/gui/kivy/uix/screens.py
       t@@ -27,8 +27,6 @@ from .context_menu import ContextMenu
        
        from electrum_gui.kivy.i18n import _
        
       -class EmptyLabel(Factory.Label):
       -    pass
        
        class CScreen(Factory.Screen):
            __events__ = ('on_activate', 'on_deactivate', 'on_enter', 'on_leave')
       t@@ -219,7 +217,6 @@ class SendScreen(CScreen):
                pr = make_unsigned_request(req).SerializeToString()
                pr = PaymentRequest(pr)
                self.app.wallet.invoices.add(pr)
       -        self.app.update_tab('invoices')
                self.app.show_info(_("Invoice saved"))
                if pr.is_pr():
                    self.screen.is_pr = True
       t@@ -390,205 +387,10 @@ class ReceiveScreen(CScreen):
                addr = self.get_new_address()
                if not addr:
                    self.app.show_info(_('Please use the existing requests first.'))
       -        else:
       -            self.save_request()
       -            self.app.show_info(_('New request added to your list.'))
       -
       -
       -invoice_text = {
       -    PR_UNPAID:_('Pending'),
       -    PR_UNKNOWN:_('Unknown'),
       -    PR_PAID:_('Paid'),
       -    PR_EXPIRED:_('Expired')
       -}
       -request_text = {
       -    PR_UNPAID: _('Pending'),
       -    PR_UNKNOWN: _('Unknown'),
       -    PR_PAID: _('Received'),
       -    PR_EXPIRED: _('Expired')
       -}
       -pr_icon = {
       -    PR_UNPAID: 'atlas://gui/kivy/theming/light/important',
       -    PR_UNKNOWN: 'atlas://gui/kivy/theming/light/important',
       -    PR_PAID: 'atlas://gui/kivy/theming/light/confirmed',
       -    PR_EXPIRED: 'atlas://gui/kivy/theming/light/close'
       -}
       -
       -
       -class InvoicesScreen(CScreen):
       -    kvname = 'invoices'
       -    cards = {}
       -
       -    def get_card(self, pr):
       -        key = pr.get_id()
       -        ci = self.cards.get(key)
       -        if ci is None:
       -            ci = Factory.InvoiceItem()
       -            ci.key = key
       -            ci.screen = self
       -            self.cards[key] = ci
       -
       -        ci.requestor = pr.get_requestor()
       -        ci.memo = pr.get_memo()
       -        amount = pr.get_amount()
       -        if amount:
       -            ci.amount = self.app.format_amount_and_units(amount)
       -            status = self.app.wallet.invoices.get_status(ci.key)
       -            ci.status = invoice_text[status]
       -            ci.icon = pr_icon[status]
       -        else:
       -            ci.amount = _('No Amount')
       -            ci.status = ''
       -        exp = pr.get_expiration_date()
       -        ci.date = format_time(exp) if exp else _('Never')
       -        return ci
       -
       -    def update(self):
       -        self.menu_actions = [('Pay', self.do_pay), ('Details', self.do_view), ('Delete', self.do_delete)]
       -        invoices_list = self.screen.ids.invoices_container
       -        invoices_list.clear_widgets()
       -        _list = self.app.wallet.invoices.sorted_list()
       -        for pr in _list:
       -            ci = self.get_card(pr)
       -            invoices_list.add_widget(ci)
       -        if not _list:
       -            msg = _('This screen shows the list of payment requests that have been sent to you. You may also use it to store contact addresses.')
       -            invoices_list.add_widget(EmptyLabel(text=msg))
       -
       -    def do_pay(self, obj):
       -        pr = self.app.wallet.invoices.get(obj.key)
       -        self.app.on_pr(pr)
       -
       -    def do_view(self, obj):
       -        pr = self.app.wallet.invoices.get(obj.key)
       -        pr.verify(self.app.wallet.contacts)
       -        self.app.show_pr_details(pr.get_dict(), obj.status, True)
       -
       -    def do_delete(self, obj):
       -        from .dialogs.question import Question
       -        def cb(result):
       -            if result:
       -                self.app.wallet.invoices.remove(obj.key)
       -                self.app.update_tab('invoices')
       -        d = Question(_('Delete invoice?'), cb)
       -        d.open()
       -
       -
       -address_icon = {
       -    'Pending' : 'atlas://gui/kivy/theming/light/important',
       -    'Paid' : 'atlas://gui/kivy/theming/light/confirmed'
       -}
       - 
       -class AddressScreen(CScreen):
       -    kvname = 'address'
       -    cards = {}
       -
       -    def get_card(self, addr, balance, is_used, label):
       -        ci = self.cards.get(addr)
       -        if ci is None:
       -            ci = Factory.AddressItem()
       -            ci.screen = self
       -            ci.address = addr
       -            self.cards[addr] = ci
       -
       -        ci.memo = label
       -        ci.amount = self.app.format_amount_and_units(balance)
       -        request = self.app.wallet.get_payment_request(addr, self.app.electrum_config)
       -        if is_used:
       -            ci.status = _('Used')
       -        elif request:
       -            status, conf = self.app.wallet.get_request_status(addr)
       -            requested_amount = request.get('amount')
       -            # make sure that requested amount is > 0
       -            if status == PR_PAID:
       -                s = _('Request paid')
       -            elif status == PR_UNPAID:
       -                s = _('Request pending')
       -            elif status == PR_EXPIRED:
       -                s = _('Request expired')
       -            else:
       -                s = ''
       -            ci.status = s + ': ' + self.app.format_amount_and_units(requested_amount)
       -        else:
       -            ci.status = _('Funded') if balance>0 else _('Unused')
       -        return ci
       -
       -
       -    def update(self):
       -        self.menu_actions = [('Receive', self.do_show), ('Details', self.do_view)]
       -        wallet = self.app.wallet
       -        if self.screen.show_change == 0:
       -            _list = wallet.get_receiving_addresses()
       -        elif self.screen.show_change == 1:
       -            _list = wallet.get_change_addresses()
       -        else:
       -            _list = wallet.get_addresses()
       -        search = self.screen.message
       -        container = self.screen.ids.search_container
       -        container.clear_widgets()
       -        n = 0
       -        for address in _list:
       -            label = wallet.labels.get(address, '')
       -            balance = sum(wallet.get_addr_balance(address))
       -            is_used = wallet.is_used(address)
       -            if self.screen.show_used == 1 and (balance or is_used):
       -                continue
       -            if self.screen.show_used == 2 and balance == 0:
       -                continue
       -            if self.screen.show_used == 3 and not is_used:
       -                continue
       -            card = self.get_card(address, balance, is_used, label)
       -            if search and not self.ext_search(card, search):
       -                continue
       -            container.add_widget(card)
       -            n += 1
       -        if not n:
       -            msg = _('No address matching your search')
       -            container.add_widget(EmptyLabel(text=msg))
       -
       -    def do_show(self, obj):
       -        self.app.show_request(obj.address)
       -
       -    def do_view(self, obj):
       -        req = self.app.wallet.get_payment_request(obj.address, self.app.electrum_config)
       -        if req:
       -            c, u, x = self.app.wallet.get_addr_balance(obj.address)
       -            balance = c + u + x
       -            if balance > 0:
       -                req['fund'] = balance
       -            status = req.get('status')
       -            amount = req.get('amount')
       -            address = req['address']
       -            if amount:
       -                status = req.get('status')
       -                status = request_text[status]
       -            else:
       -                received_amount = self.app.wallet.get_addr_received(address)
       -                status = self.app.format_amount_and_units(received_amount)
       -            self.app.show_pr_details(req, status, False)
       -
       -        else:
       -            req = { 'address': obj.address, 'status' : obj.status }
       -            status = obj.status
       -            c, u, x = self.app.wallet.get_addr_balance(obj.address)
       -            balance = c + u + x
       -            if balance > 0:
       -                req['fund'] = balance
       -            self.app.show_addr_details(req, status)
       -
       -    def do_delete(self, obj):
       -        from .dialogs.question import Question
       -        def cb(result):
       -            if result:
       -                self.app.wallet.remove_payment_request(obj.address, self.app.electrum_config)
       -                self.update()
       -        d = Question(_('Delete request?'), cb)
       -        d.open()
       -
       -    def ext_search(self, card, search):
       -        return card.memo.find(search) >= 0 or card.amount.find(search) >= 0
       -
        
       +    def do_save(self):
       +        self.save_request()
       +        self.app.show_info(_('Request was saved.'))
        
        
        class TabbedCarousel(Factory.TabbedPanel):
   DIR diff --git a/gui/kivy/uix/ui_screens/address.kv b/gui/kivy/uix/ui_screens/address.kv
       t@@ -1,90 +0,0 @@
       -#:import _ electrum_gui.kivy.i18n._
       -#:import Decimal decimal.Decimal
       -#:set btc_symbol chr(171)
       -#:set mbtc_symbol chr(187)
       -#:set font_light 'gui/kivy/data/fonts/Roboto-Condensed.ttf'
       -
       -<AddressLabel@Label>
       -    text_size: self.width, None
       -    halign: 'left'
       -    valign: 'top'
       -
       -<AddressItem@CardItem>
       -    address: ''
       -    memo: ''
       -    amount: ''
       -    status: ''
       -    BoxLayout:
       -        spacing: '8dp'
       -        height: '32dp'
       -        orientation: 'vertical'
       -        Widget
       -        AddressLabel:
       -            text: root.address
       -            shorten: True
       -        Widget
       -        AddressLabel:
       -            text: (root.amount if root.status == 'Funded' else root.status) + '     ' + root.memo
       -            color: .699, .699, .699, 1
       -            font_size: '13sp'
       -            shorten: True
       -        Widget
       -
       -AddressScreen:
       -    id: addr_screen
       -    name: 'address'
       -    message: ''
       -    pr_status: 'Pending'
       -    show_change: 0
       -    show_used: 0
       -    on_message:
       -        self.parent.update()
       -    BoxLayout
       -        padding: '12dp', '70dp', '12dp', '12dp'
       -        spacing: '12dp'
       -        orientation: 'vertical'
       -        size_hint: 1, 1.1
       -        BoxLayout:
       -            spacing: '6dp'
       -            size_hint: 1, None
       -            orientation: 'horizontal'
       -            AddressFilter:
       -                opacity: 1
       -                size_hint: 1, None
       -                height: self.minimum_height
       -                spacing: '5dp'
       -                AddressButton:
       -                    id: search
       -                    text: {0:_('Receiving'), 1:_('Change'), 2:_('All')}[root.show_change]
       -                    on_release:
       -                        root.show_change = (root.show_change + 1) % 3
       -                        Clock.schedule_once(lambda dt: app.address_screen.update())
       -            AddressFilter:
       -                opacity: 1
       -                size_hint: 1, None
       -                height: self.minimum_height
       -                spacing: '5dp'
       -                AddressButton:
       -                    id: search
       -                    text: {0:_('All'), 1:_('Unused'), 2:_('Funded'), 3:_('Used')}[root.show_used]
       -                    on_release:
       -                        root.show_used = (root.show_used + 1) % 4
       -                        Clock.schedule_once(lambda dt: app.address_screen.update())
       -            AddressFilter:
       -                opacity: 1
       -                size_hint: 1, None
       -                height: self.minimum_height
       -                spacing: '5dp'
       -                canvas.before:
       -                    Color:
       -                        rgba: 0.9, 0.9, 0.9, 1
       -                AddressButton:
       -                    id: change
       -                    text: root.message if root.message else _('Search')
       -                    on_release: Clock.schedule_once(lambda dt: app.description_dialog(addr_screen))
       -        ScrollView:
       -            GridLayout:
       -                cols: 1
       -                id: search_container
       -                size_hint_y: None
       -                height: self.minimum_height
   DIR diff --git a/gui/kivy/uix/ui_screens/invoices.kv b/gui/kivy/uix/ui_screens/invoices.kv
       t@@ -1,66 +0,0 @@
       -<InvoicesLabel@Label>
       -    #color: .305, .309, .309, 1
       -    text_size: self.width, None
       -    halign: 'left'
       -    valign: 'top'
       -
       -<InvoiceItem@CardItem>
       -    requestor: ''
       -    memo: ''
       -    amount: ''
       -    status: ''
       -    date: ''
       -    icon: 'atlas://gui/kivy/theming/light/important'
       -    Image:
       -        id: icon
       -        source: root.icon
       -        size_hint: None, 1
       -        width: self.height *.54
       -        mipmap: True
       -    BoxLayout:
       -        spacing: '8dp'
       -        height: '32dp'
       -        orientation: 'vertical'
       -        Widget
       -        InvoicesLabel:
       -            text: root.requestor
       -            shorten: True
       -        Widget
       -        InvoicesLabel:
       -            text: root.memo
       -            color: .699, .699, .699, 1
       -            font_size: '13sp'
       -            shorten: True
       -        Widget
       -    BoxLayout:
       -        spacing: '8dp'
       -        height: '32dp'
       -        orientation: 'vertical'
       -        Widget
       -        InvoicesLabel:
       -            text: root.amount
       -            font_size: '15sp'
       -            halign: 'right'
       -            width: '110sp'
       -        Widget
       -        InvoicesLabel:
       -            text: root.status
       -            font_size: '13sp'
       -            halign: 'right'
       -            color: .699, .699, .699, 1
       -        Widget
       -
       -
       -InvoicesScreen:
       -    name: 'invoices'
       -    BoxLayout:
       -        orientation: 'vertical'
       -        spacing: '1dp'
       -        ScrollView:
       -            GridLayout:
       -                cols: 1
       -                id: invoices_container
       -                size_hint: 1, None
       -                height: self.minimum_height
       -                spacing: '2dp'
       -                padding: '12dp'
   DIR diff --git a/gui/kivy/uix/ui_screens/receive.kv b/gui/kivy/uix/ui_screens/receive.kv
       t@@ -70,7 +70,7 @@ ReceiveScreen:
                            id: address_label
                            text: s.address if s.address else _('Bitcoin Address')
                            shorten: True
       -                    disabled: True
       +                    on_release: Clock.schedule_once(lambda dt: app.addresses_dialog(s))
                    CardSeparator:
                        opacity: message_selection.opacity
                        color: blue_bottom.foreground_color
       t@@ -110,16 +110,31 @@ ReceiveScreen:
                BoxLayout:
                    size_hint: 1, None
                    height: '48dp'
       +            IconButton:
       +                icon: 'atlas://gui/kivy/theming/light/save'
       +                size_hint: 0.6, None
       +                height: '48dp'
       +                on_release: s.parent.do_save()
                    Button:
       -                text: _('Copy')
       +                text: _('Requests')
                        size_hint: 1, None
                        height: '48dp'
       -                on_release: s.parent.do_copy()
       +                on_release: Clock.schedule_once(lambda dt: app.requests_dialog(s))
                    Button:
       -                text: _('Share')
       +                text: _('Copy')
                        size_hint: 1, None
                        height: '48dp'
       +                on_release: s.parent.do_copy()
       +            IconButton:
       +                icon: 'atlas://gui/kivy/theming/light/share'
       +                size_hint: 0.6, None
       +                height: '48dp'
                        on_release: s.parent.do_share()
       +        BoxLayout:
       +            size_hint: 1, None
       +            height: '48dp'
       +            Widget
       +                size_hint: 2, 1
                    Button:
                        text: _('New')
                        size_hint: 1, None
   DIR diff --git a/gui/kivy/uix/ui_screens/requests.kv b/gui/kivy/uix/ui_screens/requests.kv
       t@@ -1,66 +0,0 @@
       -<RequestLabel@Label>
       -    #color: .305, .309, .309, 1
       -    text_size: self.width, None
       -    halign: 'left'
       -    valign: 'top'
       -
       -<RequestItem@CardItem>
       -    address: ''
       -    memo: ''
       -    amount: ''
       -    status: ''
       -    date: ''
       -    icon: 'atlas://gui/kivy/theming/light/important'
       -    Image:
       -        id: icon
       -        source: root.icon
       -        size_hint: None, 1
       -        width: self.height *.54
       -        mipmap: True
       -    BoxLayout:
       -        spacing: '8dp'
       -        height: '32dp'
       -        orientation: 'vertical'
       -        Widget
       -        RequestLabel:
       -            text: root.address
       -            shorten: True
       -        Widget
       -        RequestLabel:
       -            text: root.memo
       -            color: .699, .699, .699, 1
       -            font_size: '13sp'
       -            shorten: True
       -        Widget
       -    BoxLayout:
       -        spacing: '8dp'
       -        height: '32dp'
       -        orientation: 'vertical'
       -        Widget
       -        RequestLabel:
       -            text: root.amount
       -            halign: 'right'
       -            font_size: '15sp'
       -        Widget
       -        RequestLabel:
       -            text: root.status
       -            halign: 'right'
       -            font_size: '13sp'
       -            color: .699, .699, .699, 1
       -        Widget
       -
       -
       -
       -RequestsScreen:
       -    name: 'requests'
       -    BoxLayout:
       -        orientation: 'vertical'
       -        spacing: '1dp'
       -        ScrollView:
       -            GridLayout:
       -                cols: 1
       -                id: requests_container
       -                size_hint_y: None
       -                height: self.minimum_height
       -                spacing: '2dp'
       -                padding: '12dp'
   DIR diff --git a/gui/kivy/uix/ui_screens/send.kv b/gui/kivy/uix/ui_screens/send.kv
       t@@ -34,6 +34,7 @@ SendScreen:
                            text: s.address if s.address else _('Recipient')
                            shorten: True
                            on_release: Clock.schedule_once(lambda dt: app.show_info(_('Copy and paste the recipient address using the Paste button, or use the camera to scan a QR code.')))
       +                    #on_release: Clock.schedule_once(lambda dt: app.popup_dialog('contacts'))
                    CardSeparator:
                        opacity: int(not root.is_pr)
                        color: blue_bottom.foreground_color
       t@@ -93,25 +94,29 @@ SendScreen:
                    size_hint: 1, None
                    height: '48dp'
                    IconButton:
       -                id: qr
                        size_hint: 0.6, 1
       -                on_release: Clock.schedule_once(lambda dt: app.scan_qr(on_complete=app.on_qr))
       -                icon: 'atlas://gui/kivy/theming/light/camera'
       +                on_release: s.parent.do_save()
       +                icon: 'atlas://gui/kivy/theming/light/save'
       +            Button:
       +                text: _('Invoices')
       +                size_hint: 1, 1
       +                on_release: Clock.schedule_once(lambda dt: app.invoices_dialog(s))
                    Button:
                        text: _('Paste')
                        on_release: s.parent.do_paste()
       -            Button:
       -                text: _('Clear')
       -                on_release: s.parent.do_clear()
                    IconButton:
       +                id: qr
                        size_hint: 0.6, 1
       -                on_release: s.parent.do_save()
       -                icon: 'atlas://gui/kivy/theming/light/save'
       +                on_release: Clock.schedule_once(lambda dt: app.scan_qr(on_complete=app.on_qr))
       +                icon: 'atlas://gui/kivy/theming/light/camera'
                BoxLayout:
                    size_hint: 1, None
                    height: '48dp'
       +            Button:
       +                text: _('Clear')
       +                on_release: s.parent.do_clear()
                    Widget:
       -                size_hint: 2, 1
       +                size_hint: 1, 1
                    Button:
                        text: _('Pay')
                        size_hint: 1, 1