Make android save more robust

This commit is contained in:
Yousef Khadadeh 2026-05-17 22:18:53 +03:00
parent 3ba403f30e
commit e8cba9dc15
14 changed files with 61 additions and 33 deletions

View file

@ -36,6 +36,7 @@ import org.libsdl.app.SDLDummyEdit;
import org.libsdl.app.SDLSurface;
public class InfiniPaint extends SDLActivity {
public static native void androidOnStop();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -50,6 +51,11 @@ public class InfiniPaint extends SDLActivity {
// window.setNavigationBarContrastEnforced(false);
}
protected void onStop() {
androidOnStop();
super.onStop();
}
protected SDLSurface createSDLSurface(Context context) {
return new InfiniPaintSurface(context);
}

View file

@ -49,6 +49,7 @@ jstring string2jstring(JNIEnv* env, const std::string& s) {
namespace AndroidJNICalls {
InputManager* globalInputManager;
std::mutex globalMutex;
std::mutex textboxMutex;
CustomEvents::InputTextBoxID textboxID = 0;
@ -345,4 +346,12 @@ Java_com_erroratline0_infinipaint_InfiniPaintNetworkService_networkServiceDestro
NetThreadManager::get().destroy_thread();
}
#endif
extern "C"
JNIEXPORT void JNICALL
Java_com_erroratline0_infinipaint_InfiniPaint_androidOnStop(JNIEnv *env, jclass clazz) {
std::scoped_lock a{globalMutex};
if(AndroidJNICalls::globalInputManager)
AndroidJNICalls::globalInputManager->main.input_android_on_stop_callback();
}
#endif

View file

@ -25,6 +25,7 @@ struct InputManager;
namespace AndroidJNICalls {
extern InputManager* globalInputManager;
extern std::mutex globalMutex;
void startTextInput(CustomEvents::InputTextBoxID newTextboxID, const std::shared_ptr<RichText::TextBox>& newTextbox, const std::shared_ptr<RichText::TextBox::Cursor>& newCursor, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& modMap, int inputType);
void startNetworkService();

View file

@ -365,17 +365,18 @@ void MainProgram::post_callback() {
g.gui.layout_if_necessary();
}
void MainProgram::input_app_about_to_go_to_background_callback() {
screen->input_app_about_to_go_to_background_callback();
void MainProgram::input_android_on_stop_callback() {
Logger::get().log(Logger::LogType::INFO, "[input_android_on_stop_callback] onStop received");
save_config();
post_callback();
screen->input_android_on_stop_callback();
}
void MainProgram::input_app_about_to_go_to_background_callback() {
NetThreadManager::get().go_to_background();
}
void MainProgram::input_app_about_to_go_to_foreground_callback() {
NetThreadManager::get().go_to_foreground();
screen->input_app_about_to_go_to_foreground_callback();
post_callback();
}
void MainProgram::input_add_file_to_canvas_callback(const CustomEvents::AddFileToCanvasEvent& addFile) {

View file

@ -162,6 +162,7 @@ class MainProgram {
void input_paste_callback(const CustomEvents::PasteEvent& paste);
void input_android_text_box_input_callback(const CustomEvents::AndroidTextBoxInputEvent& textboxInput);
void input_android_on_stop_callback();
void input_app_about_to_go_to_background_callback();
void input_app_about_to_go_to_foreground_callback();
void input_global_back_button_callback();

View file

@ -1202,6 +1202,12 @@ void FileSelectScreen::input_global_back_button_callback() {
mainMenuOpenAnim->animation_trigger_reverse();
else if(editMode)
editMode = false;
else if(selectedMenu != SelectedMenu::FILES) {
selectedMenu = SelectedMenu::FILES;
update_file_list(fileList, savePath, false);
mainMenuOpenAnim->animation_trigger_reverse();
if(mainViewScrollArea) mainViewScrollArea->reset_scroll();
}
else
main.setToQuit = true;
main.g.gui.set_to_layout();
@ -1218,7 +1224,7 @@ void FileSelectScreen::save_files() {
SDL_SaveFile(infoPath.string().c_str(), saveJson.c_str(), saveJson.size());
}
void FileSelectScreen::input_app_about_to_go_to_background_callback() {
void FileSelectScreen::input_android_on_stop_callback() {
save_files();
}

View file

@ -31,7 +31,7 @@ class FileSelectScreen : public Screen {
virtual void input_paste_callback(const CustomEvents::PasteEvent& paste) override;
virtual void input_open_infinipaint_file_callback(const CustomEvents::OpenInfiniPaintFileEvent& openFile) override;
virtual void input_global_back_button_callback() override;
virtual void input_app_about_to_go_to_background_callback() override;
virtual void input_android_on_stop_callback() override;
struct TrashInfo {
struct TrashFile {

View file

@ -443,7 +443,7 @@ void PhoneDrawingProgramScreen::top_toolbar() {
svg_icon_button(gui, "back exit button", "data/icons/RemixIcon/arrow-left-s-line.svg", {
.drawType = SelectableButton::DrawType::TRANSPARENT_ALL,
.onClick = [&] {
save_to_file();
save_to_file(true);
main.set_tab_to_close(main.world.get());
}
});
@ -1231,19 +1231,19 @@ void PhoneDrawingProgramScreen::input_global_back_button_callback() {
main.g.gui.set_to_layout();
}
else {
save_to_file();
save_to_file(true);
main.set_tab_to_close(main.world.get());
main.g.gui.set_to_layout();
}
}
void PhoneDrawingProgramScreen::save_to_file() {
void PhoneDrawingProgramScreen::save_to_file(bool saveThumbnail) {
if(!main.world->netClient)
main.world->save_to_file(main.world->filePath);
main.world->save_to_file(main.world->filePath, saveThumbnail);
}
void PhoneDrawingProgramScreen::input_app_about_to_go_to_background_callback() {
save_to_file();
void PhoneDrawingProgramScreen::input_android_on_stop_callback() {
save_to_file(false); // not saving thumbnail for now, since thumbnail requires GPU
}
void PhoneDrawingProgramScreen::on_tab_close() {
@ -1274,3 +1274,9 @@ void PhoneDrawingProgramScreen::color_selector_button(const char* id, Vector4f*
}
});
}
PhoneDrawingProgramScreen::~PhoneDrawingProgramScreen() {
#ifndef __ANDROID__
save_to_file(true);
#endif
}

View file

@ -24,10 +24,11 @@
class PhoneDrawingProgramScreen : public DrawingProgramScreen {
public:
PhoneDrawingProgramScreen(MainProgram& m);
~PhoneDrawingProgramScreen();
virtual void update() override;
virtual void gui_layout_run() override;
virtual void input_global_back_button_callback() override;
virtual void input_app_about_to_go_to_background_callback() override;
virtual void input_android_on_stop_callback() override;
virtual void on_tab_close() override;
struct ColorSelectorData {
std::function<void()> onChange;
@ -100,7 +101,7 @@ class PhoneDrawingProgramScreen : public DrawingProgramScreen {
void bottom_toolbar();
void main_display();
void tool_settings_popup();
void save_to_file();
void save_to_file(bool saveThumbnail);
std::string serverToConnectTo;
std::string serverLocalID;

View file

@ -82,8 +82,7 @@ void Screen::input_finger_touch_callback(const InputManager::FingerTouchCallback
void Screen::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) {}
void Screen::input_window_resize_callback(const InputManager::WindowResizeCallbackArgs& w) {}
void Screen::input_window_scale_callback(const InputManager::WindowScaleCallbackArgs& w) {}
void Screen::input_app_about_to_go_to_background_callback() {}
void Screen::input_app_about_to_go_to_foreground_callback() {}
void Screen::input_android_on_stop_callback() {}
void Screen::on_tab_close() {}
float Screen::calculate_gui_scale() { return main.g.final_gui_scale_not_fit(); }
std::optional<InputManager::TextBoxStartInfo> Screen::get_text_box_start_info() { return std::nullopt; }

View file

@ -64,8 +64,7 @@ class Screen {
virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion);
virtual void input_window_resize_callback(const InputManager::WindowResizeCallbackArgs& w);
virtual void input_window_scale_callback(const InputManager::WindowScaleCallbackArgs& w);
virtual void input_app_about_to_go_to_background_callback();
virtual void input_app_about_to_go_to_foreground_callback();
virtual void input_android_on_stop_callback();
virtual float calculate_gui_scale();
virtual void on_tab_close();
virtual std::optional<InputManager::TextBoxStartInfo> get_text_box_start_info();

View file

@ -476,7 +476,7 @@ void World::autosave_to_directory(const std::filesystem::path& directoryToSaveAt
save_to_file(directoryToSaveAt / std::filesystem::path(nameToSaveUnder + "." + FILE_EXTENSION));
}
void World::save_to_file(const std::filesystem::path& filePathToSaveAt) {
void World::save_to_file(const std::filesystem::path& filePathToSaveAt, bool saveThumbnailIfAvailable) {
try {
filePath = filePathToSaveAt;
@ -508,7 +508,7 @@ void World::save_to_file(const std::filesystem::path& filePathToSaveAt) {
#else
if(!SDL_SaveFile(filePath.string().c_str(), f.view().data(), f.view().size()))
throw std::runtime_error("SDL_SaveFile failed with error: " + std::string(SDL_GetError()));
else if(saveThumbnail) {
else if(saveThumbnail && saveThumbnailIfAvailable) {
Vector2f imageCenter{main.window.size.x() * 0.5f, main.window.size.y() * 0.5f};
float imageDim = std::max(main.window.size.x(), main.window.size.y());
Vector2f imageDimVec{imageDim * 0.5f, imageDim * 0.5f};

View file

@ -84,7 +84,7 @@ class World {
bool clientStillConnecting = false;
void autosave_to_directory(const std::filesystem::path& directoryToSaveAt);
void save_to_file(const std::filesystem::path& filePathToSaveAt);
void save_to_file(const std::filesystem::path& filePathToSaveAt, bool saveThumbnailIfAvailable = true);
void load_from_file(const std::filesystem::path& filePathToLoadFrom, std::string_view buffer);
void undo_with_checks();

View file

@ -616,6 +616,9 @@ void regular_draw(MainStruct& mS) {
}
SDL_AppResult SDL_AppIterate(void *appstate) {
#ifdef __ANDROID__
std::scoped_lock a{AndroidJNICalls::globalMutex};
#endif
std::chrono::steady_clock::time_point frameTimeStart = std::chrono::steady_clock::now();
MainStruct& mS = *((MainStruct*)appstate);
@ -626,12 +629,8 @@ SDL_AppResult SDL_AppIterate(void *appstate) {
#endif
mS.m->update();
if(mS.m->setToQuit) {
#ifdef __ANDROID__
mS.m->input_app_about_to_go_to_background_callback();
#endif
if(mS.m->setToQuit)
return SDL_APP_SUCCESS;
}
if(mS.m->input.hideCursor) {
SDL_HideCursor();
@ -659,6 +658,10 @@ SDL_AppResult SDL_AppIterate(void *appstate) {
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {
#ifdef __ANDROID__
std::scoped_lock a{AndroidJNICalls::globalMutex};
#endif
MainStruct& mS = *((MainStruct*)appstate);
#ifdef NDEBUG
@ -840,12 +843,8 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {
}
#endif
if(mS.m->setToQuit) {
#ifdef __ANDROID__
mS.m->input_app_about_to_go_to_background_callback();
#endif
if(mS.m->setToQuit)
return SDL_APP_SUCCESS;
}
return SDL_APP_CONTINUE;
}