[0.1] Source code push

This commit is contained in:
2026-03-11 12:13:57 +07:00
parent ca95651705
commit 718736a72a
4 changed files with 333 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
test/
dist/
build/
.venv/
*.zip
main.spec

BIN
assets/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

327
main.py Normal file
View File

@@ -0,0 +1,327 @@
import customtkinter as ctk
from tkinter import filedialog, messagebox
ctk.set_appearance_mode("System")
ctk.set_default_color_theme("dark-blue")
class MainApp(ctk.CTk):
def __init__(self):
super().__init__()
self.title("Liskod")
self.geometry("400x403")
self.resizable(False, False)
# --- Data State ---
self.current_file_path = None
self.list_in_memory = []
self.set_in_memory = set()
self.any_change = False
# --- Grid Configuration ---
self.grid_rowconfigure(0, weight=0)
self.grid_rowconfigure(1, weight=0)
self.grid_rowconfigure(2, weight=0)
self.grid_columnconfigure(0, weight=1)
# ============================================================
# ROW 0: File Input & Mode Checkbox
# ============================================================
self.row1_frame = ctk.CTkFrame(self)
self.row1_frame.grid(row=0, column=0, padx=20, pady=(15, 10), sticky="ew")
self.row1_frame.grid_columnconfigure(0, weight=1)
self.row1_frame.grid_columnconfigure(1, weight=0)
self.var_edit_mode = ctk.BooleanVar(value=False)
self.chk_mode = ctk.CTkCheckBox(
self.row1_frame,
text="Edit Existing File",
font=("Arial", 14),
variable=self.var_edit_mode,
command=self.toggle_confirm
)
self.chk_mode.grid(row=0, column=0, padx=10, pady=(15, 5), sticky="w")
self.sort_toggle = ctk.BooleanVar(value=False)
self.chk_mode2 = ctk.CTkCheckBox(
self.row1_frame,
text="Sort Out",
font=("Arial", 14),
variable=self.sort_toggle,
command=None
)
self.chk_mode2.grid(row=0, column=1, pady=(15, 5), sticky="e")
self.entry_filepath = ctk.CTkEntry(
self.row1_frame,
text_color="gray",
font=("Arial", 14),
placeholder_text="New File (Save As)",
height=35
)
self.entry_filepath.grid(row=1, column=0, padx=(10, 0), pady=5, sticky="ew")
self.entry_filepath.configure(state="disabled")
self.btn_browse = ctk.CTkButton(
self.row1_frame,
text="Browse",
command=self.browse_file,
width=80,
height=35,
font=("Arial", 14),
)
self.btn_browse.grid(row=1, column=1, padx=(10, 10), pady=10)
# ============================================================
# ROW 1: Preview Window
# ============================================================
self.preview_frame = ctk.CTkFrame(self)
self.preview_frame.grid(row=1, column=0, padx=20, pady=(5, 10), sticky="ew")
self.preview_frame.grid_columnconfigure(0, weight=1)
self.lbl_preview = ctk.CTkLabel(self.preview_frame, text="Preview", font=("Arial", 14))
self.lbl_preview.grid(row=0, column=0, padx=10, pady=(5, 0), sticky="w")
self.txt_preview = ctk.CTkTextbox(self.preview_frame, height=110)
self.txt_preview.grid(row=1, column=0, padx=10, pady=(5, 10), sticky="ew")
self.txt_preview.configure(state="disabled")
self.input_container = ctk.CTkFrame(self.preview_frame, fg_color="transparent")
self.input_container.grid(row=2, column=0, padx=10, pady=(5, 10), sticky="ew")
self.input_container.grid_columnconfigure(0, weight=1)
self.entry_text = ctk.CTkEntry(self.input_container, placeholder_text="Type content here...", height=35, font=("Arial", 14))
self.entry_text.grid(row=0, column=0, padx=(0, 10), sticky="ew")
self.entry_text.bind("<Return>", lambda event: self.add_line_to_memory())
self.btn_add = ctk.CTkButton(
self.input_container,
text="Add",
width=80,
font=("Arial", 14),
command=self.add_line_to_memory,
height=35
)
self.btn_add.grid(row=0, column=1, sticky="e")
# ============================================================
# ROW 2: Save Button
# ============================================================
self.row3_frame = ctk.CTkFrame(self, fg_color="transparent")
self.row3_frame.grid(row=3, column=0, padx=20, pady=(5, 20), sticky="ew")
self.row3_frame.grid_columnconfigure(0, weight=0)
self.row3_frame.grid_columnconfigure(1, weight=0)
self.last_status = ctk.CTkLabel(
self.row3_frame,
height=35,
width=290,
fg_color="#282828",
corner_radius=4,
text_color="gray",
text="Status",
font=("Arial", 14),
)
self.last_status.grid(row=0, column=0, padx=(0, 10), sticky="ew")
self.btn_save = ctk.CTkButton(
self.row3_frame,
text="Save",
height=35,
width=60,
font=("Arial", 14),
fg_color="green",
hover_color="darkgreen",
command=self.save_action
)
self.btn_save.grid(row=0, column=1, sticky="e")
self.toggle_mode()
self.protocol("WM_DELETE_WINDOW", self.on_closing)
# --- Logic Methods ---
def toggle_confirm(self):
if len(self.list_in_memory) > 0:
new_state = self.var_edit_mode.get()
action = "enable" if new_state else "disable"
answer = messagebox.askyesno(
title="Confirmation",
message=f"Are you sure you want to {action} this setting?"
)
if answer:
self.delete_memory()
self.update_preview()
self.toggle_mode()
else:
self.var_edit_mode.set(not new_state)
else:
self.toggle_mode()
self.update_preview()
def toggle_mode(self):
new_state = self.var_edit_mode.get()
if new_state:
# Checked: Edit Existing Mode
self.btn_browse.configure(state="normal")
self.entry_filepath.configure(state="normal")
self.entry_filepath.delete(0, "end")
if self.current_file_path:
self.entry_filepath.insert(0, f"...{self.current_file_path[-30:]}")
else:
self.entry_filepath.insert(0, "No file loaded...")
self.btn_add.configure(state="disabled")
self.entry_filepath.configure(state="disabled")
else:
# Unchecked: New File Mode
self.current_file_path = None
self.btn_browse.configure(state="disabled")
self.btn_add.configure(state="normal")
self.entry_filepath.configure(state="normal")
self.entry_filepath.delete(0, "end")
self.entry_filepath.insert(0, "Create New File")
self.entry_filepath.configure(state="disabled")
def browse_file(self):
filename = filedialog.askopenfilename(
title="Select a Text File",
filetypes=[("Text files", "*.txt")]
)
if filename:
if not filename.lower().endswith('.txt'):
messagebox.showerror("Error", "Only .txt files are allowed!")
return
self.current_file_path = filename
self.entry_filepath.configure(state="normal")
self.entry_filepath.delete(0, "end")
self.entry_filepath.insert(0, f"...{filename[-30:]}")
self.entry_filepath.configure(state="disabled")
try:
with open(filename, "r", encoding="utf-8") as f:
self.list_in_memory = [line.strip() for line in f]
self.set_in_memory = set(self.list_in_memory)
duplicates = len(self.list_in_memory) - len(self.set_in_memory)
self.last_status.configure(
text=f"File loaded, {duplicates} duplicate(s) removed",
text_color="#9efc90"
)
self.list_in_memory = list(dict.fromkeys(self.list_in_memory))
self.btn_add.configure(state="normal")
self.update_preview()
except Exception as e:
messagebox.showerror("Error", f"Could not read file:\n{e}")
self.last_status.configure(
text=f"Could not read file:\n{e}",
text_color="#ff9d9d"
)
def add_line_to_memory(self):
text = self.entry_text.get()
if not text:
return
clean_text = text.replace('\n', '').replace('\r', '').strip()
if clean_text in self.set_in_memory:
self.entry_text.delete(0, "end")
self.last_status.configure(
text=f"Line \"{clean_text[:10]}\" already exists!",
text_color="#ff9d9d"
)
else:
if not len(clean_text) == 0:
self.any_change = True
self.list_in_memory.append(clean_text)
self.set_in_memory.add(clean_text)
self.entry_text.delete(0, "end")
self.update_preview()
self.last_status.configure(
text=f"Line \"{clean_text[:10]}\" added!",
text_color="#9efc90"
)
self.entry_text.delete(0, "end")
def delete_memory(self):
self.list_in_memory = []
self.set_in_memory = set()
def update_preview(self):
self.txt_preview.configure(state="normal")
self.txt_preview.delete("1.0", "end")
if not self.list_in_memory:
display_text = ""
elif len(self.list_in_memory) > 5:
last_five = ["..."] + self.list_in_memory[-5:]
display_text = "\n".join(last_five)
else:
last_five = self.list_in_memory[-5:]
display_text = "\n".join(last_five)
self.txt_preview.insert("1.0", display_text)
self.txt_preview.configure(state="disabled")
def save_action(self):
if len(self.list_in_memory) <= 0:
return
target_path = filedialog.asksaveasfilename(
title="Save As",
defaultextension=".txt",
filetypes=[("Text files", "*.txt")]
)
if not target_path:
return
try:
with open(target_path, "w", encoding="utf-8") as f:
to_be_saved = self.list_in_memory
if self.sort_toggle.get():
to_be_saved = sorted(self.list_in_memory)
full_content = "\n".join(to_be_saved)
f.write(full_content)
self.any_change = False
self.last_status.configure(
text="File saved successfully!",
text_color="#9efc90"
)
self.var_edit_mode.set(True)
self.current_file_path = target_path
self.entry_filepath.configure(state="normal")
self.entry_filepath.delete(0, "end")
self.entry_filepath.insert(0, f"...{self.current_file_path[-30:]}")
self.entry_filepath.configure(state="disabled")
except Exception as e:
self.last_status.configure(
text=f"Could not save file:\n{e}",
text_color="#ff9d9d"
)
def on_closing(self):
if self.any_change:
if messagebox.askokcancel("Quit", "There are unsaved changes, are you sure you want to quit?"):
self.destroy()
return
else:
self.destroy()
if __name__ == "__main__":
app = MainApp()
app.mainloop()

BIN
requirements.txt Normal file

Binary file not shown.