-
Notifications
You must be signed in to change notification settings - Fork 283
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Warn when closing window with unsaved changes (#1230)
* add MessageBox component * use element instead of string as message, since lacking rich text * refactor: replace Buffers.ofBufferOpt with Option.map * add actions * trigger modal from canQuit callback * model * behaviour * view
- Loading branch information
Showing
10 changed files
with
267 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
open Oni_Core; | ||
|
||
open Revery.UI; | ||
open Revery.UI.Components; | ||
|
||
type action('msg) = { | ||
label: string, | ||
msg: 'msg, | ||
}; | ||
|
||
module Styles = { | ||
open Style; | ||
|
||
let container = (~theme: Theme.t) => [backgroundColor(theme.background)]; | ||
|
||
let message = [ | ||
padding(20), | ||
paddingBottom(30) // I don't know why this is needed, but it is | ||
]; | ||
|
||
let actions = [flexDirection(`Row)]; | ||
|
||
let buttonOuter = (~isHovered, ~theme: Theme.t) => [ | ||
isHovered | ||
? backgroundColor(theme.menuSelectionBackground) | ||
: backgroundColor(theme.editorBackground), | ||
flexGrow(1), | ||
]; | ||
|
||
let buttonInner = [padding(10)]; | ||
|
||
let buttonText = (~isHovered, ~theme: Theme.t, ~font: UiFont.t) => [ | ||
fontFamily(font.fontFile), | ||
color(theme.foreground), | ||
isHovered | ||
? backgroundColor(theme.menuSelectionBackground) | ||
: backgroundColor(theme.editorBackground), | ||
fontSize(14), | ||
alignSelf(`Center), | ||
]; | ||
}; | ||
|
||
let%component button = (~text, ~onClick, ~theme, ~font, ()) => { | ||
let%hook (isHovered, setHovered) = Hooks.state(false); | ||
|
||
<Clickable onClick style={Styles.buttonOuter(~theme, ~isHovered)}> | ||
<View | ||
onMouseOver={_ => setHovered(_ => true)} | ||
onMouseOut={_ => setHovered(_ => false)} | ||
style=Styles.buttonInner> | ||
<Text style={Styles.buttonText(~isHovered, ~theme, ~font)} text /> | ||
</View> | ||
</Clickable>; | ||
}; | ||
|
||
let make = (~children as message, ~theme, ~font, ~actions, ~onAction, ()) => | ||
<View style={Styles.container(~theme)}> | ||
<View style=Styles.message> message </View> | ||
<View style=Styles.actions> | ||
{actions | ||
|> List.map(action => | ||
<button | ||
text={action.label} | ||
onClick={() => onAction(action.msg)} | ||
theme | ||
font | ||
/> | ||
) | ||
|> React.listToElement} | ||
</View> | ||
</View>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
type t = | ||
| UnsavedBuffersWarning; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
open Revery; | ||
open Revery.UI; | ||
|
||
open Oni_Core; | ||
open Utility; | ||
open Oni_Model; | ||
open Oni_Components; | ||
open Actions; | ||
|
||
module Styles = { | ||
open Style; | ||
|
||
let overlay = [ | ||
backgroundColor(Color.hex("#0004")), | ||
position(`Absolute), | ||
top(0), | ||
left(0), | ||
right(0), | ||
bottom(0), | ||
alignItems(`Center), | ||
justifyContent(`Center), | ||
overflow(`Hidden), | ||
flexDirection(`Column), | ||
pointerEvents(`Allow), | ||
]; | ||
|
||
let text = (~theme: Theme.t, ~font: UiFont.t) => [ | ||
fontFamily(font.fontFile), | ||
color(theme.editorForeground), | ||
backgroundColor(theme.editorBackground), | ||
fontSize(14), | ||
]; | ||
|
||
let files = [padding(10)]; | ||
|
||
let file = (~theme: Theme.t, ~font: UiFont.t) => [ | ||
fontFamily(font.fontFile), | ||
color(theme.foreground), | ||
backgroundColor(theme.editorBackground), | ||
fontSize(14), | ||
]; | ||
}; | ||
|
||
let unsavedBufferWarning = | ||
(~workingDirectory, ~buffers, ~theme, ~uiFont as font, ()) => { | ||
let modifiedFiles = | ||
buffers | ||
|> IntMap.to_seq | ||
|> Seq.map(snd) | ||
|> Seq.filter(Buffer.isModified) | ||
|> Seq.map(Buffer.getFilePath) | ||
|> List.of_seq | ||
|> OptionEx.values | ||
|> List.map( | ||
Path.toRelative(~base=Option.value(workingDirectory, ~default="")), | ||
); | ||
|
||
<MessageBox | ||
actions=MessageBox.[ | ||
{label: "Discard Changes", msg: WindowCloseDiscardConfirmed}, | ||
{label: "Cancel", msg: WindowCloseCanceled}, | ||
{label: "Save All", msg: WindowCloseSaveAllConfirmed}, | ||
] | ||
onAction={GlobalContext.current().dispatch} | ||
theme | ||
font> | ||
<Text | ||
style={Styles.text(~theme, ~font)} | ||
text="You have unsaved changes in the following files:" | ||
/> | ||
<View style=Styles.files> | ||
{modifiedFiles | ||
|> List.map(text => <Text style={Styles.file(~theme, ~font)} text />) | ||
|> React.listToElement} | ||
</View> | ||
<Text | ||
style={Styles.text(~theme, ~font)} | ||
text="Would you like to to save them before closing?" | ||
/> | ||
</MessageBox>; | ||
}; | ||
|
||
let make = (~state: State.t, ()) => { | ||
let State.{theme, uiFont, buffers, workspace, _} = state; | ||
let workingDirectory = | ||
Option.map(ws => ws.Workspace.workingDirectory, workspace); | ||
|
||
switch (state.modal) { | ||
| None => React.empty | ||
| Some(modal) => | ||
<View style=Styles.overlay> | ||
{switch (modal) { | ||
| UnsavedBuffersWarning => | ||
<unsavedBufferWarning workingDirectory buffers theme uiFont /> | ||
}} | ||
</View> | ||
}; | ||
}; |
Oops, something went wrong.