import android.util.Log;
import net.ktnx.mobileledger.json.API;
+import net.ktnx.mobileledger.json.ApiNotSupportedException;
import net.ktnx.mobileledger.json.Gateway;
import net.ktnx.mobileledger.model.LedgerTransaction;
import net.ktnx.mobileledger.model.LedgerTransactionAccount;
mProfile = profile;
simulate = false;
}
- private boolean sendOK(API apiVersion) throws IOException {
+ private void sendOK(API apiVersion) throws IOException, ApiNotSupportedException {
HttpURLConnection http = NetworkUtil.prepareConnection(mProfile, "add");
http.setRequestMethod("PUT");
http.setRequestProperty("Content-Type", "application/json");
Gateway gateway = Gateway.forApiVersion(apiVersion);
String body = gateway.transactionSaveRequest(transaction);
- return sendRequest(http, body);
+ Logger.debug("network", "Sending using API " + apiVersion);
+ sendRequest(http, body);
}
- private boolean sendRequest(HttpURLConnection http, String body) throws IOException {
+ private void sendRequest(HttpURLConnection http, String body)
+ throws IOException, ApiNotSupportedException {
if (simulate) {
debug("network", "The request would be: " + body);
try {
Logger.debug("network", ex.toString());
}
- return true;
+ return;
}
byte[] bodyBytes = body.getBytes(StandardCharsets.UTF_8);
case 400:
case 405: {
BufferedReader reader = new BufferedReader(new InputStreamReader(resp));
- String line;
+ StringBuilder errorLines = new StringBuilder();
int count = 0;
while (count <= 5) {
- line = reader.readLine();
+ String line = reader.readLine();
if (line == null)
break;
Logger.debug("network", line);
+
+ if (errorLines.length() != 0)
+ errorLines.append("\n");
+
+ errorLines.append(line);
count++;
}
- return false; // will cause a retry with another method
+ throw new ApiNotSupportedException(errorLines.toString());
}
default:
BufferedReader reader = new BufferedReader(new InputStreamReader(resp));
}
}
}
-
- return true;
}
private boolean legacySendOK() throws IOException {
HttpURLConnection http = NetworkUtil.prepareConnection(mProfile, "add");
boolean sendOK = false;
for (API ver : API.allVersions) {
Logger.debug("network", "Trying version " + ver);
- if (sendOK(ver)) {
+ try {
+ sendOK(ver);
sendOK = true;
Logger.debug("network", "Version " + ver + " request succeeded");
break;
}
+ catch (ApiNotSupportedException e) {
+ Logger.debug("network", "Version " + ver + " seems not supported");
+ }
}
+
if (!sendOK) {
Logger.debug("network", "Trying HTML form emulation");
legacySendOkWithRetry();
throw new IllegalStateException("Unexpected API version: " + profileApiVersion);
}
}
- catch (Exception e) {
+ catch (ApiNotSupportedException | Exception e) {
e.printStackTrace();
error = e.getMessage();
}
package net.ktnx.mobileledger.json;
-public class ApiNotSupportedException extends Throwable {}
+import androidx.annotation.Nullable;
+
+public class ApiNotSupportedException extends Throwable {
+ public ApiNotSupportedException() {
+ }
+ public ApiNotSupportedException(@Nullable String message) {
+ super(message);
+ }
+ public ApiNotSupportedException(@Nullable String message, @Nullable Throwable cause) {
+ super(message, cause);
+ }
+ public ApiNotSupportedException(@Nullable Throwable cause) {
+ super(cause);
+ }
+ public ApiNotSupportedException(@Nullable String message, @Nullable Throwable cause,
+ boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+}
package net.ktnx.mobileledger.model;
+import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
+import android.os.Bundle;
import android.text.TextUtils;
import android.util.SparseArray;
import net.ktnx.mobileledger.R;
import net.ktnx.mobileledger.async.DbOpQueue;
import net.ktnx.mobileledger.json.API;
+import net.ktnx.mobileledger.ui.activity.ProfileDetailActivity;
+import net.ktnx.mobileledger.ui.profiles.ProfileDetailFragment;
import net.ktnx.mobileledger.utils.Logger;
import net.ktnx.mobileledger.utils.Misc;
import net.ktnx.mobileledger.utils.SimpleDate;
db.endTransaction();
}
}
+ static public void startEditProfileActivity(Context context, MobileLedgerProfile profile) {
+ Intent intent = new Intent(context, ProfileDetailActivity.class);
+ Bundle args = new Bundle();
+ if (profile != null) {
+ int index = Data.getProfileIndex(profile);
+ if (index != -1)
+ intent.putExtra(ProfileDetailFragment.ARG_ITEM_ID, index);
+ }
+ intent.putExtras(args);
+ context.startActivity(intent, args);
+ }
public HledgerVersion getDetectedVersion() {
return detectedVersion;
}
import net.ktnx.mobileledger.model.MobileLedgerProfile;
import net.ktnx.mobileledger.ui.MainModel;
import net.ktnx.mobileledger.ui.account_summary.AccountSummaryFragment;
-import net.ktnx.mobileledger.ui.profiles.ProfileDetailFragment;
import net.ktnx.mobileledger.ui.profiles.ProfilesRecyclerViewAdapter;
import net.ktnx.mobileledger.ui.transaction_list.TransactionListFragment;
import net.ktnx.mobileledger.utils.Colors;
}
findViewById(R.id.btn_no_profiles_add).setOnClickListener(
- v -> startEditProfileActivity(null));
+ v -> MobileLedgerProfile.startEditProfileActivity(this, null));
findViewById(R.id.btn_add_transaction).setOnClickListener(this::fabNewTransactionClicked);
findViewById(R.id.nav_new_profile_button).setOnClickListener(
- v -> startEditProfileActivity(null));
+ v -> MobileLedgerProfile.startEditProfileActivity(this, null));
findViewById(R.id.transaction_list_cancel_download).setOnClickListener(
this::onStopTransactionRefreshClick);
recreate();
}
- public void startEditProfileActivity(MobileLedgerProfile profile) {
- Intent intent = new Intent(this, ProfileDetailActivity.class);
- Bundle args = new Bundle();
- if (profile != null) {
- int index = Data.getProfileIndex(profile);
- if (index != -1)
- intent.putExtra(ProfileDetailFragment.ARG_ITEM_ID, index);
- }
- intent.putExtras(args);
- startActivity(intent, args);
- }
public void fabNewTransactionClicked(View view) {
Intent intent = new Intent(this, NewTransactionActivity.class);
startActivity(intent);
builder.setMessage(error);
builder.setPositiveButton(R.string.btn_profile_options, (dialog, which) -> {
Logger.debug("error", "will start profile editor");
- startEditProfileActivity(profile);
+ MobileLedgerProfile.startEditProfileActivity(this, profile);
});
builder.create()
.show();
package net.ktnx.mobileledger.ui.activity;
import android.content.Context;
+import android.content.res.Resources;
import android.os.Bundle;
import android.renderscript.RSInvalidStateException;
import android.view.LayoutInflater;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.snackbar.Snackbar;
import net.ktnx.mobileledger.R;
+import net.ktnx.mobileledger.json.API;
import net.ktnx.mobileledger.model.Data;
import net.ktnx.mobileledger.model.LedgerTransaction;
import net.ktnx.mobileledger.model.LedgerTransactionAccount;
String error = args.getString("error");
if (error != null) {
Logger.debug("new-trans-f", String.format("Got error: %s", error));
- Snackbar.make(list, error, Snackbar.LENGTH_LONG)
- .show();
+
+ Context context = getContext();
+ if (context != null) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ final Resources resources = context.getResources();
+ final StringBuilder message = new StringBuilder();
+ message.append(resources.getString(R.string.err_json_send_error_head));
+ message.append("\n\n");
+ message.append(error);
+ if (mProfile.getApiVersion()
+ .equals(API.auto))
+ message.append(
+ resources.getString(R.string.err_json_send_error_unsupported));
+ else {
+ message.append(resources.getString(R.string.err_json_send_error_tail));
+ builder.setPositiveButton(R.string.btn_profile_options, (dialog, which) -> {
+ Logger.debug("error", "will start profile editor");
+ MobileLedgerProfile.startEditProfileActivity(context, mProfile);
+ });
+ }
+ builder.setMessage(message);
+ builder.create()
+ .show();
+ }
+ else {
+ Snackbar.make(list, error, Snackbar.LENGTH_LONG)
+ .show();
+ }
keep = true;
}
}
<string name="new_transaction_fab_description">Знак плюс</string>
<string name="api_1_19_1">Версия 1.19.1</string>
<string name="profile_server_version_title">Версия на сървъра</string>
- <string name="err_json_parser_error">Ð\93Ñ\80еÑ\88ка пÑ\80и Ñ\80азÑ\87иÑ\82ане на оÑ\82говоÑ\80а оÑ\82 Ñ\81Ñ\8aÑ\80вÑ\8aÑ\80а. Ð\92еÑ\80оÑ\8fÑ\82но наÑ\81Ñ\82Ñ\80оенаÑ\82а вÑ\80Ñ\81иÑ\8f на пÑ\80оÑ\82окола е гÑ\80еÑ\88на.</string>
+ <string name="err_json_parser_error">Ð\93Ñ\80еÑ\88ка пÑ\80и Ñ\80азÑ\87иÑ\82ане на оÑ\82говоÑ\80а оÑ\82 Ñ\81Ñ\8aÑ\80вÑ\8aÑ\80а. Ð\92еÑ\80оÑ\8fÑ\82но наÑ\81Ñ\82Ñ\80оенаÑ\82а вÑ\80Ñ\81иÑ\8f на пÑ\80оÑ\82окола не Ñ\81е поддÑ\8aÑ\80жа.</string>
<string name="btn_profile_options">Настройка на профила</string>
+ <string name="err_json_send_error_head">Грешка при изпращане на движението към сървъра</string>
+ <string name="err_json_send_error_tail">Вероятно настроената версия на протокола не се поддържа.</string>
</resources>
<string name="profile_server_version_title">Server version</string>
<string name="err_json_parser_error">Error parsing packend JSON response. Perhaps the configured API version doesn\'t match</string>
<string name="btn_profile_options">Configure profile</string>
+ <string name="err_json_send_error_head">Error storing transaction on backend server</string>
+ <string name="err_json_send_error_tail">A mismatch in the configured API version could be causing this</string>
+ <string name="err_json_send_error_unsupported">Perhaps the API of the backend server is not supported by MoLe</string>
</resources>