|
| 1 | +import datetime |
1 | 2 | import os |
2 | 3 | import shutil |
3 | 4 | import sys |
|
6 | 7 | import webbrowser |
7 | 8 | import customtkinter as ctk |
8 | 9 | import sqlite3 |
| 10 | +import zipfile |
9 | 11 | from cryptography.fernet import Fernet |
10 | 12 | from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC |
11 | 13 | from cryptography.hazmat.backends import default_backend |
@@ -384,7 +386,7 @@ def _post_close(h, lparam): |
384 | 386 | FONT_ITALIC = os.path.join(SCRIPT_DIR, "Fonts", "Nunito-Italic.ttf") |
385 | 387 | FONT_SEMIBOLD = os.path.join(SCRIPT_DIR, "Fonts", "Nunito-SemiBold.ttf") |
386 | 388 | LICENSE_TEXT = os.path.join(SCRIPT_DIR, "LICENSE.txt") |
387 | | -VERSION = "1.10.2" |
| 389 | +VERSION = "1.10.3" |
388 | 390 | # Load all the font files for Tkinter (on Windows) |
389 | 391 | if platform.system() == "Windows": |
390 | 392 | fonts = [FONT_REGULAR, FONT_MEDIUM, FONT_BOLD, FONT_LIGHT, FONT_ITALIC, FONT_SEMIBOLD] |
@@ -1669,6 +1671,7 @@ def show_settings_popup(self): |
1669 | 1671 | theme_combo.pack(padx=10, pady=(0,10)) |
1670 | 1672 | theme_combo.configure(command=lambda val: self.toggle_theme(val)) |
1671 | 1673 | ctk.CTkButton(frame, text="Show Sync Key", command = self.reshow_sync_key_display_popup, fg_color=ACCENT, text_color=BG, hover_color=ACCENT_DIM, width=120).pack(pady=10, padx=10) |
| 1674 | + ctk.CTkButton(frame, text="Import Icon Bundle", command=self.import_icon_bundle, fg_color=ACCENT, text_color=BG, hover_color=ACCENT_DIM, width=120).pack(pady=10, padx=10) |
1672 | 1675 | ctk.CTkButton(frame, text="About", command=self.show_about, fg_color=ACCENT, text_color=BG, hover_color=ACCENT_DIM, width=120).pack(pady=10, padx=10) |
1673 | 1676 | ctk.CTkButton(frame, text="Check for Updates", command=lambda: self.check_for_update(False), fg_color=ACCENT, text_color=BG, hover_color=ACCENT_DIM, width=120).pack(pady=10, padx=10) |
1674 | 1677 | ctk.CTkButton(frame, text="Reset", command=self.reset_app, fg_color="#ff4d4d", text_color=BG, hover_color="#ff0000", width=120).pack(pady=10, padx=10) |
@@ -1755,6 +1758,31 @@ def toggle_startup(self, value): |
1755 | 1758 | messagebox.showerror("Error", f"Failed to update startup setting: {e}") |
1756 | 1759 | except Exception: |
1757 | 1760 | pass |
| 1761 | + def import_icon_bundle(self): |
| 1762 | + import_file = filedialog.askopenfilename( |
| 1763 | + title="Select .hawking File to Import", |
| 1764 | + filetypes=[("Hawking files", "*.hawking")] |
| 1765 | + ) |
| 1766 | + if not import_file: |
| 1767 | + return |
| 1768 | + |
| 1769 | + proceed = messagebox.askyesno( |
| 1770 | + "Warning", |
| 1771 | + "Importing this archive may overwrite existing icons in the stored icons directory. Do you want to proceed?" |
| 1772 | + ) |
| 1773 | + if not proceed: |
| 1774 | + return |
| 1775 | + |
| 1776 | + count = 0 |
| 1777 | + with zipfile.ZipFile(import_file, "r") as archive: |
| 1778 | + for member in archive.namelist(): |
| 1779 | + archive.extract(member, stored_icons_path) |
| 1780 | + count += 1 |
| 1781 | + |
| 1782 | + messagebox.showinfo( |
| 1783 | + "Imported", |
| 1784 | + f"Imported {count} icons from\n{import_file}" |
| 1785 | + ) |
1758 | 1786 | def _change_sort(self, event=None): |
1759 | 1787 | val = self.sort_var.get() |
1760 | 1788 | if val == "Title A-Z": |
@@ -2352,6 +2380,9 @@ def add_section(parent, name): |
2352 | 2380 | ctk.CTkButton(slide_btns, text=".pptx", command=self.export_pptx, |
2353 | 2381 | fg_color=ACCENT, text_color=BG, hover_color=ACCENT_DIM, width=120).pack(side="left", padx=5) |
2354 | 2382 | ctk.CTkButton(popup, text="Cancel", command=popup.destroy, fg_color="#3a3a3a", width=120).pack(pady=12) |
| 2383 | + icon_export = add_section(export_frame, "Icons") |
| 2384 | + ctk.CTkButton(icon_export, text="Export Icon Bundle", command=self.export_icons, |
| 2385 | + fg_color=ACCENT, text_color=BG, hover_color=ACCENT_DIM, width=180).pack(pady=5) |
2355 | 2386 | def fix_scrollable_frame(sf): |
2356 | 2387 | sf.update_idletasks() |
2357 | 2388 | sf._parent_canvas.configure(scrollregion=sf._parent_canvas.bbox("all")) |
@@ -2647,6 +2678,27 @@ def export_pptx(self): |
2647 | 2678 | if path: |
2648 | 2679 | prs.save(path) |
2649 | 2680 | messagebox.showinfo("Exported", f"Exported to {path}") |
| 2681 | + def export_icons(self): |
| 2682 | + export_dir = filedialog.askdirectory(title="Select Export Directory for Icons") |
| 2683 | + if not export_dir: |
| 2684 | + return |
| 2685 | + |
| 2686 | + timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M") |
| 2687 | + archive_name = f"{timestamp}.hawking" |
| 2688 | + archive_path = os.path.join(export_dir, archive_name) |
| 2689 | + |
| 2690 | + count = 0 |
| 2691 | + with zipfile.ZipFile(archive_path, "w", zipfile.ZIP_DEFLATED) as archive: |
| 2692 | + for file in os.listdir(stored_icons_path): |
| 2693 | + src = os.path.join(stored_icons_path, file) |
| 2694 | + if os.path.isfile(src): |
| 2695 | + archive.write(src, arcname=file) |
| 2696 | + count += 1 |
| 2697 | + |
| 2698 | + messagebox.showinfo( |
| 2699 | + "Exported", |
| 2700 | + f"Exported {count} icons to\n{archive_path}" |
| 2701 | + ) |
2650 | 2702 | def show_help(self): |
2651 | 2703 | help_url = "https://github.com/DirectedHunt42/BlackHole/wiki" |
2652 | 2704 | webbrowser.open_new(help_url) |
|
0 commit comments