1313
1414from mpos .apps import Activity , Intent
1515import mpos .ui
16+ from mpos .package_manager import PackageManager
17+
1618
1719class AppStore (Activity ):
1820 apps = []
@@ -250,7 +252,7 @@ def onCreate(self):
250252 self .install_label = lv .label (self .install_button )
251253 self .install_label .center ()
252254 self .set_install_label (app .fullname )
253- if self .is_update_available (app .fullname , app .version ):
255+ if PackageManager .is_update_available (app .fullname , app .version ):
254256 self .install_button .set_size (lv .pct (47 ), 40 ) # make space for update button
255257 print ("Update available, adding update button." )
256258 self .update_button = lv .button (buttoncont )
@@ -285,10 +287,10 @@ def set_install_label(self, app_fullname):
285287 # - update is separate button, only shown if already installed and new version
286288 is_installed = True
287289 update_available = False
288- builtin_app = self .is_builtin_app (app_fullname )
289- overridden_builtin_app = self .is_overridden_builtin_app (app_fullname )
290+ builtin_app = PackageManager .is_builtin_app (app_fullname )
291+ overridden_builtin_app = PackageManager .is_overridden_builtin_app (app_fullname )
290292 if not overridden_builtin_app :
291- is_installed = AppDetail .is_installed_by_name (app_fullname )
293+ is_installed = PackageManager .is_installed_by_name (app_fullname )
292294 if is_installed :
293295 if builtin_app :
294296 if overridden_builtin_app :
@@ -308,49 +310,43 @@ def toggle_install(self, download_url, fullname):
308310 if label_text == self .action_label_install :
309311 try :
310312 _thread .stack_size (mpos .apps .good_stack_size ())
311- _thread .start_new_thread (self .download_and_unzip , (download_url , f"apps/{ fullname } " , fullname ))
313+ _thread .start_new_thread (self .download_and_install , (download_url , f"apps/{ fullname } " , fullname ))
312314 except Exception as e :
313- print ("Could not start download_and_unzip thread: " , e )
315+ print ("Could not start download_and_install thread: " , e )
314316 elif label_text == self .action_label_uninstall or label_text == self .action_label_restore :
315317 print ("Uninstalling app...." )
316318 try :
317319 _thread .stack_size (mpos .apps .good_stack_size ())
318- _thread .start_new_thread (self .uninstall_app , (f"apps/ { fullname } " , fullname ))
320+ _thread .start_new_thread (self .uninstall_app , (fullname ))
319321 except Exception as e :
320- print ("Could not start download_and_unzip thread: " , e )
322+ print ("Could not start uninstall_app thread: " , e )
321323
322324 def update_button_click (self , download_url , fullname ):
323325 print (f"Update button clicked for { download_url } and fullname { fullname } " )
324326 self .update_button .add_flag (lv .obj .FLAG .HIDDEN )
325327 self .install_button .set_size (lv .pct (100 ), 40 )
326328 try :
327329 _thread .stack_size (mpos .apps .good_stack_size ())
328- _thread .start_new_thread (self .download_and_unzip , (download_url , f"apps/{ fullname } " , fullname ))
330+ _thread .start_new_thread (self .download_and_install , (download_url , f"apps/{ fullname } " , fullname ))
329331 except Exception as e :
330- print ("Could not start download_and_unzip thread: " , e )
331-
332- def uninstall_app (self , app_folder , app_fullname ):
332+ print ("Could not start download_and_install thread: " , e )
333+
334+ def uninstall_app (self , app_fullname ):
333335 self .install_button .add_state (lv .STATE .DISABLED )
334336 self .install_label .set_text ("Please wait..." ) # TODO: Put "Cancel" if cancellation is possible
335337 self .progress_bar .remove_flag (lv .obj .FLAG .HIDDEN )
336- self .progress_bar .set_value (33 , True )
337- try :
338- import shutil
339- shutil .rmtree (app_folder )
340- self .progress_bar .set_value (66 , True )
341- except Exception as e :
342- print (f"Removing app_folder { app_folder } got error: { e } " )
338+ self .progress_bar .set_value (42 , True )
339+ PackageManager .uninstall_app (app_fullname )
343340 self .progress_bar .set_value (100 , False )
344341 self .progress_bar .add_flag (lv .obj .FLAG .HIDDEN )
345342 self .progress_bar .set_value (0 , False )
346343 self .set_install_label (app_fullname )
347344 self .install_button .remove_state (lv .STATE .DISABLED )
348- if self .is_builtin_app (app_fullname ):
345+ if PackageManager .is_builtin_app (app_fullname ):
349346 self .update_button .remove_flag (lv .obj .FLAG .HIDDEN )
350347 self .install_button .set_size (lv .pct (47 ), 40 ) # if a builtin app was removed, then it was overridden, and a new version is available, so make space for update button
351-
352348
353- def download_and_unzip (self , zip_url , dest_folder , app_fullname ):
349+ def download_and_install (self , zip_url , dest_folder , app_fullname ):
354350 self .install_button .add_state (lv .STATE .DISABLED )
355351 self .install_label .set_text ("Please wait..." ) # TODO: Put "Cancel" if cancellation is possible
356352 self .progress_bar .remove_flag (lv .obj .FLAG .HIDDEN )
@@ -387,86 +383,11 @@ def download_and_unzip(self, zip_url, dest_folder, app_fullname):
387383 finally :
388384 if 'response' in locals ():
389385 response .close ()
390- try :
391- # Step 2: Unzip the file
392- print ("Unzipping it to:" , dest_folder )
393- with zipfile .ZipFile (temp_zip_path , "r" ) as zip_ref :
394- zip_ref .extractall (dest_folder )
395- self .progress_bar .set_value (80 , True )
396- print ("Unzipped successfully" )
397- # Step 3: Clean up
398- os .remove (temp_zip_path )
399- print ("Removed temporary .mpk file" )
400- except Exception as e :
401- print (f"Unzip and cleanup failed: { e } " )
402- # Would be good to show error message here if it fails...
386+ # Step 2: install it:
387+ PackageManager .install_mpk (temp_zip_path , dest_folder )
403388 # Success:
404389 self .progress_bar .set_value (100 , False )
405390 self .progress_bar .add_flag (lv .obj .FLAG .HIDDEN )
406391 self .progress_bar .set_value (0 , False )
407392 self .set_install_label (app_fullname )
408393 self .install_button .remove_state (lv .STATE .DISABLED )
409-
410- @staticmethod
411- def compare_versions (ver1 : str , ver2 : str ) -> bool :
412- """Compare two version numbers (e.g., '1.2.3' vs '4.5.6').
413- Returns True if ver1 is greater than ver2, False otherwise."""
414- print (f"Comparing versions: { ver1 } vs { ver2 } " )
415- v1_parts = [int (x ) for x in ver1 .split ('.' )]
416- v2_parts = [int (x ) for x in ver2 .split ('.' )]
417- print (f"Version 1 parts: { v1_parts } " )
418- print (f"Version 2 parts: { v2_parts } " )
419- for i in range (max (len (v1_parts ), len (v2_parts ))):
420- v1 = v1_parts [i ] if i < len (v1_parts ) else 0
421- v2 = v2_parts [i ] if i < len (v2_parts ) else 0
422- print (f"Comparing part { i } : { v1 } vs { v2 } " )
423- if v1 > v2 :
424- print (f"{ ver1 } is greater than { ver2 } " )
425- return True
426- if v1 < v2 :
427- print (f"{ ver1 } is less than { ver2 } " )
428- return False
429- print (f"Versions are equal or { ver1 } is not greater than { ver2 } " )
430- return False
431-
432- @staticmethod
433- def is_builtin_app (app_fullname ):
434- return AppDetail .is_installed_by_path (f"builtin/apps/{ app_fullname } " )
435-
436- @staticmethod
437- def is_overridden_builtin_app (app_fullname ):
438- return AppDetail .is_installed_by_path (f"apps/{ app_fullname } " ) and AppDetail .is_installed_by_path (f"builtin/apps/{ app_fullname } " )
439-
440- @staticmethod
441- def is_update_available (app_fullname , new_version ):
442- appdir = f"apps/{ app_fullname } "
443- builtinappdir = f"builtin/apps/{ app_fullname } "
444- installed_app = None
445- if AppDetail .is_installed_by_path (appdir ):
446- print (f"{ appdir } found, getting version..." )
447- installed_app = mpos .apps .parse_manifest (appdir )
448- elif AppDetail .is_installed_by_path (builtinappdir ):
449- print (f"{ builtinappdir } found, getting version..." )
450- installed_app = mpos .apps .parse_manifest (builtinappdir )
451- if not installed_app or installed_app .version == "0.0.0" : # special case, if the installed app doesn't have a version number then there's no update
452- return False
453- return AppDetail .compare_versions (new_version , installed_app .version )
454-
455- @staticmethod
456- def is_installed_by_path (dir_path ):
457- try :
458- if os .stat (dir_path )[0 ] & 0x4000 :
459- print (f"is_installed_by_path: { dir_path } found, checking manifest..." )
460- manifest = f"{ dir_path } /META-INF/MANIFEST.JSON"
461- if os .stat (manifest )[0 ] & 0x8000 :
462- return True
463- except OSError :
464- print (f"is_installed_by_path got OSError for { dir_path } " )
465- pass # Skip if directory or manifest doesn't exist
466- return False
467-
468- @staticmethod
469- def is_installed_by_name (app_fullname ):
470- print (f"Checking if app { app_fullname } is installed..." )
471- return AppDetail .is_installed_by_path (f"apps/{ app_fullname } " ) or AppDetail .is_installed_by_path (f"builtin/apps/{ app_fullname } " )
472-
0 commit comments