All right I tested it, it didnt work, I had to snapcraft clean command and then to edit YAML file. Now this looks like this:
Now my YAML file looks like this and finally works in snapstore:
name: autoskola4 # you probably want to 'snapcraft register <name>'
base: core20 # the base snap is the execution environment for this snap
version: '4.0' # just for humans, typically '1.2+git' or '1.3.2'
summary: Testing app for drivers with 2000 questions. # 79 char long summary
description: |
This app offers 2000 questions in Slovak and English for drivers to be tested
before main exam in Slovak Republic. More on https://hrubos.org Just download and be ready before driving exam.
grade: stable # must be 'stable' to release into candidate/stable channels
confinement: strict # use 'strict' once you have the right plugs and slots
parts:
autoskola4:
# See 'snapcraft plugins'
plugin: rust
source: ./
build-packages:
- cargo
- libssl-dev
stage-packages:
- libxkbcommon-x11-0
autoskola4-resources:
plugin: dump
source: ./
organize:
resources: bin/resources/
autoskola4-copy-resources:
plugin: nil
stage:
- ./*
apps:
autoskola4:
command: bin/autoskola4
common-id: org.hrubos.autoskola4
extensions: [gnome-3-38]
plugs:
- network
- home
My cargo TOML file looks like this:
[package]
name = "autoskola4"
version = "4.0.0"
authors = ["Mgr. Jan Hrubos <janko.hrubos@gmail.com>"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
iced = { version = "0.12.1", features = ["image"] }
rand = { version = "0.8.5"}
process_path = { version = "0.1.4" }
pathtrim = "2.0.0"
And my Rust main.rs looks like this:
use iced::{
widget::{column, image, text, button, row},
Sandbox, Settings, Color, Alignment, Length,
};//use crates of iced framework
use rand::prelude::*; //use crate of rand
use std::fs; //use file system crate
//use std::env::current_dir;
//use std::path::PathBuf;
//use std::path::Path;
//use pathtrim::TrimmablePath;
//function giving me random number from 1 to right_border
fn rand_range_num(right_border:i32)-> String{
let mut rng = rand::thread_rng();
let mut nums: Vec<i32> = (1..right_border).collect();
nums.shuffle(&mut rng);
nums[0].to_string()
}
//function giving me the random number from right_border to 288
fn rand_range_num2(right_border:i32)-> String{
let mut rng = rand::thread_rng();
let mut nums: Vec<i32> = (right_border..288).collect();
nums.shuffle(&mut rng);
nums[0].to_string()
}
//same like ^^^
fn rand_range_num3(right_border:i32)-> String{
let mut rng = rand::thread_rng();
let mut nums: Vec<i32> = (right_border..23).collect();
nums.shuffle(&mut rng);
nums[0].to_string()
}
//same like ^^^
fn rand_range_num4(right_border:i32)-> String{
let mut rng = rand::thread_rng();
let mut nums: Vec<i32> = (right_border..27).collect();
nums.shuffle(&mut rng);
nums[0].to_string()
}
//function returning the current directory of exe/elf
fn cur_dir1()->String{
//let path = current_dir().unwrap();
//path.display().to_string().clone()
let path = process_path::get_executable_path();
//let srcdir = PathBuf::from("./");
//fs::canonicalize(&srcdir).expect("Error returning the path from fs:: module... ").into_os_string().into_string().unwrap()
match path {
None => String::from("The process path could not be determined... "),
Some(path) => {
let len = path.clone().into_os_string().into_string().expect("Can not shorten path of 10 chars from end == minus autoskola3").chars().count();
let outa_path_exe=path.clone().into_os_string().into_string().expect("Can not shorten path of 10 chars from end == minus autoskola3").drain(0..len).collect::<String>();
//let to_replace = path.trim_to_nth(1).expect("Can not trim the path. ").into_os_string().into_string().unwrap();
//let target_str = outa_path_exe.replace(to_replace.as_str(),"");
let to_replace=String::from("/");
let mut del_farther:usize=0;
if let Some(last_index) = outa_path_exe.as_str().rfind(&to_replace.as_str()) {
del_farther = last_index;
}
outa_path_exe.as_str()[0..del_farther].to_string()+"/"
//path.trim_to_nth(1).expect("Can not trim the path. ").into_os_string().into_string().unwrap()
//target_str.to_string()
}
}
}
//calling main function in rust language
fn main() -> iced::Result {
MyApp::run(Settings::default())
}
//enum with app signals definitions:
#[derive(Debug, Clone)]
enum MyAppMessage {
GoZakon,
GoZnacka,
GoKrizovatka,
GiveAnswer,
GoLaw,
GoSign,
GoIntersection
}
//state of the application based on iced framework documentation:
#[derive(Default)]
struct MyApp{
pic_value:String,
question_value:String,
answer_value:String,
q_num:String,
t_num:String,
q_type:String,
}
//implementation for myapp struct:
impl Sandbox for MyApp {
type Message = MyAppMessage;//type alias
//app window constructor:
fn new() -> Self {
Self{
pic_value: String::from(""),
question_value: String::from("Sem načítam otázku po kliknutí na príslušné tlačítko...\n Here I load the question after adequate button click..."),
answer_value: String::from("Sem načítam odpoveď po kliknutí na príslušné tlačítko...\n Here I load the answer after adequate button click..."),
q_num: String::from("1"), //global random number of the SLOVAK question
q_type: String::from("za"), //whether zakony za or znacky zn
t_num:String::from("1"), //just the first English test as we know t1o1.txt means test1 otazka1
}
}
//title of app window:
fn title(&self) -> String {
String::from("Autoškola4 EN+SK: 2000 questions | Mgr. Janko Hruboš | janko.hrubos@gmail.com")
}
//on the state update and signals receiving do these actions:
fn update(&mut self, message: Self::Message) {
match message {
MyAppMessage::GoZakon => {
self.pic_value = cur_dir1()+"/resources/empty.jpg";
//println!("{}",cur_dir1());
self.q_num=rand_range_num(525);
let mut s2:String=cur_dir1()+"/resources/sk/otza/za_";
let s3:String=".txt".to_owned();
s2.push_str(&self.q_num);
s2.push_str(&s3);
self.question_value = fs::read_to_string(s2)
.expect("ERROR: Cant read the file, sorry...");
self.q_type=String::from("za");
self.answer_value=String::from("");
//^^^ self explanatory
}
MyAppMessage::GoZnacka => {
self.q_num=rand_range_num(144);
let s4:String=(cur_dir1()+"/resources/sk/znackyobr/z"+&self.q_num+".jpg").to_string().clone();
self.pic_value = s4;
let mut s2:String=cur_dir1()+"/resources/sk/otzn/z_";
let s3:String=".txt".to_owned();
s2.push_str(&self.q_num);
s2.push_str(&s3);
self.question_value = fs::read_to_string(s2)
.expect("ERROR: Cant read the file, sorry...");
self.q_type=String::from("zn");
self.answer_value=String::from("");
}
MyAppMessage::GoKrizovatka => {
self.q_num=rand_range_num2(144);
let s4:String=(cur_dir1()+"/resources/sk/znackyobr/z"+&self.q_num+".jpg").to_string().clone();
self.pic_value = s4;
let mut s2:String=cur_dir1()+"/resources/sk/otzn/z_";
let s3:String=".txt".to_owned();
s2.push_str(&self.q_num);
s2.push_str(&s3);
self.question_value = fs::read_to_string(s2)
.expect("ERROR: Cant read the file, sorry...");
self.q_type=String::from("kri");
self.answer_value=String::from("");
}
MyAppMessage::GoLaw => {
self.q_num=rand_range_num(15);//generate random question from 1 to 27
self.t_num=rand_range_num(35);//generate random test from 1 to 35
//let s4:String=("resources/en/znackyobr/z".to_owned()+&self.q_num+".jpg").to_string().clone();
self.pic_value = String::from(cur_dir1()+"/resources/empty.jpg");
let mut s2:String=cur_dir1()+"/resources/en/otazkytxt/t";
let s3:String=".txt".to_owned();
let s5:String="o".to_owned();
s2.push_str(&self.t_num);
s2.push_str(&s5);
s2.push_str(&self.q_num);
s2.push_str(&s3);
self.question_value = fs::read_to_string(s2)
.expect("ERROR: Cant read the file, sorry...");
self.q_type=String::from("law");
self.answer_value=String::from("");
}
MyAppMessage::GoSign => {
self.q_num=rand_range_num3(16);//generate random question from 16 to 23
self.t_num=rand_range_num(35);//generate random test from 1 to 35
let s4:String=(cur_dir1()+"/resources/en/znackyobr/t"+&self.t_num+"o"+&self.q_num+".jpg").to_string().clone();
//println!("{}",s4); //debug printout
self.pic_value = s4;
let mut s2:String=cur_dir1()+"/resources/en/otazkytxt/t";
let s3:String=".txt".to_owned();
let s5:String="o".to_owned();
s2.push_str(&self.t_num);
s2.push_str(&s5);
s2.push_str(&self.q_num);
s2.push_str(&s3);
self.question_value = fs::read_to_string(s2)
.expect("ERROR: Cant read the file, sorry...");
self.q_type=String::from("sig");
self.answer_value=String::from("");
}
MyAppMessage::GoIntersection => {
self.q_num=rand_range_num4(24);//generate random question from 24 to 27
self.t_num=rand_range_num(35);//generate random test from 1 to 35
let s4:String=(cur_dir1()+"/resources/en/znackyobr/t"+&self.t_num+"o"+&self.q_num+".jpg").to_string().clone();
//println!("{}",s4); //debug printout
self.pic_value = s4;
let mut s2:String=cur_dir1()+"/resources/en/otazkytxt/t";
let s3:String=".txt".to_owned();
let s5:String="o".to_owned();
s2.push_str(&self.t_num);
s2.push_str(&s5);
s2.push_str(&self.q_num);
s2.push_str(&s3);
self.question_value = fs::read_to_string(s2)
.expect(&("ERROR: Cant read the file, sorry... Path: ".to_owned()+&cur_dir1()));
self.q_type=String::from("int");//question type is intersection
self.answer_value=String::from("");//answer is not visible yet, coz intersection button pressed not answer button
//^^^ self explanatory what to do on these signals receiving
}
MyAppMessage::GiveAnswer => { //on button answer click:
let qnum = self.q_num.clone();
let tnum = self.t_num.clone();
let qtype = self.q_type.clone();
if qtype == "za" { //if this is Slovak zakon you know qnum is from 1 to 525
let mut s2:String=cur_dir1()+"/resources/sk/otza/zao_";
let s3:String=".txt".to_owned();
s2.push_str(&qnum);
s2.push_str(&s3);
self.answer_value=String::from("Odpoveď na otázku zákony ");
self.answer_value.push_str(&qnum);
let s4:String=" je: ".to_owned();
self.answer_value.push_str(&s4);
self.answer_value.push_str(&fs::read_to_string(s2)
.expect("ERROR: Cant read the file, sorry..."));
}
if qtype == "zn" { //if this is Slovak znacka you know qnum is from 1 to 144
let mut s2:String=cur_dir1()+"/resources/sk/otzn/zo_";
let s3:String=".txt".to_owned();
s2.push_str(&qnum);
s2.push_str(&s3);
self.answer_value=String::from("Odpoveď na otázku značky ");
self.answer_value.push_str(&qnum);
let s4:String=" je: ".to_owned();
self.answer_value.push_str(&s4);
self.answer_value.push_str(&fs::read_to_string(s2)
.expect("ERROR: Cant read the file, sorry..."));
}
if qtype == "kri" { //if this is Slovak znacka you know qnum is from (1 to 144)+144
let mut s2:String=cur_dir1()+"/resources/sk/otzn/zo_";
let s3:String=".txt".to_owned();
s2.push_str(&qnum);
s2.push_str(&s3);
self.answer_value=String::from("Odpoveď na otázku križovatky ");
self.answer_value.push_str(&qnum);
let s4:String=" je: ".to_owned();
self.answer_value.push_str(&s4);
self.answer_value.push_str(&fs::read_to_string(s2)
.expect("ERROR: Cant read the file, sorry..."));
}
if qtype == "law" {
let mut s2:String=cur_dir1()+"/resources/en/odtxt/t";
//let s3:String=".txt".to_owned();
let s5:String="od".to_owned();
s2.push_str(&tnum);
s2.push_str(&s5);
s2.push_str(&qnum);
//s2.push_str(&s3);
self.answer_value=String::from("Answer to the question from laws ");
self.answer_value.push_str(&qnum);
let s4:String=" is: ".to_owned();
self.answer_value.push_str(&s4);
//println!("{}",s2);
self.answer_value.push_str(&fs::read_to_string(s2)
.expect("ERROR: Cant read the file, sorry..."));
}
if qtype == "sig" {
let mut s2:String=cur_dir1()+"/resources/en/odtxt/t";
//let s3:String=".txt".to_owned();
let s5:String="od".to_owned();
s2.push_str(&tnum);
s2.push_str(&s5);
s2.push_str(&qnum);
//s2.push_str(&s3);
self.answer_value=String::from("Answer to the question from signs ");
self.answer_value.push_str(&qnum);
self.answer_value.push_str(" / test ");
self.answer_value.push_str(&tnum);
let s4:String=" is: ".to_owned();
self.answer_value.push_str(&s4);
//println!("{}",s2);
self.answer_value.push_str(&fs::read_to_string(s2)
.expect("ERROR: Cant read the file, sorry..."));
}
if qtype == "int" {
let mut s2:String=cur_dir1()+"/resources/en/odtxt/t";
//let s3:String=".txt".to_owned();
let s5:String="od".to_owned();
s2.push_str(&tnum);
s2.push_str(&s5);
s2.push_str(&qnum);
//s2.push_str(&s3);
self.answer_value=String::from("Answer to the question from intersections ");
self.answer_value.push_str(&qnum);
self.answer_value.push_str(" / test ");
self.answer_value.push_str(&tnum);
let s4:String=" is: ".to_owned();
self.answer_value.push_str(&s4);
//println!("{}",s2);
self.answer_value.push_str(&fs::read_to_string(s2)
.expect(&("ERROR: Cant read the file, sorry... Path: ".to_owned()+&cur_dir1())));
}
}
}
}
//basic view definitions with slots of signals:
fn view(&self) -> iced::Element<'_, Self::Message> {
let padding1:u16=10;//padding of 10px
column![
image(self.pic_value.clone()).width(600),
row![button("Náhodný zákon").on_press(MyAppMessage::GoZakon).padding(padding1),
button("Náhodná značka").on_press(MyAppMessage::GoZnacka).padding(padding1),
button("Náhodná križovatka").on_press(MyAppMessage::GoKrizovatka).padding(padding1)],
row![button("Answer/Opoveď").on_press(MyAppMessage::GiveAnswer).padding(padding1)],
row![button("Random law").on_press(MyAppMessage::GoLaw).padding(padding1),
button("Random sign").on_press(MyAppMessage::GoSign).padding(padding1),
button("Random intersection").on_press(MyAppMessage::GoIntersection).padding(padding1),],
text(self.question_value.as_str()).style(Color::from_rgb(1., 0.0, 0.0)),
text(self.answer_value.as_str()).style(Color::from_rgb(1., 0.0, 0.0)),
].width(Length::Fill).align_items(Alignment::Center).padding(20)
.into()
}
}
Now everything is tested in snapstore and with local paths. Should work now ok. If you want to download it in zip it is here: https://hrubos.org/repo/autoskola4_and_snap.zip