Exemplos de Recursos Desktop Web Go

Exemplos de recursos específicos de desktop Web Go incluindo caixas de diálogo de arquivo, caixas de mensagem e bandeja do sistema

💻 Caixas de Mensagem go

🟢 simple ⭐⭐⭐

Exibir caixas de mensagem de informação, aviso e erro

⏱️ 20 min 🏷️ go, web, desktop features
Prerequisites: Basic Go, GUI framework
// Web Go Message Box Examples
// Using Fyne and Walk for message dialogs

package main

import (
	"fmt"
	"os"
)

// 1. Using Fyne Framework

/*
import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/dialog"
)

func FyneInfoDialog() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Message Dialog")

	dialog.ShowInformation("Information", "This is an info message", myWindow)
	myWindow.ShowAndRun()
}

func FyneErrorDialog() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Error Dialog")

	dialog.ShowError(errors.New("This is an error message"), myWindow)
	myWindow.ShowAndRun()
}

func FyneConfirmDialog() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Confirm Dialog")

	dialog.ShowConfirm("Confirm", "Are you sure?", func(confirmed bool) {
		if confirmed {
			fmt.Println("User confirmed")
		} else {
			fmt.Println("User cancelled")
		}
	}, myWindow)

	myWindow.ShowAndRun()
}
*/

// 2. Using Walk Framework (Windows)

/*
import (
	"github.com/lxn/walk"
)

func WalkMessageBox() error {
	// Information
	walk.MsgBox(nil, "Information",
		"This is an info message",
		walk.MsgBoxIconInformation)

	// Warning
	walk.MsgBox(nil, "Warning",
		"This is a warning",
		walk.MsgBoxIconWarning)

	// Error
	walk.MsgBox(nil, "Error",
		"This is an error",
		walk.MsgBoxIconError)

	// Question with Yes/No
	ret, err := walk.MsgBox(nil, "Question",
		"Do you want to continue?",
		walk.MsgBoxYesNo|walk.MsgBoxIconQuestion)

	if err == nil {
		if ret == walk.DialogButtonYes {
			fmt.Println("User clicked Yes")
		} else {
			fmt.Println("User clicked No")
		}
	}

	return nil
}
*/

// 3. Cross-Platform Message Box

// MessageType defines message box type
type MessageType int

const (
	InfoMsg MessageType = iota
	WarningMsg
	ErrorMsg
	QuestionMsg
)

// MessageBoxButton defines button type
type MessageBoxButton int

const (
	OKBtn MessageBoxButton = iota
	OKCancelBtn
	YesNoBtn
	YesNoCancelBtn
	RetryCancelBtn
	AbortRetryIgnoreBtn
)

// MessageBoxResult holds message box result
type MessageBoxResult struct {
	ButtonPressed string
	Confirmed     bool
	Err           error
}

// MessageBox shows message box
func MessageBox(title, message string, msgType MessageType, buttons MessageBoxButton) MessageBoxResult {
	// Terminal-based message box
	return showTerminalMessageBox(title, message, msgType, buttons)
}

func showTerminalMessageBox(title, message string, msgType MessageType, buttons MessageBoxButton) MessageBoxResult {
	// Print message header
	var icon string
	switch msgType {
	case InfoMsg:
		icon = "ℹ️"
	case WarningMsg:
		icon = "⚠️"
	case ErrorMsg:
		icon = "❌"
	case QuestionMsg:
		icon = "❓"
	}

	fmt.Printf("\n%s %s\n", icon, title)
	fmt.Printf("%s\n", message)

	// Print buttons
	var options []string
	switch buttons {
	case OKBtn:
		options = []string{"OK"}
	case OKCancelBtn:
		options = []string{"OK", "Cancel"}
	case YesNoBtn:
		options = []string{"Yes", "No"}
	case YesNoCancelBtn:
		options = []string{"Yes", "No", "Cancel"}
	case RetryCancelBtn:
		options = []string{"Retry", "Cancel"}
	case AbortRetryIgnoreBtn:
		options = []string{"Abort", "Retry", "Ignore"}
	}

	fmt.Print("Options: ")
	for i, opt := range options {
		if i > 0 {
			fmt.Print(", ")
		}
		fmt.Printf("[%d] %s", i+1, opt)
	}
	fmt.Println()

	// Get user input
	var choice int
	fmt.Scanln(&choice)

	if choice < 1 || choice > len(options) {
		return MessageBoxResult{Err: fmt.Errorf("invalid choice")}
	}

	selected := options[choice-1]

	return MessageBoxResult{
		ButtonPressed: selected,
		Confirmed:     selected == "OK" || selected == "Yes" || selected == "Retry",
	}
}

// 4. Convenience Functions

// ShowInfo shows information message
func ShowInfo(title, message string) MessageBoxResult {
	return MessageBox(title, message, InfoMsg, OKBtn)
}

// ShowWarning shows warning message
func ShowWarning(title, message string) MessageBoxResult {
	return MessageBox(title, message, WarningMsg, OKBtn)
}

// ShowError shows error message
func ShowError(title, message string) MessageBoxResult {
	return MessageBox(title, message, ErrorMsg, OKBtn)
}

// ShowQuestion shows question with Yes/No
func ShowQuestion(title, message string) MessageBoxResult {
	result := MessageBox(title, message, QuestionMsg, YesNoBtn)
	return result
}

// ShowConfirm shows confirmation dialog
func ShowConfirm(title, message string) MessageBoxResult {
	result := MessageBox(title, message, QuestionMsg, OKCancelBtn)
	return result
}

// 5. Progress Dialog

// ProgressDialog shows progress for operations
type ProgressDialog struct {
	title      string
	total      int64
	current    int64
	cancelled bool
}

// NewProgressDialog creates progress dialog
func NewProgressDialog(title string, total int64) *ProgressDialog {
	return &ProgressDialog{
		title:   title,
		total:   total,
		current: 0,
	}
}

// Update updates progress
func (pd *ProgressDialog) Update(current int64) {
	pd.current = current

	// Clear line and show progress
	fmt.Printf("\r%s: ", pd.title)

	percentage := float64(current) / float64(pd.total) * 100
	barWidth := 40
	filled := int(float64(barWidth) * float64(current) / float64(pd.total))

	fmt.Print("[")
	for i := 0; i < barWidth; i++ {
		if i < filled {
			fmt.Print("=")
		} else {
			fmt.Print(" ")
		}
	}
	fmt.Printf("] %.1f%%", percentage)
}

// Complete marks progress as complete
func (pd *ProgressDialog) Complete() {
	pd.Update(pd.total)
	fmt.Println(" - Complete!")
}

// 6. Notification

// NotificationType defines notification type
type NotificationType int

const (
	NotificationInfo NotificationType = iota
	NotificationWarning
	NotificationError
	NotificationSuccess
)

// ShowNotification shows desktop notification
func ShowNotification(title, message string, notifType NotificationType) {
	// Terminal notification
	var icon string
	switch notifType {
	case NotificationInfo:
		icon = "ℹ️"
	case NotificationWarning:
		icon = "⚠️"
	case NotificationError:
		icon = "❌"
	case NotificationSuccess:
		icon = "✅"
	}

	fmt.Printf("\n%s %s: %s\n", icon, title, message)
}

// 7. Input Dialog

// InputDialogResult holds input dialog result
type InputDialogResult struct {
	Value string
	Err   error
}

// ShowInputDialog shows input dialog
func ShowInputDialog(title, prompt, defaultValue string) InputDialogResult {
	fmt.Printf("\n%s\n", title)
	fmt.Printf("%s", prompt)
	if defaultValue != "" {
		fmt.Printf(" [%s]", defaultValue)
	}
	fmt.Print(": ")

	var input string
	fmt.Scanln(&input)

	if input == "" {
		input = defaultValue
	}

	return InputDialogResult{Value: input}
}

// ShowPasswordDialog shows password input dialog
func ShowPasswordDialog(title, prompt string) InputDialogResult {
	fmt.Printf("\n%s\n", title)
	fmt.Printf("%s: ", prompt)

	// Note: In terminal, password won't be hidden
	// For real applications, use terminal password reading
	var input string
	fmt.Scanln(&input)

	return InputDialogResult{Value: input}
}

// 8. Select Dialog

// SelectDialogResult holds selection dialog result
type SelectDialogResult struct {
	SelectedIndex int
	SelectedValue string
	Err           error
}

// ShowSelectDialog shows selection dialog
func ShowSelectDialog(title string, options []string) SelectDialogResult {
	fmt.Printf("\n%s\n", title)

	for i, opt := range options {
		fmt.Printf("[%d] %s\n", i+1, opt)
	}

	fmt.Print("Select: ")
	var choice int
	fmt.Scanln(&choice)

	if choice < 1 || choice > len(options) {
		return SelectDialogResult{Err: fmt.Errorf("invalid choice")}
	}

	return SelectDialogResult{
		SelectedIndex: choice - 1,
		SelectedValue: options[choice-1],
	}
}

// 9. Dialog Builder

// DialogBuilder builds message dialogs
type DialogBuilder struct {
	title       string
	message     string
	msgType     MessageType
	buttons     MessageBoxButton
	onConfirm   func()
	onCancel    func()
	defaultAction func()
}

// NewDialogBuilder creates dialog builder
func NewDialogBuilder(title, message string) *DialogBuilder {
	return &DialogBuilder{
		title:   title,
		message: message,
		msgType: InfoMsg,
		buttons: OKBtn,
	}
}

func (db *DialogBuilder) WithType(msgType MessageType) *DialogBuilder {
	db.msgType = msgType
	return db
}

func (db *DialogBuilder) WithButtons(buttons MessageBoxButton) *DialogBuilder {
	db.buttons = buttons
	return db
}

func (db *DialogBuilder) OnConfirm(fn func()) *DialogBuilder {
	db.onConfirm = fn
	return db
}

func (db *DialogBuilder) OnCancel(fn func()) *DialogBuilder {
	db.onCancel = fn
	return db
}

func (db *DialogBuilder) Show() MessageBoxResult {
	result := MessageBox(db.title, db.message, db.msgType, db.buttons)

	if result.Confirmed && db.onConfirm != nil {
		db.onConfirm()
	} else if !result.Confirmed && db.onCancel != nil {
		db.onCancel()
	}

	return result
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go Message Box Examples ===\n")

	// 1. Info message
	fmt.Println("--- 1. Info Message ---")
	ShowInfo("Information", "This is an informational message")

	// 2. Warning message
	fmt.Println("\n--- 2. Warning Message ---")
	ShowWarning("Warning", "This is a warning message")

	// 3. Error message
	fmt.Println("\n--- 3. Error Message ---")
	ShowError("Error", "An error occurred!")

	// 4. Question dialog
	fmt.Println("\n--- 4. Question Dialog ---")
	result := ShowQuestion("Question", "Do you want to continue?")
	if result.Confirmed {
		fmt.Println("User chose Yes")
	} else {
		fmt.Println("User chose No")
	}

	// 5. Input dialog
	fmt.Println("\n--- 5. Input Dialog ---")
	input := ShowInputDialog("Name", "Enter your name", "")
	if input.Err == nil {
		fmt.Printf("Hello, %s!\n", input.Value)
	}

	// 6. Select dialog
	fmt.Println("\n--- 6. Select Dialog ---")
	selectResult := ShowSelectDialog("Choose Option", []string{"Option A", "Option B", "Option C"})
	if selectResult.Err == nil {
		fmt.Printf("Selected: %s\n", selectResult.SelectedValue)
	}

	// 7. Progress dialog
	fmt.Println("\n--- 7. Progress Dialog ---")
	progress := NewProgressDialog("Processing", 100)
	for i := 0; i <= 100; i += 10 {
		progress.Update(int64(i))
		time.Sleep(100 * time.Millisecond)
	}
	progress.Complete()

	// 8. Notification
	fmt.Println("
--- 8. Notification ---")
	ShowNotification("Success", "Operation completed successfully!", NotificationSuccess)

	// 9. Dialog builder
	fmt.Println("
--- 9. Dialog Builder ---")
	builderResult := NewDialogBuilder("Confirm Action", "Are you sure?").
		WithType(QuestionMsg).
		WithButtons(YesNoBtn).
		OnConfirm(func() {
			fmt.Println("Action confirmed!")
		}).
		Show()

	fmt.Printf("
Builder result: %v\n", builderResult.ButtonPressed)

	fmt.Println("
=== All Message Box Examples Completed ===")
	fmt.Println("Note: For full GUI functionality, install Fyne or Walk framework")
}

💻 Caixas de Diálogo de Arquivo go

🟡 intermediate ⭐⭐⭐

Abrir e salvar caixas de diálogo de arquivo usando frameworks GUI Fyne ou Walk

⏱️ 30 min 🏷️ go, web, desktop features
Prerequisites: Intermediate Go, GUI framework
// Web Go File Dialog Examples
// Using Fyne and Walk frameworks for file dialogs

package main

import (
	"fmt"
	"os"
	"path/filepath"
)

// 1. Using Fyne Framework (Cross-platform)

// FyneFileDialogExample demonstrates file dialogs with Fyne
// Install: go get fyne.io/fyne/v2

/*
import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/storage"
	"fyne.io/fyne/v2/widget"
)

func FyneOpenFileDialog() {
	myApp := app.New()
	myWindow := myApp.NewWindow("File Dialog")

	// Create open file dialog
	fd := dialog.NewFileOpen(func(reader fyne.URIReadCloser, err error) {
		if err == nil && reader != nil {
			defer reader.Close()
			fmt.Printf("Opened file: %v\n", reader.URI())
		}
	}, myWindow)

	fd.SetFilter(storage.NewExtensionFileFilter([]string{".txt", ".go"}))
	fd.Show()

	// Keep window running
	myWindow.ShowAndRun()
}

func FyneSaveFileDialog() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Save Dialog")

	// Create save file dialog
	sd := dialog.NewFileSave(func(writer fyne.URIWriteCloser, err error) {
		if err == nil && writer != nil {
			defer writer.Close()
			writer.Write([]byte("Hello, World!"))
			fmt.Printf("Saved file: %v\n", writer.URI())
		}
	}, myWindow)

	sd.SetFileName("untitled.txt")
	sd.Show()

	myWindow.ShowAndRun()
}

func FyneSelectFolderDialog() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Folder Dialog")

	// Create folder select dialog
	fd := dialog.NewFolderOpen(func(uri fyne.ListableURI, err error) {
		if err == nil && uri != nil {
			fmt.Printf("Selected folder: %v\n", uri)
		}
	}, myWindow)

	fd.Show()
	myWindow.ShowAndRun()
}
*/

// 2. Using Walk Framework (Windows)

// WalkFileDialogExample demonstrates file dialogs with Walk
// Install: go get github.com/lxn/walk

/*
import (
	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
)

func WalkOpenFileDialog() {
	var dlg *walk.Dialog
	var text *walk.TextEdit

	MainWindow{
		Title:  "File Dialog",
		MinSize: Size{400, 300},
		Layout:  VBox{},
		Children: []Widget{
			PushButton{
				Text: "Open File",
				OnClicked: func() {
					filePath, err := walk.FileDialog{
						Filter:   "Text Files (*.txt)|*.txt|All Files (*.*)|*.*",
						Title:    "Open File",
					}.ShowOpen(nil)

					if err == nil && filePath != "" {
						text.SetText(filePath)
						fmt.Printf("Opened: %s\n", filePath)
					}
				},
			},
			TextEdit{AssignTo: &text},
		},
	}.Create()
}

func WalkSaveFileDialog() {
	var fileName *walk.LineEdit

	MainWindow{
		Title:  "Save Dialog",
		Layout: VBox{},
		Children: []Widget{
			PushButton{
				Text: "Save File",
				OnClicked: func() {
					filePath, err := walk.FileDialog{
						Filter:   "Text Files (*.txt)|*.txt",
						Title:    "Save File",
					}.ShowSave(nil)

					if err == nil && filePath != "" {
						fmt.Printf("Save to: %s\n", filePath)
					}
				},
			},
			LineEdit{AssignTo: &fileName},
		},
	}.Create()
}
*/

// 3. Cross-Platform File Dialog Wrapper

// FileDialogOptions holds options for file dialogs
type FileDialogOptions struct {
	Title       string
	Filter      string
	InitialDir  string
	DefaultName string
}

// FileDialogResult holds file dialog result
type FileDialogResult struct {
	FilePath string
	FileName string
	Dir      string
	Err      error
}

// OpenFileDialog opens file selection dialog
func OpenFileDialog(options FileDialogOptions) FileDialogResult {
	result := FileDialogResult{}

	// Check if running in terminal environment
	if os.Getenv("TERM") != "" || os.Getenv("TERM_PROGRAM") != "" {
		// Terminal-based file selection
		return openTerminalFileDialog(options)
	}

	// Try GUI frameworks
	// Note: In a real application, you'd use Fyne or Walk here
	result.Err = fmt.Errorf("no GUI framework available")

	return result
}

// SaveFileDialog opens save file dialog
func SaveFileDialog(options FileDialogOptions) FileDialogResult {
	result := FileDialogResult{}

	// Check environment
	if os.Getenv("TERM") != "" {
		return saveTerminalFileDialog(options)
	}

	result.Err = fmt.Errorf("no GUI framework available")
	return result
}

// 4. Terminal-Based File Dialog (Fallback)

func openTerminalFileDialog(options FileDialogOptions) FileDialogResult {
	fmt.Printf("%s\n", options.Title)
	fmt.Println("Enter file path (or 'cancel'): ")

	var input string
	fmt.Scanln(&input)

	if input == "cancel" {
		return FileDialogResult{Err: fmt.Errorf("cancelled")}
	}

	if _, err := os.Stat(input); err != nil {
		return FileDialogResult{Err: err}
	}

	return FileDialogResult{
		FilePath: input,
		FileName: filepath.Base(input),
		Dir:      filepath.Dir(input),
	}
}

func saveTerminalFileDialog(options FileDialogOptions) FileDialogResult {
	fmt.Printf("%s\n", options.Title)
	defaultName := options.DefaultName
	if defaultName == "" {
		defaultName = "untitled.txt"
	}

	fmt.Printf("Enter save path [%s]: ", defaultName)
	var input string
	fmt.Scanln(&input)

	if input == "" {
		input = defaultName
	}

	return FileDialogResult{
		FilePath: input,
		FileName: filepath.Base(input),
		Dir:      filepath.Dir(input),
	}
}

// 5. File Dialog with Validation

// OpenFileDialogWithValidation opens dialog and validates file
func OpenFileDialogWithValidation(options FileDialogOptions, validateFunc func(string) error) FileDialogResult {
	result := OpenFileDialog(options)

	if result.Err != nil {
		return result
	}

	if validateFunc != nil {
		if err := validateFunc(result.FilePath); err != nil {
			return FileDialogResult{Err: err}
		}
	}

	return result
}

// ValidateFileExtension validates file extension
func ValidateFileExtension(extensions []string) func(string) error {
	return func(filePath string) error {
		ext := filepath.Ext(filePath)
		for _, validExt := range extensions {
			if ext == validExt {
				return nil
			}
		}
		return fmt.Errorf("invalid extension: %s", ext)
	}
}

// ValidateFileSize validates file size
func ValidateFileSize(maxSizeMB int64) func(string) error {
	return func(filePath string) error {
		info, err := os.Stat(filePath)
		if err != nil {
			return err
		}

		sizeMB := info.Size() / (1024 * 1024)
		if sizeMB > maxSizeMB {
			return fmt.Errorf("file too large: %dMB (max %dMB)", sizeMB, maxSizeMB)
		}

		return nil
	}
}

// 6. Batch File Selection

// BatchFileDialogResult holds multiple file selection results
type BatchFileDialogResult struct {
	FilePaths []string
	Err       error
}

// OpenMultipleFilesDialog opens dialog for multiple file selection
func OpenMultipleFilesDialog(options FileDialogOptions) BatchFileDialogResult {
	result := BatchFileDialogResult{}

	fmt.Printf("%s (Multiple files)\n", options.Title)
	fmt.Println("Enter file paths (one per line, empty line to finish):")

	var filePaths []string
	scanner := bufio.NewScanner(os.Stdin)

	for scanner.Scan() {
		path := scanner.Text()
		if path == "" {
			break
		}
		filePaths = append(filePaths, path)
	}

	if len(filePaths) == 0 {
		result.Err = fmt.Errorf("no files selected")
		return result
	}

	// Validate all files
	for _, path := range filePaths {
		if _, err := os.Stat(path); err != nil {
			result.Err = fmt.Errorf("invalid file: %s - %v", path, err)
			return result
		}
	}

	result.FilePaths = filePaths
	return result
}

// 7. Recent Files Management

// RecentFiles manages recent file list
type RecentFiles struct {
	files []string
	max   int
}

// NewRecentFiles creates recent files manager
func NewRecentFiles(maxFiles int) *RecentFiles {
	return &RecentFiles{
		files: []string{},
		max:   maxFiles,
	}
}

// Add adds file to recent list
func (rf *RecentFiles) Add(filePath string) {
	// Remove if already exists
	for i, f := range rf.files {
		if f == filePath {
			rf.files = append(rf.files[:i], rf.files[i+1:]...)
			break
		}
	}

	// Add to front
	rf.files = append([]string{filePath}, rf.files...)

	// Limit size
	if len(rf.files) > rf.max {
		rf.files = rf.files[:rf.max]
	}
}

// GetFiles returns recent files list
func (rf *RecentFiles) GetFiles() []string {
	return rf.files
}

// SaveToFile saves recent files to file
func (rf *RecentFiles) SaveToFile(filePath string) error {
	file, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer file.Close()

	for _, f := range rf.files {
		file.WriteString(f + "\n")
	}

	return nil
}

// LoadFromFile loads recent files from file
func (rf *RecentFiles) LoadFromFile(filePath string) error {
	file, err := os.Open(filePath)
	if err != nil {
		return err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		rf.Add(scanner.Text())
	}

	return scanner.Err()
}

// 8. File Dialog Presets

// OpenImageDialog opens image file dialog
func OpenImageDialog() FileDialogResult {
	return OpenFileDialog(FileDialogOptions{
		Title:  "Open Image",
		Filter: "*.png;*.jpg;*.jpeg;*.gif;*.bmp",
	})
}

// SaveTextFileDialog opens text file save dialog
func SaveTextFileDialog() FileDialogResult {
	return SaveFileDialog(FileDialogOptions{
		Title:       "Save Text File",
		Filter:      "*.txt",
		DefaultName: "untitled.txt",
	})
}

// OpenCodeFileDialog opens code file dialog
func OpenCodeFileDialog() FileDialogResult {
	return OpenFileDialog(FileDialogOptions{
		Title:  "Open Code File",
		Filter: "*.go;*.js;*.py;*.java;*.cpp",
	})
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go File Dialog Examples ===\n")

	// 1. Open file dialog
	fmt.Println("--- 1. Open File Dialog ---")
	result := OpenFileDialog(FileDialogOptions{
		Title:  "Select a File",
		Filter: "*.txt",
	})
	if result.Err == nil {
		fmt.Printf("Selected: %s\n", result.FilePath)
	}

	// 2. Save file dialog
	fmt.Println("\n--- 2. Save File Dialog ---")
	saveResult := SaveFileDialog(FileDialogOptions{
		Title:       "Save File",
		DefaultName: "output.txt",
	})
	if saveResult.Err == nil {
		fmt.Printf("Save to: %s\n", saveResult.FilePath)
	}

	// 3. File dialog with validation
	fmt.Println("\n--- 3. File Dialog with Validation ---")
	validated := OpenFileDialogWithValidation(
		FileDialogOptions{Title: "Select Text File"},
		ValidateFileExtension([]string{".txt"}),
	)
	if validated.Err != nil {
		fmt.Printf("Validation error: %v\n", validated.Err)
	}

	// 4. Multiple files
	fmt.Println("\n--- 4. Multiple Files ---")
	multi := OpenMultipleFilesDialog(FileDialogOptions{
		Title: "Select Files",
	})
	if multi.Err == nil {
		fmt.Printf("Selected %d files\n", len(multi.FilePaths))
	}

	// 5. Recent files
	fmt.Println("\n--- 5. Recent Files ---")
	recent := NewRecentFiles(5)
	recent.Add("file1.txt")
	recent.Add("file2.txt")
	recent.Add("file3.txt")
	fmt.Printf("Recent files: %v\n", recent.GetFiles())

	// 6. Presets
	fmt.Println("\n--- 6. Preset Dialogs ---")
	imageResult := OpenImageDialog()
	if imageResult.Err == nil {
		fmt.Printf("Image: %s\n", imageResult.FileName)
	}

	fmt.Println("\n=== All File Dialog Examples Completed ===")
	fmt.Println("Note: For full GUI functionality, install Fyne or Walk framework")
}

💻 Bandeja do Sistema go

🔴 complex ⭐⭐⭐⭐

Exibir ícone da bandeja do sistema com menu e notificações

⏱️ 30 min 🏷️ go, web, desktop features
Prerequisites: Intermediate Go, GUI framework, goroutines
// Web Go System Tray Examples
// System tray icon with menu using Fyne or other frameworks

package main

import (
	"fmt"
	"os"
	"time"
)

// 1. Using Fyne Framework

/*
import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/driver/desktop"
	"fyne.io/fyne/v2/menu"
	"fyne.io/fyne/v2/storage"
)

func FyneSystemTray() {
	myApp := app.New()
	myWindow := myApp.NewWindow("System Tray")

	// Create system tray
	if desk, ok := myApp.(desktop.App); ok {
		// Set system tray icon
		icon := storage.NewFileURI("icon.png")
		desk.SetSystemTrayIcon(icon)
		desk.SetSystemTrayMenu(menu.New(
			menu.NewItem("Show", func() { myWindow.Show() }),
			menu.NewItem("Hide", func() { myWindow.Hide() }),
			menu.NewSeparator(),
			menu.NewItem("Quit", func() { myApp.Quit() }),
		))
	}

	myWindow.ShowAndRun()
}
*/

// 2. Using Systray Framework (Cross-platform)

/*
import (
	"github.com/getlantern/systray"
)

func SystrayExample() {
	systray.Run(onReady, onExit)
}

func onReady() {
	// Set icon
	// iconBytes, _ := ioutil.ReadFile("icon.ico")
	// systray.SetIcon(iconBytes)

	systray.SetTitle("My App")
	systray.SetTooltip("My Application")

	// Add menu items
	mQuit := systray.AddMenuItem("Quit", "Quit the whole app")
	mShow := systray.AddMenuItem("Show", "Show window")
	mHide := systray.AddMenuItem("Hide", "Hide window")

	// Handle menu clicks
	go func() {
		for {
			select {
			case <-mShow.ClickedCh:
				fmt.Println("Show clicked")
			case <-mHide.ClickedCh:
				fmt.Println("Hide clicked")
			case <-mQuit.ClickedCh:
				fmt.Println("Quitting...")
				systray.Quit()
				return
			}
		}
	}()
}

func onExit() {
	fmt.Println("Exiting systray")
}
*/

// 3. Simulated System Tray (Terminal)

// TrayIcon represents a system tray icon
type TrayIcon struct {
	title      string
	tooltip    string
	menuItems  []TrayMenuItem
	visible    bool
	running    bool
	onQuit     func()
	notification string
}

// TrayMenuItem represents a menu item
type TrayMenuItem struct {
	Title    string
	Tooltip  string
	Disabled bool
	OnClick  func()
}

// NewTrayIcon creates new tray icon
func NewTrayIcon(title, tooltip string) *TrayIcon {
	return &TrayIcon{
		title:     title,
		tooltip:   tooltip,
		menuItems: []TrayMenuItem{},
		visible:   false,
		running:   false,
	}
}

// SetTitle sets tray icon title
func (ti *TrayIcon) SetTitle(title string) {
	ti.title = title
	fmt.Printf("[Tray] Title set to: %s\n", title)
}

// SetTooltip sets tooltip
func (ti *TrayIcon) SetTooltip(tooltip string) {
	ti.tooltip = tooltip
	fmt.Printf("[Tray] Tooltip set to: %s\n", tooltip)
}

// AddMenuItem adds menu item
func (ti *TrayIcon) AddMenuItem(title, tooltip string, onClick func()) {
	item := TrayMenuItem{
		Title:   title,
		Tooltip: tooltip,
		OnClick: onClick,
	}
	ti.menuItems = append(ti.menuItems, item)
	fmt.Printf("[Tray] Menu item added: %s\n", title)
}

// AddSeparator adds separator
func (ti *TrayIcon) AddSeparator() {
	fmt.Println("[Tray] Separator added")
}

// Show shows tray icon
func (ti *TrayIcon) Show() {
	ti.visible = true
	ti.running = true
	fmt.Printf("[Tray] Icon shown: %s\n", ti.title)
	ti.run()
}

// Hide hides tray icon
func (ti *TrayIcon) Hide() {
	ti.visible = false
	fmt.Println("[Tray] Icon hidden")
}

// Quit quits tray icon
func (ti *TrayIcon) Quit() {
	ti.running = false
	if ti.onQuit != nil {
		ti.onQuit()
	}
	fmt.Println("[Tray] Quit")
}

// OnQuit sets quit handler
func (ti *TrayIcon) OnQuit(fn func()) {
	ti.onQuit = fn
}

// ShowNotification shows notification
func (ti *TrayIcon) ShowNotification(title, message string) {
	ti.notification = fmt.Sprintf("%s: %s", title, message)
	fmt.Printf("[Tray] Notification: %s\n", ti.notification)
}

// run runs tray icon loop
func (ti *TrayIcon) run() {
	fmt.Println("[Tray] Running... (Press Ctrl+C to quit)")
	fmt.Println("Menu items:")

	for i, item := range ti.menuItems {
		fmt.Printf("  [%d] %s\n", i+1, item.Title)
	}

	// Simple menu loop
	for ti.running {
		time.Sleep(100 * time.Millisecond)
	}
}

// 4. Tray Menu Manager

// TrayMenu manages tray menu
type TrayMenu struct {
	items []TrayMenuItem
}

// NewTrayMenu creates tray menu
func NewTrayMenu() *TrayMenu {
	return &TrayMenu{
		items: []TrayMenuItem{},
	}
}

// AddItem adds menu item
func (tm *TrayMenu) AddItem(title, tooltip string, onClick func()) {
	tm.items = append(tm.items, TrayMenuItem{
		Title:   title,
		Tooltip: tooltip,
		OnClick: onClick,
	})
}

// AddSubmenu adds submenu
func (tm *TrayMenu) AddSubmenu(title string) *TrayMenu {
	submenu := &TrayMenu{}
	fmt.Printf("[Tray] Submenu added: %s\n", title)
	return submenu
}

// AddSeparator adds separator
func (tm *TrayMenu) AddSeparator() {
	fmt.Println("[Tray] Separator added")
}

// 5. Tray Application

// TrayApp represents a complete tray application
type TrayApp struct {
	tray     *TrayIcon
	menu     *TrayMenu
	running  bool
}

// NewTrayApp creates new tray application
func NewTrayApp(title, tooltip string) *TrayApp {
	tray := NewTrayIcon(title, tooltip)
	return &TrayApp{
		tray:    tray,
		menu:    NewTrayMenu(),
		running: false,
	}
}

// AddMenuItem adds menu item
func (ta *TrayApp) AddMenuItem(title, tooltip string, onClick func()) {
	ta.tray.AddMenuItem(title, tooltip, onClick)
}

// AddSeparator adds separator
func (ta *TrayApp) AddSeparator() {
	ta.tray.AddSeparator()
}

// SetOnQuit sets quit handler
func (ta *TrayApp) SetOnQuit(fn func()) {
	ta.tray.OnQuit(fn)
}

// Run runs tray application
func (ta *TrayApp) Run() {
	ta.running = true
	ta.tray.Show()
}

// ShowNotification shows notification
func (ta *TrayApp) ShowNotification(title, message string) {
	ta.tray.ShowNotification(title, message)
}

// Quit quits application
func (ta *TrayApp) Quit() {
	ta.running = false
	ta.tray.Quit()
}

// 6. Tray Builder

// TrayBuilder builds tray applications
type TrayBuilder struct {
	app *TrayApp
}

// NewTrayBuilder creates tray builder
func NewTrayBuilder(title, tooltip string) *TrayBuilder {
	return &TrayBuilder{
		app: NewTrayApp(title, tooltip),
	}
}

func (tb *TrayBuilder) WithItem(title, tooltip string, onClick func()) *TrayBuilder {
	tb.app.AddMenuItem(title, tooltip, onClick)
	return tb
}

func (tb *TrayBuilder) WithSeparator() *TrayBuilder {
	tb.app.AddSeparator()
	return tb
}

func (tb *TrayBuilder) OnQuit(fn func()) *TrayBuilder {
	tb.app.SetOnQuit(fn)
	return tb
}

func (tb *TrayBuilder) Build() *TrayApp {
	return tb.app
}

// 7. Advanced Tray Features

// TrayStatus holds tray status
type TrayStatus struct {
	Enabled   bool
	Tooltip   string
	IconIndex int
}

// UpdateStatus updates tray status
func (ta *TrayApp) UpdateStatus(status TrayStatus) {
	if status.Tooltip != "" {
		ta.tray.SetTooltip(status.Tooltip)
	}
	fmt.Printf("[Tray] Status updated\n")
}

// SetIcon sets tray icon
func (ta *TrayApp) SetIcon(iconPath string) {
	fmt.Printf("[Tray] Icon set to: %s\n", iconPath)
}

// ToggleVisibility toggles tray visibility
func (ta *TrayApp) ToggleVisibility() {
	fmt.Println("[Tray] Visibility toggled")
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go System Tray Examples ===\n")

	// 1. Basic tray icon
	fmt.Println("--- 1. Basic Tray Icon ---")
	tray := NewTrayIcon("My App", "My Application")
	tray.AddMenuItem("Show", "Show window", func() {
		fmt.Println("Show clicked")
	})
	tray.AddMenuItem("Hide", "Hide window", func() {
		fmt.Println("Hide clicked")
	})
	tray.AddSeparator()
	tray.AddMenuItem("Quit", "Quit application", func() {
		fmt.Println("Quit clicked")
		tray.Quit()
	})
	tray.OnQuit(func() {
		fmt.Println("Cleanup on quit")
	})

	// Simulate running (in real app, this would be goroutine)
	fmt.Println("Tray icon created (simulated)")
	tray.running = true
	time.Sleep(1 * time.Second)
	tray.Quit()

	// 2. Tray application
	fmt.Println("
--- 2. Tray Application ---")
	app := NewTrayApp("Tray App", "System Tray Application")
	app.AddMenuItem("Open", "Open application", func() {
		fmt.Println("Open clicked")
	})
	app.AddMenuItem("Settings", "Open settings", func() {
		fmt.Println("Settings clicked")
	})
	app.AddSeparator()
	app.SetOnQuit(func() {
		fmt.Println("Application quitting")
	})

	fmt.Println("Tray application created (simulated)")

	// 3. Tray builder
	fmt.Println("
--- 3. Tray Builder ---")
	builtApp := NewTrayBuilder("Builder App", "Built with Builder").
		WithItem("Start", "Start service", func() {
			fmt.Println("Service started")
		}).
		WithItem("Stop", "Stop service", func() {
			fmt.Println("Service stopped")
		}).
		WithSeparator().
		WithItem("Exit", "Exit application", func() {
			fmt.Println("Exiting")
		}).
		OnQuit(func() {
			fmt.Println("Builder cleanup")
		}).
		Build()

	fmt.Println("Built app created (simulated)")

	// 4. Status update
	fmt.Println("
--- 4. Status Update ---")
	builtApp.UpdateStatus(TrayStatus{
		Enabled: true,
		Tooltip: "Running",
	})

	// 5. Notification
	fmt.Println("
--- 5. Notification ---")
	builtApp.ShowNotification("Update Available", "Version 2.0 is ready")

	// 6. Menu manager
	fmt.Println("
--- 6. Menu Manager ---")
	menu := NewTrayMenu()
	menu.AddItem("File", "File operations", func() {
		fmt.Println("File menu")
	})
	menu.AddItem("Edit", "Edit operations", func() {
		fmt.Println("Edit menu")
	})
	menu.AddSeparator()
	menu.AddItem("View", "View options", func() {
		fmt.Println("View menu")
	})

	fmt.Printf("Menu created with %d items\n", len(menu.items))

	fmt.Println("
=== All System Tray Examples Completed ===")
	fmt.Println("Note: For full system tray functionality, install Systray or Fyne framework")
}