ui: setup buttons style, add server loading progress for node and metrics, optimize node status
This commit is contained in:
parent
532a79fc47
commit
ffc68bc6ae
14 changed files with 203 additions and 135 deletions
|
@ -5,6 +5,7 @@ import android.os.Bundle;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.OrientationEventListener;
|
import android.view.OrientationEventListener;
|
||||||
import com.google.androidgamesdk.GameActivity;
|
import com.google.androidgamesdk.GameActivity;
|
||||||
|
@ -29,7 +30,7 @@ public class MainActivity extends GameActivity {
|
||||||
|
|
||||||
// Callback to update display cutouts at native code.
|
// Callback to update display cutouts at native code.
|
||||||
OrientationEventListener orientationEventListener = new OrientationEventListener(this,
|
OrientationEventListener orientationEventListener = new OrientationEventListener(this,
|
||||||
SensorManager.SENSOR_DELAY_GAME) {
|
SensorManager.SENSOR_DELAY_FASTEST) {
|
||||||
@Override
|
@Override
|
||||||
public void onOrientationChanged(int orientation) {
|
public void onOrientationChanged(int orientation) {
|
||||||
onDisplayCutoutsChanged(Utils.getDisplayCutouts(MainActivity.this));
|
onDisplayCutoutsChanged(Utils.getDisplayCutouts(MainActivity.this));
|
||||||
|
@ -82,6 +83,7 @@ public class MainActivity extends GameActivity {
|
||||||
|
|
||||||
// Called from native code
|
// Called from native code
|
||||||
public void onExit() {
|
public void onExit() {
|
||||||
|
Log.d("12345", "onExit");
|
||||||
mManualExit = true;
|
mManualExit = true;
|
||||||
BackgroundService.stop(this);
|
BackgroundService.stop(this);
|
||||||
finish();
|
finish();
|
||||||
|
|
|
@ -5,6 +5,9 @@ network:
|
||||||
metrics: Metrics
|
metrics: Metrics
|
||||||
mining: Mining
|
mining: Mining
|
||||||
settings: Server settings
|
settings: Server settings
|
||||||
|
enable: Enable
|
||||||
|
disable: Disable
|
||||||
|
restart: Restart
|
||||||
sync_status:
|
sync_status:
|
||||||
server_restarting: Server is restarting
|
server_restarting: Server is restarting
|
||||||
server_down: Server is down
|
server_down: Server is down
|
||||||
|
@ -36,6 +39,7 @@ network_node:
|
||||||
size: Size (GB)
|
size: Size (GB)
|
||||||
peers: Peers
|
peers: Peers
|
||||||
network_metrics:
|
network_metrics:
|
||||||
|
loading: Metrics will be available after the synchronization
|
||||||
emission: Emission
|
emission: Emission
|
||||||
inflation: Inflation
|
inflation: Inflation
|
||||||
supply: Supply
|
supply: Supply
|
||||||
|
|
|
@ -5,6 +5,9 @@ network:
|
||||||
metrics: Метрики
|
metrics: Метрики
|
||||||
mining: Майнинг
|
mining: Майнинг
|
||||||
settings: Настройки сервера
|
settings: Настройки сервера
|
||||||
|
enable: Включить
|
||||||
|
disable: Выключить
|
||||||
|
restart: Перезапустить
|
||||||
sync_status:
|
sync_status:
|
||||||
server_restarting: Сервер перезапускается
|
server_restarting: Сервер перезапускается
|
||||||
server_down: Сервер выключен
|
server_down: Сервер выключен
|
||||||
|
@ -36,6 +39,7 @@ network_node:
|
||||||
size: Размер (ГБ)
|
size: Размер (ГБ)
|
||||||
peers: Пиры
|
peers: Пиры
|
||||||
network_metrics:
|
network_metrics:
|
||||||
|
loading: Метрики будут доступны после синхронизации
|
||||||
emission: Эмиссия
|
emission: Эмиссия
|
||||||
inflation: Инфляция
|
inflation: Инфляция
|
||||||
supply: Предложение
|
supply: Предложение
|
||||||
|
|
|
@ -12,15 +12,15 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use egui::{Context, Stroke, Widget};
|
use egui::{Color32, Context, RichText, Spinner, Stroke, Widget};
|
||||||
use egui::os::OperatingSystem;
|
use egui::os::OperatingSystem;
|
||||||
use egui::style::Margin;
|
use egui::style::Margin;
|
||||||
|
|
||||||
use crate::gui::colors::COLOR_LIGHT;
|
use crate::gui::colors::{COLOR_DARK, COLOR_LIGHT, COLOR_YELLOW};
|
||||||
use crate::gui::Navigator;
|
use crate::gui::Navigator;
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::screens::Root;
|
use crate::gui::screens::Root;
|
||||||
use crate::gui::views::{Modal, ModalId, ModalLocation, ProgressLoading, View};
|
use crate::gui::views::{Modal, ModalId, ModalLocation, View};
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
|
|
||||||
pub struct PlatformApp<Platform> {
|
pub struct PlatformApp<Platform> {
|
||||||
|
@ -36,18 +36,17 @@ pub struct App {
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn ui(&mut self, ctx: &Context, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) {
|
pub fn ui(&mut self, ctx: &Context, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) {
|
||||||
let modal_open = Navigator::is_modal_open(ModalLocation::Global);
|
|
||||||
egui::CentralPanel::default()
|
egui::CentralPanel::default()
|
||||||
.frame(egui::Frame {
|
.frame(egui::Frame {
|
||||||
fill: COLOR_LIGHT,
|
fill: COLOR_LIGHT,
|
||||||
.. Default::default()
|
.. Default::default()
|
||||||
})
|
})
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
if modal_open {
|
if Navigator::is_modal_open(ModalLocation::Global) {
|
||||||
self.show_global_modal(ui, frame, cb);
|
self.show_global_modal(ui, frame, cb);
|
||||||
}
|
}
|
||||||
self.root.ui(ui, frame, cb);
|
self.root.ui(ui, frame, cb);
|
||||||
}).response.enabled = !modal_open;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_global_modal(&mut self,
|
fn show_global_modal(&mut self,
|
||||||
|
@ -60,12 +59,18 @@ impl App {
|
||||||
ModalId::Exit => {
|
ModalId::Exit => {
|
||||||
if self.show_exit_progress {
|
if self.show_exit_progress {
|
||||||
if !Node::is_running() {
|
if !Node::is_running() {
|
||||||
modal.close();
|
|
||||||
Self::exit(frame, cb);
|
Self::exit(frame, cb);
|
||||||
|
modal.close();
|
||||||
}
|
}
|
||||||
ui.add_space(12.0);
|
ui.add_space(16.0);
|
||||||
let text = Node::get_sync_status_text(Node::get_sync_status());
|
ui.vertical_centered(|ui| {
|
||||||
ProgressLoading::new(text).ui(ui);
|
Spinner::new().size(42.0).color(COLOR_YELLOW).ui(ui);
|
||||||
|
ui.add_space(10.0);
|
||||||
|
ui.label(RichText::new(Node::get_sync_status_text())
|
||||||
|
.size(18.0)
|
||||||
|
.color(COLOR_DARK)
|
||||||
|
);
|
||||||
|
});
|
||||||
ui.add_space(12.0);
|
ui.add_space(12.0);
|
||||||
} else {
|
} else {
|
||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
|
@ -77,19 +82,19 @@ impl App {
|
||||||
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
|
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
|
||||||
ui.columns(2, |columns| {
|
ui.columns(2, |columns| {
|
||||||
columns[0].vertical_centered_justified(|ui| {
|
columns[0].vertical_centered_justified(|ui| {
|
||||||
View::modal_button(ui, t!("modal_exit.exit"), || {
|
View::button(ui, t!("modal_exit.exit"), Color32::WHITE, || {
|
||||||
if !Node::is_running() {
|
if !Node::is_running() {
|
||||||
Self::exit(frame, cb);
|
Self::exit(frame, cb);
|
||||||
modal.close();
|
modal.close();
|
||||||
} else {
|
} else {
|
||||||
modal.disable_closing();
|
|
||||||
Node::stop();
|
Node::stop();
|
||||||
|
modal.disable_closing();
|
||||||
self.show_exit_progress = true;
|
self.show_exit_progress = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
columns[1].vertical_centered_justified(|ui| {
|
columns[1].vertical_centered_justified(|ui| {
|
||||||
View::modal_button(ui, t!("modal.cancel"), || {
|
View::button(ui, t!("modal.cancel"), Color32::WHITE, || {
|
||||||
modal.close();
|
modal.close();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -96,11 +96,13 @@ impl PlatformApp<Android> {
|
||||||
fn setup_visuals(ctx: &egui::Context) {
|
fn setup_visuals(ctx: &egui::Context) {
|
||||||
// Setup style
|
// Setup style
|
||||||
let mut style = (*ctx.style()).clone();
|
let mut style = (*ctx.style()).clone();
|
||||||
|
// Setup spacing for buttons.
|
||||||
// Make scroll-bar thinner
|
style.spacing.button_padding = egui::vec2(12.0, 8.0);
|
||||||
|
// Make scroll-bar thinner.
|
||||||
style.spacing.scroll_bar_width = 4.0;
|
style.spacing.scroll_bar_width = 4.0;
|
||||||
//
|
// Disable spacing between items.
|
||||||
style.spacing.item_spacing = egui::vec2(0.0, 0.0);
|
style.spacing.item_spacing = egui::vec2(0.0, 0.0);
|
||||||
|
|
||||||
ctx.set_style(style);
|
ctx.set_style(style);
|
||||||
|
|
||||||
// Setup visuals
|
// Setup visuals
|
||||||
|
@ -183,7 +185,7 @@ fn padding_panels(ctx: &egui::Context) {
|
||||||
.show_separator_line(false)
|
.show_separator_line(false)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.exact_height(DISPLAY_CUTOUT_TOP.load(Ordering::Relaxed) as f32)
|
.exact_height(DISPLAY_CUTOUT_TOP.load(Ordering::Relaxed) as f32)
|
||||||
.show(ctx, |ui| {});
|
.show(ctx, |_ui| {});
|
||||||
|
|
||||||
egui::TopBottomPanel::bottom("bottom_padding_panel")
|
egui::TopBottomPanel::bottom("bottom_padding_panel")
|
||||||
.frame(egui::Frame {
|
.frame(egui::Frame {
|
||||||
|
@ -194,7 +196,7 @@ fn padding_panels(ctx: &egui::Context) {
|
||||||
.show_separator_line(false)
|
.show_separator_line(false)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.exact_height(DISPLAY_CUTOUT_BOTTOM.load(Ordering::Relaxed) as f32)
|
.exact_height(DISPLAY_CUTOUT_BOTTOM.load(Ordering::Relaxed) as f32)
|
||||||
.show(ctx, |ui| {});
|
.show(ctx, |_ui| {});
|
||||||
|
|
||||||
egui::SidePanel::right("right_padding_panel")
|
egui::SidePanel::right("right_padding_panel")
|
||||||
.frame(egui::Frame {
|
.frame(egui::Frame {
|
||||||
|
@ -205,7 +207,7 @@ fn padding_panels(ctx: &egui::Context) {
|
||||||
.show_separator_line(false)
|
.show_separator_line(false)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.max_width(DISPLAY_CUTOUT_RIGHT.load(Ordering::Relaxed) as f32)
|
.max_width(DISPLAY_CUTOUT_RIGHT.load(Ordering::Relaxed) as f32)
|
||||||
.show(ctx, |ui| {});
|
.show(ctx, |_ui| {});
|
||||||
|
|
||||||
egui::SidePanel::left("left_padding_panel")
|
egui::SidePanel::left("left_padding_panel")
|
||||||
.frame(egui::Frame {
|
.frame(egui::Frame {
|
||||||
|
@ -216,7 +218,7 @@ fn padding_panels(ctx: &egui::Context) {
|
||||||
.show_separator_line(false)
|
.show_separator_line(false)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.max_width(DISPLAY_CUTOUT_LEFT.load(Ordering::Relaxed) as f32)
|
.max_width(DISPLAY_CUTOUT_LEFT.load(Ordering::Relaxed) as f32)
|
||||||
.show(ctx, |ui| {});
|
.show(ctx, |_ui| {});
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
|
|
@ -22,14 +22,12 @@ mod modal;
|
||||||
pub use modal::*;
|
pub use modal::*;
|
||||||
|
|
||||||
mod network;
|
mod network;
|
||||||
|
pub use network::Network;
|
||||||
|
|
||||||
mod network_node;
|
mod network_node;
|
||||||
mod network_settings;
|
mod network_settings;
|
||||||
mod network_metrics;
|
mod network_metrics;
|
||||||
mod network_mining;
|
mod network_mining;
|
||||||
pub use network::Network;
|
|
||||||
|
|
||||||
mod progress_loading;
|
|
||||||
pub use progress_loading::ProgressLoading;
|
|
||||||
|
|
||||||
pub trait NetworkTab {
|
pub trait NetworkTab {
|
||||||
fn name(&self) -> &String;
|
fn name(&self) -> &String;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use egui::{Align2, Color32, RichText, Rounding, Sense, Stroke, Vec2};
|
use egui::{Align2, Color32, RichText, Rounding, Sense, Separator, Stroke, Vec2, Widget};
|
||||||
use egui::epaint::RectShape;
|
use egui::epaint::RectShape;
|
||||||
use egui::style::Margin;
|
use egui::style::Margin;
|
||||||
use egui_extras::{Size, StripBuilder};
|
use egui_extras::{Size, StripBuilder};
|
||||||
|
@ -29,7 +29,6 @@ pub enum ModalId {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Location for [`Modal`] at application UI.
|
/// Location for [`Modal`] at application UI.
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum ModalLocation {
|
pub enum ModalLocation {
|
||||||
/// To draw globally above side panel and screen.
|
/// To draw globally above side panel and screen.
|
||||||
Global,
|
Global,
|
||||||
|
@ -204,7 +203,7 @@ impl Modal {
|
||||||
rect,
|
rect,
|
||||||
rounding,
|
rounding,
|
||||||
fill: COLOR_LIGHT,
|
fill: COLOR_LIGHT,
|
||||||
stroke: View::DEFAULT_STROKE,
|
stroke: Stroke::NONE,
|
||||||
};
|
};
|
||||||
let bg_idx = ui.painter().add(bg_shape);
|
let bg_idx = ui.painter().add(bg_shape);
|
||||||
|
|
||||||
|
@ -250,5 +249,11 @@ impl Modal {
|
||||||
// Setup background shape to be painted behind title content.
|
// Setup background shape to be painted behind title content.
|
||||||
bg_shape.rect = title_resp.rect;
|
bg_shape.rect = title_resp.rect;
|
||||||
ui.painter().set(bg_idx, bg_shape);
|
ui.painter().set(bg_idx, bg_shape);
|
||||||
|
|
||||||
|
let (rect, _) = ui.allocate_exact_size(Vec2::new(ui.available_width(), 1.0),Sense::hover());
|
||||||
|
let painter = ui.painter();
|
||||||
|
painter.hline(rect.x_range(),
|
||||||
|
painter.round_to_pixel(rect.center().y),
|
||||||
|
View::DEFAULT_STROKE);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,8 +20,8 @@ use egui_extras::{Size, StripBuilder};
|
||||||
use grin_chain::SyncStatus;
|
use grin_chain::SyncStatus;
|
||||||
use grin_core::global::ChainTypes;
|
use grin_core::global::ChainTypes;
|
||||||
|
|
||||||
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY_DARK, COLOR_YELLOW};
|
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_GRAY_DARK, COLOR_YELLOW};
|
||||||
use crate::gui::icons::{CARDHOLDER, DATABASE, DOTS_THREE_OUTLINE_VERTICAL, FACTORY, FADERS, GAUGE};
|
use crate::gui::icons::{CARDHOLDER, DATABASE, DOTS_THREE_OUTLINE_VERTICAL, FACTORY, FADERS, GAUGE, PLUGS, POWER};
|
||||||
use crate::gui::Navigator;
|
use crate::gui::Navigator;
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::views::{NetworkTab, View};
|
use crate::gui::views::{NetworkTab, View};
|
||||||
|
@ -71,7 +71,7 @@ impl Network {
|
||||||
|
|
||||||
egui::TopBottomPanel::bottom("network_tabs")
|
egui::TopBottomPanel::bottom("network_tabs")
|
||||||
.frame(egui::Frame {
|
.frame(egui::Frame {
|
||||||
outer_margin: Margin::same(6.0),
|
outer_margin: Margin::same(5.0),
|
||||||
.. Default::default()
|
.. Default::default()
|
||||||
})
|
})
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
|
@ -93,26 +93,28 @@ impl Network {
|
||||||
|
|
||||||
fn draw_tabs(&mut self, ui: &mut egui::Ui) {
|
fn draw_tabs(&mut self, ui: &mut egui::Ui) {
|
||||||
ui.scope(|ui| {
|
ui.scope(|ui| {
|
||||||
//Setup spacing between tabs
|
// Setup spacing between tabs.
|
||||||
ui.style_mut().spacing.item_spacing = egui::vec2(6.0, 0.0);
|
ui.style_mut().spacing.item_spacing = egui::vec2(5.0, 0.0);
|
||||||
|
// Setup vertical padding inside tab button.
|
||||||
|
ui.style_mut().spacing.button_padding = egui::vec2(0.0, 3.0);
|
||||||
|
|
||||||
ui.columns(4, |columns| {
|
ui.columns(4, |columns| {
|
||||||
columns[0].vertical_centered(|ui| {
|
columns[0].vertical_centered_justified(|ui| {
|
||||||
View::tab_button(ui, DATABASE, self.current_mode == Mode::Node, || {
|
View::tab_button(ui, DATABASE, self.current_mode == Mode::Node, || {
|
||||||
self.current_mode = Mode::Node;
|
self.current_mode = Mode::Node;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
columns[1].vertical_centered(|ui| {
|
columns[1].vertical_centered_justified(|ui| {
|
||||||
View::tab_button(ui, GAUGE, self.current_mode == Mode::Metrics, || {
|
View::tab_button(ui, GAUGE, self.current_mode == Mode::Metrics, || {
|
||||||
self.current_mode = Mode::Metrics;
|
self.current_mode = Mode::Metrics;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
columns[2].vertical_centered(|ui| {
|
columns[2].vertical_centered_justified(|ui| {
|
||||||
View::tab_button(ui, FACTORY, self.current_mode == Mode::Miner, || {
|
View::tab_button(ui, FACTORY, self.current_mode == Mode::Miner, || {
|
||||||
self.current_mode = Mode::Miner;
|
self.current_mode = Mode::Miner;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
columns[3].vertical_centered(|ui| {
|
columns[3].vertical_centered_justified(|ui| {
|
||||||
View::tab_button(ui, FADERS, self.current_mode == Mode::Tuning, || {
|
View::tab_button(ui, FADERS, self.current_mode == Mode::Tuning, || {
|
||||||
self.current_mode = Mode::Tuning;
|
self.current_mode = Mode::Tuning;
|
||||||
});
|
});
|
||||||
|
@ -200,9 +202,7 @@ impl Network {
|
||||||
});
|
});
|
||||||
strip.cell(|ui| {
|
strip.cell(|ui| {
|
||||||
ui.centered_and_justified(|ui| {
|
ui.centered_and_justified(|ui| {
|
||||||
// Select sync status text
|
|
||||||
let sync_status = Node::get_sync_status();
|
let sync_status = Node::get_sync_status();
|
||||||
let status_text = Node::get_sync_status_text(sync_status);
|
|
||||||
|
|
||||||
// Setup text color animation based on sync status
|
// Setup text color animation based on sync status
|
||||||
let idle = match sync_status {
|
let idle = match sync_status {
|
||||||
|
@ -219,7 +219,7 @@ impl Network {
|
||||||
// Draw sync text
|
// Draw sync text
|
||||||
let status_color_rgba = Rgba::from(COLOR_GRAY_DARK) * color_factor as f32;
|
let status_color_rgba = Rgba::from(COLOR_GRAY_DARK) * color_factor as f32;
|
||||||
let status_color = Color32::from(status_color_rgba);
|
let status_color = Color32::from(status_color_rgba);
|
||||||
View::ellipsize_text(ui, status_text, 15.0, status_color);
|
View::ellipsize_text(ui, Node::get_sync_status_text(), 15.0, status_color);
|
||||||
|
|
||||||
// Repaint based on sync status
|
// Repaint based on sync status
|
||||||
if idle {
|
if idle {
|
||||||
|
@ -231,5 +231,23 @@ impl Network {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn server_off_content(ui: &mut egui::Ui) {
|
||||||
|
View::center_content(ui, [240.0, 214.0], |ui| {
|
||||||
|
ui.label(RichText::new(PLUGS)
|
||||||
|
.size(84.0)
|
||||||
|
.color(Color32::from_gray(200))
|
||||||
|
);
|
||||||
|
ui.add_space(-16.0);
|
||||||
|
ui.label(RichText::new(Node::get_sync_status_text())
|
||||||
|
.size(19.0)
|
||||||
|
.color(Color32::from_gray(150))
|
||||||
|
);
|
||||||
|
ui.add_space(12.0);
|
||||||
|
View::button(ui, format!("{} {}", POWER, t!("network.enable")), COLOR_YELLOW, || {
|
||||||
|
Node::start(ChainTypes::Mainnet);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,12 @@
|
||||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
use eframe::epaint::{Color32, Rounding, Stroke};
|
use eframe::epaint::{Color32, Rounding, Stroke};
|
||||||
use egui::{RichText, ScrollArea, Spinner, Widget};
|
use egui::{RichText, ScrollArea, Spinner, Widget};
|
||||||
|
use grin_core::global::ChainTypes;
|
||||||
use grin_servers::DiffBlock;
|
use grin_servers::DiffBlock;
|
||||||
|
|
||||||
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_GRAY_LIGHT};
|
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_GRAY_LIGHT, COLOR_YELLOW};
|
||||||
use crate::gui::icons::{AT, COINS, CUBE_TRANSPARENT, HASH, HOURGLASS_LOW, HOURGLASS_MEDIUM, TIMER};
|
use crate::gui::icons::{AT, COINS, CUBE_TRANSPARENT, HASH, HOURGLASS_LOW, HOURGLASS_MEDIUM, PLUGS, POWER, TIMER};
|
||||||
use crate::gui::views::{NetworkTab, View};
|
use crate::gui::views::{Network, NetworkTab, View};
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
|
|
||||||
pub struct NetworkMetrics {
|
pub struct NetworkMetrics {
|
||||||
|
@ -45,11 +46,19 @@ impl NetworkTab for NetworkMetrics {
|
||||||
|
|
||||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
let server_stats = Node::get_stats();
|
let server_stats = Node::get_stats();
|
||||||
// Show loading widget if server is not working or difficulty height is zero.
|
if server_stats.is_none() || server_stats.as_ref().unwrap().diff_stats.height == 0 {
|
||||||
if !server_stats.is_some() || server_stats.as_ref().unwrap().diff_stats.height == 0 {
|
if !Node::is_running() {
|
||||||
ui.centered_and_justified(|ui| {
|
Network::server_off_content(ui);
|
||||||
Spinner::new().size(42.0).color(COLOR_GRAY).ui(ui);
|
} else {
|
||||||
});
|
View::center_content(ui, [280.0, 160.0], |ui| {
|
||||||
|
Spinner::new().size(104.0).color(COLOR_YELLOW).ui(ui);
|
||||||
|
ui.add_space(18.0);
|
||||||
|
ui.label(RichText::new(t!("network_metrics.loading"))
|
||||||
|
.size(16.0)
|
||||||
|
.color(Color32::from_gray(150))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,3 +11,28 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use egui::Ui;
|
||||||
|
use crate::gui::views::NetworkTab;
|
||||||
|
|
||||||
|
pub struct NetworkMining {
|
||||||
|
title: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for NetworkMining {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
title: t!("network.mining").to_uppercase(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NetworkTab for NetworkMining {
|
||||||
|
fn name(&self) -> &String {
|
||||||
|
&self.title
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ui(&mut self, ui: &mut Ui) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,11 +14,13 @@
|
||||||
|
|
||||||
use eframe::epaint::Stroke;
|
use eframe::epaint::Stroke;
|
||||||
use egui::{Color32, RichText, Rounding, ScrollArea, Spinner, Widget};
|
use egui::{Color32, RichText, Rounding, ScrollArea, Spinner, Widget};
|
||||||
|
use egui_extras::{Size, StripBuilder};
|
||||||
|
use grin_core::global::ChainTypes;
|
||||||
use grin_servers::PeerStats;
|
use grin_servers::PeerStats;
|
||||||
|
|
||||||
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_GRAY_LIGHT};
|
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_GRAY_LIGHT, COLOR_YELLOW};
|
||||||
use crate::gui::icons::{AT, CUBE, DEVICES, FLOW_ARROW, HANDSHAKE, PACKAGE, PLUGS_CONNECTED, SHARE_NETWORK};
|
use crate::gui::icons::{AT, CUBE, DEVICES, FLOW_ARROW, HANDSHAKE, PACKAGE, PLUGS, PLUGS_CONNECTED, POWER, SHARE_NETWORK};
|
||||||
use crate::gui::views::{NetworkTab, View};
|
use crate::gui::views::{Network, NetworkTab, View};
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
|
|
||||||
pub struct NetworkNode {
|
pub struct NetworkNode {
|
||||||
|
@ -41,9 +43,13 @@ impl NetworkTab for NetworkNode {
|
||||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
let server_stats = Node::get_stats();
|
let server_stats = Node::get_stats();
|
||||||
if !server_stats.is_some() {
|
if !server_stats.is_some() {
|
||||||
ui.centered_and_justified(|ui| {
|
if !Node::is_running() {
|
||||||
Spinner::new().size(42.0).color(COLOR_GRAY).ui(ui);
|
Network::server_off_content(ui);
|
||||||
});
|
} else {
|
||||||
|
ui.centered_and_justified(|ui| {
|
||||||
|
Spinner::new().size(104.0).color(COLOR_YELLOW).ui(ui);
|
||||||
|
});
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
// Copyright 2023 The Grim Developers
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use egui::{Response, RichText, Spinner, Ui, Widget};
|
|
||||||
|
|
||||||
use crate::gui::colors::COLOR_DARK;
|
|
||||||
|
|
||||||
pub struct ProgressLoading {
|
|
||||||
text: String
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProgressLoading {
|
|
||||||
pub fn new(text: String) -> Self {
|
|
||||||
Self {
|
|
||||||
text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Widget for ProgressLoading {
|
|
||||||
fn ui(self, ui: &mut Ui) -> Response {
|
|
||||||
ui.vertical_centered_justified(|ui| {
|
|
||||||
ui.add_space(10.0);
|
|
||||||
Spinner::new().size(36.0).color(COLOR_DARK).ui(ui);
|
|
||||||
ui.add_space(10.0);
|
|
||||||
ui.label(RichText::new(self.text).size(18.0).color(COLOR_DARK));
|
|
||||||
}).response
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,10 +14,11 @@
|
||||||
|
|
||||||
use egui::epaint::{Color32, FontId, Rounding, Stroke};
|
use egui::epaint::{Color32, FontId, Rounding, Stroke};
|
||||||
use egui::text::{LayoutJob, TextFormat};
|
use egui::text::{LayoutJob, TextFormat};
|
||||||
use egui::{Button, PointerState, Response, RichText, Sense, Widget};
|
use egui::{Button, PointerState, Response, RichText, Sense, Vec2, Widget};
|
||||||
use egui::epaint::text::TextWrapping;
|
use egui::epaint::text::TextWrapping;
|
||||||
|
use egui_extras::{Size, StripBuilder};
|
||||||
|
|
||||||
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_LIGHT, COLOR_GRAY_LIGHT, COLOR_GRAY_DARK};
|
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_LIGHT, COLOR_GRAY_LIGHT, COLOR_GRAY_DARK, COLOR_YELLOW};
|
||||||
|
|
||||||
pub struct View;
|
pub struct View;
|
||||||
|
|
||||||
|
@ -103,7 +104,6 @@ impl View {
|
||||||
false => { Color32::WHITE }
|
false => { Color32::WHITE }
|
||||||
};
|
};
|
||||||
let br = Button::new(wt)
|
let br = Button::new(wt)
|
||||||
.min_size(ui.available_size_before_wrap())
|
|
||||||
.stroke(stroke)
|
.stroke(stroke)
|
||||||
.fill(color)
|
.fill(color)
|
||||||
.ui(ui).interact(Sense::click_and_drag());
|
.ui(ui).interact(Sense::click_and_drag());
|
||||||
|
@ -111,16 +111,12 @@ impl View {
|
||||||
Self::on_button_click(ui, br, action);
|
Self::on_button_click(ui, br, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modal button with white background fill color, contains text.
|
/// Draw [`Button`] with specified background fill color.
|
||||||
pub fn modal_button(ui: &mut egui::Ui, text: String, action: impl FnOnce()) {
|
pub fn button(ui: &mut egui::Ui, text: String, fill_color: Color32, action: impl FnOnce()) {
|
||||||
let mut size = ui.available_size_before_wrap();
|
|
||||||
size.y = 36.0;
|
|
||||||
|
|
||||||
let wt = RichText::new(text.to_uppercase()).size(18.0).color(COLOR_GRAY_DARK);
|
let wt = RichText::new(text.to_uppercase()).size(18.0).color(COLOR_GRAY_DARK);
|
||||||
let br = Button::new(wt)
|
let br = Button::new(wt)
|
||||||
.stroke(Self::DEFAULT_STROKE)
|
.stroke(Self::DEFAULT_STROKE)
|
||||||
.min_size(size)
|
.fill(fill_color)
|
||||||
.fill(Color32::WHITE)
|
|
||||||
.ui(ui).interact(Sense::click_and_drag());
|
.ui(ui).interact(Sense::click_and_drag());
|
||||||
|
|
||||||
Self::on_button_click(ui, br, action);
|
Self::on_button_click(ui, br, action);
|
||||||
|
@ -169,4 +165,18 @@ impl View {
|
||||||
ui.label(RichText::new(label).color(COLOR_GRAY).size(15.0));
|
ui.label(RichText::new(label).color(COLOR_GRAY).size(15.0));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draw content in the center of current layout with specified width and height.
|
||||||
|
pub fn center_content(ui: &mut egui::Ui, w_h: [f32; 2], content: impl FnOnce(&mut egui::Ui)) {
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
let mut rect = ui.available_rect_before_wrap();
|
||||||
|
let side_margin = (ui.available_width() - w_h[0]) / 2.0;
|
||||||
|
rect.min += egui::emath::vec2(side_margin, ui.available_height() / 2.0 - w_h[1] / 2.0);
|
||||||
|
rect.max -= egui::emath::vec2(side_margin, 0.0);
|
||||||
|
// rect.set_width(w_h[0]);
|
||||||
|
ui.allocate_ui_at_rect(rect, |ui| {
|
||||||
|
(content)(ui);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -30,11 +30,11 @@ use lazy_static::lazy_static;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Static thread-aware state of [Node] to be updated from another thread.
|
/// Static thread-aware state of [`Node`] to be updated from another thread.
|
||||||
static ref NODE_STATE: Arc<Node> = Arc::new(Node::default());
|
static ref NODE_STATE: Arc<Node> = Arc::new(Node::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides [Server] control, holds current status and statistics.
|
/// Provides [`Server`] control, holds current status and statistics.
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
/// Statistics data for UI.
|
/// Statistics data for UI.
|
||||||
stats: Arc<RwLock<Option<ServerStats>>>,
|
stats: Arc<RwLock<Option<ServerStats>>>,
|
||||||
|
@ -61,12 +61,12 @@ impl Default for Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
/// Stop [Server].
|
/// Stop the [`Server`].
|
||||||
pub fn stop() {
|
pub fn stop() {
|
||||||
NODE_STATE.stop_needed.store(true, Ordering::Relaxed);
|
NODE_STATE.stop_needed.store(true, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start [Server] with provided chain type.
|
/// Start [`Server`] with provided chain type.
|
||||||
pub fn start(chain_type: ChainTypes) {
|
pub fn start(chain_type: ChainTypes) {
|
||||||
if !Self::is_running() {
|
if !Self::is_running() {
|
||||||
let mut w_chain_type = NODE_STATE.chain_type.write().unwrap();
|
let mut w_chain_type = NODE_STATE.chain_type.write().unwrap();
|
||||||
|
@ -75,7 +75,7 @@ impl Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restart [Server] with provided chain type.
|
/// Restart [`Server`] with provided chain type.
|
||||||
pub fn restart(chain_type: ChainTypes) {
|
pub fn restart(chain_type: ChainTypes) {
|
||||||
if Self::is_running() {
|
if Self::is_running() {
|
||||||
let mut w_chain_type = NODE_STATE.chain_type.write().unwrap();
|
let mut w_chain_type = NODE_STATE.chain_type.write().unwrap();
|
||||||
|
@ -86,40 +86,40 @@ impl Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if [Server] is starting.
|
/// Check if [`Server`] is starting.
|
||||||
pub fn is_starting() -> bool {
|
pub fn is_starting() -> bool {
|
||||||
NODE_STATE.starting.load(Ordering::Relaxed)
|
NODE_STATE.starting.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if [Server] is running.
|
/// Check if [`Server`] is running.
|
||||||
pub fn is_running() -> bool {
|
pub fn is_running() -> bool {
|
||||||
Self::get_stats().is_some() || Self::is_starting()
|
Self::get_sync_status().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if [Server] is stopping.
|
/// Check if [`Server`] is stopping.
|
||||||
pub fn is_stopping() -> bool {
|
pub fn is_stopping() -> bool {
|
||||||
NODE_STATE.stop_needed.load(Ordering::Relaxed)
|
NODE_STATE.stop_needed.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if [Server] is restarting.
|
/// Check if [`Server`] is restarting.
|
||||||
pub fn is_restarting() -> bool {
|
pub fn is_restarting() -> bool {
|
||||||
NODE_STATE.restart_needed.load(Ordering::Relaxed)
|
NODE_STATE.restart_needed.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get [Server] statistics.
|
/// Get [`Server`] statistics.
|
||||||
pub fn get_stats() -> RwLockReadGuard<'static, Option<ServerStats>> {
|
pub fn get_stats() -> RwLockReadGuard<'static, Option<ServerStats>> {
|
||||||
NODE_STATE.stats.read().unwrap()
|
NODE_STATE.stats.read().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get [Server] synchronization status, empty when it is not running.
|
/// Get [`Server`] synchronization status, empty when Server is not running.
|
||||||
pub fn get_sync_status() -> Option<SyncStatus> {
|
pub fn get_sync_status() -> Option<SyncStatus> {
|
||||||
// Return Shutdown status when node is stopping.
|
// Return Shutdown status when node is stopping.
|
||||||
if Self::is_stopping() {
|
if Self::is_stopping() {
|
||||||
return Some(SyncStatus::Shutdown)
|
return Some(SyncStatus::Shutdown)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return Initial status when node is starting.
|
// Return Initial status when node is starting or restarting.
|
||||||
if Self::is_starting() {
|
if Self::is_starting() || Self::is_restarting() {
|
||||||
return Some(SyncStatus::Initial)
|
return Some(SyncStatus::Initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,16 +131,24 @@ impl Node {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start a thread to launch [Server] and update [NODE_STATE] with server statistics.
|
/// Start a thread to launch [`Server`] and update [`NODE_STATE`] with server statistics.
|
||||||
fn start_server_thread() -> JoinHandle<()> {
|
fn start_server_thread() {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
NODE_STATE.starting.store(true, Ordering::Relaxed);
|
NODE_STATE.starting.store(true, Ordering::Relaxed);
|
||||||
|
|
||||||
|
// Start the server.
|
||||||
let mut server = start_server(&NODE_STATE.chain_type.read().unwrap());
|
let mut server = start_server(&NODE_STATE.chain_type.read().unwrap());
|
||||||
let mut first_start = true;
|
let mut first_start = true;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if Self::is_restarting() {
|
if Self::is_restarting() {
|
||||||
|
// Clean server stats.
|
||||||
|
{
|
||||||
|
let mut w_stats = NODE_STATE.stats.write().unwrap();
|
||||||
|
*w_stats = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the server.
|
||||||
server.stop();
|
server.stop();
|
||||||
|
|
||||||
// Create new server with current chain type.
|
// Create new server with current chain type.
|
||||||
|
@ -148,10 +156,14 @@ impl Node {
|
||||||
|
|
||||||
NODE_STATE.restart_needed.store(false, Ordering::Relaxed);
|
NODE_STATE.restart_needed.store(false, Ordering::Relaxed);
|
||||||
} else if Self::is_stopping() {
|
} else if Self::is_stopping() {
|
||||||
server.stop();
|
// Clean server stats.
|
||||||
|
{
|
||||||
|
let mut w_stats = NODE_STATE.stats.write().unwrap();
|
||||||
|
*w_stats = None;
|
||||||
|
}
|
||||||
|
|
||||||
let mut w_stats = NODE_STATE.stats.write().unwrap();
|
// Stop the server.
|
||||||
*w_stats = None;
|
server.stop();
|
||||||
|
|
||||||
NODE_STATE.starting.store(false, Ordering::Relaxed);
|
NODE_STATE.starting.store(false, Ordering::Relaxed);
|
||||||
NODE_STATE.stop_needed.store(false, Ordering::Relaxed);
|
NODE_STATE.stop_needed.store(false, Ordering::Relaxed);
|
||||||
|
@ -159,8 +171,11 @@ impl Node {
|
||||||
} else {
|
} else {
|
||||||
let stats = server.get_server_stats();
|
let stats = server.get_server_stats();
|
||||||
if stats.is_ok() {
|
if stats.is_ok() {
|
||||||
let mut w_stats = NODE_STATE.stats.write().unwrap();
|
// Update server stats.
|
||||||
*w_stats = Some(stats.as_ref().ok().unwrap().clone());
|
{
|
||||||
|
let mut w_stats = NODE_STATE.stats.write().unwrap();
|
||||||
|
*w_stats = Some(stats.as_ref().ok().unwrap().clone());
|
||||||
|
}
|
||||||
|
|
||||||
if first_start {
|
if first_start {
|
||||||
NODE_STATE.starting.store(false, Ordering::Relaxed);
|
NODE_STATE.starting.store(false, Ordering::Relaxed);
|
||||||
|
@ -170,18 +185,24 @@ impl Node {
|
||||||
}
|
}
|
||||||
thread::sleep(Duration::from_millis(250));
|
thread::sleep(Duration::from_millis(250));
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get synchronization status i18n text.
|
/// Get synchronization status i18n text.
|
||||||
pub fn get_sync_status_text(sync_status: Option<SyncStatus>) -> String {
|
pub fn get_sync_status_text() -> String {
|
||||||
|
if Node::is_starting() {
|
||||||
|
return t!("sync_status.initial")
|
||||||
|
};
|
||||||
|
|
||||||
|
if Node::is_stopping() {
|
||||||
|
return t!("sync_status.shutdown")
|
||||||
|
};
|
||||||
|
|
||||||
if Node::is_restarting() {
|
if Node::is_restarting() {
|
||||||
return t!("sync_status.server_restarting")
|
return t!("sync_status.server_restarting")
|
||||||
}
|
}
|
||||||
|
|
||||||
if Node::is_stopping() {
|
let sync_status = Self::get_sync_status();
|
||||||
return t!("sync_status.shutdown")
|
|
||||||
}
|
|
||||||
|
|
||||||
if sync_status.is_none() {
|
if sync_status.is_none() {
|
||||||
return t!("sync_status.server_down")
|
return t!("sync_status.server_down")
|
||||||
|
@ -256,7 +277,7 @@ impl Node {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start [Server] with provided chain type.
|
/// Start the [`Server`] with provided chain type.
|
||||||
fn start_server(chain_type: &ChainTypes) -> Server {
|
fn start_server(chain_type: &ChainTypes) -> Server {
|
||||||
// Initialize config
|
// Initialize config
|
||||||
let mut node_config_result = config::initial_setup_server(chain_type);
|
let mut node_config_result = config::initial_setup_server(chain_type);
|
||||||
|
@ -358,14 +379,13 @@ fn start_server(chain_type: &ChainTypes) -> Server {
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
/// Get sync status text for Android notification from [NODE_STATE] in Java string format.
|
/// Get sync status text for Android notification from [`NODE_STATE`] in Java string format.
|
||||||
pub extern "C" fn Java_mw_gri_android_BackgroundService_getSyncStatusText(
|
pub extern "C" fn Java_mw_gri_android_BackgroundService_getSyncStatusText(
|
||||||
_env: jni::JNIEnv,
|
_env: jni::JNIEnv,
|
||||||
_class: jni::objects::JObject,
|
_class: jni::objects::JObject,
|
||||||
_activity: jni::objects::JObject,
|
_activity: jni::objects::JObject,
|
||||||
) -> jstring {
|
) -> jstring {
|
||||||
let sync_status = Node::get_sync_status();
|
let status_text = Node::get_sync_status_text();
|
||||||
let status_text = Node::get_sync_status_text(sync_status);
|
|
||||||
let j_text = _env.new_string(status_text);
|
let j_text = _env.new_string(status_text);
|
||||||
return j_text.unwrap().into_raw();
|
return j_text.unwrap().into_raw();
|
||||||
}
|
}
|
||||||
|
@ -388,7 +408,7 @@ pub extern "C" fn Java_mw_gri_android_BackgroundService_getSyncTitle(
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
/// Calling on unexpected application termination (removal from recent apps)
|
/// Calling on unexpected Android application termination (removal from recent apps).
|
||||||
pub extern "C" fn Java_mw_gri_android_MainActivity_onTermination(
|
pub extern "C" fn Java_mw_gri_android_MainActivity_onTermination(
|
||||||
_env: jni::JNIEnv,
|
_env: jni::JNIEnv,
|
||||||
_class: jni::objects::JObject,
|
_class: jni::objects::JObject,
|
||||||
|
|
Loading…
Reference in a new issue