]> git.ktnx.net Git - mobile-ledger.git/commitdiff
asynchronous profile initialisation
authorDamyan Ivanov <dam+mobileledger@ktnx.net>
Sun, 11 Apr 2021 20:44:52 +0000 (20:44 +0000)
committerDamyan Ivanov <dam+mobileledger@ktnx.net>
Sun, 11 Apr 2021 20:44:52 +0000 (20:44 +0000)
the problem here was that the startup profile is read from the DB,
synchronously, and all DB operations need to happen via Room off the
main thread

since at activity startup only the theme is needed, that, and the startup
profile ID can be stored in the android preferences. actual loading of
profile and further data can be done after the theme is setup, in the
background, via Room

app/src/main/java/net/ktnx/mobileledger/App.java
app/src/main/java/net/ktnx/mobileledger/dao/ProfileDAO.java
app/src/main/java/net/ktnx/mobileledger/db/DB.java
app/src/main/java/net/ktnx/mobileledger/model/Data.java
app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java
app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java
app/src/main/java/net/ktnx/mobileledger/ui/activity/ProfileThemedActivity.java
app/src/main/java/net/ktnx/mobileledger/ui/activity/SplashActivity.java
app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionActivity.java
app/src/main/java/net/ktnx/mobileledger/ui/profiles/ProfilesRecyclerViewAdapter.java

index 2fc6d65c276dafd0b41131791317f7f3238af843..a781ccf105bebc377117bd8d5744ce79e2f8c00d 100644 (file)
@@ -18,6 +18,7 @@
 package net.ktnx.mobileledger;
 
 import android.app.Application;
+import android.content.SharedPreferences;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.sqlite.SQLiteDatabase;
@@ -26,6 +27,7 @@ import android.util.Log;
 import net.ktnx.mobileledger.db.DB;
 import net.ktnx.mobileledger.model.Data;
 import net.ktnx.mobileledger.ui.profiles.ProfileDetailModel;
+import net.ktnx.mobileledger.utils.Colors;
 import net.ktnx.mobileledger.utils.Globals;
 import net.ktnx.mobileledger.utils.Logger;
 import net.ktnx.mobileledger.utils.MobileLedgerDatabase;
@@ -39,6 +41,9 @@ import java.net.URL;
 import java.util.Locale;
 
 public class App extends Application {
+    public static final String PREF_NAME = "MoLe";
+    public static final String PREF_THEME_HUE = "theme-hue";
+    public static final String PREF_PROFILE_ID = "profile-id";
     public static App instance;
     private static ProfileDetailModel profileModel;
     private MobileLedgerDatabase dbHelper;
@@ -58,6 +63,23 @@ public class App extends Application {
     public static void resetAuthenticationData() {
         profileModel = null;
     }
+    public static void storeStartupProfileAndTheme(long currentProfileId, int currentTheme) {
+        SharedPreferences prefs =
+                instance.getSharedPreferences(PREF_NAME, MODE_PRIVATE);
+        SharedPreferences.Editor editor = prefs.edit();
+        editor.putLong(PREF_PROFILE_ID,
+                currentProfileId);
+        editor.putInt(PREF_THEME_HUE, currentTheme);
+        editor.apply();
+    }
+    public static long getStartupProfile() {
+        SharedPreferences prefs = instance.getSharedPreferences(PREF_NAME, MODE_PRIVATE);
+        return prefs.getLong(PREF_PROFILE_ID, -1);
+    }
+    public static int getStartupTheme() {
+        SharedPreferences prefs = instance.getSharedPreferences(PREF_NAME, MODE_PRIVATE);
+        return prefs.getInt(PREF_THEME_HUE, Colors.DEFAULT_HUE_DEG);
+    }
     private String getAuthURL() {
         if (profileModel != null)
             return profileModel.getUrl();
index b4eaf93572bf1b93934526869811fa2ef82ca8d1..52071745c4fc1eb35d620e0c7e8e023bb8f938e0 100644 (file)
@@ -17,6 +17,7 @@
 
 package net.ktnx.mobileledger.dao;
 
+import androidx.lifecycle.LiveData;
 import androidx.room.Dao;
 import androidx.room.Delete;
 import androidx.room.Insert;
@@ -38,4 +39,10 @@ public abstract class ProfileDAO extends BaseDAO<Profile> {
 
     @Query("select * from profiles where id = :profileId")
     public abstract Profile getByIdSync(long profileId);
+
+    @Query("SELECT * FROM profiles WHERE id=:profileId")
+    public abstract LiveData<Profile> getById(long profileId);
+
+    @Query("SELECT * FROM profiles LIMIT 1")
+    public abstract Profile getAnySync();
 }
index 2e7ca655c8cf8271d5c446dba8e14b906dd2e1c0..ca2d9092bd7f693e765565980456cae9628f8c4e 100644 (file)
@@ -18,6 +18,7 @@
 package net.ktnx.mobileledger.db;
 
 import android.content.res.Resources;
+import android.database.Cursor;
 import android.database.SQLException;
 
 import androidx.annotation.NonNull;
@@ -97,6 +98,25 @@ abstract public class DB extends RoomDatabase {
                 String fileName = String.format(Locale.US, "db_%d", toVersion);
 
                 applyRevisionFile(db, fileName);
+
+                // when migrating to version 59, migrate profile/theme options to the
+                // SharedPreferences
+                if (toVersion == 59) {
+                    try (Cursor c = db.query(
+                            "SELECT p.id, p.theme_hue FROM profiles p WHERE p.id=(SELECT o.value " +
+                            "FROM options WHERE o.profile_uid IS NULL AND o.name=?",
+                            new Object[]{"profile_id"}))
+                    {
+                        if (c.moveToFirst()) {
+                            long currentProfileId = c.getLong(0);
+                            int currentTheme = c.getInt(1);
+
+                            if (currentProfileId >= 0 && currentTheme >= 0) {
+                                App.storeStartupProfileAndTheme(currentProfileId, currentTheme);
+                            }
+                        }
+                    }
+                }
             }
         };
     }
index 24e3042ad193de358adec2ee48680187d4e53850..15d78ac034e475fde08bbf5724282189b98c6dd1 100644 (file)
 
 package net.ktnx.mobileledger.model;
 
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.lifecycle.LifecycleOwner;
 import androidx.lifecycle.MutableLiveData;
 import androidx.lifecycle.Observer;
 
-import net.ktnx.mobileledger.App;
 import net.ktnx.mobileledger.async.RetrieveTransactionsTask;
 import net.ktnx.mobileledger.utils.LockHolder;
 import net.ktnx.mobileledger.utils.Locker;
 import net.ktnx.mobileledger.utils.Logger;
-import net.ktnx.mobileledger.utils.MLDB;
 
 import java.text.NumberFormat;
 import java.text.ParseException;
@@ -93,11 +88,9 @@ public final class Data {
         backgroundTasksRunning.postValue(cnt > 0);
     }
     public static void setCurrentProfile(@NonNull MobileLedgerProfile newProfile) {
-        MLDB.setLongOption(MLDB.OPT_PROFILE_ID, newProfile.getId());
         profile.setValue(newProfile);
     }
     public static void postCurrentProfile(@NonNull MobileLedgerProfile newProfile) {
-        MLDB.setLongOption(MLDB.OPT_PROFILE_ID, newProfile.getId());
         profile.postValue(newProfile);
     }
     public static int getProfileIndex(MobileLedgerProfile profile) {
@@ -129,21 +122,6 @@ public final class Data {
             return -1;
         }
     }
-    public static int retrieveCurrentThemeIdFromDb() {
-        long profileId = MLDB.getLongOption(MLDB.OPT_PROFILE_ID, 0);
-        if (profileId == 0)
-            return -1;
-
-        SQLiteDatabase db = App.getDatabase();
-        try (Cursor c = db.rawQuery("SELECT theme from profiles where id=?",
-                new String[]{String.valueOf(profileId)}))
-        {
-            if (c.moveToNext())
-                return c.getInt(0);
-        }
-
-        return -1;
-    }
     @Nullable
     public static MobileLedgerProfile getProfile(long profileId) {
         MobileLedgerProfile profile;
@@ -211,19 +189,6 @@ public final class Data {
                                       Observer<MobileLedgerProfile> observer) {
         profile.observe(lifecycleOwner, observer);
     }
-    public synchronized static MobileLedgerProfile initProfile() {
-        MobileLedgerProfile currentProfile = profile.getValue();
-        if (currentProfile != null)
-            return currentProfile;
-
-        long profileId = MLDB.getLongOption(MLDB.OPT_PROFILE_ID, 0);
-        MobileLedgerProfile startupProfile = getProfile(profileId);
-        if (startupProfile != null)
-            setCurrentProfile(startupProfile);
-        Logger.debug("profile", "initProfile() returning " + startupProfile);
-        return startupProfile;
-    }
-
     public static void removeProfileObservers(LifecycleOwner owner) {
         profile.removeObservers(owner);
     }
index 0016bb374cb4c7f94bf594a1f7f19fc39c68a5e8..8cdc9c914e00bd8b312093752d1725abcd70125d 100644 (file)
@@ -40,6 +40,7 @@ import net.ktnx.mobileledger.dao.TransactionDAO;
 import net.ktnx.mobileledger.db.AccountValue;
 import net.ktnx.mobileledger.db.AccountWithAmounts;
 import net.ktnx.mobileledger.db.DB;
+import net.ktnx.mobileledger.db.Profile;
 import net.ktnx.mobileledger.json.API;
 import net.ktnx.mobileledger.ui.profiles.ProfileDetailActivity;
 import net.ktnx.mobileledger.ui.profiles.ProfileDetailFragment;
@@ -184,6 +185,26 @@ public final class MobileLedgerProfile {
         intent.putExtras(args);
         context.startActivity(intent, args);
     }
+    public static MobileLedgerProfile fromDBO(Profile newProfile) {
+        MobileLedgerProfile p = new MobileLedgerProfile(newProfile.getId());
+        p.setDetectedVersion(new HledgerVersion(newProfile.getDetectedVersionMajor(),
+                newProfile.getDetectedVersionMinor()));
+        p.setApiVersion(newProfile.getApiVersion());
+        p.setAuthEnabled(newProfile.useAuthentication());
+        p.setAuthUserName(newProfile.getAuthUser());
+        p.setAuthPassword(newProfile.getAuthPassword());
+        p.setDefaultCommodity(newProfile.getDefaultCommodity());
+        p.setFutureDates(newProfile.getFutureDates());
+        p.setName(newProfile.getName());
+        p.setPostingPermitted(newProfile.permitPosting());
+        p.setPreferredAccountsFilter(newProfile.getPreferredAccountsFilter());
+        p.setShowCommentsByDefault(newProfile.getShowCommentsByDefault());
+        p.setShowCommodityByDefault(newProfile.getShowCommodityByDefault());
+        p.setUrl(newProfile.getUrl());
+        p.setThemeId(newProfile.getTheme());
+
+        return p;
+    }
     public HledgerVersion getDetectedVersion() {
         return detectedVersion;
     }
index aba83f0551d04b04e65f1d3dc3e0af58c5b4e515..28a1af842325996c663d993083c8b9f54620840b 100644 (file)
@@ -352,8 +352,11 @@ public class MainActivity extends ProfileThemedActivity implements FabManager.Fa
                                      .setIcon(Icon.createWithResource(this,
                                              R.drawable.thick_plus_icon))
                                      .setIntent(new Intent(Intent.ACTION_VIEW, null, this,
-                                             NewTransactionActivity.class).putExtra("profile_id",
-                                             p.getId()))
+                                             NewTransactionActivity.class).putExtra(
+                                             ProfileThemedActivity.PARAM_PROFILE_ID, p.getId())
+                                                                          .putExtra(
+                                                                                  ProfileThemedActivity.PARAM_THEME,
+                                                                                  p.getThemeHue()))
                                      .setRank(i)
                                      .build();
             shortcuts.add(si);
@@ -456,6 +459,8 @@ public class MainActivity extends ProfileThemedActivity implements FabManager.Fa
     }
     public void fabNewTransactionClicked(View view) {
         Intent intent = new Intent(this, NewTransactionActivity.class);
+        intent.putExtra(ProfileThemedActivity.PARAM_PROFILE_ID, profile.getId());
+        intent.putExtra(ProfileThemedActivity.PARAM_THEME, profile.getThemeHue());
         startActivity(intent);
         overridePendingTransition(R.anim.slide_in_up, R.anim.dummy);
     }
index 07aae23c7d53ed64087da59d0aadd0a516703ff9..4aa60241dd3bab3fda24b661d901f793f7b9763a 100644 (file)
 package net.ktnx.mobileledger.ui.activity;
 
 import android.annotation.SuppressLint;
+import android.os.AsyncTask;
 import android.os.Bundle;
 
 import androidx.annotation.Nullable;
 
+import net.ktnx.mobileledger.App;
+import net.ktnx.mobileledger.dao.ProfileDAO;
+import net.ktnx.mobileledger.db.DB;
+import net.ktnx.mobileledger.db.Profile;
 import net.ktnx.mobileledger.model.Data;
 import net.ktnx.mobileledger.model.MobileLedgerProfile;
 import net.ktnx.mobileledger.utils.Colors;
 import net.ktnx.mobileledger.utils.Logger;
 
+import java.util.Locale;
+
 @SuppressLint("Registered")
 public class ProfileThemedActivity extends CrashReportingActivity {
+    public static final String TAG = "prf-thm-act";
+    protected static final String PARAM_PROFILE_ID = "profile-id";
+    protected static final String PARAM_THEME = "theme";
     protected MobileLedgerProfile mProfile;
     private boolean themeSetUp = false;
     private boolean mIgnoreProfileChange;
-    protected void setupProfileColors() {
-        final int themeHue = (mProfile == null) ? -1 : mProfile.getThemeHue();
+    private int mThemeHue;
+    protected void setupProfileColors(int newHue) {
+        if (themeSetUp && newHue == mThemeHue) {
+            Logger.debug(TAG,
+                    String.format(Locale.ROOT, "Ignore request to set theme to the same value (%d)",
+                            newHue));
+            return;
+        }
 
-        Colors.setupTheme(this, themeHue);
+        Logger.debug(TAG,
+                String.format(Locale.ROOT, "Changing theme from %d to %d", mThemeHue, newHue));
+
+        mThemeHue = newHue;
+        Colors.setupTheme(this, mThemeHue);
 
         if (themeSetUp) {
-            Logger.debug("prf-thm-act",
-                    "setupProfileColors(): theme already set up, recreating activity");
+            Logger.debug(TAG, "setupProfileColors(): theme already set up, recreating activity");
             this.recreate();
         }
         themeSetUp = true;
 
-        Colors.profileThemeId = Data.retrieveCurrentThemeIdFromDb();
+        Colors.profileThemeId = mThemeHue;
     }
     @Override
     protected void onStart() {
@@ -53,21 +72,53 @@ public class ProfileThemedActivity extends CrashReportingActivity {
     }
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         initProfile();
-        setupProfileColors();
 
-        mIgnoreProfileChange = true;
         Data.observeProfile(this, profile -> {
-            if (!mIgnoreProfileChange) {
-                mProfile = profile;
-                setupProfileColors();
+            if (profile == null) {
+                Logger.debug(TAG, "No current profile, leaving");
+                finish();
+                return;
             }
 
-            mIgnoreProfileChange = false;
+            mProfile = profile;
+            int hue = profile.getThemeHue();
+
+            if (hue != mThemeHue) {
+                storeProfilePref(profile);
+                setupProfileColors(hue);
+            }
         });
 
         super.onCreate(savedInstanceState);
     }
+    public void storeProfilePref(MobileLedgerProfile profile) {
+        App.storeStartupProfileAndTheme(profile.getId(), profile.getThemeHue());
+    }
     protected void initProfile() {
-        mProfile = Data.initProfile();
+        long profileId = App.getStartupProfile();
+        int hue = App.getStartupTheme();
+        if (profileId == -1)
+            mThemeHue = Colors.DEFAULT_HUE_DEG;
+
+        setupProfileColors(hue);
+
+        initProfile(profileId);
+    }
+    protected void initProfile(long profileId) {
+        AsyncTask.execute(() -> initProfileAsync(profileId));
+    }
+    private void initProfileAsync(long profileId) {
+        ProfileDAO dao = DB.get()
+                           .getProfileDAO();
+        Profile profile = dao.getByIdSync(profileId);
+
+        if (profile == null) {
+            Logger.debug(TAG, String.format(Locale.ROOT, "Profile %d not found. Trying any other",
+                    profileId));
+
+            profile = dao.getAnySync();
+        }
+
+        Data.postCurrentProfile(MobileLedgerProfile.fromDBO(profile));
     }
 }
index 41f3cddf719701171b5b7794404616dc3117e3fb..9b35b947c4e402c8243b9934316995fc27304f86 100644 (file)
@@ -25,10 +25,8 @@ import android.os.Handler;
 import androidx.annotation.Nullable;
 
 import net.ktnx.mobileledger.R;
-import net.ktnx.mobileledger.model.Data;
 import net.ktnx.mobileledger.model.MobileLedgerProfile;
 import net.ktnx.mobileledger.utils.Logger;
-import net.ktnx.mobileledger.utils.MLDB;
 import net.ktnx.mobileledger.utils.MobileLedgerDatabase;
 
 public class SplashActivity extends CrashReportingActivity {
@@ -103,10 +101,6 @@ public class SplashActivity extends CrashReportingActivity {
         protected Void doInBackground(Void... voids) {
             MobileLedgerProfile.loadAllFromDB(0);
 
-            long profileId = MLDB.getLongOption(MLDB.OPT_PROFILE_ID, 0);
-            MobileLedgerProfile startupProfile = Data.getProfile(profileId);
-            if (startupProfile != null)
-                Data.postCurrentProfile(startupProfile);
             return null;
         }
         @Override
index 469e773e95470a55570a210dcfc423404b9fd3b9..11d014d369bd983144220d76a6267846a92e6d9e 100644 (file)
@@ -72,6 +72,7 @@ public class NewTransactionActivity extends ProfileThemedActivity
         implements TaskCallback, NewTransactionFragment.OnNewTransactionFragmentInteractionListener,
         QR.QRScanTrigger, QR.QRScanResultReceiver, DescriptionSelectedCallback,
         FabManager.FabHandler {
+    final String TAG = "new-t-a";
     private NavController navController;
     private NewTransactionModel model;
     private ActivityResultLauncher<Void> qrScanLauncher;
@@ -115,16 +116,23 @@ public class NewTransactionActivity extends ProfileThemedActivity
     }
     @Override
     protected void initProfile() {
-        long profileId = getIntent().getLongExtra("profile_id", 0);
+        long profileId = getIntent().getLongExtra(PARAM_PROFILE_ID, 0);
+        int profileHue = getIntent().getIntExtra(PARAM_THEME, -1);
 
-        if (profileId != 0) {
-            mProfile = Data.getProfile(profileId);
-            if (mProfile == null)
-                finish();
-            Data.setCurrentProfile(mProfile);
+        if (profileHue < 0) {
+            Logger.debug(TAG, "Started with invalid/missing theme; quitting");
+            finish();
+            return;
         }
-        else
-            super.initProfile();
+
+        if (profileId <= 0) {
+            Logger.debug(TAG, "Started with invalid/missing profile_id; quitting");
+            finish();
+            return;
+        }
+
+        setupProfileColors(profileHue);
+        initProfile(profileId);
     }
     @Override
     public void finish() {
index 21984333500a80d4733e684a7f7bd284967eac86..e7346b1b0487a4d4d09fea3ee474047f43592efa 100644 (file)
@@ -39,6 +39,7 @@ import androidx.recyclerview.widget.RecyclerView;
 import net.ktnx.mobileledger.R;
 import net.ktnx.mobileledger.model.Data;
 import net.ktnx.mobileledger.model.MobileLedgerProfile;
+import net.ktnx.mobileledger.ui.activity.MainActivity;
 import net.ktnx.mobileledger.utils.Colors;
 
 import java.lang.ref.WeakReference;
@@ -148,8 +149,10 @@ public class ProfilesRecyclerViewAdapter
         if (profile == null)
             throw new IllegalStateException("Profile row without associated profile");
         debug("profiles", "Setting profile to " + profile.getName());
-        if (Data.getProfile() != profile)
+        if (Data.getProfile() != profile) {
             Data.drawerOpen.setValue(false);
+            ((MainActivity) v.getContext()).storeProfilePref(profile);
+        }
         Data.setCurrentProfile(profile);
     }
     @NonNull