#!/usr/bin/python3
import sys, os, locale, requests
from requests.auth import HTTPBasicAuth
from locale import gettext as _
from datetime import datetime
import gi, subprocess, time, locale, pickle, signal, shutil
gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')
gi.require_version('Notify', '0.7')
from gi.repository import Gtk, GLib, Notify, Pango
from gi.repository import AppIndicator3 as appindicator
if os.path.exists('updaterlib.py'):
  import updaterlib
else:
  from update_applet import updaterlib

import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)

DOMAIN = 'rosa-update-system'
LOCALE_DIR = '/usr/share/locale'
locale.bindtextdomain(DOMAIN, LOCALE_DIR)
locale.textdomain(DOMAIN)

cfgdir = os.environ['HOME'] + '/.config/update_applet'
autostartdir = os.environ['HOME'] + '/.config/autostart'
desktopfile = '/usr/share/applications/update_applet.desktop'
updated = False*116*883*1#
started = False
timer_id = False
notify = None
lastlog = []
sec =  60 # единица измерения 1 - sec, 60 - min
pwf_time = 30 # секунд
token_file = '/etc/dnf/vars/token'

# дефолт для сохраняемых настроек, после изменений здесь, нужно сбрасывать настройки апплета
config = {}
config['upd_times'] = (15, 60, 360, 720, 0) # в минутах
config['timeout'] = 360 # одно значение из списка выше

UI = '/usr/share/update_applet/update_applet.ui'
update_wrp='update_applet.helper'
iconpath='/usr/share/update_applet'
if os.path.exists('update_applet'):
  UI = './update_applet.glade'
  #iconpath=''
  update_wrp='./update_applet.helper'

ICON = os.path.join(iconpath, 'update_applet_ok.svg')
green = os.path.join(iconpath,  'update_applet_ok.svg')
yellow = os.path.join(iconpath, 'update_applet_warning.svg')
red = os.path.join(iconpath, 'update_applet_error.svg')

# самоубиться если лайв ОС
if os.path.exists('/dev/mapper/live-base'):
  print('live OS detected, quit!')
  quit()

# True если ключ уже есть или если не нужен
def check_token():
  if not os.path.exists(token_file):
    return True
  elif os.stat(token_file).st_size != 0:
    return True
  else:
    return set_token()

def set_token(*args):
  stoptimers()
  token = get_token()
  if not token:
    return False
  ret = subprocess.Popen([ 'pkexec bash -c "echo ' + token + ' > ' + token_file + '"'], stdout=subprocess.PIPE, shell=True).wait()
  if ret != 0:
    dialog(first=_('Error'), second=_('Can not save token!'), mtype='error')
    return False
  runtimer(config['timeout'])
  return True

# вернет либо введенный в диалогово окошке ключ либо False
def get_token():
  token = dialog(first=_('Warning'), second=_('For access for Rosa repos please enter the key'), mtype='info', entry=True)
  if not token:
    return False
  token = str(token).strip()
  while not ( len(token) == 15 and token == token.lower() and token.isalnum() ):
    token = dialog(first=_('Wrong token format'), second=_('Please enter the key again'), mtype='info', entry=True)
    if not token:
      return False
    token = str(token).strip()
  return token

def dialog(first=_('Warning'), second=None, mtype='info',
          btn=[Gtk.STOCK_OK, Gtk.ResponseType.OK], entry=False,
          passwd=False):
  '''
  По умолчанию информационное окно с кнопкой ОК
  Можно установить свои кнопки и добавить поле ввода
  Если есть entry и текст не пустой - вернет текст
  Если есть entry и пустой возвращает  как если entry нет
  Если нажать OK - и вернет True
  Если CANCEL или закрыть окно - False
  Если свои кнопки вернет, то что назначено кнопке
  '''
  if mtype == 'info':
      mtype = Gtk.MessageType.INFO
  elif mtype == 'error':
      mtype = Gtk.MessageType.ERROR
  text = None
  parent=None
  if 'window' in globals():
    parent=window
  messagedialog = Gtk.MessageDialog(transient_for=parent,
          destroy_with_parent=True,
          modal=True,
          message_type=Gtk.MessageType.INFO,
          text=first)
  if second:
    messagedialog.format_secondary_text(second)
  if entry:
    dialogBox = messagedialog.get_content_area()
    msgEntry = Gtk.Entry()
    if passwd:
      msgEntry.set_visibility(False)
      msgEntry.set_invisible_char("*")
    dialogBox.pack_end(msgEntry, False, False, 0)
  messagedialog.add_buttons(*btn)
  messagedialog.show_all()
  response = messagedialog.run()
  if entry:
    text = msgEntry.get_text()
  messagedialog.destroy()
  messagedialog.destroy()
  if text:
    return text
  if response == Gtk.ResponseType.OK:
      return True
  elif response == Gtk.ResponseType.CANCEL or response == Gtk.ResponseType.DELETE_EVENT:
      return False
  else:
      return response

def first_check():
  first_counter = int(time.perf_counter())
  checknet = False
  waittime = 0
  while checknet == False and  waittime <= 300:
    print(f'Network check time: {waittime} sec')
    for addr in ('https://ya.ru', 'https://abf.io', 'https://google.com'):
      try:
        requests.get(addr).status_code
        checknet = True
        break
      except:
        time.sleep(30)
    waittime = int(time.perf_counter()) - first_counter
  os_data = sysinfo()
  if not check_request(os_data):
    fn_set_token()
  fn_indicator_once()

def check_request(os_data):
  user_agent = f"{os_data['os_name']}:{os_data['build_id']}:{os_data['machine_id']}"
  addr = f'https://mirror.rosa.ru/key-check/rosa{os_data["platform"]}/check.txt'
  session = requests.Session()
  session.headers.update({'User-Agent': user_agent })
  basic = HTTPBasicAuth(os_data["token"], '')
  a = session.get(addr, auth=basic).status_code
  print('check key code: ' + str(a))
  if a == 401 and os.path.exists(token_file):
    notify_send(_('Attention!'), _('Wrong or obsolete key, or error in the server side'), 'warning', False )
    return False
  return True

def pickle_write():
  with open(cfgdir + '/dump', 'wb') as f:
   pickle.dump(config, f)

def notify_send(header, body, status, button):
    global notify
    if notify:
        notify.close()
    notify = Notify.Notification.new(header, body, f'/usr/share/update_applet/update_applet_{status}.svg')
    notify.set_app_name(_('Update applet'))
    if status != 'error':
        notify.set_urgency(Notify.Urgency.NORMAL)
    else:
        notify.set_urgency(Notify.Urgency.CRITICAL)
    if button:
        notify.add_action('clicked', _('Get updates'), fn_get_updates)
    try:
        notify.show()
    except:
        pass

def runtimer(timeout):
  global timer_id
  if timeout != 0 and not timer_id:
    print('timer:' + str(config['timeout'] * sec) + 'sec')
    timer_id = GLib.timeout_add_seconds(timeout * sec, fn_indicator, ind_app)

def checkupd():
    global started
    global update_counter
    global lastlog
    global upd_lines
    upd_lines = 0
    started = True
    checked = False
    for a in  (1, 2, 3):
        if runit(update_wrp + ' refresh', _('Update repositories'), 94, get_repos(), 1):
          checked = True
          break
        echo(_('Update repositories') + ' - ERROR',  _('Update repositories') + ': ' + _('Update repositories') + ' ERROR, try:' + str(a) )
        print('refresh false, try: ' + str(a))
        time.sleep(a)

    if checked:
        lastlog = []
        updates_found = False
        echo('==> ' + _('Check updates'), _('Check updates'))
        with subprocess.Popen([ update_wrp + ' check' ], stdout=subprocess.PIPE, shell=True) as proc:
            for line in proc.stdout:
                if decode_it(line):
                    updates_found = True
                    header = _('Packages that need to be updated:')
                    echo('==> ' + header,  _('Check updates') + ': ' + header)
                    lastlog.append(header)
                    break
        if updates_found:
            with subprocess.Popen([ update_wrp + ' listupd' ], stdout=subprocess.PIPE, shell=True) as proc:
                for line in proc.stdout:
                    decoded_line = decode_it(line)
                    if decoded_line:
                        echo(decoded_line,  _('Check updates') + ': ' + decoded_line)
                        lastlog.append(decoded_line)
                        upd_lines += 1
                    else:
                        refresh()
            echo('\n', _('Check updates') + ': ' + _('Updates found'))
            update_button.show()
            pwf_button.show()
            ind_app.set_icon(yellow)
            update_counter = int(time.perf_counter())
        else:
            echo('\n    ' + _('Updates not found'), _('Check updates') + ': ' + _('Updates not found'))
            ind_app.set_title(_('Already up to date') + '\n' + _('Last check: ') + timenow() )
            ind_app.set_icon(green)
        refresh()
    else:
        print('check updates error')
        echo('ERROR!!!', 'ERROR: ' + _('Update repositories'))
        ind_app.set_icon(red)
        notify_send(_('ERROR:'), _('Cannot refresh metadata'), 'error', False )
        ind_app.set_title(_('Cannot refresh metadata') + '\n' + _('Last check: ') + timenow() )
    started = False
    progress.hide()
    return False

def stoptimers():
    global timer_id
    global once_timer_id
    if 'once_timer_id' in globals():
      try:
        GLib.Source.remove(once_timer_id)
      except Warning:
        pass
    if 'timer_id' in globals():
      GLib.Source.remove(timer_id)
    timer_id = False
    first_timer_id = False
    print('stop timers')


def timelabel(time):
  if time == 0:
      return _('On startup')
  t = _('min')
  if time >= 60:
      time = time / 60
      t = _('h')
  return f'{str(time)} {t}.'

def timenow():
  return datetime.now().strftime('%d.%m.%Y %H:%M')


def check_autostart():
    newfile =True
    if not os.path.exists(os.path.join(autostartdir, 'update_applet.desktop')):
        return True
    with open(os.path.join(autostartdir, 'update_applet.desktop'), 'r') as desktop:
        lines = desktop.readlines()
        for line in lines:
            line = line.strip()
            if line.startswith('Hidden'):
                newfile = False
                if 'false' in line:
                    return True
        if newfile:
            return True
    return False

def show_icon_update(times):
  for itime  in times:
    submenu_icon_item[itime] = Gtk.MenuItem( label=timelabel(itime) )
    submenu_icon_item[itime].connect("activate", fn_icon_update[itime], '')
    submenu_icon_item[itime].show()
    submenu_icon_update.append(submenu_icon_item[itime])

def decode_it(line):
    try:
        decoded_line = line.rstrip().decode('UTF-8')
    except:
        decoded_line = '.'
    if decoded_line != '.':
        return decoded_line
    else:
        return False

def runit(cmd, action, percent, lines=None, skip=None):
    echo('==> ' + action, action)
    if lines:
        # расчет шага движения прогрессбара
        cur_progress = progress.get_fraction()
        delta = percent / 100 - cur_progress
        step = delta / lines
        # print('percent', 'lines', 'cur_progress', 'delta', 'step', 'skip')
        # print(percent, lines, cur_progress, delta, step, skip)
    with subprocess.Popen([cmd], stdout=subprocess.PIPE, shell=True) as proc:
        for line in proc.stdout:
            decoded_line = decode_it(line)
            if decoded_line:
                if decoded_line.startswith('<=v=>'):
                    action = _(decoded_line.replace('<=v=>', ''))
                elif decoded_line.startswith('[SKIPPED]'):
                    continue
                else:
                    echo(decoded_line, action + ': ' + decoded_line)
                    if skip:
                        skip -= 1
                    elif lines:
                        if  (cur_progress + step ) * 100 <= percent:
                            # двигаемся по расчитанным примерно шагам
                            cur_progress += step
                        else:
                            # если расчет не верен и уперлись в лимит двигаемся дальше уменьшая шаги
                            step = (1 - cur_progress) / 2.1
                            cur_progress += step
                        if cur_progress > 0.999:
                            cur_progress = 0.999
                        progress.set_fraction(cur_progress)
                        progress.set_text(str(format(cur_progress * 100, '.2f') ) + '%')

            else:
                refresh()
    if  cur_progress * 100 < percent:
      # если прогресс не дотянул до запланированного, дотягиваем
      progress.set_fraction(percent / 100)
      progress.set_text(str(percent) + '%')
    refresh()
    ret = proc.wait()
    if ret != 0:
        return False
    return True

def echo(text, status):
    textbuffer.insert( textbuffer.get_end_iter(), '\n' + text )
    adj = scroll.get_vadjustment()
    adj.set_value(adj.get_upper() - adj.get_page_size())
    if len(status) > 0:
        statusbar.push(context_id, str(status))
    refresh()

def update():
    global updated
    global started
    global upd_lines
    started = True
    updated = False
    update_button.hide()
    pwf_button.show()
    progress.set_fraction(0.0)
    progress.set_text('0' + '%')
    progress.show()
    # команда, текст заголовка, максимальный процент прогресс бара, кол-во строк расчетное, кол-во лишних строк перед
    if not runit('timeout 10m ' + update_wrp + ' update', _('Install packages'), 98, upd_lines * 5 + 40 , 1):
      echo('ERROR!!!', 'ERROR: ' + update_wrp)
      ind_app.set_icon(red)
      update_button.show()
      ind_app.set_title(_('Automatic update failed. Update check timer stopped.') + '\n' +
                        _('Try upgrading later, or use system package manager'))
      notify_send(_('Automatic update failed. Update check timer stopped.'), \
                  _('Try upgrading later, or use system package manager'), 'error', False)
      started = False
      halt_timer(pwf_time)
      return False
    updated = True
    started = False
    echo('', _('Complete'))
    notify_send(_('Complete'), _('The system has been successfully updated'), 'ok', False)
    progress.hide()
    ind_app.set_icon(green)
    ind_app.set_title(_('Already up to date') + '\n' + _('Last check: ') + timenow() )
    runtimer(config['timeout'])
    halt_timer(pwf_time)
    return False

def get_repos():
    N = -1
    with subprocess.Popen(['dnf repolist'], stdout=subprocess.PIPE, shell=True) as proc:
        for line in proc.stdout:
            decoded_line = decode_it(line)
            if decoded_line:
                N += 1
    return N

def refresh():
    while Gtk.events_pending():
        Gtk.main_iteration_do(True)
    return True

def clear():
    textbuffer.set_text('\n')
    statusbar.push(context_id, '')
    progress.set_fraction(0)
    progress.set_text('0%')

def halt_timer(time):
    if builder.get_object('CHECK_HALT').get_active():
        if not updaterlib.poweroff():
            pwf_id = GLib.timeout_add_seconds(time, os.execlp, 'poweroff', 'poweroff')
            if dialog(first=_("Time to shutdown: ")+ str(pwf_time), second=_("Cancel?"), btn=[Gtk.STOCK_YES, 1, Gtk.STOCK_NO, 0 ] ):
                GLib.Source.remove(pwf_id)
def sysinfo():
  info = {'machine_id': '', 'os_name': '', 'token': '',
          'platform': '', 'build_id': ''}
  try:
    with open(token_file, 'r') as tfile:
      for line in tfile.readlines():
        if len(line.strip()) == 15:
          info['token'] = line.strip()
  except:
    info['token'] = 'not set'

  try:
    with open('/etc/machine-id', 'r') as fmachine:
      for line in fmachine.readlines():
        if len(line.strip()) == 32:
          info['machine_id'] = line.strip()
  except:
    info['machine_id'] = 'not set'

  try:
    with open('/etc/os-release', 'r') as osrelease:
      for line in osrelease.readlines():
        if line.startswith('NAME'):
          info['os_name'] = line.strip().split('=')[1]
        elif line.startswith('VERSION_ID'):
          info['platform'] = line.strip().split('=')[1]
  except:
    info['machine_id'] = 'not set'
    info['platform'] = '2021.1'

  try:
    with open('/var/lib/rosa-iso-info', 'r') as isoinfo:
      for line in isoinfo.readlines():
        if line.startswith('BUILD_ID'):
          info['build_id'] = line.strip().split('=')[1]
  except:
    info['build_id'] = 'not set'
  return info

# функции привязанные к кнопкам и пунктам меню
def fn_indicator_once():
    fn_indicator(ind_app)
    return False

def fn_indicator(ind_app):
    global update_couter
    checkupd()
    updates = ''
    n = 40
    for decoded_line in lastlog:
        if not decoded_line.startswith(' '):
            continue
        try:
            decoded_line.split()[4]
            updates += decoded_line.split()[0] + ' - ' + decoded_line.split()[2] + '\n'
        except:
            pass
        n = n - 1
        if n == 0:
            updates += '...'
            break
    if updates:
        ind_app.set_icon(yellow)
        ind_app.set_title(updates + '\n' + _('Last check: ') + timenow() )
        if window.props.visible:
            notify_send(_('Attention!'), _('Found packages to update'), 'warning', False )
        else:
            notify_send(_('Attention!'), _('Found packages to update'), 'warning', True )
        update_couner = int(time.perf_counter())
        print('auto check')
    if config['timeout'] == 0:
        print('kill timer')
        return False
    return True

def fn_exit(w, data):
  os.remove(lockfile)
  Gtk.main_quit()

def fn_set_token(*args):
  if not set_token():
    return
  os_data = sysinfo()
  if not check_request(os_data):
    fn_set_token()

def fn_get_updates(w, data):
  global timer_id
  global ind_app
  global started
  global update_counter
  global updated
  stoptimers()
  window.show_all()
  if updated:
    updated = False
    update_counter = int(time.perf_counter()) - 100
  else:
    if 'update_counter' in globals():
        timedelta = int(time.perf_counter()) - update_counter
    else:
        timedelta = 100
    print('last check: ' + str(timedelta) + 'sec')
    if  timedelta > 30:
      update_button.hide()
      if not started:
        pwf_button.hide()
        clear()
        GLib.idle_add(fn_indicator_once)
    elif started:
      update_button.hide()
    else:
      clear()
      progress.hide()
      for decoded_line in lastlog:
        echo(decoded_line,  _('Check updates') + ': ' + decoded_line)
      echo('\n',  '{text} ({n}{sec})'.format(text = _('Updates found'), n = str(timedelta), sec = _('sec ago')))
  ind_app.set_status (appindicator.IndicatorStatus.PASSIVE)

def fn_autostart(w, data):
    newfile = True
    enabled = True
    if os.path.exists(os.path.join(autostartdir, 'update_applet.desktop')):
        with open(os.path.join(autostartdir, 'update_applet.desktop'), 'r') as desktop:
            lines = desktop.readlines()
        with open(os.path.join(autostartdir, 'update_applet.desktop'), 'w') as desktop:
            for line in lines:
                line = line.strip()
                if line.startswith('Hidden'):
                    newfile = False
                    if 'true' in line:
                        print('Hidden=false', file=desktop)
                    else:
                        print('Hidden=true', file=desktop)
                        enabled = False
                else:
                    print(line, file=desktop)
            if newfile:
                print('Hidden=true', file=desktop)
                enabled = False
    else:
        if not os.path.exists(autostartdir):
            os.makedirs(autostartdir)
        shutil.copy(desktopfile, os.path.join(autostartdir, 'update_applet.desktop'))
        with open(os.path.join(autostartdir, 'update_applet.desktop'), 'a') as desktop:
            print('Hidden=true', file=desktop)
            enabled = False

    if enabled:
        menu_autostart.set_label(_('Disable autostart'))
    else:
        menu_autostart.set_label(_('Enable autostart'))

#генератор функций для каждого значения в кортеже upd_times
fn_icon_update = {}
def f2(time_):
  global config
  global timer_id
  submenu_icon_item[config['timeout']].set_label( timelabel(config['timeout']) )
  config['timeout'] = time_
  submenu_icon_item[config['timeout']].set_label(timelabel(config['timeout']) + " *" )
  stoptimers()
  runtimer(config['timeout'])
  pickle_write()
for i in config['upd_times']:
  fn_icon_update[i] = lambda x, y, i=i: f2(i)

class Handler:
    def __init__(self):
        clear()
    def on_CHECK_HALT_activate(self, button):
        pass

    def onSUBMIT(self, button):
        if updaterlib.powercheck():
            clear()
            GLib.idle_add(update)
        else:
            notify_send(_('Attention!'), _('The battery charge status is not enough '), 'warning', False )

    def onEXIT(self, button):
        global timer_id
        global updated
        global started
        ind_app.set_status (appindicator.IndicatorStatus.ACTIVE)
        window.hide()
        if started and not updated:
            ind_app.set_icon(yellow)
            ind_app.set_title(_('Update process started...'))
        else:
            clear()
            runtimer(config['timeout'])
        if updated:
            updated = False

# самоубиться если другой экземпляр апплета запущен
lockfile = os.path.join('/run/user', str(os.getuid()), 'update_applet')
proc = ''
if os.path.exists(lockfile):
    with open(lockfile, 'r') as f:
        pid = f.read().strip()
    if os.path.exists(os.path.join('/proc', pid, 'cmdline')):
        with open(os.path.join('/proc', pid, 'cmdline'), 'r') as f:
            proc = f.read().strip()
    else:
        print('remove lock')
        os.remove(lockfile)

if 'update_applet' in proc:
    print('ERROR')
    dialog(first=_('ERROR'), second=_('Another update_applet was found!'), mtype='error')
    quit()

# устанавливаем новый lock файл.
with open(lockfile, 'w') as f:
    print(str(os.getpid()), file=f)

# сбросить настройки если запустить с любым аргументом
if len(sys.argv) > 1:
  print( sys.argv[0], '- tray applet to update sysytem\n')
  if os.path.isfile(f'{cfgdir}/dump'):
      try:
          os.remove(f'{cfgdir}/dump')
      except:
          print('Cannot remove dump')
  if os.path.isfile(f'{autostartdir}/update_applet.desktop'):
      try:
          os.remove(f'{autostartdir}/update_applet.desktop')
      except:
          print('Cannot remove desktop file from autostart dir')
  os.remove(lockfile)
  quit()

if os.path.exists(cfgdir + '/dump'):
  with open(cfgdir + '/dump', 'rb') as f:
    config = pickle.load(f)
else:
  os.makedirs(cfgdir, exist_ok=True)
  pickle_write()

submenu_icon_item = {}

signal.signal(signal.SIGINT, signal.SIG_DFL)
builder = Gtk.Builder()
builder.set_translation_domain(DOMAIN)
builder.add_from_file(UI)

textaria = builder.get_object('TEXTAREA')
textaria.override_font(Pango.FontDescription('Monospace 10'))
textbuffer = textaria.get_buffer()

progress = builder.get_object('PROGRESS')
statusbar = builder.get_object('STATUS')
context_id = statusbar.get_context_id('updater')

label = builder.get_object('LABEL')
label.set_text(_('Updates log:'))

update_button = builder.get_object('SUBMIT')
pwf_button = builder.get_object('CHECK_HALT')
builder.connect_signals(Handler())
scroll = builder.get_object('SCROLL')

window = builder.get_object('window_main')
window.set_icon_from_file(ICON)
window.connect("destroy", Gtk.main_quit)

ind_app = appindicator.Indicator.new (
   "update-status-indicator",
   green,
   appindicator.IndicatorCategory.SYSTEM_SERVICES)
ind_app.set_status (appindicator.IndicatorStatus.ACTIVE)
ind_app.set_title(_("Update applet") + ' ' + updaterlib.get_os_name())

# create a menu
menu = Gtk.Menu()

######## update applet
submenuItem2 = Gtk.MenuItem(label=_('Updates check frequency'))
submenu_icon_update = Gtk.Menu()
submenuItem2.set_submenu(submenu_icon_update)
menu.append(submenuItem2)
submenuItem2.show()
show_icon_update(config['upd_times'])
submenu_icon_item[config['timeout']].set_label(timelabel(config['timeout']) + " *" )

######## updates
menu_updates = Gtk.MenuItem(label=_('Get updates'))
menu_updates.connect("activate", fn_get_updates, '')
menu_updates.show()
menu.append(menu_updates)


######## repository key
if os.path.exists(token_file):
  menu_token = Gtk.MenuItem(label=_('Set token'))
  menu_token.connect("activate", fn_set_token, '')
  menu_token.show()
  menu.append(menu_token)

######### separator
separ = Gtk.SeparatorMenuItem()
menu.append(separ)
separ.show()

######### toggle autostart
if check_autostart():
    autostart_label = (_('Disable autostart'))
else:
    autostart_label = (_('Enable autostart'))
menu_autostart = Gtk.MenuItem(label=autostart_label)
menu_autostart.connect("activate", fn_autostart, '')
menu_autostart.show()
menu.append(menu_autostart)

######### exit
menu_exit = Gtk.MenuItem(label=_('Exit'))
menu_exit.connect("activate", fn_exit, '')
menu_exit.show()
menu.append(menu_exit)

#########
menu.show()
ind_app.set_menu(menu)

first_timeout = 10
if updaterlib.detect_DE == 'plasma':
    # без задержки появления индикатора в трее апплет запускается,
    # но работает не корректно в plasma, причина пока не ясна
    time.sleep(5)
    # увеличена задержка перед первой проверкой обновлений,
    # при одновременном запуске с baloo dnf refresh сильно нагружает
    # систему мешая нормальной загрузке plasma
    first_timeout = 60

if not check_token():
  quit()
once_timer_id = GLib.timeout_add_seconds(first_timeout , first_check)
runtimer(config['timeout'])

Notify.init(app_name=_('Update applet'))
Gtk.main()
