]> git.ktnx.net Git - mobile-ledger-staging.git/blobdiff - app/src/main/java/net/ktnx/mobileledger/ui/profiles/ProfileDetailModel.java
fix server version detection when the first profile is being created
[mobile-ledger-staging.git] / app / src / main / java / net / ktnx / mobileledger / ui / profiles / ProfileDetailModel.java
index e64c4bc1dc13c8a19caee33efab7eef631aeaf7d..92d3ab508dd98930c8fd2fa1a4aec07ef2328312 100644 (file)
 
 package net.ktnx.mobileledger.ui.profiles;
 
+import android.text.TextUtils;
+
 import androidx.lifecycle.LifecycleOwner;
 import androidx.lifecycle.MutableLiveData;
 import androidx.lifecycle.Observer;
 import androidx.lifecycle.ViewModel;
 
-import net.ktnx.mobileledger.async.SendTransactionTask;
+import net.ktnx.mobileledger.App;
+import net.ktnx.mobileledger.json.API;
 import net.ktnx.mobileledger.model.Currency;
+import net.ktnx.mobileledger.model.HledgerVersion;
 import net.ktnx.mobileledger.model.MobileLedgerProfile;
+import net.ktnx.mobileledger.utils.Colors;
+import net.ktnx.mobileledger.utils.Logger;
 import net.ktnx.mobileledger.utils.Misc;
+import net.ktnx.mobileledger.utils.NetworkUtil;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 public class ProfileDetailModel extends ViewModel {
     private static final String HTTPS_URL_START = "https://";
@@ -35,14 +52,18 @@ public class ProfileDetailModel extends ViewModel {
     private final MutableLiveData<MobileLedgerProfile.FutureDates> futureDates =
             new MutableLiveData<>(MobileLedgerProfile.FutureDates.None);
     private final MutableLiveData<Boolean> showCommodityByDefault = new MutableLiveData<>(false);
+    private final MutableLiveData<Boolean> showCommentsByDefault = new MutableLiveData<>(true);
     private final MutableLiveData<Boolean> useAuthentication = new MutableLiveData<>(false);
-    private final MutableLiveData<SendTransactionTask.API> apiVersion =
-            new MutableLiveData<>(SendTransactionTask.API.auto);
+    private final MutableLiveData<API> apiVersion = new MutableLiveData<>(API.auto);
     private final MutableLiveData<String> url = new MutableLiveData<>(null);
     private final MutableLiveData<String> authUserName = new MutableLiveData<>(null);
     private final MutableLiveData<String> authPassword = new MutableLiveData<>(null);
     private final MutableLiveData<String> preferredAccountsFilter = new MutableLiveData<>(null);
     private final MutableLiveData<Integer> themeId = new MutableLiveData<>(-1);
+    private final MutableLiveData<HledgerVersion> detectedVersion = new MutableLiveData<>(null);
+    private final MutableLiveData<Boolean> detectingHledgerVersion = new MutableLiveData<>(false);
+    public int initialThemeHue = Colors.DEFAULT_HUE_DEG;
+    private VersionDetectionThread versionDetectionThread;
     public ProfileDetailModel() {
     }
     String getProfileName() {
@@ -69,6 +90,13 @@ public class ProfileDetailModel extends ViewModel {
     void observePostingPermitted(LifecycleOwner lfo, Observer<Boolean> o) {
         postingPermitted.observe(lfo, o);
     }
+    public void setShowCommentsByDefault(boolean newValue) {
+        if (newValue != showCommentsByDefault.getValue())
+            showCommentsByDefault.setValue(newValue);
+    }
+    void observeShowCommentsByDefault(LifecycleOwner lfo, Observer<Boolean> o) {
+        showCommentsByDefault.observe(lfo, o);
+    }
     MobileLedgerProfile.FutureDates getFutureDates() {
         return futureDates.getValue();
     }
@@ -99,7 +127,7 @@ public class ProfileDetailModel extends ViewModel {
     void observeShowCommodityByDefault(LifecycleOwner lfo, Observer<Boolean> o) {
         showCommodityByDefault.observe(lfo, o);
     }
-    Boolean getUseAuthentication() {
+    public Boolean getUseAuthentication() {
         return useAuthentication.getValue();
     }
     void setUseAuthentication(boolean newValue) {
@@ -109,17 +137,25 @@ public class ProfileDetailModel extends ViewModel {
     void observeUseAuthentication(LifecycleOwner lfo, Observer<Boolean> o) {
         useAuthentication.observe(lfo, o);
     }
-    SendTransactionTask.API getApiVersion() {
+    API getApiVersion() {
         return apiVersion.getValue();
     }
-    void setApiVersion(SendTransactionTask.API newValue) {
+    void setApiVersion(API newValue) {
         if (newValue != apiVersion.getValue())
             apiVersion.setValue(newValue);
     }
-    void observeApiVersion(LifecycleOwner lfo, Observer<SendTransactionTask.API> o) {
+    void observeApiVersion(LifecycleOwner lfo, Observer<API> o) {
         apiVersion.observe(lfo, o);
     }
-    String getUrl() {
+    HledgerVersion getDetectedVersion() { return detectedVersion.getValue(); }
+    void setDetectedVersion(HledgerVersion newValue) {
+        if (!Objects.equals(detectedVersion.getValue(), newValue))
+            detectedVersion.setValue(newValue);
+    }
+    void observeDetectedVersion(LifecycleOwner lfo, Observer<HledgerVersion> o) {
+        detectedVersion.observe(lfo, o);
+    }
+    public String getUrl() {
         return url.getValue();
     }
     void setUrl(String newValue) {
@@ -133,7 +169,7 @@ public class ProfileDetailModel extends ViewModel {
     void observeUrl(LifecycleOwner lfo, Observer<String> o) {
         url.observe(lfo, o);
     }
-    String getAuthUserName() {
+    public String getAuthUserName() {
         return authUserName.getValue();
     }
     void setAuthUserName(String newValue) {
@@ -147,7 +183,7 @@ public class ProfileDetailModel extends ViewModel {
     void observeUserName(LifecycleOwner lfo, Observer<String> o) {
         authUserName.observe(lfo, o);
     }
-    String getAuthPassword() {
+    public String getAuthPassword() {
         return authPassword.getValue();
     }
     void setAuthPassword(String newValue) {
@@ -184,15 +220,19 @@ public class ProfileDetailModel extends ViewModel {
     void observeThemeId(LifecycleOwner lfo, Observer<Integer> o) {
         themeId.observe(lfo, o);
     }
+    void observeDetectingHledgerVersion(LifecycleOwner lfo, Observer<Boolean> o) {
+        detectingHledgerVersion.observe(lfo, o);
+    }
     void setValuesFromProfile(MobileLedgerProfile mProfile, int newProfileHue) {
         final int profileThemeId;
         if (mProfile != null) {
             profileName.setValue(mProfile.getName());
             postingPermitted.setValue(mProfile.isPostingPermitted());
+            showCommentsByDefault.setValue(mProfile.getShowCommentsByDefault());
             showCommodityByDefault.setValue(mProfile.getShowCommodityByDefault());
             {
                 String comm = mProfile.getDefaultCommodity();
-                if (Misc.isEmptyOrNull(comm))
+                if (TextUtils.isEmpty(comm))
                     setDefaultCommodity(null);
                 else
                     setDefaultCommodity(new Currency(-1, comm));
@@ -205,27 +245,29 @@ public class ProfileDetailModel extends ViewModel {
             authPassword.setValue(mProfile.isAuthEnabled() ? mProfile.getAuthPassword() : "");
             preferredAccountsFilter.setValue(mProfile.getPreferredAccountsFilter());
             themeId.setValue(mProfile.getThemeHue());
+            detectedVersion.setValue(mProfile.getDetectedVersion());
         }
         else {
             profileName.setValue(null);
             url.setValue(HTTPS_URL_START);
             postingPermitted.setValue(true);
+            showCommentsByDefault.setValue(true);
             showCommodityByDefault.setValue(false);
             setFutureDates(MobileLedgerProfile.FutureDates.None);
-            setApiVersion(SendTransactionTask.API.auto);
+            setApiVersion(API.auto);
             useAuthentication.setValue(false);
             authUserName.setValue("");
             authPassword.setValue("");
             preferredAccountsFilter.setValue(null);
             themeId.setValue(newProfileHue);
+            detectedVersion.setValue(null);
         }
-
-
     }
     void updateProfile(MobileLedgerProfile mProfile) {
         mProfile.setName(profileName.getValue());
         mProfile.setUrl(url.getValue());
         mProfile.setPostingPermitted(postingPermitted.getValue());
+        mProfile.setShowCommentsByDefault(showCommentsByDefault.getValue());
         Currency c = defaultCommodity.getValue();
         mProfile.setDefaultCommodity((c == null) ? null : c.getName());
         mProfile.setShowCommodityByDefault(showCommodityByDefault.getValue());
@@ -236,5 +278,90 @@ public class ProfileDetailModel extends ViewModel {
         mProfile.setThemeHue(themeId.getValue());
         mProfile.setFutureDates(futureDates.getValue());
         mProfile.setApiVersion(apiVersion.getValue());
+        mProfile.setDetectedVersion(detectedVersion.getValue());
+    }
+    synchronized public void triggerVersionDetection() {
+        if (versionDetectionThread != null)
+            versionDetectionThread.interrupt();
+
+        versionDetectionThread = new VersionDetectionThread(this);
+        versionDetectionThread.start();
+    }
+    static class VersionDetectionThread extends Thread {
+        static final int TARGET_PROCESS_DURATION = 1000;
+        private final Pattern versionPattern =
+                Pattern.compile("^\"(\\d+)\\.(\\d+)(?:\\.(\\d+))?\"$");
+        private final ProfileDetailModel model;
+        public VersionDetectionThread(ProfileDetailModel model) {
+            this.model = model;
+        }
+        private HledgerVersion detectVersion() {
+            App.setAuthenticationDataFromProfileModel(model);
+            HttpURLConnection http = null;
+            try {
+                http = NetworkUtil.prepareConnection(model.getUrl(), "version",
+                        model.getUseAuthentication());
+                switch (http.getResponseCode()) {
+                    case 200:
+                        break;
+                    case 404:
+                        return new HledgerVersion(true);
+                    default:
+                        Logger.debug("profile", String.format(Locale.US,
+                                "HTTP error detecting hledger-web version: [%d] %s",
+                                http.getResponseCode(), http.getResponseMessage()));
+                        return null;
+                }
+                InputStream stream = http.getInputStream();
+                BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
+                String version = reader.readLine();
+                Matcher m = versionPattern.matcher(version);
+                if (m.matches()) {
+                    int major = Integer.parseInt(Objects.requireNonNull(m.group(1)));
+                    int minor = Integer.parseInt(Objects.requireNonNull(m.group(2)));
+                    final boolean hasPatch = m.groupCount() >= 3;
+                    int patch = hasPatch ? Integer.parseInt(Objects.requireNonNull(m.group(3))) : 0;
+
+                    return hasPatch ? new HledgerVersion(major, minor, patch)
+                                    : new HledgerVersion(major, minor);
+                }
+                else {
+                    Logger.debug("profile",
+                            String.format("Unrecognised version string '%s'", version));
+                    return null;
+                }
+            }
+            catch (IOException e) {
+                e.printStackTrace();
+                return null;
+            }
+            finally {
+                App.resetAuthenticationData();
+            }
+        }
+        @Override
+        public void run() {
+            model.detectingHledgerVersion.postValue(true);
+            try {
+                long startTime = System.currentTimeMillis();
+
+                final HledgerVersion version = detectVersion();
+
+                long elapsed = System.currentTimeMillis() - startTime;
+                Logger.debug("profile", "Detection duration " + elapsed);
+                if (elapsed < TARGET_PROCESS_DURATION) {
+                    try {
+                        Thread.sleep(TARGET_PROCESS_DURATION - elapsed);
+                    }
+                    catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                }
+                model.detectedVersion.postValue(version);
+            }
+            finally {
+                model.detectingHledgerVersion.postValue(false);
+            }
+        }
     }
 }