Path: blob/main/examples/app/persisting_preferences.rs
30632 views
//! Demonstrates persistence of user preferences.1//!2//! A counter is shown in the window. It can be incremented and decremented via input press.3//! Its value persists between app sessions via user preferences.4//!5//! On desktop, if you quit the app and then restart it, the counter value should display6//! the most recent value the app had before exiting.7//! On web, if you navigate away and then come back to the window, the counter8//! should display the most recent value the app had before navigating away.9use std::time::Duration;1011use bevy::{12prelude::*,13settings::{14PreferencesPlugin, ReflectSettingsGroup, SavePreferencesDeferred, SavePreferencesSync,15SettingsGroup,16},17window::{ExitCondition, WindowCloseRequested},18};1920fn main() {21App::new()22.add_plugins(DefaultPlugins.set(WindowPlugin {23// We want to intercept the exit so that we can save prefs.24exit_condition: ExitCondition::DontExit,25primary_window: Some(Window {26title: "Prefs Counter".into(),27..default()28}),29..default()30}))31.add_plugins(PreferencesPlugin::new(32"org.bevy.examples.persisting_preferences",33))34.add_systems(Startup, setup)35.add_systems(Update, (show_count, change_count, on_window_close))36.run();37}3839#[derive(Resource, SettingsGroup, Reflect, Default)]40#[reflect(Resource, SettingsGroup, Default)]41struct Counter {42count: i32,43}4445/// A different settings group which has the name group name as the previous. The two groups will be46/// merged into a single section in the config file.47#[derive(Resource, SettingsGroup, Reflect, Default)]48#[reflect(Resource, SettingsGroup, Default)]49#[settings_group(group = "counter")]50#[expect(51dead_code,52reason = "Example showing additional settings in the same group"53)]54struct OtherSettings {55enabled: bool,56}5758#[derive(Component)]59struct CounterDisplay;6061fn setup(mut commands: Commands) {62commands.spawn((Camera::default(), Camera2d));63commands64.spawn(Node {65width: percent(100),66height: percent(100),67display: Display::Flex,68flex_direction: FlexDirection::Column,69align_items: AlignItems::Center,70justify_content: JustifyContent::Center,71..default()72})73.with_children(|parent| {74parent.spawn((75Text::new("---"),76TextFont {77font_size: FontSize::Px(33.0),78..default()79},80CounterDisplay,81TextColor(Color::srgb(0.9, 0.9, 0.9)),82));83parent.spawn((84Text::new("Press SPACE to increment, BACKSPACE to decrement."),85TextFont {86font_size: FontSize::Px(20.0),87..default()88},89));90});91}9293fn show_count(mut query: Query<&mut Text, With<CounterDisplay>>, counter: Res<Counter>) {94if counter.is_changed() {95for mut text in query.iter_mut() {96text.0 = format!("Count: {}", counter.count);97}98}99}100101fn change_count(102mut counter: ResMut<Counter>,103keyboard: Res<ButtonInput<KeyCode>>,104mut commands: Commands,105) {106let mut changed = false;107if keyboard.just_pressed(KeyCode::Space) {108counter.count += 1;109changed = true;110}111if keyboard.just_pressed(KeyCode::Backspace) || keyboard.just_pressed(KeyCode::Delete) {112counter.count -= 1;113changed = true;114}115116if changed {117commands.queue(SavePreferencesDeferred(Duration::from_secs_f32(0.1)));118}119}120121fn on_window_close(mut close: MessageReader<WindowCloseRequested>, mut commands: Commands) {122// Save preferences immediately, then quit.123if let Some(_close_event) = close.read().next() {124commands.queue(SavePreferencesSync::IfChanged);125commands.queue(ExitAfterSave);126}127}128129struct ExitAfterSave;130131impl Command for ExitAfterSave {132type Out = ();133134fn apply(self, world: &mut World) {135world.write_message(AppExit::Success);136}137}138139140