init
This commit is contained in:
261
page2.py
Normal file
261
page2.py
Normal file
@@ -0,0 +1,261 @@
|
||||
import customtkinter as ctk
|
||||
from tkinter import filedialog
|
||||
import os
|
||||
import threading
|
||||
from PIL import Image, ImageDraw
|
||||
import json
|
||||
import re
|
||||
|
||||
class Page2:
|
||||
def __init__(self, parent):
|
||||
self.parent = parent
|
||||
self.frame = ctk.CTkFrame(parent)
|
||||
self.frame.pack(fill=ctk.BOTH, expand=True)
|
||||
|
||||
self.work_dir = "apk_work"
|
||||
rootPath = os.path.dirname(os.path.abspath(__file__))
|
||||
self.apktool_jar_path = os.path.join(rootPath, "apktool_2.11.1.jar")
|
||||
self.jdk_path = os.path.join(rootPath, r"jdk-21.0.7\bin\java.exe")
|
||||
|
||||
self.icon_path = ""
|
||||
|
||||
self.app_name = ""
|
||||
|
||||
ctk.CTkLabel(self.frame, text="Page 2: Replace Icon and App name").pack(pady=10)
|
||||
|
||||
icon_frame = ctk.CTkFrame(self.frame)
|
||||
icon_frame.pack(pady=5)
|
||||
|
||||
self.label_icon = ctk.CTkLabel(icon_frame, text="Not selected icon file")
|
||||
self.label_icon.pack(pady=3)
|
||||
|
||||
self.btn_choose_icon = ctk.CTkButton(icon_frame, text="Choose icon file", command=self.choose_icon)
|
||||
self.btn_choose_icon.pack(pady=3)
|
||||
|
||||
self.btn_replace = ctk.CTkButton(icon_frame, text="Replace all icons", command=self.replace_icons, state=ctk.DISABLED)
|
||||
self.btn_replace.pack(pady=10)
|
||||
|
||||
app_name_frame = ctk.CTkFrame(self.frame)
|
||||
app_name_frame.pack(pady=10)
|
||||
|
||||
ctk.CTkLabel(app_name_frame, text="App Name:").pack(side=ctk.LEFT)
|
||||
self.app_name_entry = ctk.CTkEntry(app_name_frame)
|
||||
self.app_name_entry.pack(side=ctk.LEFT, padx=5)
|
||||
|
||||
self.btn_change_name = ctk.CTkButton(app_name_frame, text="Change App Name", command=self.change_app_name, state=ctk.DISABLED)
|
||||
self.btn_change_name.pack(side=ctk.LEFT, padx=5)
|
||||
|
||||
self.loading_label = ctk.CTkLabel(self.frame, text="")
|
||||
self.loading_label.pack()
|
||||
|
||||
self.log_output = ctk.CTkTextbox(self.frame, width=600, height=200, corner_radius=0)
|
||||
self.log_output.pack(pady=5)
|
||||
|
||||
self.refresh()
|
||||
|
||||
def choose_icon(self):
|
||||
file_path = filedialog.askopenfilename(
|
||||
title="Choose icon file",
|
||||
filetypes=[("Image files", "*.png *.jpg *.jpeg")]
|
||||
)
|
||||
if file_path:
|
||||
self.icon_path = file_path
|
||||
self.label_icon.configure(text=f"Icon file: {file_path}")
|
||||
self.btn_replace.configure(state=ctk.NORMAL)
|
||||
self.log(f"Selected icon file: {file_path}")
|
||||
|
||||
|
||||
def replace_icons(self):
|
||||
self.log("\nSearching for icon sizes...")
|
||||
self.search_and_display_sizes()
|
||||
try:
|
||||
if not hasattr(self, 'icon_sizes') or not self.icon_sizes:
|
||||
self.error("No icon sizes found. Please extract APK first.")
|
||||
return
|
||||
|
||||
if not hasattr(self, 'icon_path') or not self.icon_path:
|
||||
self.error("Not selected icon file")
|
||||
return
|
||||
|
||||
try:
|
||||
with Image.open(self.icon_path) as img:
|
||||
original_size = img.size
|
||||
except Exception as e:
|
||||
self.error(f"Cannot open icon file: {e}")
|
||||
return
|
||||
|
||||
self.loading_label.configure(text="Replacing icons...")
|
||||
self.btn_replace.configure(state=ctk.DISABLED)
|
||||
self.btn_choose_icon.configure(state=ctk.DISABLED)
|
||||
|
||||
threading.Thread(target=self.replace_icons_thread, daemon=True).start()
|
||||
except Exception as e:
|
||||
self.error(f"Error when replacing icons: {e}")
|
||||
self.reset_ui()
|
||||
|
||||
def replace_icons_thread(self):
|
||||
try:
|
||||
with Image.open(self.icon_path) as img:
|
||||
for mipmap_dir, sizes in self.icon_sizes.items():
|
||||
mipmap_path = os.path.join(self.work_dir, 'res', mipmap_dir)
|
||||
if not os.path.isdir(mipmap_path):
|
||||
self.log(f"Not found directory {mipmap_dir}")
|
||||
continue
|
||||
|
||||
self.log(f"\nProcessing directory {mipmap_dir}:")
|
||||
|
||||
for icon, target_size in sizes.items():
|
||||
target_path = os.path.join(mipmap_path, icon)
|
||||
if not os.path.exists(target_path):
|
||||
self.log(f"Not found file {icon}")
|
||||
continue
|
||||
|
||||
try:
|
||||
resized_img = img.resize(target_size)
|
||||
|
||||
if "round" in icon.lower() and "ic_launcher_background" not in icon:
|
||||
mask = Image.new("L", target_size, 255)
|
||||
draw = ImageDraw.Draw(mask)
|
||||
|
||||
radius = min(target_size) * 0.2
|
||||
|
||||
draw.rounded_rectangle((0, 0) + target_size, radius=radius, fill=255)
|
||||
|
||||
resized_img.putalpha(mask)
|
||||
else:
|
||||
resized_img = resized_img.convert("RGBA")
|
||||
|
||||
resized_img.save(target_path, format='PNG')
|
||||
self.log(f"Replaced {icon} with size {target_size[0]}x{target_size[1]}")
|
||||
|
||||
except Exception as e:
|
||||
self.log(f"Error when processing {icon}: {e}")
|
||||
|
||||
self.log("\nCompleted replacing all icons!")
|
||||
|
||||
except Exception as e:
|
||||
self.log(f"Error when replacing icons: {e}")
|
||||
|
||||
finally:
|
||||
self.loading_label.configure(text="")
|
||||
self.btn_replace.configure(state=ctk.NORMAL)
|
||||
self.btn_choose_icon.configure(state=ctk.NORMAL)
|
||||
|
||||
def search_and_display_sizes(self):
|
||||
try:
|
||||
res_dir = os.path.join(self.work_dir, 'res')
|
||||
if not os.path.exists(res_dir):
|
||||
self.log(f"Not found directory res")
|
||||
return
|
||||
|
||||
icon_files = ['app_icon.png', 'app_icon_round.png', 'ic_launcher_background.png']
|
||||
|
||||
mipmap_dirs = [d for d in os.listdir(res_dir) if d.startswith('mipmap')]
|
||||
|
||||
if not mipmap_dirs:
|
||||
self.log("Not found mipmap directory")
|
||||
return
|
||||
|
||||
for mipmap_dir in mipmap_dirs:
|
||||
mipmap_path = os.path.join(res_dir, mipmap_dir)
|
||||
if not os.path.isdir(mipmap_path):
|
||||
continue
|
||||
|
||||
for icon in icon_files:
|
||||
file_path = os.path.join(mipmap_path, icon)
|
||||
icon_sizes = {}
|
||||
|
||||
has_all_icons = False
|
||||
for mipmap_dir in mipmap_dirs:
|
||||
mipmap_path = os.path.join(res_dir, mipmap_dir)
|
||||
if not os.path.isdir(mipmap_path):
|
||||
continue
|
||||
|
||||
found_icons = 0
|
||||
for icon in icon_files:
|
||||
if os.path.exists(os.path.join(mipmap_path, icon)):
|
||||
found_icons += 1
|
||||
if found_icons == len(icon_files):
|
||||
has_all_icons = True
|
||||
|
||||
sizes = {}
|
||||
for icon in icon_files:
|
||||
file_path = os.path.join(mipmap_path, icon)
|
||||
try:
|
||||
with Image.open(file_path) as img:
|
||||
width, height = img.size
|
||||
sizes[icon] = (width, height)
|
||||
except Exception as e:
|
||||
self.log(f"Not found size of {file_path}: {e}")
|
||||
|
||||
icon_sizes[mipmap_dir] = sizes
|
||||
|
||||
if not has_all_icons:
|
||||
self.log("Not found all icons")
|
||||
else:
|
||||
self.log("\nSize of icons:")
|
||||
self.log(json.dumps(icon_sizes, indent=2))
|
||||
|
||||
self.icon_sizes = icon_sizes
|
||||
self.log("\nSaved information size icon to use for replacement later")
|
||||
|
||||
except Exception as e:
|
||||
self.log(f"Error when searching file: {e}")
|
||||
|
||||
def refresh(self):
|
||||
try:
|
||||
strings_path = os.path.join(self.work_dir, 'res', 'values', 'strings.xml')
|
||||
if os.path.exists(strings_path):
|
||||
with open(strings_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
match = re.search(r'<string name="app_name">(.*?)</string>', content)
|
||||
if match:
|
||||
self.app_name = match.group(1)
|
||||
self.app_name_entry.delete(0, ctk.END)
|
||||
self.app_name_entry.insert(0, self.app_name)
|
||||
self.btn_change_name.configure(state=ctk.NORMAL)
|
||||
self.log(f"Loaded app name: {self.app_name}")
|
||||
else:
|
||||
self.app_name_entry.delete(0, ctk.END)
|
||||
self.log("Could not find app_name in strings.xml")
|
||||
except Exception as e:
|
||||
self.app_name_entry.delete(0, ctk.END)
|
||||
self.log(f"Error loading app name: {e}")
|
||||
|
||||
def change_app_name(self):
|
||||
new_name = self.app_name_entry.get()
|
||||
if not new_name:
|
||||
self.error("Please enter a new app name")
|
||||
return
|
||||
|
||||
try:
|
||||
strings_path = os.path.join(self.work_dir, 'res', 'values', 'strings.xml')
|
||||
if os.path.exists(strings_path):
|
||||
with open(strings_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
new_content = re.sub(r'(<string name="app_name">).*?(</string>)',
|
||||
r'\g<1>' + new_name + r'\g<2>',
|
||||
content)
|
||||
|
||||
with open(strings_path, 'w', encoding='utf-8') as f:
|
||||
f.write(new_content)
|
||||
|
||||
self.app_name = new_name
|
||||
self.log(f"Successfully changed app name to: {new_name}")
|
||||
else:
|
||||
self.error("strings.xml file not found")
|
||||
except Exception as e:
|
||||
self.error(f"Error changing app name: {e}")
|
||||
|
||||
def log(self, msg):
|
||||
self.log_output.insert(ctk.END, f"{msg}\n")
|
||||
self.log_output.see(ctk.END)
|
||||
|
||||
def error(self, msg):
|
||||
self.log(f"Error: {msg}")
|
||||
|
||||
def reset_ui(self):
|
||||
self.loading_label.configure(text="")
|
||||
self.btn_replace.configure(state=ctk.NORMAL)
|
||||
self.btn_choose_icon.configure(state=ctk.NORMAL)
|
||||
Reference in New Issue
Block a user