golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/ui/updatepage.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package ui
     7  
     8  import (
     9  	"github.com/lxn/walk"
    10  
    11  	"golang.zx2c4.com/wireguard/windows/l18n"
    12  	"golang.zx2c4.com/wireguard/windows/manager"
    13  	"golang.zx2c4.com/wireguard/windows/updater"
    14  )
    15  
    16  type UpdatePage struct {
    17  	*walk.TabPage
    18  }
    19  
    20  func NewUpdatePage() (*UpdatePage, error) {
    21  	var err error
    22  	var disposables walk.Disposables
    23  	defer disposables.Treat()
    24  
    25  	up := &UpdatePage{}
    26  
    27  	if up.TabPage, err = walk.NewTabPage(); err != nil {
    28  		return nil, err
    29  	}
    30  	disposables.Add(up)
    31  
    32  	up.SetTitle(l18n.Sprintf("An Update is Available!"))
    33  
    34  	tabIcon, _ := loadShieldIcon(16)
    35  	up.SetImage(tabIcon)
    36  
    37  	up.SetLayout(walk.NewVBoxLayout())
    38  
    39  	instructions, err := walk.NewTextLabel(up)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  	instructions.SetText(l18n.Sprintf("An update to WireGuard is available. It is highly advisable to update without delay."))
    44  	instructions.SetMinMaxSize(walk.Size{1, 0}, walk.Size{0, 0})
    45  
    46  	status, err := walk.NewTextLabel(up)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	status.SetText(l18n.Sprintf("Status: Waiting for user"))
    51  	status.SetMinMaxSize(walk.Size{1, 0}, walk.Size{0, 0})
    52  
    53  	bar, err := walk.NewProgressBar(up)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	bar.SetVisible(false)
    58  
    59  	button, err := walk.NewPushButton(up)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	updateIcon, _ := loadSystemIcon("shell32", -47, 32)
    64  	button.SetImage(updateIcon)
    65  	button.SetText(l18n.Sprintf("Update Now"))
    66  
    67  	if !IsAdmin {
    68  		button.SetText(l18n.Sprintf("Please ask the system administrator to update."))
    69  		button.SetEnabled(false)
    70  		status.SetText(l18n.Sprintf("Status: Waiting for administrator"))
    71  	}
    72  
    73  	walk.NewVSpacer(up)
    74  
    75  	switchToUpdatingState := func() {
    76  		if !bar.Visible() {
    77  			up.SetSuspended(true)
    78  			button.SetEnabled(false)
    79  			button.SetVisible(false)
    80  			bar.SetVisible(true)
    81  			bar.SetMarqueeMode(true)
    82  			up.SetSuspended(false)
    83  			status.SetText(l18n.Sprintf("Status: Waiting for updater service"))
    84  		}
    85  	}
    86  
    87  	switchToReadyState := func() {
    88  		if bar.Visible() {
    89  			up.SetSuspended(true)
    90  			bar.SetVisible(false)
    91  			bar.SetValue(0)
    92  			bar.SetRange(0, 1)
    93  			bar.SetMarqueeMode(false)
    94  			button.SetVisible(true)
    95  			button.SetEnabled(true)
    96  			up.SetSuspended(false)
    97  		}
    98  	}
    99  
   100  	button.Clicked().Attach(func() {
   101  		switchToUpdatingState()
   102  		err := manager.IPCClientUpdate()
   103  		if err != nil {
   104  			switchToReadyState()
   105  			status.SetText(l18n.Sprintf("Error: %v. Please try again.", err))
   106  		}
   107  	})
   108  
   109  	manager.IPCClientRegisterUpdateProgress(func(dp updater.DownloadProgress) {
   110  		up.Synchronize(func() {
   111  			switchToUpdatingState()
   112  			if dp.Error != nil {
   113  				switchToReadyState()
   114  				err := dp.Error
   115  				status.SetText(l18n.Sprintf("Error: %v. Please try again.", err))
   116  				return
   117  			}
   118  			if len(dp.Activity) > 0 {
   119  				stateText := dp.Activity
   120  				status.SetText(l18n.Sprintf("Status: %s", stateText))
   121  			}
   122  			if dp.BytesTotal > 0 {
   123  				bar.SetMarqueeMode(false)
   124  				bar.SetRange(0, int(dp.BytesTotal))
   125  				bar.SetValue(int(dp.BytesDownloaded))
   126  			} else {
   127  				bar.SetMarqueeMode(true)
   128  				bar.SetValue(0)
   129  				bar.SetRange(0, 1)
   130  			}
   131  			if dp.Complete {
   132  				switchToReadyState()
   133  				status.SetText(l18n.Sprintf("Status: Complete!"))
   134  				return
   135  			}
   136  		})
   137  	})
   138  
   139  	disposables.Spare()
   140  
   141  	return up, nil
   142  }