use crate::LxApp;
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub enum TabBarPosition {
#[serde(rename = "bottom")]
#[default]
Bottom,
#[serde(rename = "left")]
Left,
#[serde(rename = "right")]
Right,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum TabItemGroup {
#[serde(rename = "start")]
Start,
#[serde(rename = "end")]
End,
}
impl TabBarPosition {
pub fn to_i32(&self) -> i32 {
match self {
TabBarPosition::Bottom => 0,
TabBarPosition::Left => 1,
TabBarPosition::Right => 2,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(non_snake_case)]
pub struct TabBar {
#[serde(default = "default_unselected_color")]
pub color: String,
#[serde(default = "default_selected_color")]
pub selectedColor: String,
#[serde(default = "default_background_color")]
pub backgroundColor: String,
#[serde(default = "default_border_color")]
pub borderStyle: String,
pub list: Vec<TabBarItem>,
#[serde(default)]
pub position: TabBarPosition,
#[serde(default = "default_dimension")]
pub dimension: i32,
#[serde(skip)]
pub is_visible: bool,
#[serde(skip)]
pub selected_index: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(non_snake_case)]
pub struct TabBarItem {
pub pagePath: String,
#[serde(default)]
pub text: Option<String>,
#[serde(default)]
pub iconPath: Option<String>,
#[serde(default)]
pub selectedIconPath: Option<String>,
#[serde(default)]
pub selected: bool,
#[serde(default)]
pub group: Option<TabItemGroup>,
#[serde(skip)]
pub badge: Option<String>,
#[serde(skip)]
pub has_red_dot: bool,
}
impl TabBar {
pub const MIN_ITEMS: usize = 2;
pub const MAX_ITEMS: usize = 5;
pub fn is_valid(&self) -> bool {
let count = self.list.len();
(Self::MIN_ITEMS..=Self::MAX_ITEMS).contains(&count)
}
pub(crate) fn with_absolute_paths(&self, base_path: &Path) -> Self {
let mut result = self.clone();
result.is_visible = true;
result.selected_index = 0;
for item in &mut result.list {
if let Some(icon_path) = &item.iconPath {
let abs_path = base_path.join(icon_path);
item.iconPath = Some(abs_path.to_string_lossy().to_string());
} else {
item.iconPath = Some("".to_string());
}
if let Some(selected_icon_path) = &item.selectedIconPath {
let abs_path = base_path.join(selected_icon_path);
item.selectedIconPath = Some(abs_path.to_string_lossy().to_string());
} else {
item.selectedIconPath = item.iconPath.clone();
}
item.badge = None;
item.has_red_dot = false;
}
result
}
pub fn get_item(&self, index: i32) -> Option<&TabBarItem> {
self.list.get(index as usize)
}
pub fn set_visible(&mut self, visible: bool) {
self.is_visible = visible;
}
pub fn set_badge(&mut self, index: i32, text: &str) -> bool {
if let Some(item) = self.list.get_mut(index as usize) {
if text.is_empty() {
item.badge = None;
} else {
item.badge = Some(text.to_string());
}
true
} else {
false
}
}
pub fn remove_badge(&mut self, index: i32) -> bool {
if let Some(item) = self.list.get_mut(index as usize) {
item.badge = None;
true
} else {
false
}
}
pub fn set_red_dot(&mut self, index: i32, show: bool) -> bool {
if let Some(item) = self.list.get_mut(index as usize) {
item.has_red_dot = show;
true
} else {
false
}
}
pub fn set_color(&mut self, color: &str) -> &mut Self {
self.color = color.to_string();
self
}
pub fn set_selected_color(&mut self, color: &str) -> &mut Self {
self.selectedColor = color.to_string();
self
}
pub fn set_background_color(&mut self, color: &str) -> &mut Self {
self.backgroundColor = color.to_string();
self
}
pub fn set_border_style(&mut self, style: &str) -> &mut Self {
self.borderStyle = style.to_string();
self
}
pub fn set_position(&mut self, position: TabBarPosition) -> &mut Self {
self.position = position;
self
}
pub fn set_dimension(&mut self, dimension: i32) -> &mut Self {
self.dimension = dimension;
self
}
pub fn get_item_mut(&mut self, index: i32) -> Option<&mut TabBarItem> {
self.list.get_mut(index as usize)
}
pub fn get_item_ref(&self, index: i32) -> Option<&TabBarItem> {
self.list.get(index as usize)
}
pub fn set_item_text(&mut self, index: i32, text: &str) -> &mut Self {
if let Some(item) = self.get_item_mut(index) {
item.text = Some(text.to_string());
}
self
}
pub fn set_item_icon(&mut self, index: i32, icon_path: &str) -> &mut Self {
if let Some(item) = self.get_item_mut(index) {
item.iconPath = Some(icon_path.to_string());
}
self
}
pub fn set_item_selected_icon(&mut self, index: i32, icon_path: &str) -> &mut Self {
if let Some(item) = self.get_item_mut(index) {
item.selectedIconPath = Some(icon_path.to_string());
}
self
}
pub fn set_item_badge(&mut self, index: i32, badge: &str) -> &mut Self {
if let Some(item) = self.get_item_mut(index) {
item.badge = Some(badge.to_string());
}
self
}
pub fn clear_item_badge(&mut self, index: i32) -> &mut Self {
if let Some(item) = self.get_item_mut(index) {
item.badge = None;
}
self
}
pub fn set_item_red_dot(&mut self, index: i32, show: bool) -> &mut Self {
if let Some(item) = self.get_item_mut(index) {
item.has_red_dot = show;
}
self
}
pub fn get_selected_index(&self) -> i32 {
self.selected_index
}
pub fn set_selected_index(&mut self, index: i32) -> &mut Self {
if index >= 0 && (index as usize) < self.list.len() {
self.selected_index = index;
}
self
}
pub fn find_index_by_path(&self, path: &str) -> Option<i32> {
self.list
.iter()
.position(|item| item.pagePath == path)
.map(|i| i as i32)
}
pub fn is_tabbar_page(&self, path: &str) -> bool {
self.list.iter().any(|item| item.pagePath == path)
}
pub fn get_tabbar_pages(&self) -> Vec<String> {
self.list.iter().map(|item| item.pagePath.clone()).collect()
}
}
fn default_selected_color() -> String {
"#1677FF".to_string()
}
fn default_unselected_color() -> String {
"#666666".to_string()
}
fn default_background_color() -> String {
"#ffffff".to_string()
}
fn default_border_color() -> String {
"#F0F0F0".to_string()
}
fn default_dimension() -> i32 {
64
}
impl LxApp {
pub fn get_tabbar(&self) -> Option<TabBar> {
let state = self.state.lock().unwrap();
state
.tabbar
.as_ref()
.filter(|tabbar| tabbar.is_valid())
.cloned()
}
pub fn get_tabbar_item(&self, index: i32) -> Option<TabBarItem> {
let state = self.state.lock().unwrap();
let tabbar = state.tabbar.as_ref().filter(|tabbar| tabbar.is_valid())?;
tabbar.get_item(index).cloned()
}
pub fn with_tabbar_mut<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce(&mut TabBar) -> R,
{
let mut state = self.state.lock().unwrap();
if let Some(ref mut tabbar) = state.tabbar {
if tabbar.is_valid() {
Some(f(tabbar))
} else {
None
}
} else {
None
}
}
}