added troubleshooting
This commit is contained in:
		| @@ -3,4 +3,4 @@ | ||||
|   Name = "TurtleSilicon" | ||||
|   ID = "com.tairasu.turtlesilicon" | ||||
|   Version = "1.2.2" | ||||
|   Build = 58 | ||||
|   Build = 65 | ||||
|   | ||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @@ -42,4 +42,5 @@ require ( | ||||
| 	golang.org/x/sys v0.30.0 // indirect | ||||
| 	golang.org/x/text v0.22.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| 	howett.net/plist v1.0.1 // indirect | ||||
| ) | ||||
|   | ||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							| @@ -47,6 +47,7 @@ github.com/hack-pad/safejs v0.1.0 h1:qPS6vjreAqh2amUqj4WNG1zIw7qlRQJ9K10eDKMCnE8 | ||||
| github.com/hack-pad/safejs v0.1.0/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio= | ||||
| github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08 h1:wMeVzrPO3mfHIWLZtDcSaGAe2I4PW9B/P5nMkRSwCAc= | ||||
| github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o= | ||||
| github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= | ||||
| github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe972w/cYF+FjW34v27+9Vo5106B4M= | ||||
| github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw= | ||||
| github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||||
| @@ -86,5 +87,8 @@ golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= | ||||
| gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= | ||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM= | ||||
| howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= | ||||
|   | ||||
| @@ -142,6 +142,11 @@ func createBottomBar(myWindow fyne.Window) fyne.CanvasObject { | ||||
| 		showOptionsPopup() | ||||
| 	}) | ||||
|  | ||||
| 	// Troubleshooting button | ||||
| 	troubleshootingButton = widget.NewButton("Troubleshooting", func() { | ||||
| 		showTroubleshootingPopup() | ||||
| 	}) | ||||
|  | ||||
| 	// GitHub button | ||||
| 	githubButton := widget.NewButton("GitHub", func() { | ||||
| 		githubURL := "https://github.com/tairasu/TurtleSilicon" | ||||
| @@ -168,7 +173,7 @@ func createBottomBar(myWindow fyne.Window) fyne.CanvasObject { | ||||
|  | ||||
| 	leftButtons := container.NewHBox( | ||||
| 		optionsButton, | ||||
| 		widget.NewSeparator(), // Visual separator | ||||
| 		troubleshootingButton, | ||||
| 		githubButton, | ||||
| 	) | ||||
|  | ||||
|   | ||||
							
								
								
									
										160
									
								
								pkg/ui/popup.go
									
									
									
									
									
								
							
							
						
						
									
										160
									
								
								pkg/ui/popup.go
									
									
									
									
									
								
							| @@ -1,9 +1,20 @@ | ||||
| package ui | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| 	"fyne.io/fyne/v2" | ||||
| 	"fyne.io/fyne/v2/container" | ||||
| 	"fyne.io/fyne/v2/dialog" | ||||
| 	"fyne.io/fyne/v2/widget" | ||||
|  | ||||
| 	"howett.net/plist" | ||||
|  | ||||
| 	"turtlesilicon/pkg/paths" | ||||
| 	"turtlesilicon/pkg/utils" | ||||
| ) | ||||
|  | ||||
| // showOptionsPopup creates and shows an integrated popup window for options | ||||
| @@ -123,3 +134,152 @@ func showRemapWarningPopup() { | ||||
|  | ||||
| 	warningPopup.Show() | ||||
| } | ||||
|  | ||||
| // showTroubleshootingPopup creates and shows a popup window for troubleshooting actions | ||||
| func showTroubleshootingPopup() { | ||||
| 	if currentWindow == nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// --- CrossOver Version Check --- | ||||
| 	crossoverVersion := getCrossoverVersion(paths.CrossoverPath) | ||||
| 	var crossoverStatusShort *widget.Label | ||||
| 	var crossoverStatusDetail *widget.Label | ||||
| 	if crossoverVersion == "" { | ||||
| 		crossoverStatusShort = widget.NewLabel("Not found") | ||||
| 		crossoverStatusDetail = widget.NewLabel("") | ||||
| 	} else if isCrossoverVersionRecommended(crossoverVersion) { | ||||
| 		crossoverStatusShort = widget.NewLabelWithStyle("✔ "+crossoverVersion, fyne.TextAlignTrailing, fyne.TextStyle{Bold: true}) | ||||
| 		crossoverStatusDetail = widget.NewLabelWithStyle("✔ Recommended version of CrossOver installed", fyne.TextAlignLeading, fyne.TextStyle{Italic: true}) | ||||
| 	} else { | ||||
| 		crossoverStatusShort = widget.NewLabelWithStyle("⚠️ "+crossoverVersion, fyne.TextAlignTrailing, fyne.TextStyle{Italic: true}) | ||||
| 		crossoverStatusDetail = widget.NewLabelWithStyle("⚠️ Please update to CrossOver 25.0.1 or later!", fyne.TextAlignLeading, fyne.TextStyle{Italic: true}) | ||||
| 	} | ||||
| 	crossoverStatusDetail.Wrapping = fyne.TextWrapWord | ||||
|  | ||||
| 	// --- Delete WDB Directory --- | ||||
| 	wdbDeleteButton = widget.NewButton("Delete", func() { | ||||
| 		wdbPath := filepath.Join(paths.TurtlewowPath, "WDB") | ||||
| 		if !utils.DirExists(wdbPath) { | ||||
| 			dialog.ShowInformation("WDB Not Found", "No WDB directory found in your TurtleWoW folder.", currentWindow) | ||||
| 			return | ||||
| 		} | ||||
| 		dialog.NewConfirm("Delete WDB Directory", "Are you sure you want to delete the WDB directory? This will remove all cached data. No important data will be lost.", func(confirm bool) { | ||||
| 			if confirm { | ||||
| 				err := os.RemoveAll(wdbPath) | ||||
| 				if err != nil { | ||||
| 					dialog.ShowError(fmt.Errorf("Failed to delete WDB: %v", err), currentWindow) | ||||
| 				} else { | ||||
| 					dialog.ShowInformation("WDB Deleted", "WDB directory deleted successfully.", currentWindow) | ||||
| 				} | ||||
| 			} | ||||
| 		}, currentWindow).Show() | ||||
| 	}) | ||||
|  | ||||
| 	// --- Delete Wine Prefixes --- | ||||
| 	wineDeleteButton = widget.NewButton("Delete", func() { | ||||
| 		homeDir, _ := os.UserHomeDir() | ||||
| 		userWine := filepath.Join(homeDir, ".wine") | ||||
| 		turtleWine := filepath.Join(paths.TurtlewowPath, ".wine") | ||||
| 		msg := "Are you sure you want to delete the following Wine prefixes?\n\n- " + userWine + "\n- " + turtleWine + "\n\nThis cannot be undone." | ||||
| 		dialog.NewConfirm("Delete Wine Prefixes", msg, func(confirm bool) { | ||||
| 			if confirm { | ||||
| 				err1 := os.RemoveAll(userWine) | ||||
| 				err2 := os.RemoveAll(turtleWine) | ||||
| 				if err1 != nil && !os.IsNotExist(err1) { | ||||
| 					dialog.ShowError(fmt.Errorf("Failed to delete ~/.wine: %v", err1), currentWindow) | ||||
| 					return | ||||
| 				} | ||||
| 				if err2 != nil && !os.IsNotExist(err2) { | ||||
| 					dialog.ShowError(fmt.Errorf("Failed to delete TurtleWoW/.wine: %v", err2), currentWindow) | ||||
| 					return | ||||
| 				} | ||||
| 				dialog.ShowInformation("Wine Prefixes Deleted", "Wine prefixes deleted successfully.", currentWindow) | ||||
| 			} | ||||
| 		}, currentWindow).Show() | ||||
| 	}) | ||||
|  | ||||
| 	troubleshootingTitle := widget.NewLabel("Troubleshooting") | ||||
| 	troubleshootingTitle.TextStyle = fyne.TextStyle{Bold: true} | ||||
|  | ||||
| 	rowCrossover := container.NewBorder(nil, nil, widget.NewLabel("CrossOver version:"), crossoverStatusShort, nil) | ||||
| 	rowWDB := container.NewBorder(nil, nil, widget.NewLabel("Delete WDB directory (cache):"), wdbDeleteButton, nil) | ||||
| 	rowWine := container.NewBorder(nil, nil, widget.NewLabel("Delete Wine prefixes (~/.wine & TurtleWoW/.wine):"), wineDeleteButton, nil) | ||||
| 	appMgmtNote := widget.NewLabel("Please ensure TurtleSilicon is enabled in System Settings > Privacy & Security > App Management.") | ||||
| 	appMgmtNote.Wrapping = fyne.TextWrapWord | ||||
| 	appMgmtNote.TextStyle = fyne.TextStyle{Italic: true} | ||||
|  | ||||
| 	content := container.NewVBox( | ||||
| 		troubleshootingTitle, | ||||
| 		widget.NewSeparator(), | ||||
| 		rowCrossover, | ||||
| 		crossoverStatusDetail, | ||||
| 		rowWDB, | ||||
| 		rowWine, | ||||
| 		appMgmtNote, | ||||
| 	) | ||||
|  | ||||
| 	scrollContainer := container.NewScroll(content) | ||||
|  | ||||
| 	troubleshootingCloseButton = widget.NewButton("Close", func() {}) | ||||
|  | ||||
| 	popupContent := container.NewBorder( | ||||
| 		nil, // top | ||||
| 		container.NewCenter(troubleshootingCloseButton), // bottom | ||||
| 		nil,                                  // left | ||||
| 		nil,                                  // right | ||||
| 		container.NewPadded(scrollContainer), // center | ||||
| 	) | ||||
|  | ||||
| 	windowSize := currentWindow.Content().Size() | ||||
| 	popupWidth := windowSize.Width * 5 / 6 | ||||
| 	popupHeight := windowSize.Height * 5 / 6 | ||||
|  | ||||
| 	popup := widget.NewModalPopUp(popupContent, currentWindow.Canvas()) | ||||
| 	popup.Resize(fyne.NewSize(popupWidth, popupHeight)) | ||||
|  | ||||
| 	troubleshootingCloseButton.OnTapped = func() { | ||||
| 		popup.Hide() | ||||
| 	} | ||||
|  | ||||
| 	popup.Show() | ||||
| } | ||||
|  | ||||
| // getCrossoverVersion reads the Info.plist and returns the version string, or "" if not found | ||||
| func getCrossoverVersion(appPath string) string { | ||||
| 	if appPath == "" { | ||||
| 		return "" | ||||
| 	} | ||||
| 	plistPath := filepath.Join(appPath, "Contents", "Info.plist") | ||||
| 	f, err := os.Open(plistPath) | ||||
| 	if err != nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 	defer f.Close() | ||||
| 	var data struct { | ||||
| 		Version string `plist:"CFBundleShortVersionString"` | ||||
| 	} | ||||
| 	decoder := plist.NewDecoder(f) | ||||
| 	if err := decoder.Decode(&data); err != nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return data.Version | ||||
| } | ||||
|  | ||||
| // isCrossoverVersionRecommended returns true if version >= 25.0.1 | ||||
| func isCrossoverVersionRecommended(version string) bool { | ||||
| 	parts := strings.Split(version, ".") | ||||
| 	if len(parts) < 3 { | ||||
| 		return false | ||||
| 	} | ||||
| 	major := parts[0] | ||||
| 	minor := parts[1] | ||||
| 	patch := parts[2] | ||||
| 	if major > "25" { | ||||
| 		return true | ||||
| 	} | ||||
| 	if major == "25" && minor >= "0" && patch >= "1" { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|   | ||||
| @@ -53,4 +53,13 @@ var ( | ||||
|  | ||||
| 	// Pulsing effect variables (pulsingActive is in status.go) | ||||
| 	pulsingTicker *time.Ticker | ||||
|  | ||||
| 	// Troubleshooting popup and controls | ||||
| 	troubleshootingButton       *widget.Button | ||||
| 	troubleshootingPopupActive  bool | ||||
| 	crossoverVersionStatusLabel *widget.RichText | ||||
| 	wdbDeleteButton             *widget.Button | ||||
| 	wineDeleteButton            *widget.Button | ||||
| 	appMgmtPermissionButton     *widget.Button | ||||
| 	troubleshootingCloseButton  *widget.Button | ||||
| ) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 aomizu
					aomizu