Skip to content

Fix/load user avatar#1

Open
Detritalw wants to merge 25 commits intomainfrom
fix/load-user-avatar
Open

Fix/load user avatar#1
Detritalw wants to merge 25 commits intomainfrom
fix/load-user-avatar

Conversation

@Detritalw
Copy link
Member

No description provided.

Resolves NameError encountered during runtime when opening chat view.

Error log:

File 'app/view/chat_interface.py', line 119, in __init__

    self.send_btn = PrimaryPushButton('发送', self)

                    ^^^^^^^^^^^^^^^^^

NameError: name 'PrimaryPushButton' is not defined

Fix:

Import PrimaryPushButton from qfluentwidgets in app/view/chat_interface.py.
Refactored ChatView.addMessage to use proper nested layouts:

1. Introduced top-level QHBoxLayout for the message row.

2. Added missing Avatar placeholder (IconWidget).

3. Separated NameLabel and MessageBubble into a vertical column to prevent overlap.

4. Applied distinctive styling for self/other messages (colors, borders).

5. Fixed alignment issues (Left for others, Right for self).
@gemini-code-assist
Copy link

Summary of Changes

Hello @Detritalw, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request lays the groundwork for a new desktop QQ client application, focusing on a modern user interface and robust backend integration. It provides a complete framework for real-time messaging, contact management, and user customization, built upon PyQt6 and QFluentWidgets. The changes encompass everything from API communication and local data storage to a responsive and feature-rich chat interface, marking the initial release of the application's core components.

Highlights

  • New Application Core: This pull request introduces the foundational codebase for a new Python-based QQ client application, leveraging PyQt6 and QFluentWidgets for a modern Fluent UI experience.
  • NapCat API Integration: The application is fully integrated with the NapCat QQ API (a OneBot v11 implementation) for all communication, including messaging, contact management, and real-time updates via HTTP and WebSockets.
  • Rich Chat Features: Comprehensive chat functionalities are implemented, supporting text and image messages, file uploads, message recall, emoji reactions, @mentions, and message replies, all displayed within interactive chat bubbles.
  • Local History Persistence: A local SQLite database is used to store and manage chat message history, ensuring messages are persistent and easily retrievable, with raw message data compressed using zlib.
  • Customizable User Interface: Users can personalize their experience through various settings, including theme (light, dark, auto), message layout, chat font family, and image preview behavior (QuickLook or system default).
  • Project Infrastructure Setup: Initial project infrastructure has been established, including GitHub funding configuration, issue templates for bug reports and feature requests, and VS Code launch configurations for development and packaging.
Changelog
  • .github/FUNDING.yml
    • Added GitHub funding configuration.
  • .github/ISSUE_TEMPLATE/BugReport.yml
    • Added a bug report issue template in Chinese.
  • .github/ISSUE_TEMPLATE/FeatureRequest.yml
    • Added a feature request issue template in Chinese.
  • .github/ISSUE_TEMPLATE/config.yml
    • Added issue template configuration with contact links to discussions and QQ groups.
  • .gitignore
    • Added '/napcat' to the ignore list, likely for build outputs or temporary files.
  • .vscode/launch.json
    • Added VS Code launch configurations for Python debugging and PyInstaller packaging.
  • Fluent-QQ.py
    • Added the main application entry point, responsible for initializing the PyQt6 application, setting high DPI scaling, applying the theme, and launching the main window.
  • app/common/api_client.py
    • Introduced the 'NapCatClient' class for handling HTTP API calls and WebSocket communication with the OneBot v11 compatible QQ API.
    • Implemented methods for sending messages (text, image), uploading files, recalling messages, managing emoji reactions, and fetching various contact and message data.
  • app/common/config.py
    • Defined the 'Config' class using qfluentwidgets.QConfig for managing application settings.
    • Included configurable options for API/WebSocket URLs, authentication token, theme mode, message layout, image preview mode, chat font family, and language.
  • app/common/history_manager.py
    • Added 'HistoryManager' for local message history persistence using an SQLite database.
    • Implemented methods for saving and retrieving single or batch messages, with raw message data stored as zlib-compressed JSON blobs.
  • app/common/launch_quicklook.ps1
    • Added a PowerShell script to launch the 'QuickLook' application for enhanced file previews, including error handling and logging.
  • app/common/system_utils.py
    • Added utility function 'get_system_accent_color' to retrieve the Windows system accent color from the registry.
  • app/common/theme_manager.py
    • Introduced 'ThemeManager' to apply manual theme patches for standard Qt widgets, ensuring consistent styling with the Fluent UI theme, especially in dark mode.
  • app/common/time_utils.py
    • Added a utility function 'get_relative_time' to convert Unix timestamps into human-readable relative time strings (e.g., '5 minutes ago').
  • app/view/chat_interface.py
    • Implemented 'MessageCard' for displaying message previews in the message center.
    • Added 'ChatLineEdit' to support image pasting from the clipboard.
    • Created 'ImagePasteDialog' for confirming pasted image sends.
    • Developed 'ChatView' for individual chat windows, featuring message history display, input area, reply bar, and handling of various message types and actions.
    • Designed 'ChatInterface' as the main chat management view, utilizing a TabBar for navigation and a SegmentedWidget for filtering contact lists.
  • app/view/components/init.py
    • Exported 'ImageWidget' for module accessibility.
  • app/view/components/avatar_widget.py
    • Added 'AvatarWidget' for displaying circular user avatars with asynchronous loading capabilities from URLs.
  • app/view/components/chat_bubble.py
    • Implemented 'ReplyQuote' for displaying reply references within chat bubbles.
    • Introduced 'ReactionChip' for showing emoji reactions with counts.
    • Developed 'ChatBubble' as the core message display component, supporting different styles for self/other messages, and providing context menus for message actions like recall, reply, and reactions.
  • app/view/components/image_widget.py
    • Added 'ImageWidget' for displaying images within chat bubbles, handling loading, scaling, and offering options for QuickLook or system default viewer for full-size previews.
  • app/view/components/member_select_dialog.py
    • Created a dialog for selecting group members for @mentions, including search functionality and an '@ALL' option for administrators.
  • app/view/contact_interface.py
    • Implemented 'ContactCard' for displaying individual friends or groups.
    • Developed 'ContactInterface' to manage and display friend and group lists, with search and tab-based filtering capabilities.
  • app/view/main_window.py
    • Added the 'MainWindow' class, serving as the application's main window, integrating all UI components, managing navigation, and handling system-level features like system tray icon and theme synchronization.
  • app/view/setting_interface.py
    • Introduced 'FontSettingCard' for custom font selection in settings.
    • Developed 'SettingInterface' to provide a comprehensive settings panel, categorized into Appearance, Behavior, and Connection, allowing users to configure various application aspects.
  • config.json
    • Added a default configuration file for the application, specifying initial API endpoints, theme, and other settings.
  • test_gui.py
    • Added a minimal PyQt6 GUI test file.
  • test_qf.py
    • Added a minimal QFluentWidgets test file.
  • tests/test_api_client.py
    • Added unit tests for the 'NapCatClient' API communication.
  • tests/test_bubble_reaction.py
    • Added UI tests for the rendering of emoji reactions within 'ChatBubble' components.
  • tests/test_font_config.py
    • Added unit tests for the font configuration functionality.
  • tests/test_layout_warning.py
    • Added a test to specifically check for PyQt layout warnings related to 'ChatBubble' instantiation.
  • tests/test_reaction_logic.py
    • Added unit tests for the logic governing the display and behavior of reactions in chat bubbles.
  • tests/test_reply_logic.py
    • Added unit tests for the 'HistoryManager's ability to retrieve reply messages by ID.
  • tests/test_reply_ui.py
    • Added UI tests for the click functionality of reply quotes within 'ChatBubble' components.
  • tests/test_setting_interface.py
    • Added unit tests for the instantiation and functionality of the 'SettingInterface' and its font selection card.
Ignored Files
  • Ignored by pattern: .github/workflows/** (9)
    • .github/workflows/Nuitka-Build.yml
    • .github/workflows/Release.yml.closed
    • .github/workflows/build.yml
    • .github/workflows/file-list.json
    • .github/workflows/issue.yml.closed
    • .github/workflows/issue_closed.yml.closed
    • .github/workflows/refresh-version.py
    • .github/workflows/release.md
    • .github/workflows/wingetcreate.yml.closed
Activity
  • The pull request introduces a substantial amount of new code, indicating the initial creation or a significant overhaul of a Python-based QQ client application.
  • Numerous new files across common utilities, API integration, and various UI components (chat, contacts, settings) have been added.
  • A suite of unit and UI tests has been included, suggesting a focus on ensuring the correctness and stability of the newly introduced features and components.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a substantial amount of code, effectively building out the entire initial structure of the Fluent QQ application. The changes include the main application window, chat and settings interfaces, various UI components, an API client, and configuration management. While the overall structure is well-organized and utilizes modern Python and PyQt6 practices, there are several critical issues and areas for improvement regarding security, performance, and code quality that should be addressed. Key issues include a hardcoded token in a configuration file, a critical bug due to a call to a non-existent method, performance bottlenecks from synchronous network calls in the UI thread, and several code quality improvements such as replacing print statements with a proper logger and avoiding bad practices like bare except clauses.

if not ref_msg:
# Try remote
try:
res = client.get_msg(reply_ref_id)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The method client.get_msg() is called here, but it is not defined in the NapCatClient class in app/common/api_client.py. This will cause a runtime AttributeError. You need to either implement the get_msg method in the API client or use an existing method to fetch a single message.

"api_url": "http://127.0.0.1:3000",
"language": "zh_CN",
"theme": "Light",
"token": "shenmitoken",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Hardcoding secrets like API tokens directly into version-controlled files is a major security risk. This token is now exposed in the repository's history. It should be removed immediately. Secrets should be managed through environment variables or a local configuration file that is included in .gitignore.

Comment on lines +98 to +99
except:
pass

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using a bare except: pass is dangerous as it silently ignores all exceptions, including system-exiting ones like SystemExit or KeyboardInterrupt. This can hide bugs and make debugging extremely difficult. At a minimum, you should catch Exception and log the error.

Suggested change
except:
pass
except Exception as e:
print(f"[AvatarLoader] Failed to load image from {self.url}: {e}")

try:
conn = sqlite3.connect(self.db_path)
# Enable memory mapping for faster access
conn.execute("PRAGMA mmap_size = 30000000000")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The PRAGMA mmap_size is set to 30GB, which is an extremely large value and could cause issues on systems with less memory. Furthermore, this pragma is executed every time a database operation is performed, which is redundant. It should be set only once when the database connection is established. Consider reducing the mmap_size to a more reasonable value (e.g., 256MB) and setting it only in the _init_db method after the connection is created.

Comment on lines +381 to +383
chat_interface = self.window().findChild(QFrame, "chatInterface")
if chat_interface and chat_interface.self_id:
self.current_self_id = str(chat_interface.self_id)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Accessing parent components using self.window().findChild(...) creates tight coupling between components and makes the code harder to maintain and test. A better approach is to pass necessary information (like self_id) down to child widgets through their constructors or dedicated methods. This promotes component independence and follows the principle of dependency injection.

Comment on lines +54 to +56
except Exception as e:
print(f"[Client] API Error: {e}")
return None

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Catching a broad Exception can hide bugs and make debugging more difficult. It's better to catch more specific exceptions that you expect to handle, such as requests.exceptions.RequestException for network errors or json.JSONDecodeError for parsing issues. This makes the error handling more precise and robust.

Suggested change
except Exception as e:
print(f"[Client] API Error: {e}")
return None
except requests.exceptions.RequestException as e:
print(f"[Client] API Network Error: {e}")
return None
except json.JSONDecodeError as e:
print(f"[Client] API JSON Decode Error: {e}")
return None

Comment on lines +43 to +58
def _load():
try:
response = requests.get(url, timeout=5)
if response.status_code == 200:
pixmap = QPixmap()
pixmap.loadFromData(response.content)
# Update UI in main thread (not strictly safe here but ImageLabel usually handles pixmap setting well,
# but for safety we should use signals if this was complex.
# For simplicity in this context, we'll assume direct setPixmap works or needs invokeMethod.
# Actually, PySide/PyQt UI updates MUST be in main thread.
# Let's use a simple QTimer or custom signal approach if needed,
# but for now let's just use a simple synchronous load in thread with signal
# Wait, we can't emit signal from thread without defining it.
pass
except Exception as e:
print(f"[AvatarWidget] Error loading {url}: {e}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block contains an old, incorrect, and commented-out implementation for loading an image. Since the correct implementation using AvatarLoader is already in place, this dead code should be removed to improve clarity and maintainability.

setTheme(theme)
ThemeManager.apply_theme_patches(theme)

from app.view.main_window import MainWindow

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For better code organization and to adhere to PEP 8 guidelines, it's recommended to move all imports to the top of the file. Local imports, like this one for MainWindow, can sometimes be justified (e.g., to avoid circular dependencies or for optional features), but in this case, moving it to the top would improve readability and consistency.

Move `from app.view.main_window import MainWindow` to the top of the file with other imports.


r_layout.addStretch(1)
layout.addWidget(self.reaction_container)
print("DEBUG: reaction_container added to layout")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This print statement appears to be for debugging purposes. It should be removed from the production code. For diagnostics, consider using the logging module, which allows for configurable log levels and outputs.

self.api_url = config.get("api_url").rstrip('/')
self.ws_url = config.get("ws_url")
self.token = config.get("token")
print(f"[Client] Config refreshed: API={self.api_url}, WS={self.ws_url}, Token={'***' if self.token else 'None'}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Throughout the application, print() is used for logging. For a more robust and configurable logging solution, it's highly recommended to use Python's built-in logging module. This allows you to control log levels (e.g., DEBUG, INFO, ERROR), direct output to files, and easily enable or disable logging in production builds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant