From 0ff025fb1589fd0441ef5efda28b679997a239f4 Mon Sep 17 00:00:00 2001 From: PhuocNTB Date: Mon, 13 Jul 2026 15:52:35 +0700 Subject: [PATCH] fix block ci cd --- client/INSTALL_LINUX.md | 8 ++-- client/app.go | 26 +++++++++-- client/frontend/package-lock.json | 4 +- client/frontend/package.json | 2 +- client/frontend/package.json.md5 | 2 +- client/frontend/src/main.js | 2 +- client/internal/blocker/blocker_darwin.go | 1 + client/internal/blocker/blocker_linux.go | 1 + client/internal/blocker/blocker_windows.go | 1 + client/internal/screen/screen_darwin.go | 47 ++++++++++++++++++- client/internal/screen/screen_other.go | 53 +++++++++++++++++++++- client/main.go | 2 +- client/wails.json | 2 +- 13 files changed, 134 insertions(+), 17 deletions(-) diff --git a/client/INSTALL_LINUX.md b/client/INSTALL_LINUX.md index 0fa1a5e..ca73cf0 100644 --- a/client/INSTALL_LINUX.md +++ b/client/INSTALL_LINUX.md @@ -46,13 +46,13 @@ cd client chmod +x build.sh ./build.sh ``` -Sau khi build xong, file thực thi sẽ nằm tại: `client/build/bin/simple_care_v1.1` +Sau khi build xong, file thực thi sẽ nằm tại: `client/build/bin/simple_care_v1.2` --- ## 2. Cho Người dùng cuối (End-user - Chỉ chạy ứng dụng) -Người dùng cuối **không cần** cài đặt Go, Node hay trình biên dịch C. Họ chỉ cần tệp thực thi `simple_care_v1.1` và cài đặt các thư viện đồ họa cơ bản của hệ thống: +Người dùng cuối **không cần** cài đặt Go, Node hay trình biên dịch C. Họ chỉ cần tệp thực thi `simple_care_v1.2` và cài đặt các thư viện đồ họa cơ bản của hệ thống: * **Ubuntu / Debian / Linux Mint:** ```bash @@ -73,8 +73,8 @@ Người dùng cuối **không cần** cài đặt Go, Node hay trình biên d ### Lệnh chạy ứng dụng: Cấp quyền chạy cho file và khởi chạy: ```bash -chmod +x simple_care_v1.1 -./simple_care_v1.1 +chmod +x simple_care_v1.2 +./simple_care_v1.2 ``` --- diff --git a/client/app.go b/client/app.go index cd960f8..8d9a0a6 100644 --- a/client/app.go +++ b/client/app.go @@ -306,10 +306,28 @@ func (a *App) HandleBeforeClose() (prevent bool) { return false } - a.reportViolation("app_closed", "Sinh viên tự đóng ứng dụng khi đang giám sát ("+mode+")") - a.tearDownBeforeQuit() - a.clearRunLock() - return false + selection, err := runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{ + Type: runtime.QuestionDialog, + Title: "Xác nhận thoát", + Message: "Bạn có chắc chắn muốn thoát ứng dụng không?\n\nLưu ý: Thoát ứng dụng khi đang trong giờ thi/học sẽ được ghi nhận là VI PHẠM.", + Buttons: []string{"Có, thoát ứng dụng", "Không, tiếp tục"}, + DefaultButton: "Không, tiếp tục", + }) + if err != nil { + a.reportViolation("app_closed", "Sinh viên tự đóng ứng dụng khi đang giám sát ("+mode+")") + a.tearDownBeforeQuit() + a.clearRunLock() + return false + } + + if selection == "Có, thoát ứng dụng" { + a.reportViolation("app_closed", "Sinh viên tự đóng ứng dụng khi đang giám sát ("+mode+")") + a.tearDownBeforeQuit() + a.clearRunLock() + return false + } + + return true // Prevent close! } // tearDownBeforeQuit ngắt mọi kênh giám sát ngay — trước khi hiện dialog (tránh treo OK để duy trì kết nối). diff --git a/client/frontend/package-lock.json b/client/frontend/package-lock.json index 79320fd..bee0857 100644 --- a/client/frontend/package-lock.json +++ b/client/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "frontend", - "version": "1.1.0", + "version": "1.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "frontend", - "version": "1.1.0", + "version": "1.2.0", "dependencies": { "pdfjs-dist": "^3.11.174" }, diff --git a/client/frontend/package.json b/client/frontend/package.json index d3d6f5f..2eb20ba 100644 --- a/client/frontend/package.json +++ b/client/frontend/package.json @@ -1,7 +1,7 @@ { "name": "frontend", "private": true, - "version": "1.1.0", + "version": "1.2.0", "scripts": { "dev": "vite", "build": "vite build", diff --git a/client/frontend/package.json.md5 b/client/frontend/package.json.md5 index c51c624..be93c51 100644 --- a/client/frontend/package.json.md5 +++ b/client/frontend/package.json.md5 @@ -1 +1 @@ -39a3c87a78e46d8e7ef5f5042d044ee3 \ No newline at end of file +06a16f2c007333cdf273a92d4914c63b \ No newline at end of file diff --git a/client/frontend/src/main.js b/client/frontend/src/main.js index 039062d..7dd2a17 100644 --- a/client/frontend/src/main.js +++ b/client/frontend/src/main.js @@ -19,7 +19,7 @@ if (typeof window.go.main.App === 'undefined') { } const brandLogoHtml = `Simple Care`; -const APP_VERSION = '1.1'; +const APP_VERSION = '1.2'; // Trạng thái cục bộ let loggedIn = false; diff --git a/client/internal/blocker/blocker_darwin.go b/client/internal/blocker/blocker_darwin.go index c6ae439..a4e8413 100644 --- a/client/internal/blocker/blocker_darwin.go +++ b/client/internal/blocker/blocker_darwin.go @@ -172,6 +172,7 @@ var systemAllowed = map[string]bool{ "client": true, "simple_care_v1.0": true, "simple_care_v1.1": true, + "simple_care_v1.2": true, "simple_care": true, "wails": true, "code": true, // VSCode diff --git a/client/internal/blocker/blocker_linux.go b/client/internal/blocker/blocker_linux.go index 634f1b9..8ee84bf 100644 --- a/client/internal/blocker/blocker_linux.go +++ b/client/internal/blocker/blocker_linux.go @@ -237,6 +237,7 @@ var systemAllowed = map[string]bool{ "client": true, "simple_care_v1.0": true, "simple_care_v1.1": true, + "simple_care_v1.2": true, "simple_care": true, } diff --git a/client/internal/blocker/blocker_windows.go b/client/internal/blocker/blocker_windows.go index 5de3df9..06c70ca 100644 --- a/client/internal/blocker/blocker_windows.go +++ b/client/internal/blocker/blocker_windows.go @@ -330,6 +330,7 @@ var systemAllowed = map[string]bool{ "client.exe": true, "simple_care_v1.0.exe": true, "simple_care_v1.1.exe": true, + "simple_care_v1.2.exe": true, "simple_care.exe": true, "wails.exe": true, "msedgewebview2.exe": true, // WebView2 runtime (Wails renderer) diff --git a/client/internal/screen/screen_darwin.go b/client/internal/screen/screen_darwin.go index 6f15e24..a073281 100644 --- a/client/internal/screen/screen_darwin.go +++ b/client/internal/screen/screen_darwin.go @@ -47,9 +47,54 @@ static unsigned char* CaptureFullDesktop(int* outLen, int quality) { } @autoreleasepool { - NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithCGImage:image]; + // Calculate new size maintaining aspect ratio (limiting to max 1024x768) + CGFloat originalWidth = CGImageGetWidth(image); + CGFloat originalHeight = CGImageGetHeight(image); + CGFloat maxWidth = 1024.0f; + CGFloat maxHeight = 768.0f; + CGFloat ratio = 1.0f; + if (originalWidth > maxWidth || originalHeight > maxHeight) { + CGFloat ratioW = maxWidth / originalWidth; + CGFloat ratioH = maxHeight / originalHeight; + ratio = ratioW < ratioH ? ratioW : ratioH; + } + size_t newWidth = (size_t)(originalWidth * ratio); + size_t newHeight = (size_t)(originalHeight * ratio); + if (newWidth < 1) newWidth = 1; + if (newHeight < 1) newHeight = 1; + + // Create bitmap context + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(NULL, + newWidth, + newHeight, + 8, + newWidth * 4, + colorSpace, + kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); + CGColorSpaceRelease(colorSpace); + if (!context) { + CGImageRelease(image); + *outLen = 0; + return NULL; + } + + // Draw image into context to resize + CGContextSetInterpolationQuality(context, kCGInterpolationHigh); + CGContextDrawImage(context, CGRectMake(0, 0, newWidth, newHeight), image); CGImageRelease(image); + // Get resized image + CGImageRef resizedImage = CGBitmapContextCreateImage(context); + CGContextRelease(context); + if (!resizedImage) { + *outLen = 0; + return NULL; + } + + NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithCGImage:resizedImage]; + CGImageRelease(resizedImage); + if (!rep) { *outLen = 0; return NULL; diff --git a/client/internal/screen/screen_other.go b/client/internal/screen/screen_other.go index a0f52bb..8f3a1e4 100644 --- a/client/internal/screen/screen_other.go +++ b/client/internal/screen/screen_other.go @@ -6,11 +6,35 @@ import ( "bytes" "encoding/base64" "fmt" + "image" "image/jpeg" "github.com/kbinani/screenshot" ) +// resizeRGBA resizes a *image.RGBA image using Nearest-Neighbor scaling for maximum performance. +func resizeRGBA(src *image.RGBA, width, height int) *image.RGBA { + dst := image.NewRGBA(image.Rect(0, 0, width, height)) + srcBounds := src.Bounds() + dx := srcBounds.Dx() + dy := srcBounds.Dy() + minX := srcBounds.Min.X + minY := srcBounds.Min.Y + + for y := 0; y < height; y++ { + srcY := minY + (y * dy) / height + for x := 0; x < width; x++ { + srcX := minX + (x * dx) / width + + srcOffset := src.PixOffset(srcX, srcY) + dstOffset := dst.PixOffset(x, y) + + copy(dst.Pix[dstOffset:dstOffset+4], src.Pix[srcOffset:srcOffset+4]) + } + } + return dst +} + // CaptureScreen chụp màn hình chính và trả về chuỗi Base64 dạng "data:image/jpeg;base64,..." // Non-darwin: dùng kbinani/screenshot func CaptureScreen() (string, error) { @@ -26,9 +50,36 @@ func CaptureScreen() (string, error) { return "", fmt.Errorf("failed to capture screen: %w", err) } + // Tối ưu hóa kích thước ảnh giống dự án Raia: + // Giới hạn chiều rộng tối đa là 1024px và chiều cao tối đa là 768px để giảm dung lượng mạng. + dx := bounds.Dx() + dy := bounds.Dy() + + maxWidth := 1024 + maxHeight := 768 + + newWidth := dx + newHeight := dy + + if dx > maxWidth || dy > maxHeight { + ratioWidth := float64(maxWidth) / float64(dx) + ratioHeight := float64(maxHeight) / float64(dy) + ratio := ratioWidth + if ratioHeight < ratioWidth { + ratio = ratioHeight + } + newWidth = int(float64(dx) * ratio) + newHeight = int(float64(dy) * ratio) + } + + var finalImg image.Image = img + if newWidth != dx || newHeight != dy { + finalImg = resizeRGBA(img, newWidth, newHeight) + } + var buf bytes.Buffer // Nén chất lượng JPEG khoảng 50% để truyền tải mượt mà qua mạng - err = jpeg.Encode(&buf, img, &jpeg.Options{Quality: 50}) + err = jpeg.Encode(&buf, finalImg, &jpeg.Options{Quality: 50}) if err != nil { return "", fmt.Errorf("failed to encode jpeg: %w", err) } diff --git a/client/main.go b/client/main.go index 672f2df..a76ff85 100644 --- a/client/main.go +++ b/client/main.go @@ -62,7 +62,7 @@ func main() { // Create application with options err := wails.Run(&options.App{ - Title: "Simple Care v1.1 — Rikkei Education", + Title: "Simple Care v1.2 — Rikkei Education", Width: 1024, Height: 768, Menu: appMenu, diff --git a/client/wails.json b/client/wails.json index a9da5c2..a1b8d1a 100644 --- a/client/wails.json +++ b/client/wails.json @@ -1,7 +1,7 @@ { "$schema": "https://wails.io/schemas/config.v2.json", "name": "Simple Care by Rikkei Edu", - "outputfilename": "simple_care_v1.1", + "outputfilename": "simple_care_v1.2", "frontend:install": "npm install", "frontend:build": "npm run build", "frontend:dev:watcher": "npm run dev",