工作日倒数 v0.1.0
说明
学了应该快2个月的Rust,只看不动手,那肯定是不行的。所以写个小东西来实践一下。
同时发现坑也是真的多,Rust是真的难,代码还没有完成,也还有很多错误(又不是不能运行),还在持续学习。没有注释,有空再来说一下每个函数的作用。
还有雾化提醒没有加(开玩笑
成品放打赏区。可能会报毒,但放心使用!
上代码!
#![windows_subsystem = "windows"] use chrono::{Datelike, Local, TimeZone}; use iced::theme::Theme; use iced::widget::{column, container, pick_list, scrollable, text, vertical_space}; use iced::window::Position; use iced::{Alignment, Application, Command, Element, Length, Settings}; use serde::{Deserialize, Serialize}; use std::fs; const SETTINGS_FILE: &str = "settings.json"; #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Eq)] pub enum WeekName { SmallWeek, BigWeek, } #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Eq)] pub enum WorkingMode { Weekends, SingleDay, AutoSwitch(WeekName), } impl WorkingMode { const ALL: [WorkingMode; 4] = [ WorkingMode::Weekends, WorkingMode::SingleDay, WorkingMode::AutoSwitch(WeekName::BigWeek), WorkingMode::AutoSwitch(WeekName::SmallWeek), ]; } impl std::fmt::Display for WorkingMode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{}", match self { WorkingMode::Weekends => "双休", WorkingMode::SingleDay => "单休", WorkingMode::AutoSwitch(week_name) => { if *week_name == WeekName::BigWeek { "大小周(双休)" } else { "大小周(单休)" } } } ) } } impl Default for WorkingMode { fn default() -> Self { WorkingMode::Weekends } } #[derive(Debug, Clone, Copy, Serialize, Deserialize)] struct SettingsData { first_time: bool, mode: WorkingMode, current_week: WorkingMode, last_update_date: chrono::DateTime<Local>, } struct Holiday { holiday_name: String, result_day: i32, need_day: u32, working_week: String, mode_picklist_state: Option<WorkingMode>, settings: SettingsData, } #[derive(Debug, Clone)] enum Message { ModeSelected(WorkingMode), } impl Default for SettingsData { fn default() -> Self { let today = Local::now(); SettingsData { mode: WorkingMode::default(), current_week: WorkingMode::default(), first_time: true, last_update_date: today, } } } impl SettingsData { fn load() -> Self { match fs::read_to_string(SETTINGS_FILE) { Ok(contents) => { if let Ok(data) = serde_json::from_str(&contents) { data } else { SettingsData::default() } } Err(_) => SettingsData::default(), } } fn save(&self) { if let Ok(data) = serde_json::to_string(self) { if let Err(err) = fs::write(SETTINGS_FILE, data) { eprintln!("保存失败: {}", err); } } else { eprintln!("序列化失败"); } } } impl Holiday { fn is_monday(&self) -> bool { let today = Local::now(); today.weekday() == chrono::Weekday::Mon } fn is_same_week( &self, date1: &chrono::DateTime<Local>, date2: &chrono::DateTime<Local>, ) -> bool { let duration = date1.signed_duration_since(*date2); duration.num_weeks() == 0 } fn update_settings(&mut self, mode: WorkingMode) { let current_date = Local::now(); let last_update_date = self.settings.last_update_date; self.settings.current_week = mode; self.settings.first_time = false; if !self.is_monday() && self.is_same_week(¤t_date, &last_update_date) { self.settings.mode = mode; self.settings.save(); } else { self.settings.mode = match mode { WorkingMode::AutoSwitch(WeekName::BigWeek) => { self.settings.current_week = WorkingMode::AutoSwitch(WeekName::SmallWeek); WorkingMode::AutoSwitch(WeekName::SmallWeek) } WorkingMode::AutoSwitch(WeekName::SmallWeek) => { self.settings.current_week = WorkingMode::AutoSwitch(WeekName::BigWeek); WorkingMode::AutoSwitch(WeekName::BigWeek) } _ => mode, }; self.mode_picklist_state = Some(self.settings.mode); self.settings.last_update_date = Local::now(); self.update_values(); // self.settings.first_time = false; self.settings.save(); } } fn update_values(&mut self) { let weekday = Local::now().weekday(); self.working_week = match self.settings.mode { WorkingMode::Weekends => "双休".to_string(), WorkingMode::SingleDay => "单休".to_string(), WorkingMode::AutoSwitch(WeekName::BigWeek) => "大小周(双休)".to_string(), WorkingMode::AutoSwitch(WeekName::SmallWeek) => "大小周(单休)".to_string(), }; self.need_day = match self.working_week.as_str() { "双休" | "大小周(双休)" => { if weekday == chrono::Weekday::Mon { 5 - weekday.number_from_monday() } else { 6 - weekday.number_from_monday() } } "单休" | "大小周(单休)" => { if weekday == chrono::Weekday::Mon { 6 - weekday.number_from_monday() } else { 7 - weekday.number_from_monday() } } _ => panic!("工作模式错误"), }; let fes = [ ("元旦", 2023, 1, 1), ("春节", 2023, 1, 22), ("清明节", 2023, 4, 5), ("劳动节", 2023, 5, 1), ("端午节", 2023, 6, 22), ("中秋节", 2023, 9, 29), ("国庆节", 2023, 10, 1), ]; let mut name = Vec::new(); let mut result = Vec::new(); for (_i, day) in fes.iter().enumerate() { let x: (&str, i32, u32, u32) = *day; let holiday_name = x.0; let year = x.1; let month = x.2; let day = x.3; let festival_date = Local.with_ymd_and_hms(year, month, day, 0, 0, 0).unwrap(); let today = Local::now(); let day_until = festival_date.signed_duration_since(today).num_days() as i32; if day_until > 0 { result.push(day_until); name.push(holiday_name.to_string()); } } let smallest_day = *result.iter().min().unwrap(); let smallest_day_index = result.iter().position(|&x| x == smallest_day).unwrap(); self.holiday_name = name[smallest_day_index].clone(); self.result_day = smallest_day; } } impl Application for Holiday { type Message = Message; type Executor = iced::executor::Default; type Flags = (); type Theme = Theme; fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) { let settings = SettingsData::load(); let mode_picklist_state = Some(settings.mode); let mut holiday = Self { holiday_name: String::new(), result_day: 0, mode_picklist_state, settings, need_day: 0, working_week: String::new(), }; holiday.update_values(); let command = Command::perform(async {}, move |_| Message::ModeSelected(settings.mode)); (holiday, command) } fn title(&self) -> String { String::from("Holiday") } fn update(&mut self, message: Self::Message) -> Command<Self::Message> { match message { Message::ModeSelected(mode) => { self.update_settings(mode); self.settings.save(); self.mode_picklist_state = Some(self.settings.mode); self.update_values(); Command::none() } } } fn view(&self) -> Element<Message> { let pick_list = pick_list( &WorkingMode::ALL[..], self.mode_picklist_state, Message::ModeSelected, ) .placeholder("选择模式") .text_size(16); let content = if self.need_day == 0 { format!( "{}\n周末啦!\n距离{}还有{}天!", self.working_week, self.holiday_name, self.result_day ) } else { format!( "{}\n还需【{}】天就到周末啦!\n距离【{}】还有【{}】天!", self.working_week, self.need_day, self.holiday_name, self.result_day ) }; let content = column![ vertical_space(0), "", pick_list, vertical_space(20), text(content) ] .align_items(Alignment::Center) .spacing(10); container(scrollable(content)) .width(Length::Fill) .height(Length::Fill) .center_x() .into() } } pub fn main() -> iced::Result { SettingsData::load(); Holiday::run(Settings { // 窗口属性 window: iced::window::Settings { size: (270, 200), resizable: false, decorations: true, transparent: false, always_on_top: false, position: Position::Centered, ..iced::window::Settings::default() }, // 字体路径 default_font: Some(include_bytes!( r#"..\HarmonyOS_Sans_SC_Regular.ttf"# )), ..Settings::default() }) }
这个iced有个坑,那就是中文会乱码,所以得设置一个字体,打包的时候会把字体也包进去(猜测。
一个字体8MB,总共应用才14MB。
上效果!
就是这样,非常简陋,但是有靓点(应该算)!
就是这个大小周,他是会自动切换的,运行首次设置一下本周是大周还是小周,如果这周设置为[大小周(单休)]
,那下周就会自动切换为[大小周(双休)]
。单休、双休
,顾名思义,就是一直单休
或者一直双休
。
问题
现在的问题是,没有实现自动获取节假日,只在代码里写死了今年有假放的节日
因为我还不会别的,只会一捏捏基础。打算今年给他完善一下(flag
因为明年就不是那个时间点的节日了😂
好家伙,鱼排技术学院啊
好家伙,鱼排技术学院啊