mirror of
https://github.com/afollestad/nock-nock.git
synced 2025-04-20 19:45:17 +00:00
Added different types of validation in addition to status code checks, including custom JavaScript evaluation.
This commit is contained in:
parent
ef8031d848
commit
08a0d42f65
20 changed files with 568 additions and 50 deletions
|
@ -8,8 +8,8 @@ android {
|
|||
applicationId "com.afollestad.nocknock"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 24
|
||||
versionCode 8
|
||||
versionName "0.1.1.0"
|
||||
versionCode 9
|
||||
versionName "0.1.2.0"
|
||||
|
||||
jackOptions {
|
||||
enabled true
|
||||
|
@ -34,6 +34,7 @@ dependencies {
|
|||
compile 'com.afollestad.material-dialogs:core:0.8.6.2'
|
||||
compile 'com.afollestad.material-dialogs:commons:0.8.6.2'
|
||||
compile 'com.afollestad:bridge:3.2.5'
|
||||
compile 'com.afollestad:inquiry:2.0.2'
|
||||
compile 'com.afollestad:inquiry:3.1.0'
|
||||
compile 'com.android.support:design:24.1.1'
|
||||
compile files('libs/rhino-1.7.7.1.jar')
|
||||
}
|
BIN
app/libs/rhino-1.7.7.1.jar
Normal file
BIN
app/libs/rhino-1.7.7.1.jar
Normal file
Binary file not shown.
|
@ -116,7 +116,7 @@ public class ServerAdapter extends RecyclerView.Adapter<ServerAdapter.ServerVH>
|
|||
holder.textStatus.setText(R.string.checking_status);
|
||||
break;
|
||||
case ServerStatus.ERROR:
|
||||
holder.textStatus.setText(R.string.something_wrong);
|
||||
holder.textStatus.setText(model.reason);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,4 +27,10 @@ public class ServerModel implements Serializable {
|
|||
public long lastCheck;
|
||||
@Column
|
||||
public String reason;
|
||||
|
||||
@Column
|
||||
@ValidationMode.Enum
|
||||
public int validationMode;
|
||||
@Column
|
||||
public String validationContent;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.afollestad.nocknock.api;
|
||||
|
||||
import android.support.annotation.IntDef;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* @author Aidan Follestad (afollestad)
|
||||
*/
|
||||
public final class ValidationMode {
|
||||
|
||||
public final static int STATUS_CODE = 1;
|
||||
public final static int TERM_SEARCH = 2;
|
||||
public final static int JAVASCRIPT = 3;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({STATUS_CODE, TERM_SEARCH, JAVASCRIPT})
|
||||
public @interface Enum {
|
||||
}
|
||||
}
|
|
@ -17,11 +17,12 @@ public class BootReceiver extends BroadcastReceiver {
|
|||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
|
||||
Inquiry.init(context, MainActivity.DB_NAME, 1);
|
||||
ServerModel[] models = Inquiry.get()
|
||||
final Inquiry inq = Inquiry.newInstance(context, MainActivity.DB_NAME).build(false);
|
||||
ServerModel[] models = inq
|
||||
.selectFrom(MainActivity.SITES_TABLE_NAME, ServerModel.class)
|
||||
.all();
|
||||
AlarmUtil.setSiteChecks(context, models);
|
||||
inq.destroyInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,9 @@ public class ConnectivityReceiver extends BroadcastReceiver {
|
|||
public void onReceive(Context context, Intent intent) {
|
||||
final boolean hasInternet = NetworkUtil.hasInternet(context);
|
||||
Log.v("ConnectivityReceiver", "Connectivity state changed... has internet? " + hasInternet);
|
||||
if (hasInternet)
|
||||
if (hasInternet) {
|
||||
context.startService(new Intent(context, CheckService.class)
|
||||
.putExtra(CheckService.ONLY_WAITING, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,14 +16,17 @@ import android.widget.Toast;
|
|||
|
||||
import com.afollestad.bridge.Bridge;
|
||||
import com.afollestad.bridge.BridgeException;
|
||||
import com.afollestad.bridge.Response;
|
||||
import com.afollestad.inquiry.Inquiry;
|
||||
import com.afollestad.inquiry.Query;
|
||||
import com.afollestad.nocknock.BuildConfig;
|
||||
import com.afollestad.nocknock.R;
|
||||
import com.afollestad.nocknock.api.ServerModel;
|
||||
import com.afollestad.nocknock.api.ServerStatus;
|
||||
import com.afollestad.nocknock.api.ValidationMode;
|
||||
import com.afollestad.nocknock.ui.MainActivity;
|
||||
import com.afollestad.nocknock.ui.ViewSiteActivity;
|
||||
import com.afollestad.nocknock.util.JsUtil;
|
||||
import com.afollestad.nocknock.util.NetworkUtil;
|
||||
|
||||
import java.util.Locale;
|
||||
|
@ -31,6 +34,7 @@ import java.util.Locale;
|
|||
/**
|
||||
* @author Aidan Follestad (afollestad)
|
||||
*/
|
||||
@SuppressWarnings("CheckResult")
|
||||
public class CheckService extends Service {
|
||||
|
||||
public static String ACTION_CHECK_UPDATE = BuildConfig.APPLICATION_ID + ".CHECK_UPDATE";
|
||||
|
@ -89,7 +93,7 @@ public class CheckService extends Service {
|
|||
}
|
||||
|
||||
private void updateStatus(ServerModel site) {
|
||||
Inquiry.get()
|
||||
Inquiry.get(this)
|
||||
.update(MainActivity.SITES_TABLE_NAME, ServerModel.class)
|
||||
.where("_id = ?", site.id)
|
||||
.values(site)
|
||||
|
@ -151,13 +155,13 @@ public class CheckService extends Service {
|
|||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
Inquiry.init(this, MainActivity.DB_NAME, 1);
|
||||
Inquiry.newInstance(this, MainActivity.DB_NAME).build();
|
||||
isRunning(true);
|
||||
Bridge.config()
|
||||
.defaultHeader("User-Agent", getString(R.string.app_name) + " (Android)");
|
||||
|
||||
new Thread(() -> {
|
||||
final Query<ServerModel, Integer> query = Inquiry.get()
|
||||
final Query<ServerModel, Integer> query = Inquiry.get(this)
|
||||
.selectFrom(MainActivity.SITES_TABLE_NAME, ServerModel.class);
|
||||
if (intent != null && intent.hasExtra(MODEL_ID)) {
|
||||
query.where("_id = ?", intent.getLongExtra(MODEL_ID, -1));
|
||||
|
@ -190,12 +194,27 @@ public class CheckService extends Service {
|
|||
updateStatus(site);
|
||||
|
||||
try {
|
||||
Bridge.get(site.url)
|
||||
final Response response = Bridge.get(site.url)
|
||||
.throwIfNotSuccess()
|
||||
.cancellable(false)
|
||||
.request();
|
||||
.request()
|
||||
.response();
|
||||
|
||||
site.reason = null;
|
||||
site.status = ServerStatus.OK;
|
||||
|
||||
if (site.validationMode == ValidationMode.TERM_SEARCH) {
|
||||
final String body = response.asString();
|
||||
if (body == null || !body.contains(site.validationContent)) {
|
||||
site.status = ServerStatus.ERROR;
|
||||
site.reason = "Term \"" + site.validationContent + "\" not found in response body.";
|
||||
}
|
||||
} else if (site.validationMode == ValidationMode.JAVASCRIPT) {
|
||||
final String body = response.asString();
|
||||
site.reason = JsUtil.exec(site.validationContent, body);
|
||||
if (site.reason != null && !site.toString().isEmpty())
|
||||
site.status = ServerStatus.ERROR;
|
||||
}
|
||||
} catch (BridgeException e) {
|
||||
processError(e, site);
|
||||
}
|
||||
|
@ -212,4 +231,10 @@ public class CheckService extends Service {
|
|||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Inquiry.destroy(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import android.view.ViewAnimationUtils;
|
|||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
|
@ -23,6 +24,7 @@ import android.widget.TextView;
|
|||
import com.afollestad.nocknock.R;
|
||||
import com.afollestad.nocknock.api.ServerModel;
|
||||
import com.afollestad.nocknock.api.ServerStatus;
|
||||
import com.afollestad.nocknock.api.ValidationMode;
|
||||
|
||||
/**
|
||||
* @author Aidan Follestad (afollestad)
|
||||
|
@ -37,6 +39,7 @@ public class AddSiteActivity extends AppCompatActivity implements View.OnClickLi
|
|||
private EditText inputInterval;
|
||||
private Spinner spinnerInterval;
|
||||
private TextView textUrlWarning;
|
||||
private Spinner responseValidationSpinner;
|
||||
|
||||
private boolean isClosing;
|
||||
|
||||
|
@ -51,6 +54,7 @@ public class AddSiteActivity extends AppCompatActivity implements View.OnClickLi
|
|||
textUrlWarning = (TextView) findViewById(R.id.textUrlWarning);
|
||||
inputInterval = (EditText) findViewById(R.id.checkIntervalInput);
|
||||
spinnerInterval = (Spinner) findViewById(R.id.checkIntervalSpinner);
|
||||
responseValidationSpinner = (Spinner) findViewById(R.id.responseValidationMode);
|
||||
|
||||
toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
toolbar.setNavigationOnClickListener(view -> closeActivityWithReveal());
|
||||
|
@ -71,6 +75,7 @@ public class AddSiteActivity extends AppCompatActivity implements View.OnClickLi
|
|||
|
||||
ArrayAdapter<String> intervalOptionsAdapter = new ArrayAdapter<>(this, R.layout.list_item_spinner,
|
||||
getResources().getStringArray(R.array.interval_options));
|
||||
intervalOptionsAdapter.setDropDownViewResource(R.layout.list_item_spinner_dropdown);
|
||||
spinnerInterval.setAdapter(intervalOptionsAdapter);
|
||||
|
||||
inputUrl.setOnFocusChangeListener((view, hasFocus) -> {
|
||||
|
@ -90,6 +95,38 @@ public class AddSiteActivity extends AppCompatActivity implements View.OnClickLi
|
|||
}
|
||||
});
|
||||
|
||||
ArrayAdapter<String> validationOptionsAdapter = new ArrayAdapter<>(this, R.layout.list_item_spinner,
|
||||
getResources().getStringArray(R.array.response_validation_options));
|
||||
validationOptionsAdapter.setDropDownViewResource(R.layout.list_item_spinner_dropdown);
|
||||
responseValidationSpinner.setAdapter(validationOptionsAdapter);
|
||||
responseValidationSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
final View searchTerm = findViewById(R.id.responseValidationSearchTerm);
|
||||
final View javascript = findViewById(R.id.responseValidationScript);
|
||||
final TextView modeDesc = (TextView) findViewById(R.id.validationModeDescription);
|
||||
|
||||
searchTerm.setVisibility(i == 1 ? View.VISIBLE : View.GONE);
|
||||
javascript.setVisibility(i == 2 ? View.VISIBLE : View.GONE);
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
modeDesc.setText(R.string.validation_mode_status_desc);
|
||||
break;
|
||||
case 1:
|
||||
modeDesc.setText(R.string.validation_mode_term_desc);
|
||||
break;
|
||||
case 2:
|
||||
modeDesc.setText(R.string.validation_mode_javascript_desc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.doneBtn).setOnClickListener(this);
|
||||
}
|
||||
|
||||
|
@ -192,6 +229,21 @@ public class AddSiteActivity extends AppCompatActivity implements View.OnClickLi
|
|||
|
||||
model.lastCheck = System.currentTimeMillis() - model.checkInterval;
|
||||
|
||||
switch (responseValidationSpinner.getSelectedItemPosition()) {
|
||||
case 0:
|
||||
model.validationMode = ValidationMode.STATUS_CODE;
|
||||
model.validationContent = null;
|
||||
break;
|
||||
case 1:
|
||||
model.validationMode = ValidationMode.TERM_SEARCH;
|
||||
model.validationContent = ((EditText) findViewById(R.id.responseValidationSearchTerm)).getText().toString().trim();
|
||||
break;
|
||||
case 2:
|
||||
model.validationMode = ValidationMode.JAVASCRIPT;
|
||||
model.validationContent = ((EditText) findViewById(R.id.responseValidationScriptInput)).getText().toString().trim().replace("\n", " ");
|
||||
break;
|
||||
}
|
||||
|
||||
setResult(RESULT_OK, new Intent()
|
||||
.putExtra("model", model));
|
||||
finish();
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.afollestad.nocknock.ui;
|
|||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
|
@ -33,6 +34,7 @@ import com.afollestad.materialdialogs.MaterialDialog;
|
|||
import com.afollestad.nocknock.R;
|
||||
import com.afollestad.nocknock.adapter.ServerAdapter;
|
||||
import com.afollestad.nocknock.api.ServerModel;
|
||||
import com.afollestad.nocknock.api.ValidationMode;
|
||||
import com.afollestad.nocknock.dialogs.AboutDialog;
|
||||
import com.afollestad.nocknock.services.CheckService;
|
||||
import com.afollestad.nocknock.util.AlarmUtil;
|
||||
|
@ -44,7 +46,8 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
|
|||
private final static int ADD_SITE_RQ = 6969;
|
||||
private final static int VIEW_SITE_RQ = 6923;
|
||||
public final static String DB_NAME = "nock_nock";
|
||||
public final static String SITES_TABLE_NAME = "sites";
|
||||
public final static String SITES_TABLE_NAME_OLD = "sites";
|
||||
public final static String SITES_TABLE_NAME = "site_models";
|
||||
|
||||
private FloatingActionButton mFab;
|
||||
private RecyclerView mList;
|
||||
|
@ -72,6 +75,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
|
|||
}
|
||||
};
|
||||
|
||||
@SuppressLint("CommitPrefEdits")
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -94,9 +98,33 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
|
|||
mFab = (FloatingActionButton) findViewById(R.id.fab);
|
||||
mFab.setOnClickListener(this);
|
||||
|
||||
Inquiry.init(this, DB_NAME, 1);
|
||||
Inquiry.newInstance(this, DB_NAME).build();
|
||||
Bridge.config()
|
||||
.defaultHeader("User-Agent", getString(R.string.app_name) + " (Android)");
|
||||
|
||||
final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
if (!sp.getBoolean("migrated_db", false)) {
|
||||
final Inquiry mdb = Inquiry.newInstance(this, DB_NAME)
|
||||
.instanceName("migrate_db")
|
||||
.build(false);
|
||||
final ServerModel[] models = Inquiry.get(this)
|
||||
.selectFrom(SITES_TABLE_NAME_OLD, ServerModel.class)
|
||||
.projection("_id", "name", "url", "status", "checkInterval", "lastCheck", "reason")
|
||||
.all();
|
||||
if (models != null) {
|
||||
Log.d("SiteMigration", "Migrating " + models.length + " sites to the new table.");
|
||||
for (ServerModel model : models) {
|
||||
model.validationMode = ValidationMode.STATUS_CODE;
|
||||
model.validationContent = null;
|
||||
}
|
||||
//noinspection CheckResult
|
||||
mdb.insertInto(SITES_TABLE_NAME, ServerModel.class)
|
||||
.values(models)
|
||||
.run();
|
||||
mdb.dropTable(SITES_TABLE_NAME_OLD);
|
||||
}
|
||||
sp.edit().putBoolean("migrated_db", true).commit();
|
||||
}
|
||||
}
|
||||
|
||||
private void showRefreshTutorial() {
|
||||
|
@ -141,6 +169,10 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
|
|||
super.onPause();
|
||||
CheckService.isAppOpen(this, false);
|
||||
|
||||
if (isFinishing()) {
|
||||
Inquiry.destroy(this);
|
||||
}
|
||||
|
||||
NotificationManagerCompat.from(this).cancel(CheckService.NOTI_ID);
|
||||
try {
|
||||
unregisterReceiver(mReceiver);
|
||||
|
@ -152,7 +184,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
|
|||
private void refreshModels() {
|
||||
mAdapter.clear();
|
||||
mEmptyText.setVisibility(View.VISIBLE);
|
||||
Inquiry.get()
|
||||
Inquiry.get(this)
|
||||
.selectFrom(SITES_TABLE_NAME, ServerModel.class)
|
||||
.all(this::setModels);
|
||||
}
|
||||
|
@ -225,28 +257,21 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
|
|||
if (requestCode == ADD_SITE_RQ) {
|
||||
mAdapter.add(model);
|
||||
mEmptyText.setVisibility(View.GONE);
|
||||
Inquiry.get().insertInto(SITES_TABLE_NAME, ServerModel.class)
|
||||
Inquiry.get(this).insertInto(SITES_TABLE_NAME, ServerModel.class)
|
||||
.values(model)
|
||||
.run(inserted -> {
|
||||
AlarmUtil.setSiteChecks(MainActivity.this, model);
|
||||
checkSite(MainActivity.this, model);
|
||||
});
|
||||
} else if (requestCode == VIEW_SITE_RQ) {
|
||||
Inquiry.get()
|
||||
.update(MainActivity.SITES_TABLE_NAME, ServerModel.class)
|
||||
.where("_id = ?", model.id)
|
||||
.values(model)
|
||||
.run(changed -> {
|
||||
mAdapter.update(model);
|
||||
AlarmUtil.setSiteChecks(MainActivity.this, model);
|
||||
checkSite(MainActivity.this, model);
|
||||
});
|
||||
mAdapter.update(model);
|
||||
AlarmUtil.setSiteChecks(MainActivity.this, model);
|
||||
checkSite(MainActivity.this, model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeSite(final Context context, final ServerModel model, final Runnable onRemoved) {
|
||||
Inquiry.init(context, DB_NAME, 1);
|
||||
new MaterialDialog.Builder(context)
|
||||
.title(R.string.remove_site)
|
||||
.content(Html.fromHtml(context.getString(R.string.remove_site_prompt, model.name)))
|
||||
|
@ -256,10 +281,15 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
|
|||
AlarmUtil.cancelSiteChecks(context, model);
|
||||
final NotificationManagerCompat nm = NotificationManagerCompat.from(context);
|
||||
nm.cancel(model.url, CheckService.NOTI_ID);
|
||||
Inquiry.get()
|
||||
.deleteFrom(SITES_TABLE_NAME, ServerModel.class)
|
||||
//noinspection CheckResult
|
||||
final Inquiry rinq = Inquiry.newInstance(context, DB_NAME)
|
||||
.instanceName("remove_site")
|
||||
.build(false);
|
||||
//noinspection CheckResult
|
||||
rinq.deleteFrom(SITES_TABLE_NAME, ServerModel.class)
|
||||
.where("_id = ?", model.id)
|
||||
.run();
|
||||
rinq.destroyInstance();
|
||||
if (onRemoved != null)
|
||||
onRemoved.run();
|
||||
}).show();
|
||||
|
|
|
@ -14,15 +14,18 @@ import android.util.Log;
|
|||
import android.util.Patterns;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.afollestad.bridge.Bridge;
|
||||
import com.afollestad.inquiry.Inquiry;
|
||||
import com.afollestad.nocknock.R;
|
||||
import com.afollestad.nocknock.api.ServerModel;
|
||||
import com.afollestad.nocknock.api.ServerStatus;
|
||||
import com.afollestad.nocknock.api.ValidationMode;
|
||||
import com.afollestad.nocknock.services.CheckService;
|
||||
import com.afollestad.nocknock.util.TimeUtil;
|
||||
import com.afollestad.nocknock.views.StatusImageView;
|
||||
|
@ -44,6 +47,7 @@ public class ViewSiteActivity extends AppCompatActivity implements View.OnClickL
|
|||
private TextView textLastCheckResult;
|
||||
private TextView textNextCheck;
|
||||
private TextView textUrlWarning;
|
||||
private Spinner responseValidationSpinner;
|
||||
|
||||
private ServerModel mModel;
|
||||
|
||||
|
@ -77,9 +81,11 @@ public class ViewSiteActivity extends AppCompatActivity implements View.OnClickL
|
|||
checkIntervalSpinner = (Spinner) findViewById(R.id.checkIntervalSpinner);
|
||||
textLastCheckResult = (TextView) findViewById(R.id.textLastCheckResult);
|
||||
textNextCheck = (TextView) findViewById(R.id.textNextCheck);
|
||||
responseValidationSpinner = (Spinner) findViewById(R.id.responseValidationMode);
|
||||
|
||||
ArrayAdapter<String> intervalOptionsAdapter = new ArrayAdapter<>(this, R.layout.list_item_spinner,
|
||||
getResources().getStringArray(R.array.interval_options));
|
||||
intervalOptionsAdapter.setDropDownViewResource(R.layout.list_item_spinner_dropdown);
|
||||
checkIntervalSpinner.setAdapter(intervalOptionsAdapter);
|
||||
|
||||
inputUrl.setOnFocusChangeListener((view, hasFocus) -> {
|
||||
|
@ -99,6 +105,38 @@ public class ViewSiteActivity extends AppCompatActivity implements View.OnClickL
|
|||
}
|
||||
});
|
||||
|
||||
ArrayAdapter<String> validationOptionsAdapter = new ArrayAdapter<>(this, R.layout.list_item_spinner,
|
||||
getResources().getStringArray(R.array.response_validation_options));
|
||||
validationOptionsAdapter.setDropDownViewResource(R.layout.list_item_spinner_dropdown);
|
||||
responseValidationSpinner.setAdapter(validationOptionsAdapter);
|
||||
responseValidationSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
final View searchTerm = findViewById(R.id.responseValidationSearchTerm);
|
||||
final View javascript = findViewById(R.id.responseValidationScript);
|
||||
final TextView modeDesc = (TextView) findViewById(R.id.validationModeDescription);
|
||||
|
||||
searchTerm.setVisibility(i == 1 ? View.VISIBLE : View.GONE);
|
||||
javascript.setVisibility(i == 2 ? View.VISIBLE : View.GONE);
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
modeDesc.setText(R.string.validation_mode_status_desc);
|
||||
break;
|
||||
case 1:
|
||||
modeDesc.setText(R.string.validation_mode_term_desc);
|
||||
break;
|
||||
case 2:
|
||||
modeDesc.setText(R.string.validation_mode_javascript_desc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
}
|
||||
});
|
||||
|
||||
mModel = (ServerModel) getIntent().getSerializableExtra("model");
|
||||
update();
|
||||
|
||||
|
@ -115,7 +153,7 @@ public class ViewSiteActivity extends AppCompatActivity implements View.OnClickL
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@SuppressLint({"SetTextI18n", "SwitchIntDef"})
|
||||
private void update() {
|
||||
final SimpleDateFormat df = new SimpleDateFormat("MMMM dd, hh:mm:ss a", Locale.getDefault());
|
||||
|
||||
|
@ -169,6 +207,16 @@ public class ViewSiteActivity extends AppCompatActivity implements View.OnClickL
|
|||
}
|
||||
}
|
||||
|
||||
responseValidationSpinner.setSelection(mModel.validationMode - 1);
|
||||
switch (mModel.validationMode) {
|
||||
case ValidationMode.TERM_SEARCH:
|
||||
((TextView) findViewById(R.id.responseValidationSearchTerm)).setText(mModel.validationContent);
|
||||
break;
|
||||
case ValidationMode.JAVASCRIPT:
|
||||
((TextView) findViewById(R.id.responseValidationScriptInput)).setText(mModel.validationContent);
|
||||
break;
|
||||
}
|
||||
|
||||
findViewById(R.id.doneBtn).setOnClickListener(this);
|
||||
}
|
||||
|
||||
|
@ -195,26 +243,24 @@ public class ViewSiteActivity extends AppCompatActivity implements View.OnClickL
|
|||
}
|
||||
}
|
||||
|
||||
// Save button
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
private void performSave(boolean withValidation) {
|
||||
mModel.name = inputName.getText().toString().trim();
|
||||
mModel.url = inputUrl.getText().toString().trim();
|
||||
mModel.status = ServerStatus.WAITING;
|
||||
|
||||
if (mModel.name.isEmpty()) {
|
||||
if (withValidation && mModel.name.isEmpty()) {
|
||||
inputName.setError(getString(R.string.please_enter_name));
|
||||
return;
|
||||
} else {
|
||||
inputName.setError(null);
|
||||
}
|
||||
|
||||
if (mModel.url.isEmpty()) {
|
||||
if (withValidation && mModel.url.isEmpty()) {
|
||||
inputUrl.setError(getString(R.string.please_enter_url));
|
||||
return;
|
||||
} else {
|
||||
inputUrl.setError(null);
|
||||
if (!Patterns.WEB_URL.matcher(mModel.url).find()) {
|
||||
if (withValidation && !Patterns.WEB_URL.matcher(mModel.url).find()) {
|
||||
inputUrl.setError(getString(R.string.please_enter_valid_url));
|
||||
return;
|
||||
} else {
|
||||
|
@ -245,6 +291,35 @@ public class ViewSiteActivity extends AppCompatActivity implements View.OnClickL
|
|||
|
||||
mModel.lastCheck = System.currentTimeMillis() - mModel.checkInterval;
|
||||
|
||||
switch (responseValidationSpinner.getSelectedItemPosition()) {
|
||||
case 0:
|
||||
mModel.validationMode = ValidationMode.STATUS_CODE;
|
||||
mModel.validationContent = null;
|
||||
break;
|
||||
case 1:
|
||||
mModel.validationMode = ValidationMode.TERM_SEARCH;
|
||||
mModel.validationContent = ((EditText) findViewById(R.id.responseValidationSearchTerm)).getText().toString().trim();
|
||||
break;
|
||||
case 2:
|
||||
mModel.validationMode = ValidationMode.JAVASCRIPT;
|
||||
mModel.validationContent = ((EditText) findViewById(R.id.responseValidationScriptInput)).getText().toString().trim().replace("\n", " ");
|
||||
break;
|
||||
}
|
||||
|
||||
final Inquiry inq = Inquiry.newInstance(this, MainActivity.DB_NAME)
|
||||
.build(false);
|
||||
//noinspection CheckResult
|
||||
inq.update(MainActivity.SITES_TABLE_NAME, ServerModel.class)
|
||||
.where("_id = ?", mModel.id)
|
||||
.values(mModel)
|
||||
.run();
|
||||
inq.destroyInstance();
|
||||
}
|
||||
|
||||
// Save button
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
performSave(true);
|
||||
setResult(RESULT_OK, new Intent().putExtra("model", mModel));
|
||||
finish();
|
||||
}
|
||||
|
@ -253,10 +328,11 @@ public class ViewSiteActivity extends AppCompatActivity implements View.OnClickL
|
|||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.refresh:
|
||||
performSave(false);
|
||||
MainActivity.checkSite(this, mModel);
|
||||
return true;
|
||||
case R.id.remove:
|
||||
MainActivity.removeSite(this, mModel, () -> finish());
|
||||
MainActivity.removeSite(this, mModel, this::finish);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
72
app/src/main/java/com/afollestad/nocknock/util/JsUtil.java
Normal file
72
app/src/main/java/com/afollestad/nocknock/util/JsUtil.java
Normal file
|
@ -0,0 +1,72 @@
|
|||
package com.afollestad.nocknock.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.EvaluatorException;
|
||||
import org.mozilla.javascript.Function;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
||||
/**
|
||||
* @author Aidan Follestad (afollestad)
|
||||
*/
|
||||
public class JsUtil {
|
||||
|
||||
public static String exec(String code, String response) {
|
||||
try {
|
||||
final String func = String.format(
|
||||
"function validate(response) { " +
|
||||
"try { " +
|
||||
"%s " +
|
||||
"} catch(e) { " +
|
||||
"return e; " +
|
||||
"} " +
|
||||
"}", code.replace("\n", " "));
|
||||
|
||||
// Every Rhino VM begins with the enter()
|
||||
// This Context is not Android's Context
|
||||
Context rhino = Context.enter();
|
||||
|
||||
// Turn off optimization to make Rhino Android compatible
|
||||
rhino.setOptimizationLevel(-1);
|
||||
try {
|
||||
Scriptable scope = rhino.initStandardObjects();
|
||||
|
||||
// Note the forth argument is 1, which means the JavaScript source has
|
||||
// been compressed to only one line using something like YUI
|
||||
rhino.evaluateString(scope, func, "JavaScript", 1, null);
|
||||
|
||||
// Get the functionName defined in JavaScriptCode
|
||||
Function jsFunction = (Function) scope.get("validate", scope);
|
||||
|
||||
// Call the function with params
|
||||
Object jsResult = jsFunction.call(rhino, scope, scope, new Object[]{response});
|
||||
|
||||
// Parse the jsResult object to a String
|
||||
String result = Context.toString(jsResult);
|
||||
|
||||
boolean success = result != null && result.equals("true");
|
||||
String message = "The script returned a value other than true!";
|
||||
if (!success && result != null && !result.equals("false")) {
|
||||
if (result.equals("undefined")) {
|
||||
message = "The script did not return or throw anything!";
|
||||
} else {
|
||||
message = result;
|
||||
}
|
||||
}
|
||||
|
||||
Log.d("JsUtil", "Evaluated to " + message + " (" + success + "): " + code);
|
||||
return !success ? message : null;
|
||||
} finally {
|
||||
Context.exit();
|
||||
}
|
||||
} catch (EvaluatorException e) {
|
||||
return e.getMessage();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private JsUtil() {
|
||||
}
|
||||
}
|
|
@ -26,8 +26,7 @@
|
|||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/content_inset"
|
||||
android:paddingLeft="@dimen/content_inset"
|
||||
android:paddingRight="@dimen/content_inset"
|
||||
android:paddingTop="@dimen/content_inset_less">
|
||||
android:paddingRight="@dimen/content_inset">
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -80,12 +79,17 @@
|
|||
android:visibility="gone"
|
||||
tools:text="Warning: this app checks for server availability with HTTP requests. It's recommended that you use an HTTP URL." />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="@dimen/content_inset"
|
||||
android:background="@color/dividerColorDark" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/checkIntervalLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/list_text_spacing"
|
||||
android:layout_marginTop="@dimen/content_inset_more"
|
||||
android:layout_marginTop="@dimen/content_inset"
|
||||
android:fontFamily="sans-serif"
|
||||
android:text="@string/check_interval"
|
||||
android:textColor="?colorAccent"
|
||||
|
@ -121,6 +125,104 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="@dimen/content_inset"
|
||||
android:background="@color/dividerColorDark" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/responseValidation"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/content_inset"
|
||||
android:fontFamily="sans-serif"
|
||||
android:text="@string/response_validation_mode"
|
||||
android:textColor="?colorAccent"
|
||||
android:textSize="@dimen/caption_font_size" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/responseValidationMode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/responseValidationSearchTerm"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/content_inset_less"
|
||||
android:layout_marginLeft="-4dp"
|
||||
android:layout_marginRight="-4dp"
|
||||
android:layout_marginTop="-4dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:hint="@string/search_term"
|
||||
android:textSize="@dimen/body_font_size"
|
||||
android:visibility="gone" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/responseValidationScript"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/content_inset"
|
||||
android:layout_marginTop="@dimen/content_inset_half"
|
||||
android:background="@color/colorPrimaryDark"
|
||||
android:elevation="@dimen/fab_elevation"
|
||||
android:padding="@dimen/content_inset_half"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="serif-monospace"
|
||||
android:lineSpacingMultiplier="1.4"
|
||||
android:singleLine="true"
|
||||
android:text="@string/function_declaration"
|
||||
android:textSize="@dimen/code_font_size" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/responseValidationScriptInput"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:fontFamily="serif-monospace"
|
||||
android:gravity="top"
|
||||
android:hint="@string/default_js"
|
||||
android:inputType="textMultiLine"
|
||||
android:lineSpacingMultiplier="1.4"
|
||||
android:paddingBottom="@dimen/content_inset_less"
|
||||
android:paddingEnd="@dimen/content_inset_more"
|
||||
android:paddingStart="@dimen/content_inset_more"
|
||||
android:paddingTop="@dimen/content_inset_less"
|
||||
android:scrollHorizontally="true"
|
||||
android:textSize="@dimen/code_font_size"
|
||||
tools:ignore="LabelFor,RtlSymmetry" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="serif-monospace"
|
||||
android:text="@string/function_end"
|
||||
android:textSize="@dimen/code_font_size" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/validationModeDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/content_inset_half"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:text="@string/validation_mode_status_desc"
|
||||
android:textSize="@dimen/body_font_size" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/doneBtn"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
android:paddingBottom="@dimen/content_inset"
|
||||
android:paddingLeft="@dimen/content_inset"
|
||||
android:paddingRight="@dimen/content_inset"
|
||||
android:paddingTop="@dimen/content_inset_less">
|
||||
android:paddingTop="@dimen/content_inset_half">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -95,15 +95,14 @@
|
|||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="@dimen/content_inset_more"
|
||||
android:background="#37474F" />
|
||||
android:layout_marginTop="@dimen/content_inset_less"
|
||||
android:background="@color/dividerColorDark" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/checkIntervalLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/list_text_spacing"
|
||||
android:layout_marginTop="@dimen/content_inset_more"
|
||||
android:layout_marginTop="@dimen/content_inset"
|
||||
android:fontFamily="sans-serif"
|
||||
android:text="@string/check_interval"
|
||||
android:textColor="?colorAccent"
|
||||
|
@ -139,10 +138,114 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="@dimen/content_inset_less"
|
||||
android:background="@color/dividerColorDark" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/responseValidation"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/content_inset"
|
||||
android:fontFamily="sans-serif"
|
||||
android:text="@string/response_validation_mode"
|
||||
android:textColor="?colorAccent"
|
||||
android:textSize="@dimen/caption_font_size" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/responseValidationMode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/responseValidationSearchTerm"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/content_inset_less"
|
||||
android:layout_marginLeft="-4dp"
|
||||
android:layout_marginRight="-4dp"
|
||||
android:layout_marginTop="-4dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:hint="@string/search_term"
|
||||
android:textSize="@dimen/body_font_size"
|
||||
android:visibility="gone" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/responseValidationScript"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/content_inset"
|
||||
android:layout_marginTop="@dimen/content_inset_half"
|
||||
android:background="@color/colorPrimaryDark"
|
||||
android:elevation="@dimen/fab_elevation"
|
||||
android:padding="@dimen/content_inset_half"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="serif-monospace"
|
||||
android:lineSpacingMultiplier="1.4"
|
||||
android:singleLine="true"
|
||||
android:text="@string/function_declaration"
|
||||
android:textSize="@dimen/code_font_size" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/responseValidationScriptInput"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:fontFamily="serif-monospace"
|
||||
android:gravity="top"
|
||||
android:hint="@string/default_js"
|
||||
android:inputType="textMultiLine"
|
||||
android:lineSpacingMultiplier="1.4"
|
||||
android:paddingBottom="@dimen/content_inset_less"
|
||||
android:paddingEnd="@dimen/content_inset_more"
|
||||
android:paddingStart="@dimen/content_inset_more"
|
||||
android:paddingTop="@dimen/content_inset_less"
|
||||
android:scrollHorizontally="true"
|
||||
android:textSize="@dimen/code_font_size"
|
||||
tools:ignore="LabelFor,RtlSymmetry" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="serif-monospace"
|
||||
android:text="@string/function_end"
|
||||
android:textSize="@dimen/code_font_size" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/validationModeDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/content_inset_half"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:text="@string/validation_mode_status_desc"
|
||||
android:textSize="@dimen/body_font_size" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="@dimen/content_inset"
|
||||
android:background="@color/dividerColorDark" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/content_inset_more"
|
||||
android:layout_marginTop="@dimen/content_inset"
|
||||
android:text="@string/last_check_result"
|
||||
android:textColor="?colorAccent"
|
||||
android:textSize="@dimen/caption_font_size" />
|
||||
|
@ -160,7 +263,7 @@
|
|||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/content_inset_more"
|
||||
android:layout_marginTop="@dimen/content_inset"
|
||||
android:text="@string/next_check"
|
||||
android:textColor="?colorAccent"
|
||||
android:textSize="@dimen/caption_font_size" />
|
||||
|
@ -181,7 +284,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="-4dp"
|
||||
android:layout_marginRight="-4dp"
|
||||
android:layout_marginTop="@dimen/content_inset_double"
|
||||
android:layout_marginTop="@dimen/content_inset_more"
|
||||
android:text="@string/save"
|
||||
android:textColor="#fff" />
|
||||
|
||||
|
|
|
@ -4,7 +4,5 @@
|
|||
android:layout_height="@dimen/button_height"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:gravity="center_vertical|start"
|
||||
android:paddingLeft="@dimen/content_inset"
|
||||
android:paddingRight="@dimen/content_inset"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/body_font_size" />
|
10
app/src/main/res/layout/list_item_spinner_dropdown.xml
Normal file
10
app/src/main/res/layout/list_item_spinner_dropdown.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/button_height"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:gravity="center_vertical|start"
|
||||
android:paddingLeft="@dimen/content_inset"
|
||||
android:paddingRight="@dimen/content_inset"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/body_font_size" />
|
|
@ -11,4 +11,6 @@
|
|||
<color name="md_yellow">#FDD835</color>
|
||||
<color name="md_green">#43A047</color>
|
||||
|
||||
<color name="dividerColorDark">#37474F</color>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -18,5 +18,6 @@
|
|||
<dimen name="fab_elevation_pressed">8dp</dimen>
|
||||
<dimen name="button_height">52dp</dimen>
|
||||
<dimen name="tutorial_button_width">300dp</dimen>
|
||||
<dimen name="code_font_size">14sp</dimen>
|
||||
|
||||
</resources>
|
|
@ -18,6 +18,7 @@
|
|||
<a href=\'https://github.com/afollestad\'>GitHub</a>
|
||||
<a href=\'https://www.linkedin.com/in/afollestad\'>LinkedIn</a>
|
||||
<br/><i>Nock Nock is open source! Check out the <a href=\'https://github.com/afollestad/nock-nock\'>GitHub page</a>!</i>
|
||||
<br/>Icon by <a href=\'https://plus.google.com/+KevinAguilarC\'>Kevin Aguilar</a> of <b>221 Pixels</b>.
|
||||
]]></string>
|
||||
<string name="dismiss">Dismiss</string>
|
||||
<string name="add_site">Add Site</string>
|
||||
|
@ -49,6 +50,15 @@
|
|||
<string name="warning_http_url">
|
||||
Warning: this app checks for server availability with HTTP requests. It\'s recommended that you use an HTTP URL.
|
||||
</string>
|
||||
<string name="default_js">var responseObj = JSON.parse(response);\nreturn responseObj.success === true;</string>
|
||||
<string name="function_declaration">function validate(response) {</string>
|
||||
<string name="function_end">}</string>
|
||||
<string name="response_validation_mode">Response Validation Mode</string>
|
||||
<string name="search_term">Search term…</string>
|
||||
|
||||
<string name="validation_mode_status_desc">The HTTP status code is checked. If it\'s a successful status code, the site passes the check.</string>
|
||||
<string name="validation_mode_term_desc">The status code check is done first. If it\'s successful, the response body is checked. If it contains your search term, the site passes the check.</string>
|
||||
<string name="validation_mode_javascript_desc">The status code check is done first. If it\'s successful, the response body is passed to the JavaScript function above. If the function returns true, the site passes the check. Throw an exception to pass custom error messages to Nock Nock.</string>
|
||||
|
||||
<string-array name="interval_options">
|
||||
<item>Minute(s)</item>
|
||||
|
@ -62,4 +72,10 @@
|
|||
<item>@string/remove_site</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="response_validation_options">
|
||||
<item>Status Code</item>
|
||||
<item>Search Term</item>
|
||||
<item>JavaScript Evaluation</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -15,6 +15,7 @@ buildscript {
|
|||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven { url "https://jitpack.io" }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue