diff --git a/CHANGELOG.md b/CHANGELOG.md index 0de76bb04..df8a84dc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Resolve BCM2046 and BCM2070 support on macOS 13.3 and newer - Workaround 13.3+ Kernel Panic on AMD GCN GPUs playing DRM content - Add new macOS Installer download menu (Jazzzny) +- Refresh download UI (Jazzzny) - Add support for Universal 2 distribution (x86_64 and ARM64) - Drops Rosetta requirement on Apple Silicon Macs - Note building from source will require Python 3.11 or newer and up-to-date Python modules diff --git a/resources/constants.py b/resources/constants.py index 8b82d70ac..13d2009c0 100644 --- a/resources/constants.py +++ b/resources/constants.py @@ -119,6 +119,7 @@ class Constants: self.original_path: Path = Path(__file__).parent.parent.resolve() self.payload_path: Path = self.current_path / Path("payloads") + # Patcher Settings ## Internal settings self.allow_oc_everywhere: bool = False # Set whether Patcher can be run on unsupported Macs @@ -235,6 +236,14 @@ class Constants: os_data.os_data.ventura, ] + self.icons_path = [ + str(self.icon_path_macos_generic), + str(self.icon_path_macos_big_sur), + str(self.icon_path_macos_monterey), + str(self.icon_path_macos_ventura), + str(self.icon_path_macos_sonoma) + ] + @property def special_build(self): """ @@ -679,7 +688,27 @@ class Constants: @property def icon_path_ssd(self): return self.payload_path / Path("Icon/SSD/.VolumeIcon.icns") - + + @property + def icon_path_macos_generic(self): + return self.payload_path / Path("Icon/AppIcons/Generic.icns") + + @property + def icon_path_macos_big_sur(self): + return self.payload_path / Path("Icon/AppIcons/BigSur.icns") + + @property + def icon_path_macos_monterey(self): + return self.payload_path / Path("Icon/AppIcons/Monterey.icns") + + @property + def icon_path_macos_ventura(self): + return self.payload_path / Path("Icon/AppIcons/Ventura.icns") + + @property + def icon_path_macos_sonoma(self): + return self.payload_path / Path("Icon/AppIcons/Sonoma.icns") + @property def gui_path(self): return self.payload_path / Path("Icon/Resources.zip") @@ -741,4 +770,4 @@ class Constants: "Mac-942B59F58194171B", # iMac12,2 "Mac-94245AF5819B141B", # AppleInternal MacBookPro8,3 "Mac-942B5B3A40C91381", # AppleInternal iMac12,2 - ] + ] \ No newline at end of file diff --git a/resources/utilities.py b/resources/utilities.py index d83810f85..9c866e948 100644 --- a/resources/utilities.py +++ b/resources/utilities.py @@ -61,9 +61,9 @@ def seconds_to_readable_time(seconds) -> str: time = "" if seconds == 0: - return "Almost done" + return "0m " if seconds < 0: - return "Indeterminate" + return "Indeterminate time " years, seconds = divmod(seconds, 31536000) days, seconds = divmod(seconds, 86400) @@ -80,8 +80,8 @@ def seconds_to_readable_time(seconds) -> str: time += f"{hours}h " if minutes > 0: time += f"{minutes}m " - if seconds > 0: - time += f"{seconds}s" + #if seconds > 0: + # time += f"{seconds}s" return time diff --git a/resources/wx_gui/gui_build.py b/resources/wx_gui/gui_build.py index d04f2c3b3..fd5525ce5 100644 --- a/resources/wx_gui/gui_build.py +++ b/resources/wx_gui/gui_build.py @@ -78,7 +78,7 @@ class BuildFrame(wx.Frame): self.text_box = text_box # Button: Return to Main Menu - return_button = wx.Button(frame, label="Return to Main Menu", pos=(-1, text_box.GetPosition()[1] + text_box.GetSize()[1] + 5), size=(200, 30)) + return_button = wx.Button(frame, label="Return to Main Menu", pos=(-1, text_box.GetPosition()[1] + text_box.GetSize()[1] + 5), size=(150, 30)) return_button.Bind(wx.EVT_BUTTON, self.on_return_to_main_menu) return_button.Centre(wx.HORIZONTAL) return_button.Disable() diff --git a/resources/wx_gui/gui_download.py b/resources/wx_gui/gui_download.py index bb496f9fb..e1d77d42f 100644 --- a/resources/wx_gui/gui_download.py +++ b/resources/wx_gui/gui_download.py @@ -16,13 +16,17 @@ class DownloadFrame(wx.Frame): """ Update provided frame with download stats """ - def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, download_obj: network_handler.DownloadObject, item_name: str) -> None: + def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, download_obj: network_handler.DownloadObject, item_name: str, download_icon = None) -> None: logging.info("Initializing Download Frame") self.constants: constants.Constants = global_constants self.title: str = title self.parent: wx.Frame = parent self.download_obj: network_handler.DownloadObject = download_obj self.item_name: str = item_name + if download_icon: + self.download_icon: str = download_icon + else: + self.download_icon: str = "/System/Library/CoreServices/Installer.app/Contents/Resources/package.icns" self.user_cancelled: bool = False @@ -37,27 +41,23 @@ class DownloadFrame(wx.Frame): """ frame = self if not frame else frame + icon = self.download_icon + icon = wx.StaticBitmap(frame, bitmap=wx.Bitmap(icon, wx.BITMAP_TYPE_ICON), pos=(-1, 20)) + icon.SetSize((100, 100)) + icon.Centre(wx.HORIZONTAL) - title_label = wx.StaticText(frame, label=f"Downloading: {self.item_name}", pos=(-1,5)) + title_label = wx.StaticText(frame, label=f"Downloading: {self.item_name}", pos=(-1,icon.GetPosition()[1] + icon.GetSize()[1] + 20)) title_label.SetFont(gui_support.font_factory(19, wx.FONTWEIGHT_BOLD)) title_label.Centre(wx.HORIZONTAL) - label_amount = wx.StaticText(frame, label="0.00 B downloaded of 0.00B (0.00%)", pos=(-1, title_label.GetPosition()[1] + title_label.GetSize()[1] + 5)) + progress_bar = wx.Gauge(frame, range=100, pos=(-1, title_label.GetPosition()[1] + title_label.GetSize()[1] + 5), size=(300, 20)) + progress_bar.Centre(wx.HORIZONTAL) + + label_amount = wx.StaticText(frame, label="Preparing download", pos=(-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1])) label_amount.SetFont(gui_support.font_factory(13, wx.FONTWEIGHT_NORMAL)) label_amount.Centre(wx.HORIZONTAL) - label_speed = wx.StaticText(frame, label="Average download speed: Unknown", pos=(-1, label_amount.GetPosition()[1] + label_amount.GetSize()[1] + 5)) - label_speed.SetFont(gui_support.font_factory(13, wx.FONTWEIGHT_NORMAL)) - label_speed.Centre(wx.HORIZONTAL) - - label_est_time = wx.StaticText(frame, label="Estimated time remaining: Unknown", pos=(-1, label_speed.GetPosition()[1] + label_speed.GetSize()[1] + 5)) - label_est_time.SetFont(gui_support.font_factory(13, wx.FONTWEIGHT_NORMAL)) - label_est_time.Centre(wx.HORIZONTAL) - - progress_bar = wx.Gauge(frame, range=100, pos=(-1, label_est_time.GetPosition()[1] + label_est_time.GetSize()[1] + 5), size=(300, 20)) - progress_bar.Centre(wx.HORIZONTAL) - - return_button = wx.Button(frame, label="Return", pos=(-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 5)) + return_button = wx.Button(frame, label="Cancel", pos=(-1, label_amount.GetPosition()[1] + label_amount.GetSize()[1] + 10)) return_button.Bind(wx.EVT_BUTTON, lambda event: self.terminate_download()) return_button.Centre(wx.HORIZONTAL) @@ -67,31 +67,25 @@ class DownloadFrame(wx.Frame): self.download_obj.download() while self.download_obj.is_active(): + percentage: int = self.download_obj.get_percent() if percentage == -1: - amount_str = f"{utilities.human_fmt(self.download_obj.downloaded_file_size)} downloaded" + amount_str = f"{utilities.human_fmt(self.download_obj.downloaded_file_size)} downloaded ({utilities.human_fmt(self.download_obj.get_speed())}/s)" progress_bar.Pulse() else: - amount_str = f"{utilities.human_fmt(self.download_obj.downloaded_file_size)} downloaded of {utilities.human_fmt(self.download_obj.total_file_size)} ({percentage:.2f}%)" + amount_str = f"{utilities.seconds_to_readable_time(self.download_obj.get_time_remaining())}left - {utilities.human_fmt(self.download_obj.downloaded_file_size)} of {utilities.human_fmt(self.download_obj.total_file_size)} ({utilities.human_fmt(self.download_obj.get_speed())}/s)" progress_bar.SetValue(int(percentage)) label_amount.SetLabel(amount_str) label_amount.Centre(wx.HORIZONTAL) - label_speed.SetLabel( - f"Average download speed: {utilities.human_fmt(self.download_obj.get_speed())}/s" - ) - - label_est_time.SetLabel( - f"Estimated time remaining: {utilities.seconds_to_readable_time(self.download_obj.get_time_remaining())}" - ) - wx.Yield() if self.download_obj.download_complete is False and self.user_cancelled is False: wx.MessageBox(f"Download failed: \n{self.download_obj.error_msg}", "Error", wx.OK | wx.ICON_ERROR) + progress_bar.Destroy() frame.Destroy() diff --git a/resources/wx_gui/gui_install_oc.py b/resources/wx_gui/gui_install_oc.py index 7f083f43d..58182d653 100644 --- a/resources/wx_gui/gui_install_oc.py +++ b/resources/wx_gui/gui_install_oc.py @@ -158,12 +158,12 @@ class InstallOCFrame(wx.Frame): disk_label.Centre(wx.HORIZONTAL) # Add button: Search for disks again - search_button = wx.Button(dialog, label="Search for disks again", size=(160,30), pos=(-1, disk_label.GetPosition()[1] + disk_label.GetSize()[1] + 5)) + search_button = wx.Button(dialog, label="Search for disks again", size=(150,30), pos=(-1, disk_label.GetPosition()[1] + disk_label.GetSize()[1] + 5)) search_button.Centre(wx.HORIZONTAL) search_button.Bind(wx.EVT_BUTTON, self.on_reload_frame) # Add button: Return to main menu - return_button = wx.Button(dialog, label="Return to main menu", size=(160,30), pos=(-1, search_button.GetPosition()[1] + 20)) + return_button = wx.Button(dialog, label="Return to Main Menu", size=(150,30), pos=(-1, search_button.GetPosition()[1] + 20)) return_button.Centre(wx.HORIZONTAL) return_button.Bind(wx.EVT_BUTTON, self.on_return_to_main_menu) @@ -209,7 +209,7 @@ class InstallOCFrame(wx.Frame): spacer += 25 # Add button: Return to main menu - return_button = wx.Button(dialog, label="Return to main menu", size=(150,30), pos=(-1, disk_button.GetPosition()[1] + disk_button.GetSize()[1])) + return_button = wx.Button(dialog, label="Return to Main Menu", size=(150,30), pos=(-1, disk_button.GetPosition()[1] + disk_button.GetSize()[1])) return_button.Centre(wx.HORIZONTAL) return_button.Bind(wx.EVT_BUTTON, self.on_return_to_main_menu) @@ -246,7 +246,7 @@ class InstallOCFrame(wx.Frame): self.text_box = text_box # Add button: Return to main menu - return_button = wx.Button(dialog, label="Return to main menu", size=(200,30), pos=(-1, text_box.GetPosition()[1] + text_box.GetSize()[1] + 10)) + return_button = wx.Button(dialog, label="Return to Main Menu", size=(150,30), pos=(-1, text_box.GetPosition()[1] + text_box.GetSize()[1] + 10)) return_button.Centre(wx.HORIZONTAL) return_button.Bind(wx.EVT_BUTTON, self.on_return_to_main_menu) return_button.Disable() diff --git a/resources/wx_gui/gui_macos_installer_download.py b/resources/wx_gui/gui_macos_installer_download.py index d180bd1f0..6448fa2f8 100644 --- a/resources/wx_gui/gui_macos_installer_download.py +++ b/resources/wx_gui/gui_macos_installer_download.py @@ -44,6 +44,24 @@ class macOSInstallerDownloadFrame(wx.Frame): self._generate_elements(self.frame_modal) self.frame_modal.ShowWindowModal() + self.icons = [[self._icon_to_bitmap(i), self._icon_to_bitmap(i, (64, 64))] for i in self.constants.icons_path] + + def _icon_to_bitmap(self, icon: str, size: tuple = (32, 32)) -> wx.Bitmap: + """ + Convert icon to bitmap + """ + return wx.Bitmap(wx.Bitmap(icon, wx.BITMAP_TYPE_ICON).ConvertToImage().Rescale(size[0], size[1], wx.IMAGE_QUALITY_HIGH)) + + def _macos_version_to_icon(self, version: int) -> int: + """ + Convert macOS version to icon + """ + try: + self.constants.icons_path[version - 19] + return version - 19 + except IndexError: + return 0 + def _generate_elements(self, frame: wx.Frame = None) -> None: """ @@ -88,7 +106,7 @@ class macOSInstallerDownloadFrame(wx.Frame): self.Centre() # Title: Pulling installer catalog - title_label = wx.StaticText(self, label="Pulling installer catalog", pos=(-1,5)) + title_label = wx.StaticText(self, label="Finding Available Software", pos=(-1,5)) title_label.SetFont(gui_support.font_factory(19, wx.FONTWEIGHT_BOLD)) title_label.Centre(wx.HORIZONTAL) @@ -125,15 +143,9 @@ class macOSInstallerDownloadFrame(wx.Frame): """ Display available installers in frame """ - icons = [ - [wx.Bitmap(wx.Bitmap(str(self.constants.icns_resource_path / "Generic.icns"),wx.BITMAP_TYPE_ICON).ConvertToImage().Rescale(32, 32, wx.IMAGE_QUALITY_HIGH)),wx.Bitmap(wx.Bitmap(str(self.constants.icns_resource_path / "Generic.icns"),wx.BITMAP_TYPE_ICON).ConvertToImage().Rescale(64, 64, wx.IMAGE_QUALITY_HIGH))], - [wx.Bitmap(wx.Bitmap(str(self.constants.icns_resource_path / "BigSur.icns"),wx.BITMAP_TYPE_ICON).ConvertToImage().Rescale(32, 32, wx.IMAGE_QUALITY_HIGH)),wx.Bitmap(wx.Bitmap(str(self.constants.icns_resource_path / "BigSur.icns"),wx.BITMAP_TYPE_ICON).ConvertToImage().Rescale(64, 64, wx.IMAGE_QUALITY_HIGH))], - [wx.Bitmap(wx.Bitmap(str(self.constants.icns_resource_path / "Monterey.icns"),wx.BITMAP_TYPE_ICON).ConvertToImage().Rescale(32, 32, wx.IMAGE_QUALITY_HIGH)),wx.Bitmap(wx.Bitmap(str(self.constants.icns_resource_path / "Monterey.icns"),wx.BITMAP_TYPE_ICON).ConvertToImage().Rescale(64, 64, wx.IMAGE_QUALITY_HIGH))], - [wx.Bitmap(wx.Bitmap(str(self.constants.icns_resource_path / "Ventura.icns"),wx.BITMAP_TYPE_ICON).ConvertToImage().Rescale(32, 32, wx.IMAGE_QUALITY_HIGH)),wx.Bitmap(wx.Bitmap(str(self.constants.icns_resource_path / "Ventura.icns"),wx.BITMAP_TYPE_ICON).ConvertToImage().Rescale(64, 64, wx.IMAGE_QUALITY_HIGH))], - [wx.Bitmap(wx.Bitmap(str(self.constants.icns_resource_path / "Sonoma.icns"),wx.BITMAP_TYPE_ICON).ConvertToImage().Rescale(32, 32, wx.IMAGE_QUALITY_HIGH)),wx.Bitmap(wx.Bitmap(str(self.constants.icns_resource_path / "Sonoma.icns"),wx.BITMAP_TYPE_ICON).ConvertToImage().Rescale(64, 64, wx.IMAGE_QUALITY_HIGH))] - ] + - bundles = [wx.BitmapBundle.FromBitmaps(icon) for icon in icons] + bundles = [wx.BitmapBundle.FromBitmaps(icon) for icon in self.icons] self.frame_modal.Destroy() self.frame_modal = wx.Dialog(self, title="Select macOS Installer", size=(460, 500)) @@ -163,15 +175,10 @@ class macOSInstallerDownloadFrame(wx.Frame): extra = " Beta" if installers[item]['Variant'] in ["DeveloperSeed" , "PublicSeed"] else "" logging.info(f"- macOS {installers[item]['Version']} ({installers[item]['Build']}):\n - Size: {utilities.human_fmt(installers[item]['Size'])}\n - Source: {installers[item]['Source']}\n - Variant: {installers[item]['Variant']}\n - Link: {installers[item]['Link']}\n") index = self.list.InsertItem(self.list.GetItemCount(), f"macOS {installers[item]['Version']} {os_data.os_conversion.convert_kernel_to_marketing_name(int(installers[item]['Build'][:2]))}{extra} ({installers[item]['Build']})") - if int(installers[item]['Build'][:2]) > os_data.os_data.sonoma: - self.list.SetItemImage(index, 0) - else: - self.list.SetItemImage(index, int(installers[item]['Build'][:2])-19) # Darwin version to index conversion. i.e. Darwin 20 -> 1 -> BigSur.icns + self.list.SetItemImage(index, self._macos_version_to_icon(int(installers[item]['Build'][:2]))) self.list.SetItem(index, 1, utilities.human_fmt(installers[item]['Size'])) self.list.SetItem(index, 2, installers[item]['Date'].strftime("%x")) - - else: logging.error("No installers found on SUCatalog") wx.MessageDialog(self.frame_modal, "Failed to download Installer Catalog from Apple", "Error", wx.OK | wx.ICON_ERROR).ShowModal() @@ -307,6 +314,7 @@ class macOSInstallerDownloadFrame(wx.Frame): global_constants=self.constants, download_obj=download_obj, item_name=f"macOS {list(installers.values())[selected_item]['Version']} ({list(installers.values())[selected_item]['Build']})", + download_icon=self.constants.icons_path[self._macos_version_to_icon(int(list(installers.values())[selected_item]['Build'][:2]))] ) if download_obj.download_complete is False: @@ -315,7 +323,7 @@ class macOSInstallerDownloadFrame(wx.Frame): self._validate_installer(list(installers.values())[selected_item]['integrity']) - + def _validate_installer(self, chunklist_link: str) -> None: """ Validate macOS installer diff --git a/resources/wx_gui/gui_macos_installer_flash.py b/resources/wx_gui/gui_macos_installer_flash.py index 89e0036d4..a5b9fde89 100644 --- a/resources/wx_gui/gui_macos_installer_flash.py +++ b/resources/wx_gui/gui_macos_installer_flash.py @@ -201,12 +201,12 @@ class macOSInstallerFlashFrame(wx.Frame): disk_button.Centre(wx.HORIZONTAL) # Search for disks again - search_button = wx.Button(self.frame_modal, label="Search for disks again", pos=(-1, disk_button.GetPosition()[1] + disk_button.GetSize()[1]), size=(160, 30)) + search_button = wx.Button(self.frame_modal, label="Search for disks again", pos=(-1, disk_button.GetPosition()[1] + disk_button.GetSize()[1]), size=(150, 30)) search_button.Bind(wx.EVT_BUTTON, lambda event, temp=installer: self.on_select(temp)) search_button.Centre(wx.HORIZONTAL) # Button: Return to Main Menu - cancel_button = wx.Button(self.frame_modal, label="Return to Main Menu", pos=(-1, search_button.GetPosition()[1] + search_button.GetSize()[1] - 10), size=(160, 30)) + cancel_button = wx.Button(self.frame_modal, label="Return to Main Menu", pos=(-1, search_button.GetPosition()[1] + search_button.GetSize()[1] - 10), size=(150, 30)) cancel_button.Bind(wx.EVT_BUTTON, self.on_return_to_main_menu) cancel_button.Centre(wx.HORIZONTAL) diff --git a/resources/wx_gui/gui_update.py b/resources/wx_gui/gui_update.py index c9e9f24b6..a1a775924 100644 --- a/resources/wx_gui/gui_update.py +++ b/resources/wx_gui/gui_update.py @@ -102,7 +102,8 @@ class UpdateFrame(wx.Frame): title=self.title, global_constants=self.constants, download_obj=download_obj, - item_name=f"OpenCore Patcher {version_label}" + item_name=f"OpenCore Patcher {version_label}", + download_icon=str(self.constants.app_icon_path) ) if download_obj.download_complete is False: