add rust to GUI launcher

This commit is contained in:
ALEZ-DEV 2024-05-16 21:42:07 +02:00
parent 6a34cb7126
commit 5c52ddb586
13 changed files with 200 additions and 7 deletions

View File

@ -46,4 +46,11 @@ app.*.map.json
/linux
# Misc
/test
/test
# Rust related
.cargo/
target/
# Generated messages
*/**/messages/

View File

@ -0,0 +1,8 @@
# This file is used for telling Rust-related tools
# where various Rust crates are.
# This also unifies `./target` output folder and
# various Rust configurations.
[workspace]
members = ["./native/*"]
resolver = "2"

View File

@ -0,0 +1,44 @@
## Using Rust Inside Flutter
This project leverages Flutter for GUI and Rust for the backend logic,
utilizing the capabilities of the
[Rinf](https://pub.dev/packages/rinf) framework.
To run and build this app, you need to have
[Flutter SDK](https://docs.flutter.dev/get-started/install)
and [Rust toolchain](https://www.rust-lang.org/tools/install)
installed on your system.
You can check that your system is ready with the commands below.
Note that all the Flutter subcomponents should be installed.
```bash
rustc --version
flutter doctor
```
You also need to have the CLI tool for Rinf ready.
```bash
cargo install rinf
```
Messages sent between Dart and Rust are implemented using Protobuf.
If you have newly cloned the project repository
or made changes to the `.proto` files in the `./messages` directory,
run the following command:
```bash
rinf message
```
Now you can run and build this app just like any other Flutter projects.
```bash
flutter run
```
For detailed instructions on writing Rust and Flutter together,
please refer to Rinf's [documentation](https://rinf.cunarist.com).

View File

@ -4,15 +4,22 @@ import 'package:yaru/yaru.dart';
import './screens/screens.dart';
import './providers/settings_provider.dart';
import './providers/providers.dart';
class BabyloniaLauncher extends StatelessWidget {
const BabyloniaLauncher({super.key});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => SettingsProvider(),
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => SettingsProvider(),
),
ChangeNotifierProvider(
create: (context) => GameStateProvider(),
),
],
child: YaruTheme(
builder: (context, yaru, child) => MaterialApp(
title: "Babylonia Terminal",

View File

@ -3,8 +3,10 @@ import 'package:flutter/widgets.dart';
import 'package:media_kit/media_kit.dart';
import './app.dart';
import './messages/generated.dart';
void main() {
void main() async {
await initializeRust();
WidgetsFlutterBinding.ensureInitialized();
MediaKit.ensureInitialized();
runApp(const BabyloniaLauncher());

View File

@ -0,0 +1,21 @@
import 'package:babylonia_terminal_launcher/messages/game_state.pb.dart';
import 'package:flutter/material.dart';
class GameStateProvider with ChangeNotifier {
States? _gameState = null;
bool isUpdating = false;
Future updateGameState() async {
if (!isUpdating) {
isUpdating = true;
AskGameState().sendSignalToRust();
final stream = GameState.rustSignalStream;
await for (final rustSignal in stream) {
_gameState = rustSignal.message.state;
break;
}
isUpdating = false;
}
}
}

View File

@ -0,0 +1,2 @@
export './settings_provider.dart';
export './game_state_provider.dart';

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import './../widgets/background.dart';
import './../providers/settings_provider.dart';
import './../providers/providers.dart';
import './../models/settings.dart';
class HomeScreen extends StatelessWidget {
@ -62,7 +62,11 @@ class HomeScreen extends StatelessWidget {
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue[500],
),
onPressed: () {},
onPressed: () async {
Provider.of<GameStateProvider>(context,
listen: false)
.updateGameState();
},
child: const Center(
child: Text("Download"),
),

View File

@ -0,0 +1,21 @@
syntax = "proto3";
package game_state;
enum States {
ProtonNotInstalled = 0;
DXVKNotInstalled = 1;
FontNotInstalled = 2;
DependecieNotInstalled = 3;
GameNotInstalled = 4;
GameNeedUpdate = 5;
GameNotPatched = 6;
GameInstalled = 7;
}
// [RINF:RUST-SIGNAL]
message GameState {
States state = 1;
}
// [RINF:DART-SIGNAL]
message AskGameState {}

View File

@ -0,0 +1,19 @@
[package]
# Do not change the name of this crate.
name = "hub"
version = "0.1.0"
edition = "2021"
[lib]
# `lib` is required for non-library targets,
# such as tests and benchmarks.
# `cdylib` is for Linux, Android, Windows, and web.
# `staticlib` is for iOS and macOS.
crate-type = ["lib", "cdylib", "staticlib"]
[dependencies]
rinf = "6.9.0"
prost = "0.12.3"
wasm-bindgen = "0.2.91"
tokio_with_wasm = "0.4.3"
babylonia-terminal-sdk = { path = "./../../../babylonia-terminal-sdk" }

View File

@ -0,0 +1,31 @@
use babylonia_terminal_sdk::game_state::GameState;
use crate::messages::game_state::{AskGameState, GameState as GameStateMessage, States};
impl GameStateMessage {
fn from_sdk_state_to_msg_state(state: GameState) -> Self {
let game_state = match state {
GameState::ProtonNotInstalled => States::ProtonNotInstalled,
GameState::DXVKNotInstalled => States::DxvkNotInstalled,
GameState::FontNotInstalled => States::FontNotInstalled,
GameState::DependecieNotInstalled => States::DependecieNotInstalled,
GameState::GameNotInstalled => States::GameNotInstalled,
GameState::GameNeedUpdate => States::GameNeedUpdate,
GameState::GameNotPatched => States::GameNotPatched,
GameState::GameInstalled => States::GameInstalled,
};
GameStateMessage {
state: game_state.into(),
}
}
}
pub async fn get_game_state() {
let mut receiver = AskGameState::get_dart_signal_receiver();
while let Some(_) = receiver.recv().await {
let result_state = GameState::get_current_state().await;
if let Ok(state) = result_state {
GameStateMessage::from_sdk_state_to_msg_state(state).send_signal_to_dart();
}
}
}

View File

@ -0,0 +1,25 @@
//! This `hub` crate is the
//! entry point of the Rust logic.
// This `tokio` will be used by Rinf.
// You can replace it with the original `tokio`
// if you're not targeting the web.
use tokio_with_wasm::tokio;
mod game_state;
mod messages;
rinf::write_interface!();
// Always use non-blocking async functions
// such as `tokio::fs::File::open`.
// If you really need to use blocking code,
// use `tokio::task::spawn_blocking`.
async fn main() {
// Repeat `tokio::spawn` anywhere in your code
// if more concurrent tasks are needed.
//tokio::spawn(sample_functions::tell_numbers());
//tokio::spawn(sample_functions::stream_fractal());
//tokio::spawn(sample_functions::run_debug_tests());
tokio::spawn(game_state::get_game_state());
}

View File

@ -44,6 +44,8 @@ dependencies:
media_kit_libs_video: any
media_kit_native_event_loop: any
provider: ^6.1.2
rinf: ^6.9.0
protobuf: ^3.1.0
dependency_overrides:
media_kit: