7WCB5YQJJZIPUAFHTCQBWNI6ZM5XMIQJAKTLYTR7NOR5NKESRMDQC WT3GA27PQ2AOAIGK65O3Q4DMX4AZDVNULBLRL6GF4QW6QCASUEAAC D7A7MSIHJS3IAOLEPK52M4CZLDPLO7JB3Y62XACT2AM6UUCPQ6BAC V55EAIWQXWER2HWKZHPJBV7DDJMSPSPWSO3FSSAYODJHVDBHUN6QC NWJD6VM6POMYKQTTPP3X6LVCWU3FHLDRIHMCSC2PPUT7JWNY42LAC BFN2VHZS7VCBUHQ4S3CQ3LFQV2V4M6VANNAF32XMRFQVWRGYSZ6AC GWZGYNIBQP2AA7WYULNBS2BCV4B36IHK4OS7XHVOTUUG27E76XFQC 23SFYK4Q5NKBPJG53PQNPWQH6UOUU2YKJEL7RLXYBRLJOJYV7AWQC OPXFZKEBDHZZLXEJ2JRDYBOJH6YIN7UZNZYHVHMWMQVDTE2ZD53QC 3QVNMRNMI63L2VOFVTMPCVPXH3J4JXLXVTIIPNOMACQCPCAPWILQC MYGIBRRHHXPKVRAMQQRJTZH74L2XOK3SF7J57JPCRKSVRLZ2D6NQC PKJCFSBMXXA2H3US47IJEB7QMIYLEKTLGWQUYEZSKCDODDQTD6HQC WGID4LS4EISIOXB5Y5SOFGEF5PLBJSCPFCETH2CGRTFN3NC4WGJQC I56UGW7UUKLSR4753EYRGNROZB5PD522REEOGHVAQOZZTSVRUEEQC X6AK4QPXKTGTWIMJ5CIR46CVIXVUXV5WKTP73CNQOIRANQN4MD5QC KMB6FND35LWT4XTRUNEJZ7SQXFZEUYIJAADGWJVB4RY4IIAT4KSQC YYKXNBFL44LLOBABLXBKOF7IFUIGIEL2SYIPLGDH6UOEY5EZZZSQC 5CYU7UT74NXJWCC36GNQGVBXH676BHBXWZQVIINRMPDEJ27SBRGAC ESMM3FELOBYIX7FUNOU37FYKRJHFU2IMX6LY6EGJTVPTBDU3SEEQC TSFQFCB2NXDOBLBRUSAT63VJIXLPPTJGSTIDNOTLGHVVWSHITRNQC I2AG42PAVOII4V4TWDJV5ZVNDIHKBRDT254BFQLFUIY723TW6CCQC SASAN2XCWDQ2VEHZ7TAQEN2R3Y7AG7JUGEFVRL4DZAGHXDFEZFRQC KWTBNTO3QUUE2YADF6SYW6G6ZOKYEWRJQKIWDGZXR33S3YNDVIZQC 5MUEECMJHU44FL5RDUR3VFBIWK3H4X2L5MVJ73J37PYHZWLUKU2AC 3TLPJ57B2OD5OWJN5WMS7A4W7IGFUWJJHVIXRM34VT6KUN6R4YSAC WXQBBQ2ACNPKCTDF7OTBLP342324ZIOJK42PUO2KT2IYVJ2ETCMAC UR4J677RWA3OFG6HQTD46BUUE5YFPSBEFCJAEM5OMT4V5A7SBNNQC A6Z4O6RC33HYWP7JIVQ6FDWE4EOCQWQTIGENK2WAHUGSHDDLSA7QC 7BLZN73OYUAJEYTJ6WWHRZ7S7ONDGRBKNJGFGW62NAIZBUK3CECQC JZXYSIYDPBWQZCAMGDZ5BFMN6SU73EVVDIYEGTDJN6DVOSBNHN4QC 5ZRDYL6KIQPUI3ZZETH5KJ64N6RUF7KYM3P6Q6HER5XVJZ7GZ4WQC OJPGHVC3RFBQ7TTSCZH6URSSATII3TESD74EISDNOTNXXSX7PQMAC 3XRG4BB6V5V4DICZCMOZMLQNTANWKPO7BBRATTXOZLRNSEUQIA5AC S4WH75Y32ZYLEWXBLHRG6Z3H7KWHSXAS6H37CFQIW3FXKKWFFQ2QC WAOGSCOJ5A372BZKHEYD2BCDBCENNVLFYW3INKUOOAZMDADDIFIQC WH57EHNML4OTGQQZBT2SG6SOFTBOD6OJPJYHJVGPH22CSSOE25AAC EJPSD5XO43DWUBBZGNQMY4TMCAXL5EWCGX3OEHUERQ5GRASGWQLQC YK3MOJJLRYEKZ4FUCNJ3YKMTKOINWIYOJKR3ER7IRSGTC7O6FJZQC TQEZQJV4G4OXAYDLTMJW3NCRQV6W7I3MUBOKNCSOSXCSVLABW4QQC PSKE5G36S3IAGKGEXS2ZN2KIBV754J2OHQRZV577X4QQCLQJ6LIQC XSZZB47UXR6KGYFZZQFQR63X2LDKOH6TPNNBRRGHUCI5JJ4JIWVAC VCNKFNUF7OWVSWC6I5D25KUZ3XZZICZ3LHWVPF2N5ZSP7LQ2JOUQC 6YZAVBWU6E5FYOI5JGEIPXGZLIKAW6LS2AOFIQWEE5DMOPPCD5PQC use inflorescence_model::{self as model, action, selection, Log, ReadyState, RecordMsg, SubState,};
use inflorescence_model::model::{Log, ReadyState, RecordMsg, SubState};use inflorescence_model::{action, model, selection};
el(button(text(channel)).on_press_maybe(has_other_channels.then_some(Msg::Action(action::Msg::SelectChannel)),)),
el(button(text(channel)).on_press_maybe(has_other_channels.then_some(Msg::Action(action::FilteredMsg::SelectChannel,)))),
el(button(text("Save")).on_press(Msg::Action(action::Msg::SaveRecord))),el(button(text("Postpone")).on_press(Msg::Action(action::Msg::PostponeRecord))),el(button(text("Discard")).on_press(Msg::Action(action::Msg::DiscardRecord))),
el(button(text("Save")).on_press(Msg::Action(action::FilteredMsg::SaveRecord,))),el(button(text("Postpone")).on_press(Msg::Action(action::FilteredMsg::PostponeRecord,))),el(button(text("Discard")).on_press(Msg::Action(action::FilteredMsg::DiscardRecord,))),
.on_press(Msg::Action(action::Msg::Selection(selection::Msg::Select(selection::Select::Channel { ix, name: channel.clone() }))))
.on_press(Msg::UnfilteredSelection(selection::UnfilteredMsg::Select(selection::Select::Channel { ix, name: channel.clone() })))
.on_press(Msg::Action(action::Msg::Selection(selection::Msg::Select(selection::Select::LogChange {ix,hash: *hash,message: message.clone(),}),)))
.on_press(Msg::UnfilteredSelection(selection::UnfilteredMsg::Select(selection::Select::LogChange {ix,hash: *hash,message: message.clone(),},),))
use crate::{action, diff, log, selection};use iced_expl_widget::nav_scrollable;use libflorescence::identity::Id;use libflorescence::repo;use iced::widget::text_editor;use std::collections::HashMap;use std::path::PathBuf;pub fn is_ready(state: &State) -> Option<&ReadyState> {if let SubState::Ready(state) = &state.sub {return Some(state);}None}pub fn is_ready_mut(state: &mut State) -> Option<&mut ReadyState> {if let SubState::Ready(state) = &mut state.sub {return Some(state);}None}#[derive(Debug)]pub struct State {pub window_size: iced::Size,pub repo_path: PathBuf,pub sub: SubState,/// Cache allowed actions. Used for action filter and for view.pub allowed_actions: Vec<action::Binding>,}#[allow(clippy::large_enum_variant,reason = "There's only ever 1 instance and the small sized cases are expected to always turn into the largest `Ready` case")]#[derive(Debug)]pub enum SubState {Loading {user_ids: Vec<Id>,repo: Option<repo::State>,},SelectingId {user_ids: Vec<Id>,user_selection_ix: usize,user_selection_nav: nav_scrollable::State,repo: Option<repo::State>,},Ready(ReadyState),}#[derive(Debug)]pub struct ReadyState {pub user_id: Id,pub repo: repo::State,pub selection: selection::State,pub navigation: Navigation,pub record_msg: Option<RecordMsg>,/// `Some` when we're writing a name of the new channel forked from currentpub forking_channel_name: Option<String>,pub logs: Logs,}#[derive(Debug)]pub enum RecordMsg {Typing(text_editor::Content),Canceled { old_msg: String },}#[derive(Debug, Default)]pub struct Navigation {/// Scrollable status view contains the overview of untracked files,/// changed files and most recent log changespub status_nav: nav_scrollable::State,/// Logs shown in the status view.pub status_logs_navs: log::Navs,/// Other channels selection's navpub other_channels_nav: nav_scrollable::State,/// Other channel log change selection's navpub other_channel_log_nav: nav_scrollable::State,/// Selected channel's name#[cfg(debug_assertions)]pub other_channel_name: Option<String>,/// Navs for a log of selected channel other than the currentpub other_channel_logs_navs: log::Navs,/// Entire log's change selection navpub entire_log_nav: nav_scrollable::State,/// Logs for the entire logpub entire_logs_navs: log::Navs,/// Diffs for untracked and changed files shown in status viewpub files_diffs: diff::FilesState,/// Diffs of status log changes, entire log changes and other channels'/// logspub log_diffs: log::FilesAndState,}#[derive(Debug, Default)]pub struct Logs {/// Populated when requested to look at the entire log of changespub entire_log: Option<Log>,/// Keys are channel namespub other_channels_logs: HashMap<String, Log>,}#[derive(Debug)]pub enum Log {Loading,Loaded { log: repo::Log },}pub fn init_channel_nav(navigation: &mut Navigation,#[cfg(debug_assertions)] name: String,) {navigation.other_channel_log_nav = nav_scrollable::State::default();navigation.other_channel_logs_navs = log::Navs::default();#[cfg(debug_assertions)]{navigation.other_channel_name = Some(name);}}
pub fn is_allowed(allowed_actions: &[Binding], msg: &Msg) -> bool {// Always allow actions that do not need to be explicitly enabledmatch msg {Msg::Selection(// Mouse selectionsselection::Msg::Select(_) |// Button releaseselection::Msg::ReleaseDir(_),) => {return true;}Msg::Confirm| Msg::Cancel| Msg::Selection(selection::Msg::PressDir(_) | selection::Msg::AltPressDir(_),)| Msg::PostponeRecord| Msg::SaveRecord| Msg::DiscardRecord| Msg::AddUntrackedFile| Msg::RmAddedFile| Msg::StartRecord| Msg::SelectChannel| Msg::ForkChannel| Msg::RefreshRepo| Msg::ShowEntireLog => {}}
pub fn is_allowed(allowed_actions: &[Binding], msg: &FilteredMsg) -> bool {
use inflorescence_model::{action, ReadyState, RecordMsg, SubState};use inflorescence_view::app;
use inflorescence_model::action;use inflorescence_model::model::{ReadyState, RecordMsg, SubState};use inflorescence_view::view;
Msg::View(app::Msg::Action(action::Msg::Selection(selection::Msg::Select(selection::Select::UntrackedFile {ix: 0,path: file_to_record.to_string(),}),))),
Msg::View(view::Msg::UnfilteredSelection(selection::UnfilteredMsg::Select(selection::Select::UntrackedFile {ix: 0,path: file_to_record.to_string(),},),)),
Msg::View(app::Msg::Action(action::Msg::Selection(selection::Msg::Select(selection::Select::UntrackedFile {ix: 0,path: file_to_record.to_string(),}),))),
Msg::View(view::Msg::UnfilteredSelection(selection::UnfilteredMsg::Select(selection::Select::UntrackedFile {ix: 0,path: file_to_record.to_string(),},),)),
Msg::View(app::Msg::Action(action::Msg::Selection(selection::Msg::Select(selection::Select::UntrackedFile {ix: 0,path: file_to_record.to_string(),}),))),
Msg::View(view::Msg::UnfilteredSelection(selection::UnfilteredMsg::Select(selection::Select::UntrackedFile {ix: 0,path: file_to_record.to_string(),},),)),
Msg::Select(select) => select_exact(select, mctx),
}}pub fn update_unfiltered(msg: UnfilteredMsg,state: &mut State,files: &mut file::State,navigation: &mut Navigation,repo: &repo::State,logs: &Logs,) -> Task<crate::Msg> {let mut ctx = Ctx {state,files,navigation,repo,logs,};let mctx = &mut ctx;match msg {UnfilteredMsg::ReleaseDir(dir) => release(dir, mctx),UnfilteredMsg::Select(select) => select_exact(select, mctx),
use inflorescence_model::{self as model, action, Log, Logs, ReadyState, RecordMsg,};use inflorescence_view::{app, Theme};
use inflorescence_model::model::{Log, Logs, ReadyState, RecordMsg};use inflorescence_model::{action, model};use inflorescence_view::{view, Theme};
app::Msg::Action(msg) => update_from_action(state, msg),app::Msg::EditRecordMsg(action) => edit_record_msg(state, action),app::Msg::EditForkChannelName(name) => {
view::Msg::Action(msg) => update_from_action(state, msg),view::Msg::EditRecordMsg(action) => edit_record_msg(state, action),view::Msg::EditForkChannelName(name) => {
action::Msg::SaveRecord => save_record(state),action::Msg::PostponeRecord => defer_record(state),action::Msg::DiscardRecord => abandon_record(state),action::Msg::AddUntrackedFile => add_untracked_file(state),action::Msg::RmAddedFile => rm_added_file(state),action::Msg::StartRecord => start_record(state),action::Msg::SelectChannel => {
action::FilteredMsg::SaveRecord => save_record(state),action::FilteredMsg::PostponeRecord => defer_record(state),action::FilteredMsg::DiscardRecord => abandon_record(state),action::FilteredMsg::AddUntrackedFile => add_untracked_file(state),action::FilteredMsg::RmAddedFile => rm_added_file(state),action::FilteredMsg::StartRecord => start_record(state),action::FilteredMsg::SelectChannel => {
let action = |msg| Some(Msg::View(app::Msg::Action(msg)));let selection = |selection| action(action::Msg::Selection(selection));
let action = |msg| Some(Msg::View(view::Msg::Action(msg)));let selection =|selection| action(action::FilteredMsg::Selection(selection));
"a" => action(action::Msg::AddUntrackedFile),"c" => action(action::Msg::SelectChannel),"e" => action(action::Msg::ShowEntireLog),"f" => action(action::Msg::ForkChannel),"r" => action(action::Msg::StartRecord),"x" => action(action::Msg::RmAddedFile),
"a" => action(action::FilteredMsg::AddUntrackedFile),"c" => action(action::FilteredMsg::SelectChannel),"e" => action(action::FilteredMsg::ShowEntireLog),"f" => action(action::FilteredMsg::ForkChannel),"r" => action(action::FilteredMsg::StartRecord),"x" => action(action::FilteredMsg::RmAddedFile),
Key::Named(key::Named::Enter) => action(action::Msg::Confirm),Key::Named(key::Named::Escape) => action(action::Msg::Cancel),
Key::Named(key::Named::Enter) => {action(action::FilteredMsg::Confirm)}Key::Named(key::Named::Escape) => {action(action::FilteredMsg::Cancel)}
Some(Msg::View(app::Msg::Action(action::Msg::Selection(selection::Msg::ReleaseDir(selection::Dir::Down),))))
Some(Msg::View(view::Msg::UnfilteredSelection(selection::UnfilteredMsg::ReleaseDir(selection::Dir::Down,),)))
Some(Msg::View(app::Msg::Action(action::Msg::Selection(selection::Msg::ReleaseDir(selection::Dir::Up),))))
Some(Msg::View(view::Msg::UnfilteredSelection(selection::UnfilteredMsg::ReleaseDir(selection::Dir::Up,),)))
Some(Msg::View(app::Msg::Action(action::Msg::Selection(selection::Msg::ReleaseDir(selection::Dir::Left),))))
Some(Msg::View(view::Msg::UnfilteredSelection(selection::UnfilteredMsg::ReleaseDir(selection::Dir::Left,),)))
Some(Msg::View(app::Msg::Action(action::Msg::Selection(selection::Msg::ReleaseDir(selection::Dir::Right),))))
Some(Msg::View(view::Msg::UnfilteredSelection(selection::UnfilteredMsg::ReleaseDir(selection::Dir::Right,),)))