Skip to content

Instantly share code, notes, and snippets.

@remixer-dec
Created April 8, 2025 16:01
Show Gist options
  • Save remixer-dec/1caa798a172a76c864eb927cff540300 to your computer and use it in GitHub Desktop.
Save remixer-dec/1caa798a172a76c864eb927cff540300 to your computer and use it in GitHub Desktop.
transparent stopwatch (only minutes) for mac os
package main
import (
"fmt"
"time"
"github.com/progrium/darwinkit/dispatch"
"github.com/progrium/darwinkit/helper/action"
"github.com/progrium/darwinkit/helper/layout"
"github.com/progrium/darwinkit/macos"
"github.com/progrium/darwinkit/macos/appkit"
"github.com/progrium/darwinkit/macos/foundation"
"github.com/progrium/darwinkit/objc"
)
func main() {
macos.RunApp(launched)
}
func launched(app appkit.Application, delegate *appkit.ApplicationDelegate) {
// Create a small, minimal window for the stopwatch
w := appkit.NewWindowWithSize(150, 100)
objc.Retain(&w)
// Make the window transparent
w.SetBackgroundColor(appkit.ColorClass.ClearColor())
w.SetOpaque(false)
w.SetTitleVisibility(appkit.WindowTitleHidden)
w.SetTitlebarAppearsTransparent(true)
// Variables to track stopwatch state
var (
startTime time.Time
elapsedTime time.Duration
isRunning bool
stopChan chan struct{}
)
// Create the time display label - only minutes
timeLabel := appkit.NewLabel("")
timeLabel.SetFont(appkit.Font_BoldSystemFontOfSize(36))
timeLabel.SetAlignment(appkit.TextAlignmentCenter)
timeLabel.SetTextColor(appkit.ColorClass.BlackColor()) // Ensure visibility on transparent background
// Create control buttons using symbols
startPauseButton := appkit.NewButtonWithTitle("▶️")
startPauseButton.SetBezelStyle(appkit.BezelStyleRounded) // Using BezelStyleRounded which we know exists
startPauseButton.SetFont(appkit.Font_SystemFontOfSize(16))
resetButton := appkit.NewButtonWithTitle("⟲")
resetButton.SetBezelStyle(appkit.BezelStyleRounded) // Using BezelStyleRounded which we know exists
resetButton.SetFont(appkit.Font_SystemFontOfSize(16))
resetButton.SetEnabled(false)
// Function to update display to show only minutes
updateMinutesDisplay := func(duration time.Duration) {
minutes := int(duration.Minutes())
timeLabel.SetStringValue(fmt.Sprintf("%d", minutes))
}
// Set up button actions
action.Set(startPauseButton, func(sender objc.Object) {
if isRunning {
// Pause the stopwatch
if stopChan != nil {
close(stopChan)
stopChan = nil
}
elapsedTime += time.Since(startTime)
startPauseButton.SetTitle("▶️")
resetButton.SetEnabled(true)
isRunning = false
// Update the display one final time
updateMinutesDisplay(elapsedTime)
} else {
// Start the stopwatch
startTime = time.Now()
startPauseButton.SetTitle("⏸️")
resetButton.SetEnabled(false)
isRunning = true
// Create a channel to signal when to stop the timer
stopChan = make(chan struct{})
// Since we're only showing minutes, we can reduce update frequency
// Update once per second is sufficient
go func() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
currentElapsed := elapsedTime + time.Since(startTime)
dispatch.MainQueue().DispatchAsync(func() {
updateMinutesDisplay(currentElapsed)
})
case <-stopChan:
return
}
}
}()
}
})
action.Set(resetButton, func(sender objc.Object) {
// Reset the stopwatch
elapsedTime = 0
updateMinutesDisplay(0)
resetButton.SetEnabled(false)
})
// Create button container
buttonStackView := appkit.StackView_StackViewWithViews([]appkit.IView{
startPauseButton,
resetButton,
})
buttonStackView.SetOrientation(appkit.UserInterfaceLayoutOrientationHorizontal)
buttonStackView.SetDistribution(appkit.StackViewDistributionFillEqually)
buttonStackView.SetSpacing(5)
// Create main container for all elements
mainStackView := appkit.StackView_StackViewWithViews([]appkit.IView{
timeLabel,
buttonStackView,
})
mainStackView.SetOrientation(appkit.UserInterfaceLayoutOrientationVertical)
mainStackView.SetAlignment(appkit.LayoutAttributeCenterX)
mainStackView.SetSpacing(10)
// Add the main container to the window
w.ContentView().AddSubview(mainStackView)
layout.PinEdgesToSuperView(mainStackView, foundation.EdgeInsets{Top: 10, Left: 10, Bottom: 10, Right: 10})
// Window configuration
w.MakeKeyAndOrderFront(nil)
w.Center()
// Handle window closing
wd := &appkit.WindowDelegate{}
wd.SetWindowWillClose(func(notification foundation.Notification) {
// Clean up timer when closing
if stopChan != nil {
close(stopChan)
}
})
w.SetDelegate(wd)
delegate.SetApplicationShouldTerminateAfterLastWindowClosed(func(appkit.Application) bool {
return true
})
// Configure application
app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular)
app.ActivateIgnoringOtherApps(true)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment