Создание приложения для управления рецептами

Язык программирования Rust уникален по сравнению с другими языками. Также чрезвычайно легко создавать мощные приложения с помощью всего лишь нескольких строк кода. Здесь я продемонстрирую, насколько легко создать приложение на Rust, показав вам, как создать простой менеджер рецептов.

Настройка ржавчины

Прежде чем мы сможем использовать Rust, нам необходимо установить его в нашей системе. к счастью, мы можем сделать это всего за несколько шагов:

Как человек, привыкший к использованию Visual Studio, я обнаружил, что использование VS Code для Rust гораздо более эффективно. Интерпретатор Rust для VS Code обновляется гораздо чаще. Сам процесс установки гораздо более подробен, но я не буду тратить на него слишком много времени, поскольку упомянутое руководство хорошо описывает пошаговый способ установки Rust в вашей системе.

Определение требований нашей программы

Программы для Windows, мобильные приложения, игры - ВСЁ БЕСПЛАТНО, в нашем закрытом телеграмм канале - Подписывайтесь:)

В соответствии со стандартными стандартами цикла разработки программ, мы должны определить, что должна делать наша программа, прежде чем мы начнем ее кодировать. Это дает нам представление о том, что нам нужно включить в него. Таким образом, вот основные функции, которые нам нужны от нашей программы:

  • Добавляйте новые рецепты
  • Посмотреть все рецепты
  • Посмотреть конкретный рецепт
  • Редактировать существующие рецепты
  • Удалить рецепты
  • Сохраняйте рецепты в файл.
  • Загрузка рецептов из файла

Это кажется достаточно простой настройкой для этой программы, и ее написание не должно быть слишком сложным. Давайте погрузимся прямо сейчас!

Настройка нашей папки и файлов

Первое, что нам нужно сделать, это создать папку для нашего проекта и открыть ее в окне терминала. Это может отличаться в зависимости от операционной системы, но большинство из них позволяют нам щелкнуть папку правой кнопкой мыши и выбрать «Открыть в терминале». Как только мы это сделаем, нам следует ввести команду:

груз новый рецепт_менеджер

При этом создается новый пакет со всеми зависимостями, которые нам нужны для написания кода на Rust. Как только мы завершим команду груза, окно терминала должно выглядеть так:

Следующее, что нам нужно сделать, это открыть нашу папку в VS Code. Это так же просто, как открыть VS Code, нажать команду «Файл» и перейти к «Открыть папку»:

Диалоговое окно «Файл» в VS Code с опцией «Открыть папку», выделенной красным.

Это даст нам окно проекта, которое выглядит примерно так:

Представление папок в VSCode с выделенными некоторыми папками.

После того, как мы настроим нашу папку, нам нужно будет создать несколько файлов, которые будут выполнять тяжелую работу для нашего проекта. Поскольку нам нужен пользовательский интерфейс, менеджер приложений и определение рецепта в разных файлах, мы создадим три файла, в которых код для этих элементов будет храниться отдельно. Мы можем сделать это, снова нажав меню «Файл» и выбрав «Новый файл». Мы переименуем эти файлы в «recipe.rs», «manager.rs» и «ui.rs». Когда мы закончим, окно нашего проекта должно выглядеть примерно так:

Окно файла проекта Rust.

Мы еще не закончили настройку. Следующее, что нам нужно сделать, это отредактировать файл Cargo.toml в нашей папке, который автоматически создается при первоначальном создании папки Cargo. Мы собираемся реализовать простую систему пользовательского интерфейса для нашего приложения (чтобы оно выглядело более эстетично). Для этого нам нужно изменить некоторые зависимости. Наш файл Cargo.toml теперь должен выглядеть так:

[package]
name = “recipe_manager”
версия = “0.1.0”
издание = “2021”

[dependencies]
serde = { версия = “1.0”, функции = [“derive”] }
serde_json = “1.0”
ледяной = “0,8”

В нашем проекте есть три зависимости, но две из них связаны. Serde — это метод сериализации данных, и поскольку наши рецепты будут иметь уникальный тип данных, нам понадобится serde для их сохранения и загрузки. Iced — простой менеджер с графическим интерфейсом, работающий в нескольких операционных системах. Мы используем его, поскольку его легко реализовать и он будет работать практически с любой ОС. Теперь, когда мы закончили с настройкой, мы можем приступить к самому интересному: написанию кода нашего приложения.

Создание сценария рецепта

Первое, что нам нужно создать, — это сценарий рецепта, в котором будут храниться наши данные. В VS Code перейдите к файлу рецепта.rs и откройте его. Файл должен отображаться как пустой на левой панели. Оттуда мы напишем этот код:

используйте serde::{Serialize, Deserialize};

паб структура Рецепт {
идентификатор паба: u32,
название паба: String,
ингредиенты паба: Vec,
инструкции публикации: Vec,
порции в пабе: u32,
}

внедрить Рецепт {
паб fn new(id: u32, название: String, ингредиенты: Vec, инструкции: Vec, порции: u32) -> Self {
Рецепт {
идентификатор,
имя,
ингредиенты,
инструкции,
порции,
}
}
}

Этот код позволяет нам создать общедоступную структуру для наших рецептов, которая включает переменные для хранения количества порции, инструкций, ингредиентов, имени и уникального идентификатора, на который можно ссылаться. У нас также есть функция-конструктор, которая поможет нам создавать новые экземпляры рецептов, как только мы получим информацию для помещения в переменные. Теперь, когда у нас есть структура рецептов, мы можем приступить к созданию менеджера приложений.

Создание диспетчера приложений

Структура рецептов позволяет нам сохранять наши рецепты, но нам нужно что-то, что будет заниматься фактическим сохранением, загрузкой и обновлением рецептов. Когда мы создавали трекер расходов на Python, мы реализовали сохранение и загрузку, но в Rust этот процесс немного другой. Вот как должен выглядеть наш менеджер приложений (хранящийся в менеджере.rs в папке нашего проекта):

использовать ящик :: рецепт :: Рецепт ;

используйте стандартный ::fs;

паб структура RecipeManager {

рецепты: Век <Рецепт> ,

next_id: u32,

}

реализовать RecipeManager {

паб fn new () -> Self {

Менеджер Рецептов {

рецепты: Vec::new(),

следующий_ид: 1,

}

}

pub fn add_recipe(&mut self, name: String, ингредиенты: Vec, инструкции: Vec, порции: u32) -> u32 {


пусть идентификатор = self.next_id;


self .recipes .push (Рецепт ::new(id, имя, ингредиенты, инструкции, порции));


self .next_id += 1;

идентификатор

}

pub fn get_all_recipes(& self ) -> &Vec {

и самостоятельные рецепты

}

pub fn get_recipe(& self, id: u32) -> Option<&Recipe> {


self .recipes.iter().find(|r| r.id == id)

}

pub fn update_recipe(&mut self, id: u32, name: String, ингредиенты: Vec, инструкции: Vec, порции: u32) -> bool {


if let Some(recipe) = self.recipes.iter_mut().find(|r| r.id == id) {

рецепт.имя = имя;

рецепт.ингредиенты = ингредиенты;

рецепт.инструкции = инструкции;

рецепт.сервировки = порции;


истинный

} еще {


ЛОЖЬ

}

}

pub fn delete_recipe(&mut self, id: u32) -> bool {


пусть Initial_len = self.recipes.len();


self .recipes.retain(|r| r.id != id);


self.recipes.len() < начальный_len
}

pub fn save_to_file(& self , filename: &str) -> std::io::Result<()> {

let json = serde_json::to_string(& self.recipes)?;

fs::write(имя файла, json)

}

pub fn load_from_file(&mut self , filename: &str) -> std::io::Result<()> {


let json = fs::read_to_string(имя файла)?;


self .recipes = serde_json::from_str(&json)?;


self .next_id = self .recipes.iter().map(|r| r.id).max().unwrap_or( 0 ) + 1 ;

Хорошо(())

}

}

Сначала мы начнем с импорта нашей структуры рецептов, которую мы написали ранее, и библиотеки fs для работы с вводом и выводом файлов (чтение и сохранение файлов). Прямо под этим мы определим наш менеджер рецептов и его экземпляр. Мы можем рассматривать менеджер рецептов как контейнер, в котором хранятся все наши рецепты и которые организованы.

После этого идет функция add_recipe, которая:

  • Принимает детали рецепта в качестве параметров.
  • Создает новый рецепт с текущим next_id.
  • Добавляет рецепт в вектор рецептов.
  • Увеличивает next_id для следующего рецепта.
  • Возвращает идентификатор вновь добавленного рецепта.

Функция get_all_recipes возвращает ссылку на весь список рецептов. Функция get_recipe ищет список рецептов и возвращает один на основе идентификатора, который она принимает в качестве входных данных. Функция update_recipe ищет рецепт, позволяет нам обновить детали этого рецепта и сохранить новую копию. Функция delete_recipe удаляет рецепт из списка.

В дополнение к этим функциям у нас есть функции работы с файлами для сохранения и загрузки списка рецептов. Это дает нам достойную основу для нашей программы, но давайте сделаем ее немного красивее.

Реализация графического интерфейса

Для этой программы мог бы подойти базовый пользовательский интерфейс командной строки, но это будет очень скучный интерфейс. Давайте немного оживим ситуацию, написав код для нашего файла ui.rs:

используйте Iced::widget::{Button, Column, Container, Row, Scrollable, Text, TextInput};

используйте Iced::{ Element , Длина , Песочница, Настройки };

используйте тему Iced::;

используйте ледяной :: Цвет;

использовать ящик :: менеджер :: RecipeManager ;

использовать ящик :: рецепт :: Рецепт ;

паб структура RecipeManagerGUI {

рецепт_менеджер: Менеджер рецептов,

имя_рецепта: Строка,

рецепт_ингредиенты: Строка,

рецепт_инструкции: Строка,

рецепт_сервингс: Строка,

selected_recipe: Option <Рецепт>,

error_message: Option,

редактирование: bool,

}


паб перечисление Сообщение {

ДобавитьРецепт,

РедактироватьРецепт(u32),

ОбновлениеРецепта,

ОтменаРедактировать,

ИмяРецептаИзменено(строка),

РецептИнгредиентыИзменено(строка),

РецептИнструкцииИзменено(строка),

RecipeServingsChanged(строка),

RecipeSelected(Рецепт),

УдалитьРецепт(u32),

СохранитьРецепты,

Загрузка рецептов,

}

внедрить песочницу для RecipeManagerGUI {


введите Сообщение = Сообщение;

fn new () -> Self {


Себя {

рецепт_менеджер: RecipeManager::new (),

имя_рецепта: String::new (),

рецепт_ингредиентс:Строка::новое(),

рецепт_инструкции:Строка::новая(),

рецепт_сервингс: String::new (),

выбранный_рецепт: Нет,

сообщение_ошибки: Нет,

редактирование: ложь,

}

}

fn title(&self) -> String {


Строка :: from («Менеджер рецептов»)

}

fn update (&mut self, message: Message) {

сопоставить сообщение {

Сообщение::AddRecipe => {


если ! self .recipe_name .is_empty () {


пусть порции = self.recipe_servings.parse().unwrap_or(1);


self .recipe_manager .add_recipe (


self .recipe_name. клон (),

self.recipe_ingredients.split( ',').map( String :: from .collect(),

self.recipe_instructions.split( '\n').map( String :: from .collect(),

порции,

);


self .recipe_name .clear();


self .recipe_ingredients .clear();


self .recipe_instructions .clear();


self .recipe_servings .clear();

}

}

Сообщение::EditRecipe(id) => {


если let Some(рецепт) = self.recipe_manager.get_recipe(id) {


self .recipe_name = рецепт.имя. клон ();


self .recipe_ingredients = рецепт.ingredients.join( “, “);


self .recipe_instructions = рецепт.instructions.join( “\n”);


self .recipe_servings = рецепт.servings.to_string();


self .selected_recipe = Some(recipe. clone());


самостоятельное редактирование = правда;

}

}

Сообщение:: UpdateRecipe => {


если let Some(recipe) = &self.selected_recipe {


пусть порции = self.recipe_servings.parse().unwrap_or(recipe.servings);


self .recipe_manager .update_recipe (


рецепт .id ,


self .recipe_name. клон (),

self.recipe_ingredients.split( ',').map( String :: from .collect(),

self.recipe_instructions.split( '\n').map( String :: from ).collect(),

порции,

);


самостоятельное редактирование = ложь;


self .selected_recipe = Нет;

}

}

Сообщение:: CancelEdit => {


самостоятельное редактирование = ложь;


self .recipe_name .clear();


self .recipe_ingredients .clear();


self .recipe_instructions .clear();


self .recipe_servings .clear();

}

Сообщение::RecipeNameChanged(имя) => {


self .recipe_name = имя;

}

Сообщение::RecipeIngredientsChanged(ингредиенты) => {


self .recipe_ingredients = ингредиенты;

}

Message::RecipeInstructionsChanged(инструкции) => {


self .recipe_instructions = инструкции;

}

Message::RecipeServingsChanged(порции) => {


self .recipe_servings = порции;

}

Сообщение::RecipeSelected(рецепт) => {


self .selected_recipe = Some(рецепт);


самостоятельное редактирование = ложь;

}

Сообщение::DeleteRecipe(id) => {


if self .recipe_manager .delete_recipe (id) {


self .selected_recipe = Нет;

}

}

Сообщение:: SaveRecipes => {


if let Err(e) = self.recipe_manager.save_to_file(“recipes.json”) {


self .error_message = Some(format!( “Не удалось сохранить рецепты: {}”, e));

}

}

Сообщение::LoadRecipes => {


match self .recipe_manager .load_from_file (“рецепты .json”) {

Хорошо(_) => self .selected_recipe = Нет,

Err(e) => self .error_message = Some(format!( “Не удалось загрузить рецепты: {}”, e)),

}

}

}

}

fn view(& self) -> Element {


пусть рецепт_форма = Столбец::новый ()


.push( TextInput::new(


«Введите название рецепта…»,

& само .recipe_name,

Сообщение::RecipeNameChanged,

))


.push( TextInput::new(


«Введите ингредиенты (через запятую)…» ,

& self .recipe_ingredients,

Сообщение::RecipeIngredientsChanged,

))


.push( TextInput::new(


«Введите инструкции (через строки)…» ,

& self .recipe_instructions,

Сообщение::RecipeInstructionsChanged,

))


.push( TextInput::new(


«Введите количество порций…» ,

& self .recipe_servings,

Сообщение::RecipeServingsChanged,

))


.толкать (


если самостоятельно .редактирование {

Button::new(Text::new( “Обновить рецепт”)).on_press(Message::UpdateRecipe)

} еще {

Button::new(Text::new( “Добавить рецепт”)).on_press(Message::AddRecipe)

}

)


.толкать (


если самостоятельно .редактирование {

Button::new(Text::new( “Отмена”)).on_press(Message::CancelEdit)

} еще {

Кнопка:: новый (Текст:: новый ( “” ))

}

);

пусть рецепты: Element<_> = self


.recipe_manager


.get_all_recipes()


.итер ()

.fold(Столбец:: новый ().spacing( 10 ), |столбец, рецепт| {


столбец .push(

Строка:: новый ()


.толкать (


Кнопка ::new(Текст ::new( & рецепт .имя ))

.on_press(Message::RecipeSelected(recipe. clone ()))

)


.толкать (

Кнопка:: новый (Текст:: новый (“Редактировать”))


.on_press (Сообщение ::EditRecipe(recipe.id))

)


.толкать (

Кнопка:: новый (Текст:: новый (“Удалить”))


.on_press (Сообщение::DeleteRecipe(recipe.id))

)

)

})


.в ();

let рецепты_list = Прокручиваемый:: новый (рецепты)


.height (Длина::Заполнить);

пусть рецепт_деталь = self.selected_recipe.as_ref().map_or(

Column:: new ().push(Text:: new («Рецепт не выбран»)),

|рецепт| {

Столбец:: новый ()


.push( Текст::new( & рецепт .имя ).размер (24))


.push ( Текст ::new(format !(” Порций: {}”, рецепт .servings )))


.push( Текст ::new(“Ингредиенты:”))

.push(Text:: new (recipe.ingredients.join( “, ” )))


.push( Текст ::new(“Инструкции:”))

.push(Text:: new (recipe.instructions.join( “\n” )))

},

);

пусть control_buttons = Row::new ()


.push (Кнопка ::new(Текст ::new(“Сохранить рецепты”)) .on_press (Сообщение ::SaveRecipes))


.push (Кнопка ::new(Текст ::new(“Загрузить рецепты”)) .on_press (Сообщение ::LoadRecipes)) ;

let error_display = если let Some(error) = &self.error_message {


Текст::new(ошибка).стиль(тема ::Текст ::Цвет(Цвет ::from_rgb(1.0, 0.0, 0.0 )))

} еще {

Текст:: новый (“”)

};

пусть контент = Столбец::новый ()


.push (форма_рецепта)


.push (список_рецептов)


.push (деталь_рецепта)


.push(control_buttons)


.push( error_display);

Контейнер:: новый (содержимое)


.width (Длина::Заполнить)


.height (Длина::Заливка)


.center_x ()


.в ()

}

}

паб fn run() -> Iced::Result {

RecipeManagerGUI::run(Настройки::default())

}

Импортировав Iced в наш файл, мы можем разработать для него пользовательский интерфейс. Пользовательский интерфейс приводит к разному пользовательскому опыту, и хотя это две разные вещи, они связаны между собой. Код внутри нашего файла пользовательского интерфейса создаст приятный интерфейс для наших пользователей и побудит их использовать нашу программу для хранения рецептов. Это также облегчает нам жизнь, поскольку навигация по пользовательскому интерфейсу в сто раз проще, чем по окну терминала. Каждое приложение отличается, поэтому вам следует экспериментировать с макетом пользовательского интерфейса, пока не найдете то, что вам нравится. Мне этот макет подходит, поэтому мы перейдем к проверке работоспособности нашего кода.

Настройка main.rs и запуск нашего кода

Внутри папки «src» нашей основной папки рецепта_manager у нас есть файл main.rs. мы собираемся перезаписать существующий код следующим образом:

рецепт мода;
менеджер модов;
способ пользовательского интерфейса;

fn main() -> Iced::Result {
ui::run()
}

Наш интерпретатор сразу же начнет жаловаться, что не может найти рецепт, менеджер или пользовательский интерфейс, но это легко исправить. Просто выберите все эти файлы из основной папки и перетащите их в папку src. Файл main.rs не видит никаких файлов, находящихся за пределами его собственной папки, так что это легкое решение этой проблемы. Как только эта проблема будет решена, мы сможем попытаться запустить наш код и посмотреть, работает ли он.

Откройте папку проекта в терминале и введите:

грузовой пробег

Вы должны увидеть, как Rust строит ваш проект. Если вы столкнулись с какими-либо ошибками, убедитесь, что ваш Rust обновлен, открыв окно терминала и набрав:

обновление ржавчины

Затем дождитесь завершения загрузки обновления и снова запустите программу. Наш окончательный менеджер рецептов выглядит примерно так:

Графическое окно, полученное в результате запуска программы Recipe Manager.

Как всегда, вы можете получить полный код этого проекта на моем GitHub. Этот проект довольно простой, но есть некоторые вещи, которые вы можете сделать самостоятельно, чтобы он выглядел лучше. На основе этого вы потенциально можете разработать надежный менеджер рецептов. В конце создания этого менеджера рецептов вы должны иметь хорошее представление о том, на что способен Rust.

Программы для Windows, мобильные приложения, игры - ВСЁ БЕСПЛАТНО, в нашем закрытом телеграмм канале - Подписывайтесь:)

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *