fix block ci cd
Some checks failed
Deploy on Master Change / deploy (push) Has been cancelled

This commit is contained in:
2026-07-13 15:52:35 +07:00
parent b56c6d722c
commit 0ff025fb15
13 changed files with 134 additions and 17 deletions

View File

@@ -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
```
---

View File

@@ -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).

View File

@@ -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"
},

View File

@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
"version": "1.1.0",
"version": "1.2.0",
"scripts": {
"dev": "vite",
"build": "vite build",

View File

@@ -1 +1 @@
39a3c87a78e46d8e7ef5f5042d044ee3
06a16f2c007333cdf273a92d4914c63b

View File

@@ -19,7 +19,7 @@ if (typeof window.go.main.App === 'undefined') {
}
const brandLogoHtml = `<img src="${logoUrl}" alt="Simple Care" class="brand-logo-img" />`;
const APP_VERSION = '1.1';
const APP_VERSION = '1.2';
// Trạng thái cục bộ
let loggedIn = false;

View File

@@ -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

View File

@@ -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,
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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)
}

View File

@@ -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,

View File

@@ -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",