use crate::LinkedHashMap;
use crate::api::block::{BlockContent, BlockContentParseError, BlockConversionError, Blocks};
use crate::api::component::{ComponentKind, UnknownComponentType};
use crate::api::view::{parse_raw_layout, ParseLayoutError, View};
use crate::parser::file::{FileItem, KeyboardSetting, Orientation, Theme};
use crate::parser::logic::{BlockContainer, ScreenLogic};
use crate::parser::logic::list_variable::ListVariable;
use crate::parser::logic::variable::Variable;
use crate::parser::view::Layout as ViewScreen;
use thiserror::Error;
use crate::parser::logic::event::EventPool;
#[derive(Debug, Clone, PartialEq)]
pub struct Screen {
pub layout_name: String,
pub java_name: String,
pub layout: Vec<View>,
pub variables: LinkedHashMap<String, Variable>,
pub list_variables: LinkedHashMap<String, ListVariable>,
pub more_blocks: LinkedHashMap<String, MoreBlock>,
pub components: LinkedHashMap<String, ComponentKind>,
pub events: Vec<Event>,
pub fab: Option<View>,
pub fullscreen_enabled: bool,
pub toolbar_enabled: bool,
pub drawer_enabled: bool,
pub fab_enabled: bool,
pub orientation: Orientation,
pub theme: Theme,
pub keyboard_setting: KeyboardSetting,
}
#[derive(Debug, Clone, PartialEq)]
pub struct MoreBlock {
pub name: String,
pub spec: BlockContent,
pub code: Blocks,
}
type ParserMoreBlock = crate::parser::logic::more_block::MoreBlock;
impl MoreBlock {
pub fn into_parser_more_block(self) -> (ParserMoreBlock, Blocks) {
(ParserMoreBlock { id: self.name, spec: self.spec.to_string() }, self.code)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Event {
pub name: String,
pub event_type: EventType,
pub code: Blocks,
}
impl Event {
pub fn get_block_container_id(&self) -> String {
match &self.event_type {
EventType::ViewEvent { id } => format!("{}_{}", id, self.name),
EventType::ComponentEvent { id, .. } => format!("{}_{}", id, self.name),
EventType::ActivityEvent => match self.name.as_str() {
"onCreate" => format!("{}_initializeLogic", self.name),
_ => format!("{}_{}", self.name, self.name)
}
}
}
pub fn into_parser_event(self) -> (ParserEvent, Blocks) {
let mut event = ParserEvent {
event_name: self.name,
event_type: 0,
target_id: "".to_string(),
target_type: 0
};
self.event_type.apply_to_parser_event(&mut event);
(event, self.code)
}
}
type ParserEvent = crate::parser::logic::event::Event;
impl TryFrom<ParserEvent> for Event {
type Error = UnknownEventType;
fn try_from(value: ParserEvent) -> Result<Self, Self::Error> {
Ok(Event {
event_type: EventType::from_parser_event(&value)?,
name: value.event_name,
code: Default::default()
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum EventType {
ViewEvent {
id: String
},
ComponentEvent {
id: String,
component_type: u8,
},
ActivityEvent,
}
impl EventType {
pub fn from_parser_event(event: &ParserEvent) -> Result<EventType, UnknownEventType> {
Ok(match event.event_type {
1 => EventType::ViewEvent { id: event.target_id.to_owned() },
2 => EventType::ComponentEvent {
id: event.target_id.to_owned(),
component_type: event.target_type,
},
3 => EventType::ActivityEvent,
_ => Err(UnknownEventType {
event_name: event.event_name.to_owned(),
event_type: event.event_type
})?
})
}
pub fn apply_to_parser_event(self, event: &mut ParserEvent) {
match self {
EventType::ViewEvent { id } => {
event.event_type = 1;
event.target_id = id;
}
EventType::ComponentEvent { id, component_type } => {
event.event_type = 2;
event.target_id = id;
event.target_type = component_type;
}
EventType::ActivityEvent => event.event_type = 3
}
}
}
#[derive(Error, Debug)]
#[error("unknown event type `{event_type}` for event `{event_name}`")]
pub struct UnknownEventType {
pub event_name: String,
pub event_type: u8,
}
impl Screen {
pub fn from_parsed(
layout_name: String,
logic_name: String,
file_entry: FileItem,
view_entry: ViewScreen,
mut logic_entry: ScreenLogic,
fab: Option<View>,
) -> Result<Self, ScreenConstructionError> {
if logic_entry.block_containers.contains_key("onCreate_initializeLogic") {
if logic_entry.events.is_none() { logic_entry.events = Some(EventPool::default()) }
if let Some(events) = &mut logic_entry.events {
events.0.insert(0, ParserEvent {
event_name: "onCreate".to_string(),
event_type: 3,
target_id: "onCreate".to_string(),
target_type: 0
})
}
}
Ok(Screen {
layout_name,
java_name: logic_name,
layout: parse_raw_layout(view_entry)
.map_err(ScreenConstructionError::LayoutParseError)?,
variables: logic_entry.variables.unwrap_or_default().0,
list_variables: logic_entry.list_variables.unwrap_or_default().0,
more_blocks: logic_entry.more_blocks.unwrap_or_default().0
.into_iter()
.map(|(mb_id, mb)|
Ok::<(String, MoreBlock), ScreenConstructionError>((mb_id.to_owned(), MoreBlock {
name: mb_id.to_owned(),
spec: BlockContent::parse_wo_params(mb.spec.as_str())
.map_err(|err| ScreenConstructionError::MoreBlockSpecParseError {
moreblock_id: mb_id.to_owned(),
source: err
})?,
code: Blocks::try_from(
logic_entry.block_containers
.remove(&*format!("{}_moreBlock", mb_id))
.unwrap_or_else(||BlockContainer(vec![])))
.map_err(|err| ScreenConstructionError::BlocksParseError {
container_name: format!("{}_moreBlock", mb_id),
source: err
})?
}))
)
.collect::<Result<LinkedHashMap<String, MoreBlock>, _>>()?,
components: logic_entry.components.unwrap_or_default().0
.into_iter()
.map(|cmp| {
let id = cmp.id.clone();
ComponentKind::from_parser_component(&cmp)
.map(|cmp| ((id, cmp)))
})
.collect::<Result<LinkedHashMap<String, ComponentKind>, UnknownComponentType>>()
.map_err(ScreenConstructionError::UnknownComponentType)?,
events: logic_entry.events.unwrap_or_default().0
.into_iter()
.map(|event| {
let mut event = Event::try_from(event)
.map_err(ScreenConstructionError::UnknownEventType)?;
let code = logic_entry.block_containers
.remove(event.get_block_container_id().as_str())
.unwrap_or_default();
event.code = Blocks::try_from(code)
.map_err(|err| ScreenConstructionError::BlocksParseError {
container_name: event.get_block_container_id(),
source: err
})?;
Ok(event)
})
.collect::<Result<Vec<Event>, ScreenConstructionError>>()?,
fab,
fullscreen_enabled: file_entry.options.fullscreen_enabled,
toolbar_enabled: file_entry.options.toolbar_enabled,
drawer_enabled: file_entry.options.drawer_enabled,
fab_enabled: file_entry.options.fab_enabled,
orientation: file_entry.orientation,
theme: file_entry.theme,
keyboard_setting: file_entry.keyboard_setting
})
}
}
#[derive(Error, Debug)]
pub enum ScreenConstructionError {
#[error("error while parsing the spec of the moreblock with id `{moreblock_id}`")]
MoreBlockSpecParseError {
moreblock_id: String,
source: BlockContentParseError
},
#[error("error while parsing the blocks of container `{container_name}`")]
BlocksParseError {
container_name: String,
source: BlockConversionError
},
#[error("{0}")]
UnknownEventType(#[from] UnknownEventType),
#[error("{0}")]
UnknownComponentType(#[from] UnknownComponentType),
#[error("error while parsing the layout: `{0:?}`")]
LayoutParseError(#[from] ParseLayoutError)
}