245 lines
9.6 KiB
Python
245 lines
9.6 KiB
Python
import tkinter as tk
|
||
from tkinter import messagebox
|
||
import threading
|
||
|
||
from analyzer import analyze_repository
|
||
from storage import register_user, check_user, get_repositories, add_repository, delete_repository
|
||
|
||
|
||
class GitAnalyzerApp:
|
||
def __init__(self):
|
||
self.root = tk.Tk()
|
||
self.root.title('Universal Git Analyzer')
|
||
self.root.geometry('1200x750')
|
||
self.root.minsize(1000, 650)
|
||
self.root.resizable(True, True)
|
||
|
||
self.current_user = None
|
||
self.bg = '#eef4ff'
|
||
self.panel = '#ffffff'
|
||
self.button = '#6aa6ff'
|
||
self.root.configure(bg=self.bg)
|
||
|
||
self.show_splash()
|
||
self.root.mainloop()
|
||
|
||
def clear(self):
|
||
for widget in self.root.winfo_children():
|
||
widget.destroy()
|
||
|
||
def make_button(self, parent, text, command, width=24):
|
||
return tk.Button(
|
||
parent,
|
||
text=text,
|
||
command=command,
|
||
width=width,
|
||
bg=self.button,
|
||
fg='white',
|
||
activebackground='#4d8ee8',
|
||
font=('Arial', 12, 'bold'),
|
||
relief='flat',
|
||
cursor='hand2',
|
||
pady=6,
|
||
)
|
||
|
||
def show_splash(self):
|
||
self.clear()
|
||
frame = tk.Frame(self.root, bg=self.bg)
|
||
frame.pack(expand=True)
|
||
|
||
tk.Label(
|
||
frame,
|
||
text='Universal Git Analyzer',
|
||
font=('Arial', 30, 'bold'),
|
||
bg=self.bg,
|
||
fg='#1d3557',
|
||
).pack(pady=20)
|
||
|
||
tk.Label(
|
||
frame,
|
||
text='Анализ Git-репозиториев: GitHub, Gitea, GitLab и другие публичные git-ссылки',
|
||
font=('Arial', 14),
|
||
bg=self.bg,
|
||
fg='#333333',
|
||
).pack(pady=10)
|
||
|
||
tk.Label(frame, text='Загрузка...', font=('Arial', 12), bg=self.bg, fg='#555555').pack(pady=30)
|
||
self.root.after(1200, self.show_login)
|
||
|
||
def show_login(self):
|
||
self.clear()
|
||
frame = tk.Frame(self.root, bg=self.panel, padx=35, pady=35)
|
||
frame.place(relx=0.5, rely=0.5, anchor='center')
|
||
|
||
tk.Label(frame, text='Вход в аккаунт', font=('Arial', 22, 'bold'), bg=self.panel).pack(pady=10)
|
||
tk.Label(frame, text='Логин', bg=self.panel, font=('Arial', 11)).pack(anchor='w')
|
||
login_entry = tk.Entry(frame, width=35, font=('Arial', 12))
|
||
login_entry.pack(pady=5)
|
||
|
||
tk.Label(frame, text='Пароль', bg=self.panel, font=('Arial', 11)).pack(anchor='w')
|
||
password_entry = tk.Entry(frame, width=35, font=('Arial', 12), show='*')
|
||
password_entry.pack(pady=5)
|
||
|
||
def login():
|
||
login_value = login_entry.get().strip()
|
||
password_value = password_entry.get().strip()
|
||
if not login_value or not password_value:
|
||
messagebox.showerror('Ошибка', 'Введите логин и пароль')
|
||
return
|
||
if check_user(login_value, password_value):
|
||
self.current_user = login_value
|
||
self.show_main_screen()
|
||
else:
|
||
messagebox.showerror('Ошибка', 'Неверный логин или пароль')
|
||
|
||
self.make_button(frame, 'Войти', login).pack(pady=12)
|
||
self.make_button(frame, 'Создать профиль', self.show_register).pack(pady=5)
|
||
|
||
def show_register(self):
|
||
self.clear()
|
||
frame = tk.Frame(self.root, bg=self.panel, padx=35, pady=35)
|
||
frame.place(relx=0.5, rely=0.5, anchor='center')
|
||
|
||
tk.Label(frame, text='Создание профиля', font=('Arial', 22, 'bold'), bg=self.panel).pack(pady=10)
|
||
tk.Label(frame, text='Логин', bg=self.panel, font=('Arial', 11)).pack(anchor='w')
|
||
login_entry = tk.Entry(frame, width=35, font=('Arial', 12))
|
||
login_entry.pack(pady=5)
|
||
|
||
tk.Label(frame, text='Пароль', bg=self.panel, font=('Arial', 11)).pack(anchor='w')
|
||
password_entry = tk.Entry(frame, width=35, font=('Arial', 12), show='*')
|
||
password_entry.pack(pady=5)
|
||
|
||
def register():
|
||
login_value = login_entry.get().strip()
|
||
password_value = password_entry.get().strip()
|
||
if not login_value or not password_value:
|
||
messagebox.showerror('Ошибка', 'Введите логин и пароль')
|
||
return
|
||
if len(password_value) < 4:
|
||
messagebox.showerror('Ошибка', 'Пароль должен быть минимум 4 символа')
|
||
return
|
||
ok, text = register_user(login_value, password_value)
|
||
if ok:
|
||
messagebox.showinfo('Готово', text)
|
||
self.show_login()
|
||
else:
|
||
messagebox.showerror('Ошибка', text)
|
||
|
||
self.make_button(frame, 'Зарегистрироваться', register).pack(pady=12)
|
||
self.make_button(frame, 'Назад', self.show_login).pack(pady=5)
|
||
|
||
def show_main_screen(self):
|
||
self.clear()
|
||
|
||
top = tk.Frame(self.root, bg='#1d3557', height=60)
|
||
top.pack(fill='x')
|
||
tk.Label(
|
||
top,
|
||
text=f'Universal Git Analyzer | Пользователь: {self.current_user}',
|
||
bg='#1d3557',
|
||
fg='white',
|
||
font=('Arial', 18, 'bold'),
|
||
).pack(side='left', padx=20, pady=15)
|
||
tk.Button(top, text='Выйти', command=self.show_login, bg='#e63946', fg='white', relief='flat', font=('Arial', 12)).pack(side='right', padx=20)
|
||
|
||
content = tk.Frame(self.root, bg=self.bg)
|
||
content.pack(fill='both', expand=True, padx=15, pady=15)
|
||
|
||
left = tk.Frame(content, bg=self.panel, padx=15, pady=15)
|
||
left.pack(side='left', fill='y')
|
||
|
||
right = tk.Frame(content, bg=self.panel, padx=15, pady=15)
|
||
right.pack(side='right', fill='both', expand=True, padx=(15, 0))
|
||
|
||
tk.Label(left, text='Мои репозитории', bg=self.panel, font=('Arial', 22, 'bold')).pack(anchor='w')
|
||
repo_listbox = tk.Listbox(left, width=48, height=20, font=('Arial', 12))
|
||
repo_listbox.pack(pady=10)
|
||
|
||
tk.Label(left, text='Новая ссылка', bg=self.panel, font=('Arial', 13)).pack(anchor='w')
|
||
repo_entry = tk.Entry(left, width=48, font=('Arial', 12))
|
||
repo_entry.pack(pady=5)
|
||
|
||
result_text = tk.Text(right, width=65, height=28, font=('Consolas', 13), wrap='word')
|
||
result_text.pack(fill='both', expand=True)
|
||
|
||
def refresh_list():
|
||
repo_listbox.delete(0, tk.END)
|
||
for repo in get_repositories(self.current_user):
|
||
repo_listbox.insert(tk.END, repo)
|
||
|
||
def get_selected_repo():
|
||
selection = repo_listbox.curselection()
|
||
if not selection:
|
||
return None
|
||
return repo_listbox.get(selection[0])
|
||
|
||
def save_repo():
|
||
link = repo_entry.get().strip()
|
||
if not link:
|
||
messagebox.showerror('Ошибка', 'Введите ссылку')
|
||
return
|
||
if not (link.startswith('https://') or link.startswith('http://') or link.startswith('git@')):
|
||
messagebox.showerror('Ошибка', 'Введите нормальную git-ссылку')
|
||
return
|
||
added = add_repository(self.current_user, link)
|
||
if added:
|
||
repo_entry.delete(0, tk.END)
|
||
refresh_list()
|
||
messagebox.showinfo('Готово', 'Ссылка сохранена')
|
||
else:
|
||
messagebox.showinfo('Информация', 'Эта ссылка уже сохранена')
|
||
|
||
def remove_repo():
|
||
link = get_selected_repo()
|
||
if not link:
|
||
messagebox.showerror('Ошибка', 'Выберите репозиторий')
|
||
return
|
||
delete_repository(self.current_user, link)
|
||
refresh_list()
|
||
result_text.delete('1.0', tk.END)
|
||
|
||
def analyze_selected():
|
||
link = get_selected_repo()
|
||
if not link:
|
||
messagebox.showerror('Ошибка', 'Выберите репозиторий')
|
||
return
|
||
|
||
result_text.delete('1.0', tk.END)
|
||
result_text.insert(tk.END, 'Загрузка данных...\n')
|
||
|
||
def worker():
|
||
try:
|
||
info = analyze_repository(link)
|
||
self.root.after(0, lambda: show_result(info))
|
||
except Exception as e:
|
||
self.root.after(0, lambda: show_error(str(e)))
|
||
|
||
def show_result(info):
|
||
result_text.delete('1.0', tk.END)
|
||
result_text.insert(tk.END, info)
|
||
|
||
def show_error(error):
|
||
result_text.delete('1.0', tk.END)
|
||
messagebox.showerror('Ошибка', f'Не удалось проанализировать репозиторий:\n{error}')
|
||
|
||
threading.Thread(target=worker, daemon=True).start()
|
||
|
||
self.make_button(left, 'Сохранить ссылку', save_repo, width=28).pack(pady=5)
|
||
self.make_button(left, 'Обновить информацию', analyze_selected, width=28).pack(pady=5)
|
||
self.make_button(left, 'Удалить ссылку', remove_repo, width=28).pack(pady=5)
|
||
|
||
tk.Label(
|
||
left,
|
||
text='Поддерживаются публичные git-ссылки:\nGitea, GitHub, GitLab, Forgejo и другие.',
|
||
bg=self.panel,
|
||
fg='#444444',
|
||
font=('Arial', 10),
|
||
justify='left',
|
||
).pack(anchor='w', pady=15)
|
||
|
||
refresh_list()
|
||
|
||
|
||
if __name__ == '__main__':
|
||
GitAnalyzerApp()
|