URI: 
       thandle app start, background wallet interfacing. UX to be merged next. - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit a1681eeeba4c212dcbb6087f1ed3201378492bd8
   DIR parent f33fbefce08468d22ecbb60802e7e38ff8db5f15
  HTML Author: qua-non <akshayaurora@gmail.com>
       Date:   Sun,  2 Mar 2014 00:41:58 +0530
       
       handle app start, background wallet interfacing. UX to be merged next.
       
       Diffstat:
         M gui/kivy/dialog.py                  |      14 +++++++++++---
         M gui/kivy/installwizard.py           |      17 ++++++++++-------
         M gui/kivy/main.kv                    |       5 +++--
         M gui/kivy/main_window.py             |     509 +++++++++++++++++++++++++++++--
       
       4 files changed, 515 insertions(+), 30 deletions(-)
       ---
   DIR diff --git a/gui/kivy/dialog.py b/gui/kivy/dialog.py
       t@@ -495,8 +495,8 @@ class RestoreSeedDialog(CreateAccountDialog):
                    tis._keyboard.bind(on_key_down=self.on_key_down)
                    stepper = self.ids.stepper
                    stepper.opacity = 1
       -            stepper.source = ('atlas://gui/kivy/theming"
       -                              "/light/stepper_restore_seed')
       +            stepper.source = ('atlas://gui/kivy/theming'
       +                              '/light/stepper_restore_seed')
                    self._back = _back = partial(self.ids.back.dispatch, 'on_release')
                    app.navigation_higherarchy.append(_back)
        
       t@@ -582,7 +582,15 @@ class ChangePasswordDialog(CreateAccountDialog):
                if value:
                    stepper = self.ids.stepper
                    stepper.opacity = 1
       -            self.ids.ti_wallet_name.focus = True
       +            t_wallet_name = self.ids.ti_wallet_name
       +            if self.mode in ('create', 'restore'):
       +                t_wallet_name.text = 'Default Wallet'
       +                t_wallet_name.readonly = True
       +                self.ids.ti_new_password.focus = True
       +            else:
       +                t_wallet_name.text = ''
       +                t_wallet_name.readonly = False
       +                t_wallet_name.focus = True
                    stepper.source = 'atlas://gui/kivy/theming/light/stepper_left'
                    self._back = _back = partial(self.ids.back.dispatch, 'on_release')
                    app.navigation_higherarchy.append(_back)
   DIR diff --git a/gui/kivy/installwizard.py b/gui/kivy/installwizard.py
       t@@ -20,7 +20,7 @@ app = App.get_running_app()
        
        
        class InstallWizard(Widget):
       -    '''Instalation Wizzard. Responsible for instantiating the
       +    '''Installation Wizard. Responsible for instantiating the
            creation/restoration of wallets.
        
            events::
       t@@ -232,7 +232,7 @@ class InstallWizard(Widget):
                            ti_new_password.focus = True
                        else:
                            ti_password.focus = True
       -                return app.show_error(_('Passwords do not match'))
       +                return app.show_error(_('Passwords do not match'), duration=.5)
        
                    if mode == 'restore':
                        try:
       t@@ -253,7 +253,7 @@ class InstallWizard(Widget):
                    try:
                        seed = wallet.decode_seed(password)
                    except BaseException:
       -                return app.show_error(_('Incorrect Password'))
       +                return app.show_error(_('Incorrect Password'), duration=.5)
        
                    # test carefully
                    try:
       t@@ -291,6 +291,7 @@ class InstallWizard(Widget):
                if mode in ('restore', 'create'):
                    # auto cycle
                    self.config.set_key('auto_cycle', True, True)
       +
                # start wallet threads
                wallet.start_threads(self.network)
        
       t@@ -303,14 +304,16 @@ class InstallWizard(Widget):
        
                def on_complete(*l):
                    if not self.network:
       -                app.show_info(_("This wallet was restored offline."
       -                    "It may contain more addresses than displayed."))
       +                app.show_info(
       +                    _("This wallet was restored offline. It may contain more"
       +                      " addresses than displayed."), duration=.5)
                        return self.dispatch('on_wizard_complete', wallet)
        
                    if wallet.is_found():
       -                app.show_info(_("Recovery successful"))
       +                app.show_info(_("Recovery successful"), duration=.5)
                    else:
       -                app.show_info(_("No transactions found for this seed"))
       +                app.show_info(_("No transactions found for this seed"),
       +                              duration=.5)
                    return self.dispatch('on_wizard_complete', wallet)
        
                self.waiting_dialog(lambda: wallet.restore(get_text),
   DIR diff --git a/gui/kivy/main.kv b/gui/kivy/main.kv
       t@@ -104,7 +104,7 @@
                    size_hint: None, 1
                    width: (root.width - dp(20)) if root.fs  else (0 if not root.icon else '32dp')
                Widget:
       -            size_hint_y: None
       +            size_hint_x: None
                    width: '5dp'
                Label:
                    id: lbl
       t@@ -112,7 +112,8 @@
                    font_size: '12sp'
                    text: root.message
                    text_size: self.width, None
       -            size_hint: None, 1
       +            valign: 'middle'
       +            size_hint: 1, 1
                    width: 0 if root.fs else (root.width - img.width)
        
        <-CreateAccountDialog>
   DIR diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
       t@@ -1,7 +1,9 @@
        import  sys
       +from decimal import Decimal
        
        from electrum import WalletStorage, Wallet
       -from electrum.i18n import _
       +from electrum.i18n import _, set_language
       +from electrum.wallet import format_satoshis
        
        from kivy.app import App
        from kivy.core.window import Window
       t@@ -10,11 +12,15 @@ from kivy.logger import Logger
        from kivy.utils import platform
        from kivy.properties import (OptionProperty, AliasProperty, ObjectProperty,
                                     StringProperty, ListProperty)
       +from kivy.clock import Clock
        
        #inclusions for factory so that widgets can be used in kv
        from gui.kivy.drawer import Drawer
        from gui.kivy.dialog import InfoBubble
        
       +# delayed imports
       +notification = None
       +
        class ElectrumWindow(App):
        
            title = _('Electrum App')
       t@@ -25,10 +31,10 @@ class ElectrumWindow(App):
            :attr:`wallet` is a `ObjectProperty` defaults to None.
            '''
        
       -    conf = ObjectProperty(None)
       +    electrum_config = ObjectProperty(None)
            '''Holds the electrum config
        
       -    :attr:`conf` is a `ObjectProperty`, defaults to None.
       +    :attr:`electrum_config` is a `ObjectProperty`, defaults to None.
            '''
        
            status = StringProperty(_('Uninitialised'))
       t@@ -37,10 +43,60 @@ class ElectrumWindow(App):
            :attr:`status` is a `StringProperty` defaults to _'uninitialised'
            '''
        
       -    base_unit = StringProperty('BTC')
       +    def _get_num_zeros(self):
       +        try:
       +            return self.electrum_config.get('num_zeros', 0)
       +        except AttributeError:
       +            return 0
       +
       +    def _set_num_zeros(self):
       +        try:
       +            self.electrum_config.set_key('num_zeros', value, True)
       +        except AttributeError:
       +            Logger.error('Electrum: Config not available '
       +                         'While trying to save value to config')
       +
       +    num_zeros = AliasProperty(_get_num_zeros , _set_num_zeros)
       +    '''Number of zeros used while representing the value in base_unit.
       +    '''
       +
       +    def _get_decimal(self):
       +        try:
       +            return self.electrum_config.get('decimal_point', 8)
       +        except AttributeError:
       +            return 8
       +
       +    def _set_decimal(self, value):
       +        try:
       +            self.electrum_config.set_key('decimal_point', value, True)
       +        except AttributeError:
       +            Logger.error('Electrum: Config not set '
       +                         'While trying to save value to config')
       +
       +    decimal_point = AliasProperty(_get_decimal, _set_decimal)
       +    '''This defines the decimal point to be used determining the
       +    :attr:`base_unit`.
       +
       +    :attr:`decimal_point` is a `AliasProperty` defaults to the value gotten
       +    from electrum config.
       +    '''
       +
       +    def _get_bu(self):
       +        assert self.decimal_point in (5,8)
       +        return "BTC" if self.decimal_point == 8 else "mBTC"
       +
       +    def _set_bu(self, value):
       +        try:
       +            self.electrum_config.set_key('base_unit', value, True)
       +        except AttributeError:
       +            Logger.error('Electrum: Config not set '
       +                         'While trying to save value to config')
       +
       +    base_unit = AliasProperty(_get_bu, _set_bu, bind=('decimal_point',))
            '''BTC or UBTC or ...
        
       -    :attr:`base_unit` is a `StringProperty` defaults to 'BTC'
       +    :attr:`base_unit` is a `AliasProperty` defaults to the unit set in
       +    electrum config.
            '''
        
            _ui_mode = OptionProperty('phone', options=('tablet', 'phone'))
       t@@ -84,13 +140,20 @@ class ElectrumWindow(App):
            def __init__(self, **kwargs):
                # initialize variables
                self.info_bubble = None
       +        self.console = None
       +        self.exchanger = None
       +
                super(ElectrumWindow, self).__init__(**kwargs)
                self.network = network = kwargs.get('network')
                self.electrum_config = config = kwargs.get('config')
        
       -    def load_wallet(self, wallet):
       -        # TODO
       -        pass
       +        # create triggers so as to minimize updation a max of 5 times a sec
       +        self._trigger_update_status = Clock.create_trigger(self.update_status,
       +                                                           .2)
       +        self._trigger_update_console = Clock.create_trigger(self.update_console,
       +                                                            .2)
       +        self._trigger_notify_transactions = \
       +            Clock.create_trigger(self.notify_transactions, .2)
        
            def build(self):
                from kivy.lang import Builder
       t@@ -98,15 +161,21 @@ class ElectrumWindow(App):
        
            def _pause(self):
                if platform == 'android':
       +            # move activity to back
                    from jnius import autoclass
                    python_act = autoclass('org.renpy.android.PythonActivity')
                    mActivity = python_act.mActivity
                    mActivity.moveTaskToBack(True)
        
            def on_start(self):
       +        ''' This is the start point of the kivy ui
       +        '''
                Window.bind(size=self.on_size,
                            on_keyboard=self.on_keyboard)
       -        Window.bind(keyboard_height=self.on_keyboard_height)
       +        Window.bind(on_key_down=self.on_key_down)
       +        if platform == 'android':
       +            #
       +            Window.bind(keyboard_height=self.on_keyboard_height)
                self.on_size(Window, Window.size)
                config = self.electrum_config
                storage = WalletStorage(config)
       t@@ -127,8 +196,11 @@ class ElectrumWindow(App):
        
                self.on_resume()
        
       +    def on_stop(self):
       +        self.wallet.stop_threads()
       +
            def on_back(self):
       -        ''' Manage screen higherarchy
       +        ''' Manage screen hierarchy
                '''
                try:
                    self.navigation_higherarchy.pop()()
       t@@ -146,9 +218,28 @@ class ElectrumWindow(App):
                    Window.children[1]
                Animation(y=Window.keyboard_height, d=.1).start(active_widg)
        
       +    def on_key_down(self, instance, key, keycode, codepoint, modifiers):
       +        if 'ctrl' in modifiers:
       +            # q=24 w=25
       +            if keycode in (24, 25):
       +                self.stop()
       +            elif keycode == 27:
       +                # r=27
       +                # force update wallet
       +                self.update_wallet()
       +            elif keycode == 112:
       +                # pageup
       +                #TODO move to next tab
       +                pass
       +            elif keycode == 117:
       +                # pagedown
       +                #TODO move to prev tab
       +                pass
       +        #TODO: alt+tab_number to activate the particular tab
       +
            def on_keyboard(self, instance, key, keycode, codepoint, modifiers):
                # override settings button
       -        if key in (319, 282):
       +        if key in (319, 282): #f1/settings button on android
                    self.gui.main_gui.toggle_settings(self)
                    return True
                if key == 27:
       t@@ -160,14 +251,18 @@ class ElectrumWindow(App):
                    Logger.debug('Electrum: No Wallet set/found. Exiting...')
                    app.show_error('Electrum: No Wallet set/found. Exiting...',
                                   exit=True)
       -        return
       +        Logger.info('wizard complete')
       +
        
       +        self.init_ui()
                # plugins that need to change the GUI do it here
                #run_hook('init')
        
                self.load_wallet(wallet)
        
       -        Clock.schedule_once(update_wallet)
       +        # check and remove this load_wallet calls update_wallet no
       +        # need for this here
       +        #Clock.schedule_once(update_wallet)
        
                #self.windows.append(w)
                #if url: w.set_url(url)
       t@@ -177,7 +272,381 @@ class ElectrumWindow(App):
        
                #self.app.exec_()
        
       -        wallet.stop_threads()
       +    def init_ui(self):
       +        ''' Initialize The Ux part of electrum. This function performs the basic
       +        tasks of setting up the ui.
       +        '''
       +
       +        # unused?
       +        #self._close_electrum = False
       +
       +        #self._tray_icon = 'icons/" + (electrum_dark_icon.png'\
       +        #    if platform == 'mac' else 'electrum_light_icon.png')
       +
       +        #setup tray
       +        #self.tray = SystemTrayIcon(self.icon, self)
       +        #self.tray.setToolTip('Electrum')
       +        #self.tray.activated.connect(self.tray_activated)
       +
       +        set_language(self.electrum_config.get('language'))
       +
       +        self.funds_error = False
       +        self.completions = []
       +
       +        # setup UX
       +        #self.load_dashboard
       +
       +        self.icon = "icons/electrum.png"
       +
       +        # load and focus the ui
       +
       +        # connect callbacks
       +        if self.network:
       +            self.network.register_callback(
       +                'updated', self._trigger_update_status)
       +            self.network.register_callback(
       +                'banner', self._trigger_update_console)
       +            self.network.register_callback(
       +                'disconnected', self._trigger_update_status)
       +            self.network.register_callback(
       +                'disconnecting', self._trigger_update_status)
       +            self.network.register_callback('new_transaction',
       +                self._trigger_notify_transactions)
       +
       +            # set initial message
       +            self.update_console()
       +
       +        self.wallet = None
       +
       +    def create_quote_text(self, btc_balance, mode='normal'):
       +        '''
       +        '''
       +        if not self.exchanger:
       +            from plugins.exchange_rate import Exchanger
       +            self.exchanger = Exchanger(self)
       +            self.exchanger.start()
       +        quote_currency = self.electrum_config.get("currency", 'EUR')
       +        quote_balance = self.exchanger.exchange(btc_balance, quote_currency)
       +
       +        if mode == 'symbol':
       +            if quote_currency:
       +                quote_currency = self.exchanger.symbols[quote_currency]
       +
       +        if quote_balance is None:
       +            quote_text = ""
       +        else:
       +            quote_text = "  (%.2f %s)" % (quote_balance, quote_currency)
       +        return quote_text
       +
       +    def set_currencies(self, quote_currencies):
       +        self._trigger_update_status
       +        #self.currencies = sorted(quote_currencies.keys())
       +
       +    def update_console(self, *dt):
       +        if self.console:
       +            self.console.showMessage(self.network.banner)
       +
       +    def load_wallet(self, wallet):
       +        self.wallet = wallet
       +        self.accounts_expanded = self.wallet.storage.get('accounts_expanded', {})
       +        self.current_account = self.wallet.storage.get('current_account', None)
       +
       +        title = 'Electrum ' + self.wallet.electrum_version + ' - '\
       +            + self.wallet.storage.path
       +        if wallet.is_watching_only():
       +            title += ' [{}]'.format(_('watching only'))
       +        self.title = title
       +        self.update_wallet()
       +        # Once GUI has been initialized check if we want to announce something
       +        # since the callback has been called before the GUI was initialized
       +        self.notify_transactions()
       +        self.update_account_selector()
       +        #TODO
       +        #self.new_account.setEnabled(self.wallet.seed_version>4)
       +        #self.update_lock_icon()
       +        #self.update_buttons_on_seed()
       +
       +        #run_hook('load_wallet', wallet)
       +
       +    def update_status(self, *dt):
       +        if not self.wallet:
       +            return
       +        if self.network is None or not self.network.is_running():
       +            text = _("Offline")
       +            #icon = QIcon(":icons/status_disconnected.png")
       +
       +        elif self.network.is_connected():
       +            unconfirmed = ''
       +            quote_text = '.'
       +            if not self.wallet.up_to_date:
       +                text = _("Synchronizing...")
       +                #icon = QIcon(":icons/status_waiting.png")
       +            elif self.network.server_lag > 1:
       +                text = _("Server is lagging (%d blocks)"%self.network.server_lag)
       +                #icon = QIcon(":icons/status_lagging.png")
       +            else:
       +                c, u = self.wallet.get_account_balance(self.current_account)
       +                text =  self.format_amount(c)
       +                if u:
       +                    unconfirmed =  " [%s unconfirmed]"\
       +                        %( self.format_amount(u, True).strip())
       +                quote_text = self.create_quote_text(Decimal(c+u)/100000000) or '.'
       +
       +                #r = {}
       +                #run_hook('set_quote_text', c+u, r)
       +                #quote = r.get(0)
       +                #if quote:
       +                #    text += "  (%s)"%quote
       +
       +                self.notify(_("Balance: ") + text)
       +                #icon = QIcon(":icons/status_connected.png")
       +        else:
       +            text = _("Not connected")
       +            #icon = QIcon(":icons/status_disconnected.png")
       +
       +        #TODO
       +        #status_card = self.root.main_screen.ids.tabs.ids.\
       +        #                screen_dashboard.ids.status_card
       +        self.status = text.strip()
       +        #status_card.quote_text = quote_text.strip()
       +        #status_card.uncomfirmed = unconfirmed.strip()
       +        ##app.base_unit = self.base_unit().strip()
       +
       +    def format_amount(self, x, is_diff=False, whitespaces=False):
       +        '''
       +        '''
       +        return format_satoshis(x, is_diff, self.num_zeros, self.decimal_point, whitespaces)
       +
       +    def update_wallet(self):
       +        '''
       +        '''
       +        self.update_status()
       +        if (self.wallet.up_to_date or
       +            not self.network or not self.network.is_connected()):
       +            #TODO
       +            #self.update_history_tab()
       +            #self.update_receive_tab()
       +            #self.update_contacts_tab()
       +            self.update_completions()
       +
       +    def update_account_selector(self):
       +        # account selector
       +        #TODO
       +        return
       +        accounts = self.wallet.get_account_names()
       +        self.account_selector.clear()
       +        if len(accounts) > 1:
       +            self.account_selector.addItems([_("All accounts")] + accounts.values())
       +            self.account_selector.setCurrentIndex(0)
       +            self.account_selector.show()
       +        else:
       +            self.account_selector.hide()
       +
       +    def update_history_tab(self, see_all=False):
       +        def parse_histories(items):
       +            results = []
       +            for item in items:
       +                tx_hash, conf, is_mine, value, fee, balance, timestamp = item
       +                if conf > 0:
       +                    try:
       +                        time_str = datetime.datetime.fromtimestamp(
       +                                        timestamp).isoformat(' ')[:-3]
       +                    except:
       +                        time_str = _("unknown")
       +
       +                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, whitespaces=True)
       +                else:
       +                    v_str = '--'
       +
       +                balance_str = self.format_amount(balance, whitespaces=True)
       +
       +                if tx_hash:
       +                    label, is_default_label = self.wallet.get_label(tx_hash)
       +                else:
       +                    label = _('Pruned transaction outputs')
       +                    is_default_label = False
       +
       +                results.append((
       +                        conf, icon, time_str, label, v_str, balance_str, tx_hash))
       +
       +            return results
       +
       +        history_card = self.root.main_screen.ids.tabs.ids.\
       +                        screen_dashboard.ids.recent_activity_card
       +        histories = parse_histories(reversed(
       +                        self.wallet.get_tx_history(self.current_account)))
       +        #history_view.content_adapter.data = histories
       +
       +        # 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
       +
       +        history_card.ids.btn_see_all.opacity = (0 if see_all or
       +                                                len(histories) < 8 else 1)
       +        if not see_all:
       +            histories = histories[:8]
       +
       +        create_quote_text = self.create_quote_text
       +        for items in histories:
       +            conf, icon, date_time, address, amount, balance, tx = items
       +            ri = RecentActivityItem()
       +            ri.icon = icon
       +            ri.date = date_time
       +            ri.address = address
       +            ri.amount = amount
       +            ri.quote_text = create_quote_text(
       +                                Decimal(amount)/100000000, mode='symbol')
       +            ri.balance = balance
       +            ri.confirmations = conf
       +            ri.tx_hash = tx
       +            history_add(ri)
       +
       +    def update_receive_tab(self):
       +        #TODO move to address managment
       +        return
       +        data = []
       +
       +        if self.current_account is None:
       +            account_items = self.wallet.accounts.items()
       +        elif self.current_account != -1:
       +            account_items = [(self.current_account, self.wallet.accounts.get(self.current_account))]
       +        else:
       +            account_items = []
       +
       +        for k, account in account_items:
       +            name = account.get('name', str(k))
       +            c, u = self.wallet.get_account_balance(k)
       +            data = [(name, '', self.format_amount(c + u), '')]
       +
       +            for is_change in ([0, 1] if self.expert_mode else [0]):
       +                if self.expert_mode:
       +                    name = "Receiving" if not is_change else "Change"
       +                    seq_item = (name, '', '', '')
       +                    data.append(seq_item)
       +                else:
       +                    seq_item = data
       +                is_red = False
       +                gap = 0
       +
       +                for address in account[is_change]:
       +                    h = self.wallet.history.get(address, [])
       +
       +                    if h == []:
       +                        gap += 1
       +                        if gap > self.wallet.gap_limit:
       +                            is_red = True
       +                    else:
       +                        gap = 0
       +
       +                    num_tx = '*' if h == ['*'] else "%d" % len(h)
       +                    item = (address, self.wallet.labels.get(address, ''), '', num_tx)
       +                    data.append(item)
       +                    self.update_receive_item(item)
       +
       +        if self.wallet.imported_keys and (self.current_account is None
       +                                          or self.current_account == -1):
       +            c, u = self.wallet.get_imported_balance()
       +            data.append((_('Imported'), '', self.format_amount(c + u), ''))
       +            for address in self.wallet.imported_keys.keys():
       +                item = (address, self.wallet.labels.get(address, ''), '', '')
       +                data.append(item)
       +                self.update_receive_item(item)
       +
       +        receive_list = app.root.main_screen.ids.tabs.ids\
       +            .screen_receive.receive_view
       +        receive_list.content_adapter.data = data
       +
       +    def update_contacts_tab(self):
       +        data = []
       +        for address in self.wallet.addressbook:
       +            label = self.wallet.labels.get(address, '')
       +            item = (address, label, "%d" % self.wallet.get_num_tx(address))
       +            data.append(item)
       +            # item.setFont(0, QFont(MONOSPACE_FONT))
       +            # # 32 = label can be edited (bool)
       +            # item.setData(0,32, True)
       +            # # 33 = payto string
       +            # item.setData(0,33, address)
       +
       +        self.run_hook('update_contacts_tab')
       +
       +        contact_list = app.root.main_screen.ids.tabs.ids.\
       +            screen_contacts.ids.contacts_list
       +        contact_list.content_adapter.data = data
       +
       +    def update_completions(self):
       +        l = []
       +        for addr, label in self.wallet.labels.items():
       +            if addr in self.wallet.addressbook:
       +                l.append(label + '  <' + addr + '>')
       +
       +        #self.run_hook('update_completions', l)
       +        self.completions = l
       +
       +    def notify_transactions(self, *dt):
       +        '''
       +        '''
       +        if not self.network or not self.network.is_connected():
       +            return
       +
       +        iface = self.network.interface
       +        if len(iface.pending_transactions_for_notifications) > 0:
       +            # Combine the transactions if there are more then three
       +            tx_amount = len(iface.pending_transactions_for_notifications)
       +            if(tx_amount >= 3):
       +                total_amount = 0
       +                for tx in iface.pending_transactions_for_notifications:
       +                    is_relevant, is_mine, v, fee = self.wallet.get_tx_value(tx)
       +                    if(v > 0):
       +                        total_amount += v
       +                self.notify(_("{txs}s new transactions received. Total amount"
       +                              "received in the new transactions {amount}s"
       +                              "{unit}s").format(txs=tx_amount,
       +                                    amount=self.format_amount(total_amount),
       +                                    unit=self.base_unit()))
       +
       +                iface.pending_transactions_for_notifications = []
       +            else:
       +              for tx in iface.pending_transactions_for_notifications:
       +                  if tx:
       +                      iface.pending_transactions_for_notifications.remove(tx)
       +                      is_relevant, is_mine, v, fee = self.wallet.get_tx_value(tx)
       +                      if(v > 0):
       +                          from pudb import set_trace; set_trace()
       +                          self.notify(
       +                              _("New transaction received. {amount}s {unit}s").
       +                              format( amount=self.format_amount(v),
       +                                     unit=self.base_unit()))
       +
       +    def notify(self, message):
       +        try:
       +            global notification, os
       +            if not notification:
       +                from plyer import notification
       +                import os
       +            icon = (os.path.dirname(os.path.realpath(__file__))
       +                    + '/../../' + self.icon)
       +            notification.notify('Electrum', message,
       +                            app_icon=icon, app_name='Electrum')
       +        except ImportError:
       +            Logger.Error('Notification: needs plyer; `sudo pip install plyer`')
        
            def on_pause(self):
                '''
       t@@ -231,7 +700,8 @@ class ElectrumWindow(App):
                           pos=None,
                           arrow_pos=None,
                           exit=False,
       -                   icon='atlas://gui/kivy/theming/light/error',):
       +                   icon='atlas://gui/kivy/theming/light/error',
       +                   duration=0):
                ''' Show a error Message Bubble.
                '''
                self.show_info_bubble(
       t@@ -240,16 +710,19 @@ class ElectrumWindow(App):
                            width=width,
                            pos=pos or Window.center,
                            arrow_pos=arrow_pos,
       -                    exit=exit)
       +                    exit=exit,
       +                    duration=duration)
        
            def show_info(self, error,
                           width='200dp',
                           pos=None,
                           arrow_pos=None,
       -                   exit=False):
       +                   exit=False,
       +                   duration=0):
                ''' Show a Info Message Bubble.
                '''
       -        self.show_error(error, icon='atlas://gui/kivy/theming/light/error')
       +        self.show_error(error, icon='atlas://gui/kivy/theming/light/error',
       +                        duration=duration)
        
            def show_info_bubble(self,
                            text=_('Hello World'),