Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion windows/src/desktop/kmshell/kmshell.dpr
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ uses
Keyman.System.UpdateStateMachine in 'main\Keyman.System.UpdateStateMachine.pas',
Keyman.System.DownloadUpdate in 'main\Keyman.System.DownloadUpdate.pas',
Keyman.System.ExecutionHistory in '..\..\..\..\common\windows\delphi\general\Keyman.System.ExecutionHistory.pas',
Keyman.Configuration.UI.UfrmStartInstall in 'main\Keyman.Configuration.UI.UfrmStartInstall.pas' {frmStartInstall};
Keyman.Configuration.UI.UfrmStartInstall in 'main\Keyman.Configuration.UI.UfrmStartInstall.pas' {frmStartInstall},
Keyman.Configuration.Util.NetworkConnection in 'util\Keyman.Configuration.Util.NetworkConnection.pas';

{$R VERSION.RES}
{$R manifest.res}
Expand Down
15 changes: 5 additions & 10 deletions windows/src/desktop/kmshell/kmshell.dproj
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@
<DCCReference Include="main\Keyman.Configuration.UI.UfrmStartInstall.pas">
<Form>frmStartInstall</Form>
</DCCReference>
<DCCReference Include="util\Keyman.Configuration.Util.NetworkConnection.pas"/>
<None Include="Profiling\AQtimeModule1.aqt"/>
<BuildConfiguration Include="Debug">
<Key>Cfg_2</Key>
Expand Down Expand Up @@ -418,15 +419,15 @@
<Platform value="Win64">False</Platform>
</Platforms>
<Deployment Version="3">
<DeployFile LocalName="bin\Win32\Debug\kmshell.rsm" Configuration="Debug" Class="DebugSymbols">
<DeployFile LocalName="Profiling\AQtimeModule1.aqt" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteName>kmshell.rsm</RemoteName>
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="bin\Win32\Debug\kmshell.exe" Configuration="Debug" Class="ProjectOutput">
<DeployFile LocalName="bin\Win32\Debug\kmshell.rsm" Configuration="Debug" Class="DebugSymbols">
<Platform Name="Win32">
<RemoteName>kmshell.exe</RemoteName>
<RemoteName>kmshell.rsm</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
Expand All @@ -436,12 +437,6 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="Profiling\AQtimeModule1.aqt" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="OSX32">
<Operation>1</Operation>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ object frmStartInstall: TfrmStartInstall
object lblUpdateMessage: TLabel
Left = 64
Top = 89
Width = 313
Width = 303
Height = 34
Caption = 'An update to Keyman has been downloaded and is ready to install.'
Font.Charset = DEFAULT_CHARSET
Expand Down Expand Up @@ -146,6 +146,34 @@ object frmStartInstall: TfrmStartInstall
414B8B49C3A0A5C5A461D0D262FA3F82D7F60E256D51F10000000049454E44AE
426082}
end
object shpMeteredWarning: TShape
Left = 60
Top = 149
Width = 314
Height = 45
Brush.Color = 15132415
Pen.Color = clRed
Visible = False
end
object lblMeteredWarning: TLabel
Left = 64
Top = 150
Width = 303
Height = 43
AutoSize = False
Caption = 'Metered Warning'
Color = 15132415
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -13
Font.Name = 'Segoe UI'
Font.Style = []
ParentColor = False
ParentFont = False
Transparent = False
Visible = False
WordWrap = True
end
object cmdInstall: TButton
Left = 229
Top = 200
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{
Keyman is copyright (C) SIL Global. MIT License.

// TODO: #12887 Localise all the labels and captions.
}
unit Keyman.Configuration.UI.UfrmStartInstall;
interface
Expand All @@ -19,43 +17,90 @@ interface
Winapi.Messages,
Winapi.Windows,
UfrmKeymanBase,
UserMessages, Vcl.Imaging.pngimage;
UserMessages,
Vcl.Imaging.pngimage;

type
// The 4 valid installation form scenarios plus a None case for validation
TInstallCase = (
icNone, // Not a valid case, can be used as check before calling creating form
icRestartRequiredMetered,
icRestartRequiredNotMetered,
icReadyToInstallNotMetered, // Metered warning never needed if ReadyToInstall
icNoInstallMessageMetered

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found this install case name confusing; is the following name accurate?

Suggested change
icNoInstallMessageMetered
icReadyToDownloadWarnMetered

I guess my confusion extends to the dialog box as well -- would it be possible for the dialog box to say something to clarify that a download is required, something like this?

The update has not yet been downloaded.
and
You're on a metered connection. Downloading now may incur data charges.

@rc-swag rc-swag Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the name change suggested because it overlaps with the first case. I can see the confusion though with you suggested messages.

In thinking about the fact I have not got on to this issue # #13711 yet. The forground update is still confusing to the user especially if they are on a slow connection and click Check for Updates followed by Install Now on a slow connection it there will be no gui while it is downloading the update. Untill #13711 we can provide more information (at least in english, hopefully it gets translated will in the pop-up) I am worried though it maybe to much and confusing.

Scenarios.
Foreground Update Tab:
Messages that can be displayed in isolation or combination off.

  1. Installing the update now will require a restar of your computer before you can use Keyman again. Update now anyway
  2. The Update has not yet been downloaded Keyman Configuration will close and it will be downloaded in the background before installing
    [The second part of this message in `` will be untill feat(windows): apply update now give progress if download still in progress #13711 is implemented then removed.]
  3. You're on a metered connection. Downloading now may incur data charges.

OnBoot:
icReadyToInstallNotMetered
This is the true backroung update scenario. The update has downloaded in the background the user is starting Keyman, it has not been run we are just letting them know we are about to install the new version and giving them an option to cancel

  1. An update to Keyman has been downloaded and is ready to install.

Now this code can be improved to actually use the StateMachine to check the state. It could be downloading or in updateavailable (if automatic updates are off).

Then for Update Tab
DownloadRequired && RestartRequired && Metered
-> icRestartRequiredMetered= show 1-3
DownloadRequired && RestartRequired && !Metered
-> icRestartRequiredNotMetered = show 1-2
DownloadRequired && !RestartRequired && !Metered
-> icDownloadRequired = show 2 (this is really now just informing about the pending silence :))
DownloadRequired && !RestartRequired && Metered
-> icNoInstallMessageMetered = show 2 & 3
!DownloadRequired && !RestartRequired && !Metered
-> no pop up required

Then for boot up

icReadyToInstallNotMetered = show 4.

Below I is the same as above but have renamed the enums for clarity with the additonal download message.

DownloadRequired && RestartRequired && Metered
-> icDownloadRestartMetered= show 1-3
DownloadRequired && RestartRequired && !Metered
-> icDownloadRestart = show 1-2
DownloadRequired && !RestartRequired && !Metered
-> icDownload = show 2 (this is really now just informing about the pending silence :))
DownloadRequired && !RestartRequired && Metered
-> icDownloadMetered = show 2 & 3
!DownloadRequired && !RestartRequired && !Metered
-> no pop up required

Then for boot up

icReadyToInstall = show 4.

);

TfrmStartInstall = class(TfrmKeymanBase)
cmdInstall: TButton;
cmdLater: TButton;
lblUpdateMessage: TLabel;
imgKeymanLogo: TImage;
shpMeteredWarning: TShape;
lblMeteredWarning: TLabel;
procedure FormCreate(Sender: TObject);
private
FRestartRequired: Boolean;
FScenario: TInstallCase;
public
constructor Create(AOwner: TComponent; const RestartRequired: Boolean); reintroduce;
constructor Create(
AOwner: TComponent;
const AScenario: TInstallCase); reintroduce;
end;

implementation

uses
MessageIdentifiers,
MessageIdentifierConsts;

{$R *.dfm}

constructor TfrmStartInstall.Create(AOwner: TComponent; const RestartRequired: Boolean);
constructor TfrmStartInstall.Create(
AOwner: TComponent;
const AScenario: TInstallCase);
begin
Assert(AScenario <> icNone, 'Invalid install case');
FScenario := AScenario;
inherited Create(AOwner);
FRestartRequired := RestartRequired;
end;

procedure TfrmStartInstall.FormCreate(Sender: TObject);
begin
inherited;
cmdInstall.Caption := MsgFromId(S_Update_Now);
cmdLater.Caption := MsgFromId(S_Later);
if FRestartRequired then
lblUpdateMessage.Caption := MsgFromId(S_Update_Restart_Req)
else
lblUpdateMessage.Caption := MsgFromId(S_Ready_To_Install);

// Default UI configuration state - metered warnings hidden initially
lblUpdateMessage.Visible := True;
lblMeteredWarning.Visible := False;
shpMeteredWarning.Visible := False;

case FScenario of
icRestartRequiredMetered:
begin
lblUpdateMessage.Caption := MsgFromId(S_Update_Restart_Req);
lblMeteredWarning.Caption := MsgFromId(S_Metered_Warning);
lblMeteredWarning.Visible := True;
shpMeteredWarning.Visible := True;
end;

icRestartRequiredNotMetered:
begin
lblUpdateMessage.Caption := MsgFromId(S_Update_Restart_Req);
end;

icReadyToInstallNotMetered:
begin
lblUpdateMessage.Caption := MsgFromId(S_Ready_To_Install);
end;

icNoInstallMessageMetered:
begin
lblUpdateMessage.Visible := False;
lblMeteredWarning.Caption := MsgFromId(S_Metered_Warning);
lblMeteredWarning.Visible := True;
shpMeteredWarning.Visible := True;
end;
end;
end;

end.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ interface
Sentry.Client,

KeymanPaths,
Keyman.Configuration.Util.NetworkConnection,
Keyman.System.ExecutionHistory,
Keyman.System.UpdateCheckResponse,
utilkmshell;
Expand Down Expand Up @@ -719,7 +720,9 @@ procedure UpdateAvailableState.EnterState;
begin
// Enter UpdateAvailableState
bucStateContext.SetRegistryState(usUpdateAvailable);
if bucStateContext.FAutomaticUpdate then

if bucStateContext.FAutomaticUpdate and
not TNetworkConnection.IsBackgroundUpdateBlocked then
begin
StartDownloadProcess;
end;
Expand Down Expand Up @@ -751,7 +754,8 @@ procedure UpdateAvailableState.HandleCheck;

function UpdateAvailableState.HandleKmShell;
begin
if bucStateContext.FAutomaticUpdate then
if bucStateContext.FAutomaticUpdate and
not TNetworkConnection.IsBackgroundUpdateBlocked then
begin
// we will use a new kmshell process to enable
// the download as background process.
Expand All @@ -773,6 +777,8 @@ procedure UpdateAvailableState.HandleAbort;

procedure UpdateAvailableState.HandleInstallNow;
begin
// This is deliberate action therefore no
// need to check if background update is allowed.
bucStateContext.SetApplyNow(True);
// A new kmshell process will be used to download
StartDownloadProcess;
Expand Down
40 changes: 34 additions & 6 deletions windows/src/desktop/kmshell/main/UfrmMain.pas
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ implementation
Keyman.System.KeymanSentryClient,
Keyman.System.UpdateStateMachine,
OptionsXMLRenderer,
Keyman.Configuration.Util.NetworkConnection,
Keyman.Configuration.System.UmodWebHttpServer,
Keyman.Configuration.System.HttpServer.App.ConfigMain,
Keyman.Configuration.UI.InstallFile,
Expand Down Expand Up @@ -817,12 +818,34 @@ procedure TfrmMain.Update_ApplyNow;
ShellPath : string;
FResult, InstallNow: Boolean;
frmStartInstallNow: TfrmStartInstall;
IsMetered: Boolean;
InstallCase: TInstallCase;
begin
InstallNow := True;
// Confirm User is ok that this will require a reset
if HasKeymanRun then
IsMetered := TNetworkConnection.IsMetered;

// If a restart is required (HasKeymanRun == True)
// OR it is a Metered connection warn the user and allow
// them to cancel their request to Install Now.
// Otherwise start installing with out pop-up warnings.
InstallCase := TInstallCase.icNone;
if HasKeymanRun and not IsMetered then
begin
frmStartInstallNow := TfrmStartInstall.Create(nil, true);
InstallCase := TInstallCase.icRestartRequiredNotMetered;
end
else if HasKeymanRun and IsMetered then
begin
InstallCase := TInstallCase.icRestartRequiredMetered;
end
else if (not HasKeymanRun) and IsMetered then
begin
InstallCase := TInstallCase.icNoInstallMessageMetered;
end;

// Render dialog if conditions require it
if InstallCase <> TInstallCase.icNone then
begin
frmStartInstallNow := TfrmStartInstall.Create(nil, InstallCase);
try
if frmStartInstallNow.ShowModal = mrOk then
InstallNow := True
Expand All @@ -833,18 +856,23 @@ procedure TfrmMain.Update_ApplyNow;
end;
end;

if InstallNow = True then
// Process installation execution execution path
if InstallNow then
begin
ShellPath := TKeymanPaths.KeymanDesktopInstallPath(TKeymanPaths.S_KMShell);
FResult := TUtilExecute.Shell(0, ShellPath, '', '-an');
if not FResult then
begin
TKeymanSentryClient.Client.MessageEvent(Sentry.Client.SENTRY_LEVEL_ERROR,
'TrmfMain: Shell Execute Update_ApplyNow Failed')
'TrmfMain: Shell Execute Update_ApplyNow Failed');
end
else
ModalResult := mrAbort;
begin
// If a splash screen is currently open when "Install Now" is executed,
// setting mrAbort ensures the splash screen is closed on the
// return of "Keyman Configuration".
ModalResult := mrAbort;
end;
end;
end;

Expand Down
3 changes: 2 additions & 1 deletion windows/src/desktop/kmshell/main/initprog.pas
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,8 @@ function ShouldSendToBUpdateSM(FSilent: Boolean; BUpdateSM: TUpdateStateMachine;
(FMode in [fmStart, fmSplash, fmMain, fmAbout,
fmHelp, fmShowHelp, fmSettings, fmBoot]) then
begin
frmStartInstall := TfrmStartInstall.Create(nil, false);
// We are ready to install Metered warning not needed even if on Metered connection
frmStartInstall := TfrmStartInstall.Create(nil, TInstallCase.icReadyToInstallNotMetered);
try
Result := frmStartInstall.ShowModal = mrOk;
finally
Expand Down
Loading