Login flow polish (#3632)
# Description - Update sign in flow # Tests - Passes CI --------- Co-authored-by: Michael Bolin <mbolin@openai.com>
This commit is contained in:
@@ -3,14 +3,14 @@
|
|||||||
*'`+*+\~/_*,
|
*'`+*+\~/_*,
|
||||||
^_,||/~~-~+\,,
|
^_,||/~~-~+\,,
|
||||||
|__/\|;_.\,''\\,
|
|__/\|;_.\,''\\,
|
||||||
/ ;||"|^ ',/_/|/
|
/ ;||"|^ /_/|/
|
||||||
|` '|*~//\ !`_"|
|
|` '|*~//\ `_"|
|
||||||
\ ~*"*||~|* |/,
|
\ ~*"*||~|* |/,
|
||||||
" ||\+/+||-_`.\||
|
" ||\+/+||-_ .\||
|
||||||
" ~\ \\|;~~+\+;||
|
" ~\ \\|;~~+\+;||
|
||||||
| ,|\,|_/_*___|*`
|
| ,|\,|_/_*___|*`
|
||||||
, "|||||""!\,"\|`
|
, "|||||""!\,"\|`
|
||||||
\`',\,*" _~"",//
|
\`',\,*" "",//
|
||||||
|' |||~*,:,/|/`
|
|' |||~*,:,/|/`
|
||||||
;`**/|+;_!//'
|
;`**/|+;_!//'
|
||||||
*, _*\_,;*
|
*, _*\_,;*
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
_=+"**+~_
|
_=+"**+~_
|
||||||
/^||*||\|=\
|
/^||*||\|=\
|
||||||
|//"\/=\|| '\
|
|//"\/=\|| '\
|
||||||
/// ;*_\|\||**|
|
/// ;' \|\||**|
|
||||||
||;_/*'=||*/|`\
|
||;_ =||*/|`\
|
||||||
|||*|' |\= !| ~.|
|
|||*| /|= !| ~.|
|
||||||
\\| /`,||||/*", |
|
\\| ,||||/*", |
|
||||||
|/; |`||/|||"; `|
|
|/; |`||/|||"; `|
|
||||||
\\|~|+~/^||"*+ /
|
\\|~|+~/^||"*+ /
|
||||||
*"__,==\*|._| ,_|
|
*"__,==\*|._| ,_|
|
||||||
|||+""/*\|;";.~|`
|
|||+""/*\|;";.~|`
|
||||||
||* |` `//, /
|
||* | `//, /
|
||||||
\|* | /,/_,|
|
\|* | /,/_,|
|
||||||
\|~"_*~//+_|
|
\|~"_*~//+_|
|
||||||
':._=:__;*
|
':._=:__;*
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
,=+++;;~,_
|
,=+++;;~,_
|
||||||
_;**|~~*=*|,"^,
|
_;**|~~*=*|,"^,
|
||||||
,*\/_==`+,"|||_"\
|
,*\/_==`+,"|||_"\
|
||||||
/|/_/|"_` '|;\~||=\
|
/|/_/|" |;\~||=\
|
||||||
|/_ ~ |"/\=\// ,
|
|/_ ~ "/\=\// ,
|
||||||
`=*,/` ,:/| /,=/|./
|
`=*,/` ,:/| /,=/|./
|
||||||
*!;/| ,//|_ *"||/=|
|
*!;/| ,//|_ *"||/=|
|
||||||
-"=|! !//||/|,||=;*
|
-"=|! !//||/ ,||=;*
|
||||||
,/*/\==+~\_|\^:\||| |
|
,/*/\==+~\_|\^:\||| |
|
||||||
|"_;__|/*\/||\!\+'+\
|
|"_;__|/*\/||\!\+'+\
|
||||||
\\\/"""****\_|*//\ \'
|
\\\/"""****\_|*//\ \'
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
_==+==+;~,_
|
_==+==+;~,_
|
||||||
_+"_;,++~__,"+;;_
|
_+"_;,++~__,"+;;_
|
||||||
_/:|*"*=","._"+//\ *
|
_/:|*"*=" "._"+//\ *
|
||||||
,||*.,^"* '\`_/=~\;\\\,
|
,||*.,^" _/=~\;\\\,
|
||||||
_\// /| _"+_\/~/|_\;\\_
|
_\// /| _\/~/|_\;\\_
|
||||||
/\| ,,~.___/,*,|'-/^/`/~!
|
/\| ,, _/,*,|'-/^/`/~!
|
||||||
||\:/ +/*/|"_/"*|=|=,
|
||\:/ +/*/|"_/"*|=|=,
|
||||||
"\-~| ^\"||;^ |;|"
|
"\-~| ^\"||;^ |;|"
|
||||||
\"" ,\==;=;+~|,|*/\, |*|`
|
\"" ,\==;=;+~|,|*/\, |*|`
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
_*\*/|,+| ' =^||\
|
_*\*/|,+| ' =^||\
|
||||||
' /|/,\|/\ .'\||,
|
' /|/,\|/\ .'\||,
|
||||||
|',|\^^_\|_* \+|||
|
|',|\^^_\|_* \+|||
|
||||||
|*||| '_;\|`| |^|/|,
|
|*||| '_;\|`| ^|/|,
|
||||||
\,||/ |+\/|,*. .`/||
|
\,||/ |+\/|,*. .`/||
|
||||||
\ \||_^ !/*=|~/+,+,,\~||
|
\ \||_^ !/*=|~/+,+,,\~||
|
||||||
! \*/=_|",|,||;|=__||='
|
! \*/=_|",|,||;|=__||='
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
/*_/||*"=!_-\_
|
/*_/||*"=!_-\_
|
||||||
/ ,||/*^^=/!\_~,
|
/ ,||/*^^=/!\_~,
|
||||||
" ||/;=_ _^,|\^|+,
|
" ||/;=_ _^,|\^|+,
|
||||||
/*";\*"|*, *.'+:+||
|
/*";\*"|*, +:+||
|
||||||
| |||"^|\;__ |'|*|||
|
| |||"^|\;* '|*|||
|
||||||
` ~*\|**|\\,".,/ `||
|
` ~*\ **|\\," / `||
|
||||||
| ~/_,\~||_/=\_| !||
|
| ~/_ ~||_/= | !||
|
||||||
! ",|" /|"|~~|+|~,||`
|
! ",|" /|"|~~|+|~,||`
|
||||||
|_|||_,|^|_||||__|||
|
|_|||_,|^|_||||__|||
|
||||||
" `^/\\|/"****||"/\|
|
" `^/\\|/"****||"/\|
|
||||||
|
|||||||
71
codex-rs/tui/src/frames.rs
Normal file
71
codex-rs/tui/src/frames.rs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
// Embed animation frames for each variant at compile time.
|
||||||
|
macro_rules! frames_for {
|
||||||
|
($dir:literal) => {
|
||||||
|
[
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_1.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_2.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_3.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_4.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_5.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_6.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_7.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_8.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_9.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_10.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_11.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_12.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_13.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_14.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_15.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_16.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_17.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_18.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_19.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_20.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_21.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_22.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_23.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_24.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_25.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_26.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_27.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_28.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_29.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_30.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_31.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_32.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_33.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_34.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_35.txt")),
|
||||||
|
include_str!(concat!("../frames/", $dir, "/frame_36.txt")),
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const FRAMES_DEFAULT: [&str; 36] = frames_for!("default");
|
||||||
|
pub(crate) const FRAMES_CODEX: [&str; 36] = frames_for!("codex");
|
||||||
|
pub(crate) const FRAMES_OPENAI: [&str; 36] = frames_for!("openai");
|
||||||
|
pub(crate) const FRAMES_BLOCKS: [&str; 36] = frames_for!("blocks");
|
||||||
|
pub(crate) const FRAMES_DOTS: [&str; 36] = frames_for!("dots");
|
||||||
|
pub(crate) const FRAMES_HASH: [&str; 36] = frames_for!("hash");
|
||||||
|
pub(crate) const FRAMES_HBARS: [&str; 36] = frames_for!("hbars");
|
||||||
|
pub(crate) const FRAMES_VBARS: [&str; 36] = frames_for!("vbars");
|
||||||
|
pub(crate) const FRAMES_SHAPES: [&str; 36] = frames_for!("shapes");
|
||||||
|
pub(crate) const FRAMES_SLUG: [&str; 36] = frames_for!("slug");
|
||||||
|
|
||||||
|
pub(crate) const ALL_VARIANTS: &[&[&str]] = &[
|
||||||
|
&FRAMES_DEFAULT,
|
||||||
|
&FRAMES_CODEX,
|
||||||
|
&FRAMES_OPENAI,
|
||||||
|
&FRAMES_BLOCKS,
|
||||||
|
&FRAMES_DOTS,
|
||||||
|
&FRAMES_HASH,
|
||||||
|
&FRAMES_HBARS,
|
||||||
|
&FRAMES_VBARS,
|
||||||
|
&FRAMES_SHAPES,
|
||||||
|
&FRAMES_SLUG,
|
||||||
|
];
|
||||||
|
|
||||||
|
pub(crate) const FRAME_TICK_DEFAULT: Duration = Duration::from_millis(80);
|
||||||
@@ -42,6 +42,7 @@ pub mod custom_terminal;
|
|||||||
mod diff_render;
|
mod diff_render;
|
||||||
mod exec_command;
|
mod exec_command;
|
||||||
mod file_search;
|
mod file_search;
|
||||||
|
mod frames;
|
||||||
mod get_git_diff;
|
mod get_git_diff;
|
||||||
mod history_cell;
|
mod history_cell;
|
||||||
pub mod insert_history;
|
pub mod insert_history;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use crate::frames::ALL_VARIANTS as FRAME_VARIANTS;
|
||||||
|
use crate::frames::FRAME_TICK_DEFAULT;
|
||||||
use crate::tui::FrameRequester;
|
use crate::tui::FrameRequester;
|
||||||
use crate::tui::Tui;
|
use crate::tui::Tui;
|
||||||
use crate::tui::TuiEvent;
|
use crate::tui::TuiEvent;
|
||||||
@@ -19,75 +21,7 @@ use ratatui::widgets::Wrap;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
// Embed animation frames for each variant at compile time.
|
const FRAME_TICK: Duration = FRAME_TICK_DEFAULT;
|
||||||
macro_rules! frames_for {
|
|
||||||
($dir:literal) => {
|
|
||||||
[
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_1.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_2.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_3.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_4.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_5.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_6.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_7.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_8.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_9.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_10.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_11.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_12.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_13.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_14.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_15.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_16.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_17.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_18.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_19.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_20.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_21.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_22.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_23.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_24.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_25.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_26.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_27.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_28.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_29.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_30.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_31.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_32.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_33.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_34.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_35.txt")),
|
|
||||||
include_str!(concat!("../frames/", $dir, "/frame_36.txt")),
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const FRAMES_DEFAULT: [&str; 36] = frames_for!("default");
|
|
||||||
const FRAMES_CODEX: [&str; 36] = frames_for!("codex");
|
|
||||||
const FRAMES_OPENAI: [&str; 36] = frames_for!("openai");
|
|
||||||
const FRAMES_BLOCKS: [&str; 36] = frames_for!("blocks");
|
|
||||||
const FRAMES_DOTS: [&str; 36] = frames_for!("dots");
|
|
||||||
const FRAMES_HASH: [&str; 36] = frames_for!("hash");
|
|
||||||
const FRAMES_HBARS: [&str; 36] = frames_for!("hbars");
|
|
||||||
const FRAMES_VBARS: [&str; 36] = frames_for!("vbars");
|
|
||||||
const FRAMES_SHAPES: [&str; 36] = frames_for!("shapes");
|
|
||||||
const FRAMES_SLUG: [&str; 36] = frames_for!("slug");
|
|
||||||
|
|
||||||
const VARIANTS: &[&[&str]] = &[
|
|
||||||
&FRAMES_DEFAULT,
|
|
||||||
&FRAMES_CODEX,
|
|
||||||
&FRAMES_OPENAI,
|
|
||||||
&FRAMES_BLOCKS,
|
|
||||||
&FRAMES_DOTS,
|
|
||||||
&FRAMES_HASH,
|
|
||||||
&FRAMES_HBARS,
|
|
||||||
&FRAMES_VBARS,
|
|
||||||
&FRAMES_SHAPES,
|
|
||||||
&FRAMES_SLUG,
|
|
||||||
];
|
|
||||||
|
|
||||||
const FRAME_TICK: Duration = Duration::from_millis(60);
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub(crate) enum ModelUpgradeDecision {
|
pub(crate) enum ModelUpgradeDecision {
|
||||||
@@ -156,11 +90,11 @@ impl ModelUpgradePopup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn frames(&self) -> &'static [&'static str] {
|
fn frames(&self) -> &'static [&'static str] {
|
||||||
VARIANTS[self.variant_idx]
|
FRAME_VARIANTS[self.variant_idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick_random_variant(&mut self) {
|
fn pick_random_variant(&mut self) {
|
||||||
let total = VARIANTS.len();
|
let total = FRAME_VARIANTS.len();
|
||||||
if total <= 1 {
|
if total <= 1 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -196,13 +130,11 @@ impl WidgetRef for &ModelUpgradePopup {
|
|||||||
lines.push("".into());
|
lines.push("".into());
|
||||||
|
|
||||||
lines.push(
|
lines.push(
|
||||||
format!(
|
format!(" Codex is now powered by {SWIFTFOX_MODEL_DISPLAY_NAME}, a new model that is")
|
||||||
" Codex is now powered by {SWIFTFOX_MODEL_DISPLAY_NAME}, a new model that is"
|
.into(),
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
);
|
);
|
||||||
lines.push(Line::from(vec![
|
lines.push(Line::from(vec![
|
||||||
" ".into(),
|
" ".into(),
|
||||||
"faster, a better collaborator, ".bold(),
|
"faster, a better collaborator, ".bold(),
|
||||||
"and ".into(),
|
"and ".into(),
|
||||||
"more steerable.".bold(),
|
"more steerable.".bold(),
|
||||||
@@ -226,6 +158,7 @@ impl WidgetRef for &ModelUpgradePopup {
|
|||||||
ModelUpgradeOption::TryNewModel,
|
ModelUpgradeOption::TryNewModel,
|
||||||
&format!("Yes, switch me to {SWIFTFOX_MODEL_DISPLAY_NAME}"),
|
&format!("Yes, switch me to {SWIFTFOX_MODEL_DISPLAY_NAME}"),
|
||||||
));
|
));
|
||||||
|
lines.push("".into());
|
||||||
lines.push(create_option(
|
lines.push(create_option(
|
||||||
1,
|
1,
|
||||||
ModelUpgradeOption::KeepCurrent,
|
ModelUpgradeOption::KeepCurrent,
|
||||||
|
|||||||
@@ -137,12 +137,12 @@ impl AuthModeWidget {
|
|||||||
fn render_pick_mode(&self, area: Rect, buf: &mut Buffer) {
|
fn render_pick_mode(&self, area: Rect, buf: &mut Buffer) {
|
||||||
let mut lines: Vec<Line> = vec![
|
let mut lines: Vec<Line> = vec![
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
"> ".into(),
|
" ".into(),
|
||||||
"Sign in with ChatGPT to use Codex as part of your paid plan".bold(),
|
"Sign in with ChatGPT to use Codex as part of your paid plan".into(),
|
||||||
]),
|
]),
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
" ".into(),
|
" ".into(),
|
||||||
"or connect an API key for usage-based billing".bold(),
|
"or connect an API key for usage-based billing".into(),
|
||||||
]),
|
]),
|
||||||
"".into(),
|
"".into(),
|
||||||
];
|
];
|
||||||
@@ -182,6 +182,7 @@ impl AuthModeWidget {
|
|||||||
"Sign in with ChatGPT",
|
"Sign in with ChatGPT",
|
||||||
"Usage included with Plus, Pro, and Team plans",
|
"Usage included with Plus, Pro, and Team plans",
|
||||||
));
|
));
|
||||||
|
lines.push("".into());
|
||||||
lines.extend(create_mode_item(
|
lines.extend(create_mode_item(
|
||||||
1,
|
1,
|
||||||
AuthMode::ApiKey,
|
AuthMode::ApiKey,
|
||||||
@@ -205,7 +206,7 @@ impl AuthModeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_continue_in_browser(&self, area: Rect, buf: &mut Buffer) {
|
fn render_continue_in_browser(&self, area: Rect, buf: &mut Buffer) {
|
||||||
let mut spans = vec!["> ".into()];
|
let mut spans = vec![" ".into()];
|
||||||
// Schedule a follow-up frame to keep the shimmer animation going.
|
// Schedule a follow-up frame to keep the shimmer animation going.
|
||||||
self.request_frame
|
self.request_frame
|
||||||
.schedule_frame_in(std::time::Duration::from_millis(100));
|
.schedule_frame_in(std::time::Duration::from_millis(100));
|
||||||
@@ -217,7 +218,8 @@ impl AuthModeWidget {
|
|||||||
&& !state.auth_url.is_empty()
|
&& !state.auth_url.is_empty()
|
||||||
{
|
{
|
||||||
lines.push(" If the link doesn't open automatically, open the following link to authenticate:".into());
|
lines.push(" If the link doesn't open automatically, open the following link to authenticate:".into());
|
||||||
lines.push(vec![" ".into(), state.auth_url.as_str().cyan().underlined()].into());
|
lines.push("".into());
|
||||||
|
lines.push(Line::from(state.auth_url.as_str().cyan().underlined()));
|
||||||
lines.push("".into());
|
lines.push("".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +233,7 @@ impl AuthModeWidget {
|
|||||||
let lines = vec![
|
let lines = vec![
|
||||||
"✓ Signed in with your ChatGPT account".fg(Color::Green).into(),
|
"✓ Signed in with your ChatGPT account".fg(Color::Green).into(),
|
||||||
"".into(),
|
"".into(),
|
||||||
"> Before you start:".into(),
|
" Before you start:".into(),
|
||||||
"".into(),
|
"".into(),
|
||||||
" Decide how much autonomy you want to grant Codex".into(),
|
" Decide how much autonomy you want to grant Codex".into(),
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ use crate::tui::TuiEvent;
|
|||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
enum Step {
|
enum Step {
|
||||||
@@ -74,6 +75,8 @@ impl OnboardingScreen {
|
|||||||
let codex_home = config.codex_home;
|
let codex_home = config.codex_home;
|
||||||
let mut steps: Vec<Step> = vec![Step::Welcome(WelcomeWidget {
|
let mut steps: Vec<Step> = vec![Step::Welcome(WelcomeWidget {
|
||||||
is_logged_in: !matches!(login_status, LoginStatus::NotAuthenticated),
|
is_logged_in: !matches!(login_status, LoginStatus::NotAuthenticated),
|
||||||
|
request_frame: tui.frame_requester(),
|
||||||
|
start: Instant::now(),
|
||||||
})];
|
})];
|
||||||
if show_login_screen {
|
if show_login_screen {
|
||||||
steps.push(Step::Auth(AuthModeWidget {
|
steps.push(Step::Auth(AuthModeWidget {
|
||||||
|
|||||||
@@ -3,23 +3,62 @@ use ratatui::layout::Rect;
|
|||||||
use ratatui::prelude::Widget;
|
use ratatui::prelude::Widget;
|
||||||
use ratatui::style::Stylize;
|
use ratatui::style::Stylize;
|
||||||
use ratatui::text::Line;
|
use ratatui::text::Line;
|
||||||
|
use ratatui::widgets::Paragraph;
|
||||||
use ratatui::widgets::WidgetRef;
|
use ratatui::widgets::WidgetRef;
|
||||||
|
use ratatui::widgets::Wrap;
|
||||||
|
|
||||||
|
use crate::frames::FRAME_TICK_DEFAULT;
|
||||||
|
use crate::frames::FRAMES_DEFAULT;
|
||||||
use crate::onboarding::onboarding_screen::StepStateProvider;
|
use crate::onboarding::onboarding_screen::StepStateProvider;
|
||||||
|
use crate::tui::FrameRequester;
|
||||||
|
|
||||||
use super::onboarding_screen::StepState;
|
use super::onboarding_screen::StepState;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
const FRAME_TICK: Duration = FRAME_TICK_DEFAULT;
|
||||||
|
|
||||||
pub(crate) struct WelcomeWidget {
|
pub(crate) struct WelcomeWidget {
|
||||||
pub is_logged_in: bool,
|
pub is_logged_in: bool,
|
||||||
|
pub request_frame: FrameRequester,
|
||||||
|
pub start: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WidgetRef for &WelcomeWidget {
|
impl WidgetRef for &WelcomeWidget {
|
||||||
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
|
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
|
||||||
let line = Line::from(vec![
|
let elapsed_ms = self.start.elapsed().as_millis();
|
||||||
">_ ".into(),
|
|
||||||
"Welcome to Codex, OpenAI's command-line coding agent".bold(),
|
// Align next draw to the next FRAME_TICK boundary to reduce jitter.
|
||||||
]);
|
{
|
||||||
line.render(area, buf);
|
let tick_ms = FRAME_TICK.as_millis();
|
||||||
|
let rem_ms = elapsed_ms % tick_ms;
|
||||||
|
let delay_ms = if rem_ms == 0 {
|
||||||
|
tick_ms
|
||||||
|
} else {
|
||||||
|
tick_ms - rem_ms
|
||||||
|
};
|
||||||
|
// Safe cast: delay_ms < tick_ms and FRAME_TICK is small.
|
||||||
|
self.request_frame
|
||||||
|
.schedule_frame_in(Duration::from_millis(delay_ms as u64));
|
||||||
|
}
|
||||||
|
|
||||||
|
let frames = &FRAMES_DEFAULT;
|
||||||
|
let idx = ((elapsed_ms / FRAME_TICK.as_millis()) % frames.len() as u128) as usize;
|
||||||
|
|
||||||
|
let mut lines: Vec<Line> = Vec::with_capacity(frames.len() + 2);
|
||||||
|
lines.extend(frames[idx].lines().map(|l| l.into()));
|
||||||
|
|
||||||
|
lines.push("".into());
|
||||||
|
lines.push(Line::from(vec![
|
||||||
|
" ".into(),
|
||||||
|
"Welcome to ".into(),
|
||||||
|
"Codex".bold(),
|
||||||
|
", OpenAI's command-line coding agent".into(),
|
||||||
|
]));
|
||||||
|
|
||||||
|
Paragraph::new(lines)
|
||||||
|
.wrap(Wrap { trim: false })
|
||||||
|
.render(area, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,3 +70,14 @@ impl StepStateProvider for WelcomeWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// A number of things break down if FRAME_TICK is zero.
|
||||||
|
#[test]
|
||||||
|
fn frame_tick_must_be_nonzero() {
|
||||||
|
assert!(FRAME_TICK.as_millis() > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user