WeChatMsg/app/ui/mainview.py

438 lines
13 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
"""
@File : mainview.py
@Author : Shuaikang Zhou
@Time : 2022/12/13 15:07
@IDE : Pycharm
@Version : Python3.10
@comment : 主窗口
"""
import json
import os.path
import traceback
2024-01-22 22:21:55 +08:00
from PyQt5.QtCore import pyqtSignal, QThread, QSize, QUrl
from PyQt5.QtGui import QPixmap, QIcon, QDesktopServices
2024-01-17 20:04:59 +08:00
from PyQt5.QtWidgets import QMainWindow, QLabel, QMessageBox
from app.DataBase import misc_db, micro_msg_db, close_db
from app.ui.Icon import Icon
from . import mainwindow
2024-01-17 21:49:47 +08:00
# 不能删,删了会出错
from .chat import ChatWindow
from .contact import ContactWindow
2024-01-17 21:49:47 +08:00
from app.ui.tool.tool_window import ToolWindow
2024-01-06 13:04:55 +08:00
from .menu.export import ExportDialog
from ..DataBase.output_pc import Output
2023-12-23 19:07:15 +08:00
from ..components.QCursorGif import QCursorGif
from ..log import logger
2023-12-30 19:26:24 +08:00
from ..person import Me
2024-01-16 21:28:38 +08:00
try:
2024-01-17 20:20:32 +08:00
from app.ui.menu.about_dialog import AboutDialog, version, UpdateThread
2024-01-16 21:28:38 +08:00
except ModuleNotFoundError:
logger.error(f'Python版本错误:Python>=3.10,仅支持3.10、3.11、3.12')
2024-01-17 21:49:47 +08:00
raise ValueError('Python版本错误:Python>=3.10,仅支持3.10、3.11、3.12')
# 美化样式表
Stylesheet = """
2024-01-24 20:02:01 +08:00
QPushButton{
background-color: rgb(238,244,249);
border-radius: 5px;
padding: 8px;
}
QPushButton:hover {
background-color: lightgray;
}
QWidget{
background: rgb(238,244,249);
}
/*去掉item虚线边框*/
QListWidget, QListView, QTreeWidget, QTreeView {
outline: 0px;
}
2024-01-24 20:02:01 +08:00
2023-12-14 23:08:12 +08:00
QMenu::item:selected {
color: black;
background: rgb(230, 235, 240);
}
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
QListWidget {
min-width: 120px;
2023-12-14 22:59:48 +08:00
max-width: 380px;
color: black;
border:none;
}
QListWidget::item{
2023-12-14 22:59:48 +08:00
min-width: 80px;
max-width: 380px;
min-height: 60px;
max-height: 60px;
}
QListWidget::item:hover {
background: rgb(230, 235, 240);
}
/*被选中时的背景颜色和左边框颜色*/
QListWidget::item:selected {
background: rgb(230, 235, 240);
2023-12-14 22:59:48 +08:00
border-left: 2px solid rgb(62, 62, 62);
color: black;
font-weight: bold;
}
/*鼠标悬停颜色*/
HistoryPanel::item:hover {
background: rgb(52, 52, 52);
}
2024-01-09 22:01:19 +08:00
QCheckBox::indicator {
background: rgb(255, 255, 255);
Width:20px;
Height:20px;
border-radius: 10px
}
QCheckBox::indicator:unchecked{
Width:20px;
Height:20px;
image: url(:/icons/icons/unselect.svg);
}
QCheckBox::indicator:checked{
Width:20px;
Height:20px;
image: url(:/icons/icons/select.svg);
}
2024-01-14 19:57:39 +08:00
QScrollBar:vertical {
border-width: 0px;
border: none;
background:rgba(133, 135, 138, 0);
width:4px;
margin: 0px 0px 0px 0px;
}
QScrollBar::handle:vertical {
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
stop: 0 rgb(133, 135, 138), stop: 0.5 rgb(133, 135, 138), stop:1 rgb(133, 135, 138));
min-height: 20px;
max-height: 20px;
margin: 0 0px 0 0px;
border-radius: 2px;
}
QScrollBar::add-line:vertical {
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
stop: 0 rgba(133, 135, 138, 0), stop: 0.5 rgba(133, 135, 138, 0), stop:1 rgba(133, 135, 138, 0));
height: 0px;
border: none;
subcontrol-position: bottom;
subcontrol-origin: margin;
}
QScrollBar::sub-line:vertical {
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
stop: 0 rgba(133, 135, 138, 0), stop: 0.5 rgba(133, 135, 138, 0), stop:1 rgba(133, 135, 138, 0));
height: 0 px;
border: none;
subcontrol-position: top;
subcontrol-origin: margin;
}
QScrollBar::sub-page:vertical {
background: rgba(133, 135, 138, 0);
}
QScrollBar::add-page:vertical {
background: rgba(133, 135, 138, 0);
}
2024-01-24 19:29:21 +08:00
QProgressBar{
height:22px;
text-align:center;
font-size:14px;
color:black;
border-radius:11px;
background:#EBEEF5;
}
QProgressBar::chunk{
border-radius:11px;
background:qlineargradient(spread:pad,x1:0,y1:0,x2:1,y2:0,stop:0 #99ffff,stop:1 #9900ff);
}
2024-01-24 20:02:01 +08:00
QComboBox
{
border-radius:3px;
border:0px ;
padding-top: 2px;
padding-left: 2px;
}
QComboBox:disabled
{
background-color:rgba(50,50,50,200);
color:rgb(160,160,160);
}
QComboBox:hover
{
background-color:rgba(230,230,230,200);
border:1px solid rgb(31,156,220) ;
}
/*下拉箭头的边框*/
QComboBox::drop-down
{
border:none;
}
2024-01-24 19:29:21 +08:00
2024-01-24 20:02:01 +08:00
/*下拉箭头样式*/
QComboBox::down-arrow
{
right:0px;/*控制箭头左右偏移*/
width: 16px;
height: 16px;
image: url(:/icons/icons/down.svg);
}
/*下拉箭头点击样式*/
QComboBox::down-arrow:on
{
width: 16px;
height: 16px;
image: url(:/icons/icons/up.svg);
}
"""
2024-01-24 20:02:01 +08:00
'''
/*点击combox的样式*/
QComboBox:on
{
border-radius:3px;
background-color:rgba(35,35,35);
font: 75 9pt "Microsoft YaHei";
color:rgb(255,255,255);
border:1px solid rgb(31,156,220) ;
}
/*下拉框的样式*/
QComboBox QAbstractItemView
{
outline: 0px solid gray; /*取消选中虚线*/
border: 1px solid rgb(31,156,220);
font: 75 9pt "Microsoft YaHei";
color: rgb(255,255,255);
background-color: rgb(45,45,45);
selection-background-color: rgb(90,90,90);
}
/*选中每一项高度*/
QComboBox QAbstractItemView::item
{
height: 25px;
}
/*选中每一项的字体颜色和背景颜色*/
QComboBox QAbstractItemView::item:selected
{
color: rgb(31,163,246);
background-color: rgb(90,90,90);
}
'''
2024-01-13 16:33:57 +08:00
class MainWinController(QMainWindow, mainwindow.Ui_MainWindow, QCursorGif):
exitSignal = pyqtSignal(bool)
okSignal = pyqtSignal(bool)
# username = ''
def __init__(self, username, parent=None):
super(MainWinController, self).__init__(parent)
self.outputThread0 = None
self.outputThread = None
self.setupUi(self)
2023-12-15 21:06:18 +08:00
# self.setWindowIcon(Icon.MainWindow_Icon)
pixmap = QPixmap(Icon.logo_ico_path)
icon = QIcon(pixmap)
self.setWindowIcon(icon)
self.setStyleSheet(Stylesheet)
self.listWidget.clear()
self.resize(QSize(800, 600))
2024-01-14 01:21:19 +08:00
self.load_flag = False
self.load_data()
self.load_num = 0
self.label = QLabel(self)
self.label.setGeometry((self.width() - 300) // 2, (self.height() - 100) // 2, 300, 100)
self.label.setPixmap(QPixmap(':/icons/icons/loading.svg'))
self.menu_output.setIcon(Icon.Output)
self.action_output_CSV.setIcon(Icon.ToCSV)
self.action_output_CSV.triggered.connect(self.output)
self.action_output_contacts.setIcon(Icon.Output)
self.action_output_contacts.triggered.connect(self.output)
self.action_batch_export.setIcon(Icon.Output)
self.action_batch_export.triggered.connect(self.output)
self.action_desc.setIcon(Icon.Help_Icon)
2024-01-24 19:29:21 +08:00
self.action_update.setIcon(Icon.Update_Icon)
def load_data(self, flag=True):
if os.path.exists('./app/data/info.json'):
with open('./app/data/info.json', 'r', encoding='utf-8') as f:
dic = json.loads(f.read())
wxid = dic.get('wxid')
if wxid:
2023-12-30 19:26:24 +08:00
me = Me()
me.wxid = dic.get('wxid')
me.name = dic.get('name')
me.mobile = dic.get('mobile')
me.wx_dir = dic.get('wx_dir')
self.set_my_info(wxid)
self.load_flag = True
else:
2024-01-17 20:04:59 +08:00
pass
def init_ui(self):
# 设置忙碌光标图片数组
self.initCursor([':/icons/icons/Cursors/%d.png' %
i for i in range(8)])
self.setCursorTimeout(100)
self.startBusy()
2024-01-17 20:20:32 +08:00
self.action_update.triggered.connect(self.update)
2024-01-22 22:21:55 +08:00
self.action_help_faq.triggered.connect(
lambda: QDesktopServices.openUrl(QUrl("https://blog.lc044.love/post/7")))
2024-01-13 16:33:57 +08:00
self.about_view = AboutDialog(main_window=self, parent=self)
def setCurrentIndex(self, row):
self.stackedWidget.setCurrentIndex(row)
if row == 2:
self.stackedWidget.currentWidget().show_contacts()
if row == 1:
self.stackedWidget.currentWidget().show_chats()
def setWindow(self, window):
try:
window.load_finish_signal.connect(self.loading)
except:
pass
self.stackedWidget.addWidget(window)
def set_my_info(self, wxid):
self.avatar = QPixmap()
try:
img_bytes = misc_db.get_avatar_buffer(wxid)
2024-01-13 16:33:57 +08:00
except:
2023-12-19 17:02:42 +08:00
close_db()
logger.error(f'数据库错误:\n{traceback.format_exc()}')
QMessageBox.critical(self, "数据库错误", "请重启微信后重试")
import shutil
shutil.rmtree('./app/Database/Msg')
return
if not img_bytes:
return
if img_bytes[:4] == b'\x89PNG':
self.avatar.loadFromData(img_bytes, format='PNG')
else:
self.avatar.loadFromData(img_bytes, format='jfif')
self.avatar.scaled(60, 60)
2023-12-29 21:50:17 +08:00
contact_info_list = micro_msg_db.get_contact_by_username(wxid)
2023-12-30 19:26:24 +08:00
me = Me()
me.set_avatar(img_bytes)
2023-12-29 21:50:17 +08:00
me.smallHeadImgUrl = contact_info_list[7]
self.myavatar.setScaledContents(True)
self.myavatar.setPixmap(self.avatar)
def stop_loading(self, a0):
self.label.setVisible(False)
self.stopBusy()
def loading(self, a0):
self.load_num += 1
if self.load_num == 1:
self.label.clear()
self.label.hide()
self.okSignal.emit(True)
self.listWidget.setVisible(True)
self.stackedWidget.setVisible(True)
self.stopBusy()
if self.load_flag:
self.listWidget.setCurrentRow(1)
self.stackedWidget.setCurrentIndex(1)
else:
self.listWidget.setCurrentRow(0)
self.stackedWidget.setCurrentIndex(0)
def output(self):
# self.startBusy()
if self.sender() == self.action_output_CSV:
self.outputThread = Output(None, type_=Output.CSV_ALL)
2024-01-13 16:33:57 +08:00
self.outputThread.startSignal.connect(lambda x: self.startBusy())
self.outputThread.okSignal.connect(
lambda x: self.message('聊天记录导出成功'))
self.outputThread.start()
elif self.sender() == self.action_output_contacts:
self.outputThread = Output(None, type_=Output.CONTACT_CSV)
self.outputThread.startSignal.connect(lambda x: self.startBusy())
self.outputThread.okSignal.connect(
lambda x: self.message('联系人导出成功'))
self.outputThread.start()
2024-01-06 13:04:55 +08:00
elif self.sender() == self.action_batch_export:
dialog = ExportDialog(None, title='批量导出聊天记录', parent=self)
2024-01-24 20:02:01 +08:00
result = dialog.exec_() # 使用exec_()获取用户的操作结果
def message(self, msg):
2023-12-23 19:07:15 +08:00
self.stopBusy()
QMessageBox.about(self, "提醒", msg)
2024-01-17 20:20:32 +08:00
def update(self):
self.update_thread = UpdateThread()
self.update_thread.updateSignal.connect(self.show_update)
self.update_thread.start()
def show_update(self, update_info):
if not update_info.get('update_available'):
QMessageBox.information(self, '更新通知', "当前已是最新版本")
return
detail = f'''
当前版本:{version},最新版本:{update_info.get('latest_version')}<br>
更新内容:
{update_info.get('description')}
<br><a href='{update_info.get('download_url')}'>点击下载</a>
'''
QMessageBox.information(self, '更新通知', detail)
def about(self):
"""
关于
"""
2024-01-13 16:33:57 +08:00
self.about_view.show()
def decrypt_success(self):
QMessageBox.about(self, "解密成功", "请重新启动")
self.close()
def closeEvent(self, event):
reply = QMessageBox.question(self, '确认退出', '确定要退出吗?',
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
close_db()
event.accept()
else:
event.ignore()
2024-01-13 16:33:57 +08:00
def close(self) -> bool:
close_db()
self.contact_window.close()
2024-01-15 19:51:08 +08:00
super().close()
self.exitSignal.emit(True)
class LoadWindowThread(QThread):
okSignal = pyqtSignal(bool)
def __init__(self):
super().__init__()
self.num = 0
def loading(self):
self.num += 1
print('加载一个了')
if self.num == 2:
self.okSignal.emit(True)
def run(self):
self.chat_window = ChatWindow()
self.contact_window = ContactWindow()
self.contact_window.load_finish_signal.connect(self.loading)
self.chat_window.load_finish_signal.connect(self.loading)
print('加载完成')
self.okSignal.emit(True)