@ -30,6 +30,7 @@ import (
"tailscale.com/client/tailscale/apitype"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/ipn"
"tailscale.com/ipn"
"tailscale.com/tailcfg"
"tailscale.com/tailcfg"
"tailscale.com/version"
_ "embed"
_ "embed"
@ -95,6 +96,8 @@ type UI struct {
open widget . Clickable
open widget . Clickable
dismiss Dismiss
dismiss Dismiss
show bool
show bool
showHistory [ ] showChange
showDebugMenu bool
useLoginServer widget . Clickable
useLoginServer widget . Clickable
copy widget . Clickable
copy widget . Clickable
@ -247,6 +250,12 @@ func newUI(store *stateStore) (*UI, error) {
ui . loginServer . SingleLine = true
ui . loginServer . SingleLine = true
ui . exitDialog . list . Axis = layout . Vertical
ui . exitDialog . list . Axis = layout . Vertical
ui . shareDialog . list . Axis = layout . Vertical
ui . shareDialog . list . Axis = layout . Vertical
// If they've ever set the control plane, give them the debug menu right away.
if v , _ := ui . store . ReadString ( customLoginServerPrefKey , "" ) ; v != "" {
ui . menu . showDebugMenu = true
}
return ui , nil
return ui , nil
}
}
@ -278,6 +287,34 @@ func (ui *UI) activeDialog() *bool {
return nil
return nil
}
}
type showChange struct {
at time . Time
shown bool
}
func ( ui * UI ) setMenuShown ( v bool ) {
if v == ui . menu . show {
return
}
ui . menu . show = v
now := time . Now ( )
const recent = 5 * time . Second
recentHistory := ui . menu . showHistory [ : 0 ]
for _ , hi := range ui . menu . showHistory {
if now . Sub ( hi . at ) < recent {
recentHistory = append ( recentHistory , hi )
}
}
ui . menu . showHistory = append ( recentHistory , showChange {
at : now ,
shown : v ,
} )
if len ( ui . menu . showHistory ) >= 6 {
ui . menu . showDebugMenu = true
}
}
func ( ui * UI ) layout ( gtx layout . Context , sysIns system . Insets , state * clientState ) [ ] UIEvent {
func ( ui * UI ) layout ( gtx layout . Context , sysIns system . Insets , state * clientState ) [ ] UIEvent {
// "Get started".
// "Get started".
if ui . intro . show {
if ui . intro . show {
@ -302,7 +339,7 @@ func (ui *UI) layout(gtx layout.Context, sysIns system.Insets, state *clientStat
}
}
}
}
for ui . menu . open . Clicked ( ) {
for ui . menu . open . Clicked ( ) {
ui . menu . show = ! ui . menu . show
ui . setMenuShown ( ! ui . menu . show )
}
}
netmap := state . backend . NetworkMap
netmap := state . backend . NetworkMap
@ -844,7 +881,7 @@ func (ui *UI) layoutIntro(gtx layout.Context, sysIns system.Insets) {
func ( ui * UI ) menuClicked ( btn * widget . Clickable ) bool {
func ( ui * UI ) menuClicked ( btn * widget . Clickable ) bool {
cl := btn . Clicked ( )
cl := btn . Clicked ( )
if cl {
if cl {
ui . menu . show = false
ui . setMenuShown ( false )
}
}
return cl
return cl
}
}
@ -1091,7 +1128,7 @@ func layoutDialog(gtx layout.Context, w layout.Widget) layout.Dimensions {
func ( ui * UI ) layoutMenu ( gtx layout . Context , sysIns system . Insets , expiry time . Time , showExits bool , needsLogin bool ) {
func ( ui * UI ) layoutMenu ( gtx layout . Context , sysIns system . Insets , expiry time . Time , showExits bool , needsLogin bool ) {
ui . menu . dismiss . Add ( gtx , color . NRGBA { } )
ui . menu . dismiss . Add ( gtx , color . NRGBA { } )
if ui . menu . dismiss . Dismissed ( gtx ) {
if ui . menu . dismiss . Dismissed ( gtx ) {
ui . menu . show = false
ui . setMenuShown ( false )
}
}
layout . Inset {
layout . Inset {
Top : unit . Add ( gtx . Metric , sysIns . Top , unit . Dp ( 2 ) ) ,
Top : unit . Add ( gtx . Metric , sysIns . Top , unit . Dp ( 2 ) ) ,
@ -1103,11 +1140,15 @@ func (ui *UI) layoutMenu(gtx layout.Context, sysIns system.Insets, expiry time.T
return D { }
return D { }
}
}
if needsLogin {
if needsLogin {
items := [ ] menuItem {
var items [ ] menuItem
{ title : "Use login server" , btn : & menu . useLoginServer } ,
title := "Tailscale " + version . Short
if ui . menu . showDebugMenu {
items = [ ] menuItem {
{ title : "Change server" , btn : & menu . useLoginServer } ,
}
}
}
return layoutMenu ( ui . theme , gtx , items , func ( gtx C ) D {
return layoutMenu ( ui . theme , gtx , items , func ( gtx C ) D {
l := material . Caption ( ui . theme , "Advanced settings" )
l := material . Caption ( ui . theme , title )
return l . Layout ( gtx )
return l . Layout ( gtx )
} )
} )
}
}