From 370b571a0bdca99d30f3f4106d01887a7db95d00 Mon Sep 17 00:00:00 2001 From: Khaja Nizamuddin Date: Wed, 31 Jul 2019 21:04:34 +0530 Subject: [PATCH 1/7] update popup works --- requirements.txt | 2 + src/main.py | 200 ++++++++++++++++++++++++++++++++++---------- src/res/update.html | 15 ++++ 3 files changed, 174 insertions(+), 43 deletions(-) create mode 100644 src/res/update.html diff --git a/requirements.txt b/requirements.txt index df698fa..e5b9e16 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,5 @@ pyinstaller==3.4.0 wxpython==4.0.3 pyxform==0.14.0 +requests==2.22.0 +packaging==19.1 \ No newline at end of file diff --git a/src/main.py b/src/main.py index 78945c8..38cd38a 100755 --- a/src/main.py +++ b/src/main.py @@ -11,10 +11,15 @@ import wx import worker +import requests +from packaging import version +import threading + # TODO pull out all strings # TODO why is the first button selected - -TITLE = 'ODK XLSForm Offline v1.10.0' +VERSION = 'v1.9.0' +TITLE = 'ODK XLSForm Offline ' + VERSION +GITHUB_RELEASES_API = "https://api.github.com/repos/opendatakit/xlsform-offline/releases/latest" APP_QUIT = 1 APP_ABOUT = 2 @@ -23,6 +28,8 @@ MAIN_WINDOW_HEIGHT = 620 ABOUT_WINDOW_WIDTH = 360 ABOUT_WINDOW_HEIGHT = 335 +UPDATE_WINDOW_WIDTH = 330 +UPDATE_WINDOW_HEIGHT = 135 MAX_PATH_LENGTH = 45 HEADER_SPACER = 6 CHOOSE_BORDER = 5 @@ -34,6 +41,8 @@ MAIN_WINDOW_HEIGHT = 750 ABOUT_WINDOW_WIDTH = 360 ABOUT_WINDOW_HEIGHT = 290 + UPDATE_WINDOW_WIDTH = 330 + UPDATE_WINDOW_HEIGHT = 100 MAX_PATH_LENGTH = 40 HEADER_SPACER = 0 CHOOSE_BORDER = 1 @@ -44,6 +53,62 @@ WORKER_PROGRESS = 'WORKER_PROGRESS' WORKER_PROGRESS_SLEEP = .05 +OS_MAP = { + 'win32': 'windows', + 'darwin': 'macos' +} + + +class UpdateChecker(threading.Thread): + + def get_update_information(self): + response = requests.get(GITHUB_RELEASES_API) + if response.status_code == 200: + json_response = response.json() + latest_version = json_response["tag_name"] + print(latest_version) + if version.parse(latest_version[1:]) > version.parse(VERSION[1:]): + download_url = '' + download_name = '' + for asset in json_response['assets']: + if OS_MAP[sys.platform] in asset['name'].lower(): + download_url = asset['browser_download_url'] + download_name = asset['name'] + + return { + 'update_available': True, + 'latest_version': latest_version, + 'download_url': download_url, + 'download_name': download_name + } + else: + return { + 'update_available': False + } + + +class UpdateAvailableFrame(wx.Frame): + def __init__(self, parent, update_info): + wx.Frame.__init__(self, parent, wx.ID_ANY, title='Update ' + update_info['latest_version'] + ' available', + size=(UPDATE_WINDOW_WIDTH, UPDATE_WINDOW_HEIGHT), + style=wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) + html = HtmlWindow(self) + html.SetStandardFonts() + update_html_path = '' + if getattr(sys, 'frozen', False): + update_html_path = os.path.join(sys._MEIPASS, 'res', 'update.html') + else: + update_html_path = os.path.join('src', 'res', 'update.html') + + update_html_text = '' + with open(update_html_path, 'r') as file: + update_html_text = file.read() + + filled_update_html_text = update_html_text.replace('@latest_version', update_info['latest_version']).replace( + '@download_url', update_info['download_url']).replace('@download_name', update_info['download_name']) + + html.SetPage(filled_update_html_text) + class AboutFrame(wx.Frame): def __init__(self, parent): @@ -52,7 +117,7 @@ def __init__(self, parent): style=wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) html = HtmlWindow(self) html.SetStandardFonts() - about = os.path.join('res','about.html') + about = os.path.join('res', 'about.html') if getattr(sys, 'frozen', False): html.LoadPage(os.path.join(sys._MEIPASS, about)) else: @@ -67,7 +132,8 @@ def OnLinkClicked(self, link): class MainFrame(wx.Frame): def __init__(self, parent, title): super(MainFrame, self).__init__(parent, title=title, - size=(MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT), + size=(MAIN_WINDOW_WIDTH, + MAIN_WINDOW_HEIGHT), style=wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) self.input_file_path = u'' self.output_folder_path = u'' @@ -81,13 +147,16 @@ def __init__(self, parent, title): self.progress_thread = None self.about_window = None + self.update_window = None self.menu_bar = wx.MenuBar() self.file_menu = wx.Menu() self.help_menu = wx.Menu() - self.quit_menu_item = wx.MenuItem(self.file_menu, APP_QUIT, '&Quit\tCtrl+Q') - self.about_menu_item = wx.MenuItem(self.help_menu, APP_ABOUT, '&About ' + TITLE) + self.quit_menu_item = wx.MenuItem( + self.file_menu, APP_QUIT, '&Quit\tCtrl+Q') + self.about_menu_item = wx.MenuItem( + self.help_menu, APP_ABOUT, '&About ' + TITLE) self.file_menu.Append(self.quit_menu_item) self.help_menu.Append(self.about_menu_item) @@ -114,20 +183,26 @@ def __init__(self, parent, title): # header self.header_box_sizer = wx.BoxSizer(wx.HORIZONTAL) self.header_box_sizer.AddStretchSpacer() - self.header_box_sizer.Add(self.about_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5) - self.header_box_sizer.Add(self.quit_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5) + self.header_box_sizer.Add( + self.about_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5) + self.header_box_sizer.Add( + self.quit_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5) # choose input file self.choose_input_static_box = wx.StaticBox(self.parent_panel, label='1. Choose XLSForm (.xls or .xlsx) for conversion') - self.choose_input_static_box_sizer = wx.StaticBoxSizer(self.choose_input_static_box, wx.HORIZONTAL) + self.choose_input_static_box_sizer = wx.StaticBoxSizer( + self.choose_input_static_box, wx.HORIZONTAL) - self.choose_file_button = wx.Button(self.parent_panel, label='Choose file...') + self.choose_file_button = wx.Button( + self.parent_panel, label='Choose file...') self.choose_file_button.Bind(wx.EVT_BUTTON, self.on_open_file) - self.chosen_file_text = wx.StaticText(self.parent_panel, label='', size=(-1, -1)) + self.chosen_file_text = wx.StaticText( + self.parent_panel, label='', size=(-1, -1)) self.choose_file_box_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.choose_file_box_sizer.Add(self.choose_file_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=0) + self.choose_file_box_sizer.Add( + self.choose_file_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=0) self.choose_file_box_sizer.AddSpacer(CHOOSE_SPACER) self.choose_file_box_sizer.Add(self.chosen_file_text, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, @@ -138,15 +213,20 @@ def __init__(self, parent, title): # choose output folder self.choose_folder_label = '2. Choose location for output file(s)' - self.choose_output_static_box = wx.StaticBox(self.parent_panel, label=self.choose_folder_label) - self.choose_output_static_box_sizer = wx.StaticBoxSizer(self.choose_output_static_box, wx.HORIZONTAL) + self.choose_output_static_box = wx.StaticBox( + self.parent_panel, label=self.choose_folder_label) + self.choose_output_static_box_sizer = wx.StaticBoxSizer( + self.choose_output_static_box, wx.HORIZONTAL) - self.choose_folder_button = wx.Button(self.parent_panel, label='Choose location...') + self.choose_folder_button = wx.Button( + self.parent_panel, label='Choose location...') self.choose_folder_button.Bind(wx.EVT_BUTTON, self.on_open_folder) - self.chosen_folder_text = wx.StaticText(self.parent_panel, label='', size=(-1, -1)) + self.chosen_folder_text = wx.StaticText( + self.parent_panel, label='', size=(-1, -1)) self.choose_folder_box_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.choose_folder_box_sizer.Add(self.choose_folder_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=0) + self.choose_folder_box_sizer.Add( + self.choose_folder_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=0) self.choose_folder_box_sizer.AddSpacer(CHOOSE_SPACER) self.choose_folder_box_sizer.Add(self.chosen_folder_text, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, @@ -156,37 +236,50 @@ def __init__(self, parent, title): border=5) # set conversion options - self.set_options_static_box = wx.StaticBox(self.parent_panel, label='3. Set conversion options') - self.set_options_static_box_sizer = wx.StaticBoxSizer(self.set_options_static_box, wx.VERTICAL) + self.set_options_static_box = wx.StaticBox( + self.parent_panel, label='3. Set conversion options') + self.set_options_static_box_sizer = wx.StaticBoxSizer( + self.set_options_static_box, wx.VERTICAL) self.overwrite_label = 'Overwrite existing output file(s)' - self.overwrite_checkbox = wx.CheckBox(self.parent_panel, label=self.overwrite_label, size=(-1, -1)) + self.overwrite_checkbox = wx.CheckBox( + self.parent_panel, label=self.overwrite_label, size=(-1, -1)) self.overwrite_checkbox.SetValue(self.overwrite) - self.Bind(wx.EVT_CHECKBOX, self.toggle_overwrite, id=self.overwrite_checkbox.GetId()) + self.Bind(wx.EVT_CHECKBOX, self.toggle_overwrite, + id=self.overwrite_checkbox.GetId()) self.validate_label = 'Validate converted XForm with ODK Validate' if self.is_java_installed(): self.validate = True - self.validate_checkbox = wx.CheckBox(self.parent_panel, label=self.validate_label, size=(-1, -1)) - self.Bind(wx.EVT_CHECKBOX, self.toggle_validate, id=self.validate_checkbox.GetId()) + self.validate_checkbox = wx.CheckBox( + self.parent_panel, label=self.validate_label, size=(-1, -1)) + self.Bind(wx.EVT_CHECKBOX, self.toggle_validate, + id=self.validate_checkbox.GetId()) else: self.validate = False - self.validate_checkbox = wx.CheckBox(self.parent_panel, label=self.validate_label + ' (Requires Java)') + self.validate_checkbox = wx.CheckBox( + self.parent_panel, label=self.validate_label + ' (Requires Java)') self.validate_checkbox.Disable() - self.Bind(wx.EVT_CHECKBOX, self.toggle_validate, id=self.validate_checkbox.GetId()) + self.Bind(wx.EVT_CHECKBOX, self.toggle_validate, + id=self.validate_checkbox.GetId()) self.validate_checkbox.SetValue(self.validate) - self.set_options_static_box_sizer.Add(self.overwrite_checkbox, flag=wx.LEFT | wx.TOP, border=5) + self.set_options_static_box_sizer.Add( + self.overwrite_checkbox, flag=wx.LEFT | wx.TOP, border=5) self.set_options_static_box_sizer.AddStretchSpacer() - self.set_options_static_box_sizer.Add(self.validate_checkbox, flag=wx.LEFT | wx.TOP, border=5) + self.set_options_static_box_sizer.Add( + self.validate_checkbox, flag=wx.LEFT | wx.TOP, border=5) self.set_options_static_box_sizer.AddStretchSpacer() self.set_options_static_box_sizer.AddSpacer(OPTIONS_SPACER) # start conversion - self.start_conversion_static_box = wx.StaticBox(self.parent_panel, label='4. Run conversion') - self.start_conversion_box_sizer = wx.StaticBoxSizer(self.start_conversion_static_box, wx.VERTICAL) + self.start_conversion_static_box = wx.StaticBox( + self.parent_panel, label='4. Run conversion') + self.start_conversion_box_sizer = wx.StaticBoxSizer( + self.start_conversion_static_box, wx.VERTICAL) - self.status_text_ctrl = wx.TextCtrl(self.parent_panel, size=(-1, 200), style=wx.TE_MULTILINE | wx.TE_LEFT) + self.status_text_ctrl = wx.TextCtrl( + self.parent_panel, size=(-1, 200), style=wx.TE_MULTILINE | wx.TE_LEFT) self.status_text_ctrl.SetEditable(False) self.status_text_ctrl.SetValue(self.status_log) self.status_gauge = wx.Gauge(self.parent_panel, range=1, size=(-1, -1)) @@ -196,7 +289,8 @@ def __init__(self, parent, title): self.action_button.Disable() self.status_gauge_box_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.status_gauge_box_sizer.Add(self.status_gauge, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5) + self.status_gauge_box_sizer.Add( + self.status_gauge, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5) self.status_gauge_box_sizer.AddSpacer(CHOOSE_SPACER) self.status_gauge_box_sizer.Add(self.action_button, proportion=0, flag=wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border=2.5) @@ -204,16 +298,22 @@ def __init__(self, parent, title): self.start_conversion_box_sizer.Add(self.status_gauge_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) - self.start_conversion_box_sizer.Add(self.status_text_ctrl, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + self.start_conversion_box_sizer.Add( + self.status_text_ctrl, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) # build ui self.parent_box_sizer.AddSpacer(15) - self.parent_box_sizer.Add(self.header_box_sizer, proportion=0, flag=wx.EXPAND | wx.RIGHT | wx.LEFT, border=20) + self.parent_box_sizer.Add( + self.header_box_sizer, proportion=0, flag=wx.EXPAND | wx.RIGHT | wx.LEFT, border=20) self.parent_box_sizer.AddSpacer(HEADER_SPACER) - self.parent_box_sizer.Add(self.choose_input_static_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) - self.parent_box_sizer.Add(self.choose_output_static_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) - self.parent_box_sizer.Add(self.set_options_static_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) - self.parent_box_sizer.Add(self.start_conversion_box_sizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + self.parent_box_sizer.Add( + self.choose_input_static_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + self.parent_box_sizer.Add( + self.choose_output_static_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + self.parent_box_sizer.Add( + self.set_options_static_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + self.parent_box_sizer.Add( + self.start_conversion_box_sizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) self.parent_panel.SetSizer(self.parent_box_sizer) worker.evt_result(self, self.on_result) @@ -222,6 +322,8 @@ def __init__(self, parent, title): self.Centre() self.Show() + self.check_update_and_show() + @staticmethod def shorten_string(string, max_length): if len(string) >= max_length: @@ -242,9 +344,11 @@ def on_open_file(self, e): dlg.CentreOnParent() if dlg.ShowModal() == wx.ID_OK: self.input_file_path = dlg.GetPath() - self.chosen_file_text.SetLabel(self.shorten_string(self.input_file_path, MAX_PATH_LENGTH)) + self.chosen_file_text.SetLabel(self.shorten_string( + self.input_file_path, MAX_PATH_LENGTH)) self.output_folder_path = ntpath.dirname(self.input_file_path) - self.chosen_folder_text.SetLabel(self.shorten_string(self.output_folder_path, MAX_PATH_LENGTH)) + self.chosen_folder_text.SetLabel(self.shorten_string( + self.output_folder_path, MAX_PATH_LENGTH)) if self.input_file_path and self.output_folder_path: self.action_button.Enable() else: @@ -262,7 +366,8 @@ def on_open_folder(self, e): dlg.CentreOnParent() if dlg.ShowModal() == wx.ID_OK: self.output_folder_path = dlg.GetPath() - self.chosen_folder_text.SetLabel(self.shorten_string(self.output_folder_path, MAX_PATH_LENGTH)) + self.chosen_folder_text.SetLabel(self.shorten_string( + self.output_folder_path, MAX_PATH_LENGTH)) if self.input_file_path and self.output_folder_path: self.action_button.Enable() else: @@ -301,7 +406,8 @@ def on_about(self, e): def on_result(self, event): if event.data is WORKER_FINISH: self.progress_thread.abort() - self.status_text_ctrl.AppendText('-----------------------------------------------------\n\n') + self.status_text_ctrl.AppendText( + '-----------------------------------------------------\n\n') self.action_button.Enable() self.enable_ui(True) self.action_button.SetLabel('Run') @@ -314,6 +420,15 @@ def on_progress(self, event): if self.result_thread is not None and self.result_thread.isAlive(): self.status_gauge.Pulse() + def check_update_and_show(self): + update_info = UpdateChecker().get_update_information() + + if self.update_window: + self.update_window.Close() + self.update_window = UpdateAvailableFrame(None, update_info) + self.update_window.Centre() + self.update_window.Show() + @staticmethod def is_java_installed(): @@ -334,7 +449,6 @@ def is_java_installed(): return java_version and java_regex.match(java_version) - def enable_ui(self, enable): # Turns UI elements on and off self.choose_file_button.Enable(enable) @@ -348,4 +462,4 @@ def enable_ui(self, enable): app = wx.App() app.SetAppName(TITLE) MainFrame(None, title=TITLE) - app.MainLoop() \ No newline at end of file + app.MainLoop() diff --git a/src/res/update.html b/src/res/update.html new file mode 100644 index 0000000..958cdb4 --- /dev/null +++ b/src/res/update.html @@ -0,0 +1,15 @@ + + + + + + + + +

+ Update @latest_version is available. Click to download.

+ @download_name +

+ + + \ No newline at end of file From def9d275139624a72aa54281ec5e23e489f73f28 Mon Sep 17 00:00:00 2001 From: Khaja Nizamuddin Date: Wed, 31 Jul 2019 21:12:32 +0530 Subject: [PATCH 2/7] timeout added and bg thread done. --- src/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.py b/src/main.py index 38cd38a..d4a396a 100755 --- a/src/main.py +++ b/src/main.py @@ -62,7 +62,7 @@ class UpdateChecker(threading.Thread): def get_update_information(self): - response = requests.get(GITHUB_RELEASES_API) + response = requests.get(GITHUB_RELEASES_API, timeout=30) if response.status_code == 200: json_response = response.json() latest_version = json_response["tag_name"] @@ -322,7 +322,7 @@ def __init__(self, parent, title): self.Centre() self.Show() - self.check_update_and_show() + threading.Thread(target=self.check_update_and_show, args=()).start() @staticmethod def shorten_string(string, max_length): From 70be534db0515159fd627aaa971179493364710e Mon Sep 17 00:00:00 2001 From: NizamLZ Date: Fri, 2 Aug 2019 22:47:28 +0530 Subject: [PATCH 3/7] update checker works in background --- src/main.py | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/main.py b/src/main.py index d4a396a..c905bd8 100755 --- a/src/main.py +++ b/src/main.py @@ -58,10 +58,25 @@ 'darwin': 'macos' } +update_checker_event = wx.NewEventType() +on_update_checker_done = wx.PyEventBinder(update_checker_event, 1) + + +class UpdateCheckDoneEvent(wx.PyCommandEvent): + def __init__(self, etype, eid, value=None): + wx.PyCommandEvent.__init__(self, etype, eid) + self.update_info = value + + def GetUpdateInfo(self): + return self.update_info + class UpdateChecker(threading.Thread): + def __init__(self, parent): + threading.Thread.__init__(self) + self._parent = parent - def get_update_information(self): + def run(self): response = requests.get(GITHUB_RELEASES_API, timeout=30) if response.status_code == 200: json_response = response.json() @@ -74,17 +89,18 @@ def get_update_information(self): if OS_MAP[sys.platform] in asset['name'].lower(): download_url = asset['browser_download_url'] download_name = asset['name'] + break - return { + wx.PostEvent(self._parent, UpdateCheckDoneEvent(update_checker_event, -1, { 'update_available': True, 'latest_version': latest_version, 'download_url': download_url, 'download_name': download_name - } + })) else: - return { + wx.PostEvent(self._parent, UpdateCheckDoneEvent(update_checker_event, -1, { 'update_available': False - } + })) class UpdateAvailableFrame(wx.Frame): @@ -322,7 +338,8 @@ def __init__(self, parent, title): self.Centre() self.Show() - threading.Thread(target=self.check_update_and_show, args=()).start() + self.Bind(on_update_checker_done, self.check_update_and_show) + UpdateChecker(self).start() @staticmethod def shorten_string(string, max_length): @@ -420,12 +437,10 @@ def on_progress(self, event): if self.result_thread is not None and self.result_thread.isAlive(): self.status_gauge.Pulse() - def check_update_and_show(self): - update_info = UpdateChecker().get_update_information() - + def check_update_and_show(self, event): if self.update_window: self.update_window.Close() - self.update_window = UpdateAvailableFrame(None, update_info) + self.update_window = UpdateAvailableFrame(None, event.GetUpdateInfo()) self.update_window.Centre() self.update_window.Show() From af605bd39ae974d8484fb2fce6e45b41719bcdbe Mon Sep 17 00:00:00 2001 From: NizamLZ Date: Fri, 2 Aug 2019 23:05:38 +0530 Subject: [PATCH 4/7] update checker moved to another file --- src/main.py | 68 ++++++++----------------------------------- src/update_checker.py | 66 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 56 deletions(-) create mode 100644 src/update_checker.py diff --git a/src/main.py b/src/main.py index c905bd8..4f62be9 100755 --- a/src/main.py +++ b/src/main.py @@ -10,6 +10,7 @@ import wx import worker +import update_checker import requests from packaging import version @@ -17,9 +18,8 @@ # TODO pull out all strings # TODO why is the first button selected -VERSION = 'v1.9.0' +VERSION = 'v1.11.0' TITLE = 'ODK XLSForm Offline ' + VERSION -GITHUB_RELEASES_API = "https://api.github.com/repos/opendatakit/xlsform-offline/releases/latest" APP_QUIT = 1 APP_ABOUT = 2 @@ -53,55 +53,6 @@ WORKER_PROGRESS = 'WORKER_PROGRESS' WORKER_PROGRESS_SLEEP = .05 -OS_MAP = { - 'win32': 'windows', - 'darwin': 'macos' -} - -update_checker_event = wx.NewEventType() -on_update_checker_done = wx.PyEventBinder(update_checker_event, 1) - - -class UpdateCheckDoneEvent(wx.PyCommandEvent): - def __init__(self, etype, eid, value=None): - wx.PyCommandEvent.__init__(self, etype, eid) - self.update_info = value - - def GetUpdateInfo(self): - return self.update_info - - -class UpdateChecker(threading.Thread): - def __init__(self, parent): - threading.Thread.__init__(self) - self._parent = parent - - def run(self): - response = requests.get(GITHUB_RELEASES_API, timeout=30) - if response.status_code == 200: - json_response = response.json() - latest_version = json_response["tag_name"] - print(latest_version) - if version.parse(latest_version[1:]) > version.parse(VERSION[1:]): - download_url = '' - download_name = '' - for asset in json_response['assets']: - if OS_MAP[sys.platform] in asset['name'].lower(): - download_url = asset['browser_download_url'] - download_name = asset['name'] - break - - wx.PostEvent(self._parent, UpdateCheckDoneEvent(update_checker_event, -1, { - 'update_available': True, - 'latest_version': latest_version, - 'download_url': download_url, - 'download_name': download_name - })) - else: - wx.PostEvent(self._parent, UpdateCheckDoneEvent(update_checker_event, -1, { - 'update_available': False - })) - class UpdateAvailableFrame(wx.Frame): def __init__(self, parent, update_info): @@ -338,8 +289,9 @@ def __init__(self, parent, title): self.Centre() self.Show() - self.Bind(on_update_checker_done, self.check_update_and_show) - UpdateChecker(self).start() + update_checker.evt_update_check_done(self, self.check_update_and_show) + + update_checker.UpdateChecker(self, VERSION).start() @staticmethod def shorten_string(string, max_length): @@ -412,6 +364,8 @@ def on_quit(self, e): self.Destroy() if self.about_window: self.about_window.Close() + if self.update_window: + self.update_window.Close() def on_about(self, e): if self.about_window: @@ -440,9 +394,11 @@ def on_progress(self, event): def check_update_and_show(self, event): if self.update_window: self.update_window.Close() - self.update_window = UpdateAvailableFrame(None, event.GetUpdateInfo()) - self.update_window.Centre() - self.update_window.Show() + + if event.data['update_available']: + self.update_window = UpdateAvailableFrame(None, event.data) + self.update_window.Centre() + self.update_window.Show() @staticmethod def is_java_installed(): diff --git a/src/update_checker.py b/src/update_checker.py new file mode 100644 index 0000000..2c022ca --- /dev/null +++ b/src/update_checker.py @@ -0,0 +1,66 @@ +import wx +import sys + +import requests +from packaging import version +import threading + +GITHUB_RELEASES_API = "https://api.github.com/repos/opendatakit/xlsform-offline/releases/latest" + +OS_MAP = { + 'win32': 'windows', + 'darwin': 'macos' +} + +EVT_UPDATE_CHECKER = wx.NewId() + + +def evt_update_check_done(win, func): + '''Define Update Check Done Event.''' + win.Connect(-1, -1, EVT_UPDATE_CHECKER, func) + + +class UpdateCheckDoneEvent(wx.PyEvent): + '''Simple event to check for updates.''' + + def __init__(self, data): + '''Init Update Check Done Event.''' + wx.PyEvent.__init__(self) + self.SetEventType(EVT_UPDATE_CHECKER) + self.data = data + + +class UpdateChecker(threading.Thread): + def __init__(self, parent, current_version): + threading.Thread.__init__(self) + self._parent = parent + self._current_version = current_version + + def run(self): + try: + response = requests.get(GITHUB_RELEASES_API, timeout=30) + if response.status_code == 200: + json_response = response.json() + latest_version = json_response["tag_name"] + print(latest_version) + if version.parse(latest_version[1:]) > version.parse(self._current_version[1:]): + download_url = '' + download_name = '' + for asset in json_response['assets']: + if OS_MAP[sys.platform] in asset['name'].lower(): + download_url = asset['browser_download_url'] + download_name = asset['name'] + break + + wx.PostEvent(self._parent, UpdateCheckDoneEvent({ + 'update_available': True, + 'latest_version': latest_version, + 'download_url': download_url, + 'download_name': download_name + })) + else: + wx.PostEvent(self._parent, UpdateCheckDoneEvent({ + 'update_available': False + })) + except Exception as ex: + pass From 94e193c4960d76f8ca2abccdaa8dddb40a2a295b Mon Sep 17 00:00:00 2001 From: NizamLZ Date: Fri, 2 Aug 2019 23:50:20 +0530 Subject: [PATCH 5/7] Show github release desciption as update description --- requirements.txt | 3 ++- src/main.py | 10 +++++----- src/res/update.html | 22 +++++++++++++--------- src/update_checker.py | 5 ++++- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/requirements.txt b/requirements.txt index e5b9e16..2bd3e2a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ pyinstaller==3.4.0 wxpython==4.0.3 pyxform==0.14.0 requests==2.22.0 -packaging==19.1 \ No newline at end of file +packaging==19.1 +markdown2==2.3.8 \ No newline at end of file diff --git a/src/main.py b/src/main.py index 4f62be9..fa8bce5 100755 --- a/src/main.py +++ b/src/main.py @@ -28,8 +28,8 @@ MAIN_WINDOW_HEIGHT = 620 ABOUT_WINDOW_WIDTH = 360 ABOUT_WINDOW_HEIGHT = 335 -UPDATE_WINDOW_WIDTH = 330 -UPDATE_WINDOW_HEIGHT = 135 +UPDATE_WINDOW_WIDTH = 360 +UPDATE_WINDOW_HEIGHT = 335 MAX_PATH_LENGTH = 45 HEADER_SPACER = 6 CHOOSE_BORDER = 5 @@ -41,8 +41,8 @@ MAIN_WINDOW_HEIGHT = 750 ABOUT_WINDOW_WIDTH = 360 ABOUT_WINDOW_HEIGHT = 290 - UPDATE_WINDOW_WIDTH = 330 - UPDATE_WINDOW_HEIGHT = 100 + UPDATE_WINDOW_WIDTH = 360 + UPDATE_WINDOW_HEIGHT = 290 MAX_PATH_LENGTH = 40 HEADER_SPACER = 0 CHOOSE_BORDER = 1 @@ -71,7 +71,7 @@ def __init__(self, parent, update_info): with open(update_html_path, 'r') as file: update_html_text = file.read() - filled_update_html_text = update_html_text.replace('@latest_version', update_info['latest_version']).replace( + filled_update_html_text = update_html_text.replace('@desc', update_info['update_desc']).replace( '@download_url', update_info['download_url']).replace('@download_name', update_info['download_name']) html.SetPage(filled_update_html_text) diff --git a/src/res/update.html b/src/res/update.html index 958cdb4..06f7de7 100644 --- a/src/res/update.html +++ b/src/res/update.html @@ -1,15 +1,19 @@ - - - + + + - -

- Update @latest_version is available. Click to download.

- @download_name -

- + +

+ @desc +
+
+
+ Download
+ @download_name +

+ \ No newline at end of file diff --git a/src/update_checker.py b/src/update_checker.py index 2c022ca..bccffd5 100644 --- a/src/update_checker.py +++ b/src/update_checker.py @@ -4,6 +4,7 @@ import requests from packaging import version import threading +import markdown2 GITHUB_RELEASES_API = "https://api.github.com/repos/opendatakit/xlsform-offline/releases/latest" @@ -56,11 +57,13 @@ def run(self): 'update_available': True, 'latest_version': latest_version, 'download_url': download_url, - 'download_name': download_name + 'download_name': download_name, + 'update_desc': markdown2.markdown(json_response["body"].replace('\n', '
')) })) else: wx.PostEvent(self._parent, UpdateCheckDoneEvent({ 'update_available': False })) except Exception as ex: + print ex pass From 3d860484d75404df0334a166eec1317a9c43db4f Mon Sep 17 00:00:00 2001 From: NizamLZ Date: Sat, 3 Aug 2019 14:37:34 +0530 Subject: [PATCH 6/7] Fix line wraps created by the formatter. --- src/main.py | 115 +++++++++++++++++----------------------------------- 1 file changed, 38 insertions(+), 77 deletions(-) diff --git a/src/main.py b/src/main.py index fa8bce5..b5fa46f 100755 --- a/src/main.py +++ b/src/main.py @@ -99,8 +99,7 @@ def OnLinkClicked(self, link): class MainFrame(wx.Frame): def __init__(self, parent, title): super(MainFrame, self).__init__(parent, title=title, - size=(MAIN_WINDOW_WIDTH, - MAIN_WINDOW_HEIGHT), + size=(MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT), style=wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) self.input_file_path = u'' self.output_folder_path = u'' @@ -120,10 +119,8 @@ def __init__(self, parent, title): self.file_menu = wx.Menu() self.help_menu = wx.Menu() - self.quit_menu_item = wx.MenuItem( - self.file_menu, APP_QUIT, '&Quit\tCtrl+Q') - self.about_menu_item = wx.MenuItem( - self.help_menu, APP_ABOUT, '&About ' + TITLE) + self.quit_menu_item = wx.MenuItem(self.file_menu, APP_QUIT, '&Quit\tCtrl+Q') + self.about_menu_item = wx.MenuItem(self.help_menu, APP_ABOUT, '&About ' + TITLE) self.file_menu.Append(self.quit_menu_item) self.help_menu.Append(self.about_menu_item) @@ -150,26 +147,20 @@ def __init__(self, parent, title): # header self.header_box_sizer = wx.BoxSizer(wx.HORIZONTAL) self.header_box_sizer.AddStretchSpacer() - self.header_box_sizer.Add( - self.about_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5) - self.header_box_sizer.Add( - self.quit_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5) + self.header_box_sizer.Add(self.about_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5) + self.header_box_sizer.Add(self.quit_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5) # choose input file self.choose_input_static_box = wx.StaticBox(self.parent_panel, label='1. Choose XLSForm (.xls or .xlsx) for conversion') - self.choose_input_static_box_sizer = wx.StaticBoxSizer( - self.choose_input_static_box, wx.HORIZONTAL) + self.choose_input_static_box_sizer = wx.StaticBoxSizer(self.choose_input_static_box, wx.HORIZONTAL) - self.choose_file_button = wx.Button( - self.parent_panel, label='Choose file...') + self.choose_file_button = wx.Button(self.parent_panel, label='Choose file...') self.choose_file_button.Bind(wx.EVT_BUTTON, self.on_open_file) - self.chosen_file_text = wx.StaticText( - self.parent_panel, label='', size=(-1, -1)) + self.chosen_file_text = wx.StaticText(self.parent_panel, label='', size=(-1, -1)) self.choose_file_box_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.choose_file_box_sizer.Add( - self.choose_file_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=0) + self.choose_file_box_sizer.Add(self.choose_file_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=0) self.choose_file_box_sizer.AddSpacer(CHOOSE_SPACER) self.choose_file_box_sizer.Add(self.chosen_file_text, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, @@ -180,20 +171,15 @@ def __init__(self, parent, title): # choose output folder self.choose_folder_label = '2. Choose location for output file(s)' - self.choose_output_static_box = wx.StaticBox( - self.parent_panel, label=self.choose_folder_label) - self.choose_output_static_box_sizer = wx.StaticBoxSizer( - self.choose_output_static_box, wx.HORIZONTAL) + self.choose_output_static_box = wx.StaticBox(self.parent_panel, label=self.choose_folder_label) + self.choose_output_static_box_sizer = wx.StaticBoxSizer(self.choose_output_static_box, wx.HORIZONTAL) - self.choose_folder_button = wx.Button( - self.parent_panel, label='Choose location...') + self.choose_folder_button = wx.Button(self.parent_panel, label='Choose location...') self.choose_folder_button.Bind(wx.EVT_BUTTON, self.on_open_folder) - self.chosen_folder_text = wx.StaticText( - self.parent_panel, label='', size=(-1, -1)) + self.chosen_folder_text = wx.StaticText(self.parent_panel, label='', size=(-1, -1)) self.choose_folder_box_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.choose_folder_box_sizer.Add( - self.choose_folder_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=0) + self.choose_folder_box_sizer.Add(self.choose_folder_button, proportion=0, flag=wx.LEFT | wx.RIGHT, border=0) self.choose_folder_box_sizer.AddSpacer(CHOOSE_SPACER) self.choose_folder_box_sizer.Add(self.chosen_folder_text, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, @@ -203,50 +189,37 @@ def __init__(self, parent, title): border=5) # set conversion options - self.set_options_static_box = wx.StaticBox( - self.parent_panel, label='3. Set conversion options') - self.set_options_static_box_sizer = wx.StaticBoxSizer( - self.set_options_static_box, wx.VERTICAL) + self.set_options_static_box = wx.StaticBox(self.parent_panel, label='3. Set conversion options') + self.set_options_static_box_sizer = wx.StaticBoxSizer(self.set_options_static_box, wx.VERTICAL) self.overwrite_label = 'Overwrite existing output file(s)' - self.overwrite_checkbox = wx.CheckBox( - self.parent_panel, label=self.overwrite_label, size=(-1, -1)) + self.overwrite_checkbox = wx.CheckBox(self.parent_panel, label=self.overwrite_label, size=(-1, -1)) self.overwrite_checkbox.SetValue(self.overwrite) - self.Bind(wx.EVT_CHECKBOX, self.toggle_overwrite, - id=self.overwrite_checkbox.GetId()) + self.Bind(wx.EVT_CHECKBOX, self.toggle_overwrite, id=self.overwrite_checkbox.GetId()) self.validate_label = 'Validate converted XForm with ODK Validate' if self.is_java_installed(): self.validate = True - self.validate_checkbox = wx.CheckBox( - self.parent_panel, label=self.validate_label, size=(-1, -1)) - self.Bind(wx.EVT_CHECKBOX, self.toggle_validate, - id=self.validate_checkbox.GetId()) + self.validate_checkbox = wx.CheckBox(self.parent_panel, label=self.validate_label, size=(-1, -1)) + self.Bind(wx.EVT_CHECKBOX, self.toggle_validate, id=self.validate_checkbox.GetId()) else: self.validate = False - self.validate_checkbox = wx.CheckBox( - self.parent_panel, label=self.validate_label + ' (Requires Java)') + self.validate_checkbox = wx.CheckBox(self.parent_panel, label=self.validate_label + ' (Requires Java)') self.validate_checkbox.Disable() - self.Bind(wx.EVT_CHECKBOX, self.toggle_validate, - id=self.validate_checkbox.GetId()) + self.Bind(wx.EVT_CHECKBOX, self.toggle_validate, id=self.validate_checkbox.GetId()) self.validate_checkbox.SetValue(self.validate) - self.set_options_static_box_sizer.Add( - self.overwrite_checkbox, flag=wx.LEFT | wx.TOP, border=5) + self.set_options_static_box_sizer.Add(self.overwrite_checkbox, flag=wx.LEFT | wx.TOP, border=5) self.set_options_static_box_sizer.AddStretchSpacer() - self.set_options_static_box_sizer.Add( - self.validate_checkbox, flag=wx.LEFT | wx.TOP, border=5) + self.set_options_static_box_sizer.Add(self.validate_checkbox, flag=wx.LEFT | wx.TOP, border=5) self.set_options_static_box_sizer.AddStretchSpacer() self.set_options_static_box_sizer.AddSpacer(OPTIONS_SPACER) # start conversion - self.start_conversion_static_box = wx.StaticBox( - self.parent_panel, label='4. Run conversion') - self.start_conversion_box_sizer = wx.StaticBoxSizer( - self.start_conversion_static_box, wx.VERTICAL) + self.start_conversion_static_box = wx.StaticBox(self.parent_panel, label='4. Run conversion') + self.start_conversion_box_sizer = wx.StaticBoxSizer(self.start_conversion_static_box, wx.VERTICAL) - self.status_text_ctrl = wx.TextCtrl( - self.parent_panel, size=(-1, 200), style=wx.TE_MULTILINE | wx.TE_LEFT) + self.status_text_ctrl = wx.TextCtrl(self.parent_panel, size=(-1, 200), style=wx.TE_MULTILINE | wx.TE_LEFT) self.status_text_ctrl.SetEditable(False) self.status_text_ctrl.SetValue(self.status_log) self.status_gauge = wx.Gauge(self.parent_panel, range=1, size=(-1, -1)) @@ -256,8 +229,7 @@ def __init__(self, parent, title): self.action_button.Disable() self.status_gauge_box_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.status_gauge_box_sizer.Add( - self.status_gauge, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5) + self.status_gauge_box_sizer.Add(self.status_gauge, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5) self.status_gauge_box_sizer.AddSpacer(CHOOSE_SPACER) self.status_gauge_box_sizer.Add(self.action_button, proportion=0, flag=wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border=2.5) @@ -265,22 +237,16 @@ def __init__(self, parent, title): self.start_conversion_box_sizer.Add(self.status_gauge_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) - self.start_conversion_box_sizer.Add( - self.status_text_ctrl, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + self.start_conversion_box_sizer.Add(self.status_text_ctrl, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) # build ui self.parent_box_sizer.AddSpacer(15) - self.parent_box_sizer.Add( - self.header_box_sizer, proportion=0, flag=wx.EXPAND | wx.RIGHT | wx.LEFT, border=20) + self.parent_box_sizer.Add(self.header_box_sizer, proportion=0, flag=wx.EXPAND | wx.RIGHT | wx.LEFT, border=20) self.parent_box_sizer.AddSpacer(HEADER_SPACER) - self.parent_box_sizer.Add( - self.choose_input_static_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) - self.parent_box_sizer.Add( - self.choose_output_static_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) - self.parent_box_sizer.Add( - self.set_options_static_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) - self.parent_box_sizer.Add( - self.start_conversion_box_sizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + self.parent_box_sizer.Add(self.choose_input_static_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + self.parent_box_sizer.Add(self.choose_output_static_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + self.parent_box_sizer.Add(self.set_options_static_box_sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + self.parent_box_sizer.Add(self.start_conversion_box_sizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) self.parent_panel.SetSizer(self.parent_box_sizer) worker.evt_result(self, self.on_result) @@ -290,7 +256,6 @@ def __init__(self, parent, title): self.Show() update_checker.evt_update_check_done(self, self.check_update_and_show) - update_checker.UpdateChecker(self, VERSION).start() @staticmethod @@ -313,11 +278,9 @@ def on_open_file(self, e): dlg.CentreOnParent() if dlg.ShowModal() == wx.ID_OK: self.input_file_path = dlg.GetPath() - self.chosen_file_text.SetLabel(self.shorten_string( - self.input_file_path, MAX_PATH_LENGTH)) + self.chosen_file_text.SetLabel(self.shorten_string(self.input_file_path, MAX_PATH_LENGTH)) self.output_folder_path = ntpath.dirname(self.input_file_path) - self.chosen_folder_text.SetLabel(self.shorten_string( - self.output_folder_path, MAX_PATH_LENGTH)) + self.chosen_folder_text.SetLabel(self.shorten_string(self.output_folder_path, MAX_PATH_LENGTH)) if self.input_file_path and self.output_folder_path: self.action_button.Enable() else: @@ -335,8 +298,7 @@ def on_open_folder(self, e): dlg.CentreOnParent() if dlg.ShowModal() == wx.ID_OK: self.output_folder_path = dlg.GetPath() - self.chosen_folder_text.SetLabel(self.shorten_string( - self.output_folder_path, MAX_PATH_LENGTH)) + self.chosen_folder_text.SetLabel(self.shorten_string(self.output_folder_path, MAX_PATH_LENGTH)) if self.input_file_path and self.output_folder_path: self.action_button.Enable() else: @@ -377,8 +339,7 @@ def on_about(self, e): def on_result(self, event): if event.data is WORKER_FINISH: self.progress_thread.abort() - self.status_text_ctrl.AppendText( - '-----------------------------------------------------\n\n') + self.status_text_ctrl.AppendText('-----------------------------------------------------\n\n') self.action_button.Enable() self.enable_ui(True) self.action_button.SetLabel('Run') From e3307193834d92717757f04a8dc0de48dce21a76 Mon Sep 17 00:00:00 2001 From: NizamLZ Date: Sat, 3 Aug 2019 14:44:15 +0530 Subject: [PATCH 7/7] remove print statement --- src/update_checker.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/update_checker.py b/src/update_checker.py index bccffd5..da06feb 100644 --- a/src/update_checker.py +++ b/src/update_checker.py @@ -43,7 +43,6 @@ def run(self): if response.status_code == 200: json_response = response.json() latest_version = json_response["tag_name"] - print(latest_version) if version.parse(latest_version[1:]) > version.parse(self._current_version[1:]): download_url = '' download_name = ''