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://";
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() {
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();
}
void observeShowCommodityByDefault(LifecycleOwner lfo, Observer<Boolean> o) {
showCommodityByDefault.observe(lfo, o);
}
- Boolean getUseAuthentication() {
+ public Boolean getUseAuthentication() {
return useAuthentication.getValue();
}
void setUseAuthentication(boolean newValue) {
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) {
void observeUrl(LifecycleOwner lfo, Observer<String> o) {
url.observe(lfo, o);
}
- String getAuthUserName() {
+ public String getAuthUserName() {
return authUserName.getValue();
}
void setAuthUserName(String newValue) {
void observeUserName(LifecycleOwner lfo, Observer<String> o) {
authUserName.observe(lfo, o);
}
- String getAuthPassword() {
+ public String getAuthPassword() {
return authPassword.getValue();
}
void setAuthPassword(String newValue) {
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));
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());
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);
+ }
+ }
}
}