Compare commits

3 Commits

4 changed files with 420 additions and 20 deletions

View File

@@ -14,15 +14,18 @@ class IRCPanel(wx.Panel):
self.parent = parent
self.main_frame = main_frame
self.messages = []
self.theme = getattr(self.main_frame, "theme", None)
self.default_text_colour = self.theme["text"] if self.theme else wx.Colour(0, 0, 0)
sizer = wx.BoxSizer(wx.VERTICAL)
# Use a better font for chat with white theme
self.text_ctrl = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2 | wx.TE_AUTO_URL)
# White theme colors
self.text_ctrl.SetBackgroundColour(wx.Colour(255, 255, 255)) # White background
self.text_ctrl.SetForegroundColour(wx.Colour(0, 0, 0)) # Black text
if self.theme:
self.text_ctrl.SetBackgroundColour(self.theme["content_bg"])
self.text_ctrl.SetForegroundColour(self.theme["text"])
self.SetBackgroundColour(self.theme["content_bg"])
# Load appropriate font
self.font = self.load_system_font()
@@ -143,7 +146,7 @@ class IRCPanel(wx.Panel):
if message_color:
attr.SetTextColour(message_color)
else:
attr.SetTextColour(wx.Colour(0, 0, 0)) # Black text for white theme
attr.SetTextColour(self.default_text_colour)
attr.SetFont(self.font)
self.text_ctrl.SetDefaultStyle(attr)
@@ -169,7 +172,7 @@ class IRCPanel(wx.Panel):
self.add_message(message, f"* {username}", username_color, wx.Colour(128, 0, 128), italic=True) # Dark purple for actions
else:
message = f"{timestamp}<{username}> {content}"
self.add_message(message, f"<{username}>", username_color, wx.Colour(0, 0, 0)) # Black text
self.add_message(message, f"<{username}>", username_color, self.default_text_colour)
except Exception as e:
logger.error(f"Error adding formatted message: {e}")

View File

@@ -19,6 +19,7 @@ class NotesDialog(wx.Frame):
style=wx.DEFAULT_FRAME_STYLE)
self.parent = parent
self.theme = getattr(parent, "theme", None)
self.notes_data = notes_data or defaultdict(dict)
self.current_note_key = None
self.updating_title = False
@@ -27,7 +28,7 @@ class NotesDialog(wx.Frame):
self.last_save_time = time.time()
self.auto_save_interval = 2 # seconds - reduced for immediate saving
self.SetBackgroundColour(wx.Colour(245, 245, 245))
self.SetBackgroundColour(self.get_theme_colour("window_bg", wx.SystemSettings().GetColour(wx.SYS_COLOUR_WINDOW)))
# Set icon if parent has one
if parent:
@@ -61,6 +62,11 @@ class NotesDialog(wx.Frame):
if self.GetParent().GetId() == pId:
self.GetParent().Close()
def get_theme_colour(self, key, fallback):
if self.theme and key in self.theme:
return self.theme[key]
return fallback
def create_controls(self):
# Create menu bar
self.create_menu_bar()
@@ -72,6 +78,7 @@ class NotesDialog(wx.Frame):
# Left panel - notes list
left_panel = wx.Panel(splitter)
left_panel.SetBackgroundColour(self.get_theme_colour("sidebar_bg", left_panel.GetBackgroundColour()))
left_sizer = wx.BoxSizer(wx.VERTICAL)
notes_label = wx.StaticText(left_panel, label="Your Notes:")
@@ -101,6 +108,7 @@ class NotesDialog(wx.Frame):
# Right panel - editor
right_panel = wx.Panel(splitter)
right_panel.SetBackgroundColour(self.get_theme_colour("content_bg", right_panel.GetBackgroundColour()))
right_sizer = wx.BoxSizer(wx.VERTICAL)
title_label = wx.StaticText(right_panel, label="Note Title:")
@@ -226,6 +234,7 @@ class NotesDialog(wx.Frame):
def setup_editor_toolbar(self, parent):
self.toolbar = wx.Panel(parent)
self.toolbar.SetBackgroundColour(self.get_theme_colour("control_bg", self.toolbar.GetBackgroundColour()))
toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL)
# Text formatting buttons

View File

@@ -43,8 +43,9 @@ class IRCFrame(wx.Frame):
def __init__(self):
super().__init__(None, title="wxIRC", size=(1200, 700))
# Apply white theme
self.apply_white_theme()
# Determine platform theme once
self.theme = self.build_theme()
self.apply_theme()
# Show privacy notice first
self.show_privacy_notice()
@@ -121,18 +122,69 @@ class IRCFrame(wx.Frame):
self.Bind(wx.EVT_MENU, self.on_find_previous, id=1002)
self.Bind(wx.EVT_MENU, self.on_quick_escape, id=1003)
def apply_white_theme(self):
"""Apply white theme to the application"""
def build_theme(self):
"""Build a small theme descriptor that respects the host platform."""
try:
# Set system colors for white theme
self.SetBackgroundColour(wx.Colour(255, 255, 255))
self.SetForegroundColour(wx.Colour(0, 0, 0))
# Set system settings for light theme
sys_settings = wx.SystemSettings()
system_window = sys_settings.GetColour(wx.SYS_COLOUR_WINDOW)
system_text = sys_settings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)
system_face = sys_settings.GetColour(wx.SYS_COLOUR_BTNFACE)
is_windows = wx.Platform == "__WXMSW__"
if is_windows:
window_bg = wx.Colour(255, 255, 255)
control_bg = wx.Colour(240, 240, 240)
text = wx.Colour(0, 0, 0)
else:
window_bg = system_window
control_bg = system_face
text = system_text
sidebar_delta = 15 if self._is_light_colour(window_bg) else -20
sidebar_bg = self._adjust_colour(control_bg if control_bg.IsOk() else window_bg, sidebar_delta)
return {
"window_bg": window_bg,
"content_bg": window_bg,
"text": text,
"sidebar_bg": sidebar_bg,
"control_bg": control_bg if control_bg.IsOk() else window_bg,
"force_light": is_windows,
}
except Exception as e:
logger.error(f"Error applying white theme: {e}")
logger.error(f"Error building theme: {e}")
# Fallback to a simple light theme
return {
"window_bg": wx.Colour(255, 255, 255),
"content_bg": wx.Colour(255, 255, 255),
"text": wx.Colour(0, 0, 0),
"sidebar_bg": wx.Colour(240, 240, 240),
"control_bg": wx.Colour(240, 240, 240),
"force_light": True,
}
def _is_light_colour(self, colour):
"""Simple luminance check to know if a colour is light."""
luminance = 0.299 * colour.Red() + 0.587 * colour.Green() + 0.114 * colour.Blue()
return luminance >= 128
def _adjust_colour(self, colour, delta):
"""Lighten or darken a colour by delta."""
def clamp(value):
return max(0, min(255, value))
return wx.Colour(
clamp(colour.Red() + delta),
clamp(colour.Green() + delta),
clamp(colour.Blue() + delta),
)
def apply_theme(self):
"""Apply the detected theme."""
try:
self.SetBackgroundColour(self.theme["window_bg"])
self.SetForegroundColour(self.theme["text"])
except Exception as e:
logger.error(f"Error applying theme: {e}")
def show_privacy_notice(self):
"""Show privacy notice dialog at startup"""
@@ -199,12 +251,12 @@ class IRCFrame(wx.Frame):
def setup_ui(self):
"""Setup UI components with white theme"""
panel = wx.Panel(self)
panel.SetBackgroundColour(wx.Colour(255, 255, 255)) # White background
panel.SetBackgroundColour(self.theme["window_bg"])
main_sizer = wx.BoxSizer(wx.HORIZONTAL)
# Left sidebar - light gray for contrast
left_panel = wx.Panel(panel)
left_panel.SetBackgroundColour(wx.Colour(240, 240, 240)) # Light gray
left_panel.SetBackgroundColour(self.theme["sidebar_bg"])
left_sizer = wx.BoxSizer(wx.VERTICAL)
conn_box = wx.StaticBox(left_panel, label="Connection")
@@ -270,7 +322,7 @@ class IRCFrame(wx.Frame):
# Center - Notebook
self.notebook = wx.Notebook(panel)
self.notebook.SetBackgroundColour(wx.Colour(255, 255, 255))
self.notebook.SetBackgroundColour(self.theme["content_bg"])
# Server panel
server_panel = IRCPanel(self.notebook, self)
@@ -280,7 +332,7 @@ class IRCFrame(wx.Frame):
# Right sidebar - Users - light gray for contrast
right_panel = wx.Panel(panel)
right_panel.SetBackgroundColour(wx.Colour(240, 240, 240)) # Light gray
right_panel.SetBackgroundColour(self.theme["sidebar_bg"])
right_sizer = wx.BoxSizer(wx.VERTICAL)
users_box = wx.StaticBox(right_panel, label="Users")

336
write.ps1 Normal file
View File

@@ -0,0 +1,336 @@
param(
[string]$usbLetter,
[string]$srcPath = ".\src",
[string]$distPath = ".\dist\main.exe"
)
function Write-Header {
param([string]$title)
$width = 80
$padding = [math]::Floor(($width - $title.Length - 2) / 2)
Write-Host ""
Write-Host ("=" * $width) -ForegroundColor Cyan
Write-Host ("=" + (" " * $padding) + $title + (" " * $padding) + "=") -ForegroundColor Cyan
Write-Host ("=" * $width) -ForegroundColor Cyan
Write-Host ""
}
function Write-Step {
param([string]$message)
Write-Host "[*] " -NoNewline -ForegroundColor Green
Write-Host $message -ForegroundColor White
}
function Write-ErrorMsg {
param([string]$message)
Write-Host "[X] " -NoNewline -ForegroundColor Red
Write-Host $message -ForegroundColor Red
}
function Write-Success {
param([string]$message)
Write-Host "[+] " -NoNewline -ForegroundColor Green
Write-Host $message -ForegroundColor Green
}
function Write-Warning {
param([string]$message)
Write-Host "[!] " -NoNewline -ForegroundColor Yellow
Write-Host $message -ForegroundColor Yellow
}
function Write-ProgressBar {
param(
[int]$current,
[int]$total,
[string]$activity
)
$percent = [math]::Min(100, [math]::Floor(($current / $total) * 100))
$barWidth = 50
$completed = [math]::Floor(($percent / 100) * $barWidth)
$remaining = $barWidth - $completed
$completedBar = "#" * $completed
$remainingBar = "-" * $remaining
$bar = "[" + $completedBar + $remainingBar + "]"
Write-Host ("`r$activity $bar $percent% ($current/$total)") -NoNewline -ForegroundColor Cyan
if ($current -eq $total) {
Write-Host ""
}
}
function Test-Prerequisites {
$errors = @()
# Check if running as admin (for autorun.inf)
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Warning "Not running as administrator. Autorun.inf may not work properly."
}
# Validate USB letter format
if ($usbLetter -notmatch '^[A-Z]:?$') {
$errors += "Invalid USB letter format. Use format like 'E:' or 'E'"
}
# Normalize USB letter
$script:usbLetter = $usbLetter.TrimEnd(':') + ':'
# Check if paths exist
if (-not (Test-Path $srcPath)) {
$errors += "Source path not found: $srcPath"
}
if (-not (Test-Path $distPath)) {
$errors += "Distribution executable not found: $distPath"
}
# Check USB drive
$usbRoot = "$($script:usbLetter)\"
if (-not (Test-Path $usbRoot)) {
$errors += "USB drive not found: $usbRoot"
} else {
# Check if USB has enough space
try {
$drive = Get-PSDrive -Name $script:usbLetter.TrimEnd(':') -ErrorAction Stop
$freeSpaceMB = [math]::Round($drive.Free / 1MB, 2)
# Estimate required space
$srcSize = (Get-ChildItem -Path $srcPath -Recurse -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -notmatch "__pycache__" } |
Measure-Object -Property Length -Sum).Sum
$distSize = (Get-Item $distPath).Length
$requiredMB = [math]::Round(($srcSize + $distSize) / 1MB * 1.1, 2)
if ($freeSpaceMB -lt $requiredMB) {
$errors += "Insufficient space on USB. Required: ~$requiredMB MB, Available: $freeSpaceMB MB"
}
} catch {
Write-Warning "Could not check USB free space: $_"
}
}
return $errors
}
Clear-Host
Write-Header "wxIRC USB Writer"
# Show usage if no USB letter provided
if (-not $usbLetter) {
Write-Host "Usage: .\write.ps1 -usbLetter E:" -ForegroundColor Yellow
Write-Host ""
Write-Host "Parameters:" -ForegroundColor Cyan
Write-Host " -usbLetter : Target USB drive letter (required)" -ForegroundColor White
Write-Host " -srcPath : Source directory (default: .\src)" -ForegroundColor White
Write-Host " -distPath : Executable path (default: .\dist\main.exe)" -ForegroundColor White
Write-Host ""
exit 1
}
Write-Step "Validating prerequisites..."
$validationErrors = Test-Prerequisites
if ($validationErrors.Count -gt 0) {
Write-Host ""
foreach ($err in $validationErrors) {
Write-ErrorMsg $err
}
Write-Host ""
exit 1
}
Write-Success "All prerequisites validated"
# Convert to absolute paths
try {
$srcPath = (Resolve-Path $srcPath -ErrorAction Stop).Path
$distPath = (Resolve-Path $distPath -ErrorAction Stop).Path
} catch {
Write-ErrorMsg "Failed to resolve paths: $_"
exit 1
}
$usbRoot = "$usbLetter\"
Write-Host ""
Write-Host "Configuration:" -ForegroundColor Cyan
Write-Host " Source : $srcPath" -ForegroundColor White
Write-Host " Executable : $distPath" -ForegroundColor White
Write-Host " USB Target : $usbRoot" -ForegroundColor White
Write-Host ""
# Confirm before proceeding
Write-Host "This will overwrite existing files on the USB drive." -ForegroundColor Yellow
$response = Read-Host "Continue? (Y/N)"
if ($response -ne 'Y' -and $response -ne 'y') {
Write-Host "Operation cancelled." -ForegroundColor Yellow
exit 0
}
Write-Host ""
$startTime = Get-Date
Write-Step "Preparing source directory..."
$srcDest = Join-Path $usbRoot "src"
if (Test-Path $srcDest) {
try {
Remove-Item -Recurse -Force $srcDest -ErrorAction Stop
} catch {
Write-ErrorMsg "Failed to remove existing src directory: $_"
exit 1
}
}
try {
New-Item -ItemType Directory -Path $srcDest -ErrorAction Stop | Out-Null
} catch {
Write-ErrorMsg "Failed to create src directory: $_"
exit 1
}
Write-Step "Scanning source files..."
$allFiles = @(Get-ChildItem -Path $srcPath -Recurse -ErrorAction SilentlyContinue | Where-Object {
$_.FullName -notmatch "__pycache__"
})
$totalFiles = $allFiles.Count
$currentFile = 0
Write-Step "Copying $totalFiles files..."
foreach ($item in $allFiles) {
$currentFile++
try {
$relative = $item.FullName.Substring($srcPath.Length)
$target = Join-Path $srcDest $relative
if ($item.PSIsContainer) {
if (-not (Test-Path $target)) {
New-Item -ItemType Directory -Path $target -ErrorAction Stop | Out-Null
}
} else {
$targetDir = Split-Path -Parent $target
if (-not (Test-Path $targetDir)) {
New-Item -ItemType Directory -Path $targetDir -ErrorAction Stop | Out-Null
}
Copy-Item $item.FullName -Destination $target -Force -ErrorAction Stop
}
Write-ProgressBar -current $currentFile -total $totalFiles -activity "Copying files"
} catch {
Write-Host ""
Write-ErrorMsg "Failed to copy $($item.FullName): $_"
}
}
Write-Success "Source files copied successfully"
Write-Step "Copying executable..."
try {
$exeDest = Join-Path $usbRoot "wxIRC.exe"
$exeSize = (Get-Item $distPath).Length
$exeSizeMB = [math]::Round($exeSize / 1MB, 2)
Write-Host " Size: $exeSizeMB MB" -ForegroundColor Gray
# Copy with progress simulation for large files
if ($exeSize -gt 5MB) {
$buffer = 1MB
$read = 0
$totalChunks = [math]::Ceiling($exeSize / $buffer)
$currentChunk = 0
$sourceStream = [System.IO.File]::OpenRead($distPath)
$destStream = [System.IO.File]::Create($exeDest)
$bufferArray = New-Object byte[] $buffer
try {
while (($read = $sourceStream.Read($bufferArray, 0, $buffer)) -gt 0) {
$destStream.Write($bufferArray, 0, $read)
$currentChunk++
Write-ProgressBar -current $currentChunk -total $totalChunks -activity "Copying executable"
}
} finally {
$sourceStream.Close()
$destStream.Close()
}
} else {
# For smaller files, just copy directly
Copy-Item $distPath -Destination $exeDest -Force -ErrorAction Stop
Write-ProgressBar -current 1 -total 1 -activity "Copying executable"
}
Write-Success "Executable copied as wxIRC.exe"
} catch {
Write-ErrorMsg "Failed to copy executable: $_"
exit 1
}
Write-Step "Creating autorun.inf..."
try {
$autorun = Join-Path $usbRoot "autorun.inf"
@(
"[AutoRun]"
"open=wxIRC.exe"
"label=wxIRC"
"icon=src\icon.ico"
) | Set-Content -Path $autorun -Encoding ASCII -ErrorAction Stop
# Try to set hidden attribute (may fail without admin)
try {
$autorunItem = Get-Item $autorun -ErrorAction Stop
$autorunItem.Attributes = $autorunItem.Attributes -bor [System.IO.FileAttributes]::Hidden
} catch {
# Silently continue if can't set hidden attribute
}
Write-Success "Autorun.inf created"
} catch {
Write-ErrorMsg "Failed to create autorun.inf: $_"
}
Write-Step "Generating write info..."
$endTime = Get-Date
$duration = ($endTime - $startTime).TotalSeconds
try {
$sizeMB = (Get-ChildItem -Recurse -Path $usbRoot -ErrorAction SilentlyContinue |
Measure-Object Length -Sum).Sum / 1MB
$speed = if ($duration -gt 0) { [math]::Round(($sizeMB / $duration), 2) } else { 0 }
$infoFile = Join-Path $usbRoot "writeinfo.txt"
@(
"wxIRC USB Write Report"
"=" * 50
"Completed : $endTime"
"Total Size : $([math]::Round($sizeMB, 2)) MB"
"Duration : $([math]::Round($duration, 2)) seconds"
"Write Speed : $speed MB/s"
"Files Copied : $totalFiles"
""
"USB Drive : $usbRoot"
) | Set-Content -Path $infoFile -ErrorAction Stop
Write-Success "Write info saved to writeinfo.txt"
} catch {
Write-ErrorMsg "Failed to create writeinfo.txt: $_"
}
Write-Host ""
Write-Host ("=" * 80) -ForegroundColor Green
Write-Host " USB WRITE COMPLETED SUCCESSFULLY!" -ForegroundColor Green
Write-Host ("=" * 80) -ForegroundColor Green
Write-Host ""
Write-Host "Summary:" -ForegroundColor Cyan
Write-Host " Files Copied : $totalFiles" -ForegroundColor White
Write-Host " Total Size : $([math]::Round($sizeMB, 2)) MB" -ForegroundColor White
Write-Host " Duration : $([math]::Round($duration, 2)) seconds" -ForegroundColor White
Write-Host " Write Speed : $speed MB/s" -ForegroundColor White
Write-Host ""
Write-Host "The USB drive is ready to use!" -ForegroundColor Green
Write-Host ""