diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..ecd817f --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..3b31283 --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 71e50ab..afe79ae 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -4,6 +4,8 @@ + + diff --git a/.travis.yml b/.travis.yml index 70085e5..3538182 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,8 @@ android: components: - tools - platform-tools - - build-tools-24.0.1 - - android-24 + - build-tools-26.0.0 + - android-26 - extra-android-support - extra-android-m2repository - extra-google-m2repository diff --git a/app/build.gradle b/app/build.gradle index 8d11f08..7ca4beb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,15 +1,15 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 24 - buildToolsVersion "24.0.1" + compileSdkVersion versions.compileSdk + buildToolsVersion versions.buildTools defaultConfig { applicationId "com.afollestad.nocknock" - minSdkVersion 21 - targetSdkVersion 24 - versionCode 14 - versionName "0.1.3.1" + minSdkVersion versions.minSdk + targetSdkVersion versions.compileSdk + versionCode versions.publishVersionCode + versionName versions.publishVersion lintOptions { abortOnError false @@ -33,11 +33,11 @@ android { } dependencies { - compile 'com.android.support:appcompat-v7:24.2.0' - compile 'com.android.support:design:24.2.0' - compile 'com.afollestad.material-dialogs:core:0.9.0.1' - compile 'com.afollestad.material-dialogs:commons:0.9.0.1' - compile 'com.afollestad:bridge:3.2.5' - compile 'com.afollestad:inquiry:3.2.1' + compile 'com.android.support:appcompat-v7:' + versions.supportLib + compile 'com.android.support:design:' + versions.supportLib + compile 'com.afollestad.material-dialogs:core:' + versions.materialDialogs + compile 'com.afollestad.material-dialogs:commons:' + versions.materialDialogs + compile 'com.afollestad:bridge:' + versions.bridge + compile 'com.afollestad:inquiry:' + versions.inquiry compile files('libs/rhino-1.7.7.1.jar') } \ No newline at end of file diff --git a/app/src/main/java/com/afollestad/nocknock/adapter/ServerAdapter.java b/app/src/main/java/com/afollestad/nocknock/adapter/ServerAdapter.java index b4da56b..0de2c5b 100644 --- a/app/src/main/java/com/afollestad/nocknock/adapter/ServerAdapter.java +++ b/app/src/main/java/com/afollestad/nocknock/adapter/ServerAdapter.java @@ -5,167 +5,165 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; 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.util.TimeUtil; import com.afollestad.nocknock.views.StatusImageView; - import java.util.ArrayList; import java.util.Collections; -/** - * @author Aidan Follestad (afollestad) - */ +/** @author Aidan Follestad (afollestad) */ public class ServerAdapter extends RecyclerView.Adapter { - private final Object LOCK = new Object(); - private ArrayList mServers; - private ClickListener mListener; + private final Object LOCK = new Object(); + private ArrayList mServers; + private ClickListener mListener; - public interface ClickListener { - void onSiteSelected(int index, ServerModel model, boolean longClick); + public interface ClickListener { + void onSiteSelected(int index, ServerModel model, boolean longClick); + } + + public void performClick(int index, boolean longClick) { + if (mListener != null) { + mListener.onSiteSelected(index, mServers.get(index), longClick); } + } - public void performClick(int index, boolean longClick) { - if (mListener != null) { - mListener.onSiteSelected(index, mServers.get(index), longClick); + public ServerAdapter(ClickListener listener) { + mListener = listener; + mServers = new ArrayList<>(2); + } + + public void add(ServerModel model) { + mServers.add(model); + notifyItemInserted(mServers.size() - 1); + } + + public void update(int index, ServerModel model) { + mServers.set(index, model); + notifyItemChanged(index); + } + + public void update(ServerModel model) { + synchronized (LOCK) { + for (int i = 0; i < mServers.size(); i++) { + if (mServers.get(i).id == model.id) { + update(i, model); + break; } + } } + } - public ServerAdapter(ClickListener listener) { - mListener = listener; - mServers = new ArrayList<>(2); - } + public void remove(int index) { + mServers.remove(index); + notifyItemRemoved(index); + } - public void add(ServerModel model) { - mServers.add(model); - notifyItemInserted(mServers.size() - 1); - } - - public void update(int index, ServerModel model) { - mServers.set(index, model); - notifyItemChanged(index); - } - - public void update(ServerModel model) { - synchronized (LOCK) { - for (int i = 0; i < mServers.size(); i++) { - if (mServers.get(i).id == model.id) { - update(i, model); - break; - } - } + public void remove(ServerModel model) { + synchronized (LOCK) { + for (int i = 0; i < mServers.size(); i++) { + if (mServers.get(i).id == model.id) { + remove(i); + break; } + } + } + } + + public void set(ServerModel[] models) { + if (models == null || models.length == 0) { + mServers.clear(); + return; + } + mServers = new ArrayList<>(models.length); + Collections.addAll(mServers, models); + notifyDataSetChanged(); + } + + public void clear() { + mServers.clear(); + notifyDataSetChanged(); + } + + @Override + public ServerAdapter.ServerVH onCreateViewHolder(ViewGroup parent, int viewType) { + final View v = + LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_server, parent, false); + return new ServerVH(v, this); + } + + @Override + public void onBindViewHolder(ServerAdapter.ServerVH holder, int position) { + final ServerModel model = mServers.get(position); + + holder.textName.setText(model.name); + holder.textUrl.setText(model.url); + holder.iconStatus.setStatus(model.status); + + switch (model.status) { + case ServerStatus.OK: + holder.textStatus.setText(R.string.everything_checks_out); + break; + case ServerStatus.WAITING: + holder.textStatus.setText(R.string.waiting); + break; + case ServerStatus.CHECKING: + holder.textStatus.setText(R.string.checking_status); + break; + case ServerStatus.ERROR: + holder.textStatus.setText(model.reason); + break; } - public void remove(int index) { - mServers.remove(index); - notifyItemRemoved(index); + if (model.checkInterval <= 0) { + holder.textInterval.setText(""); + } else { + final long now = System.currentTimeMillis(); + final long nextCheck = model.lastCheck + model.checkInterval; + final long difference = nextCheck - now; + holder.textInterval.setText(TimeUtil.str(difference)); } + } - public void remove(ServerModel model) { - synchronized (LOCK) { - for (int i = 0; i < mServers.size(); i++) { - if (mServers.get(i).id == model.id) { - remove(i); - break; - } - } - } - } + @Override + public int getItemCount() { + return mServers.size(); + } - public void set(ServerModel[] models) { - if (models == null || models.length == 0) { - mServers.clear(); - return; - } - mServers = new ArrayList<>(models.length); - Collections.addAll(mServers, models); - notifyDataSetChanged(); - } + public static class ServerVH extends RecyclerView.ViewHolder + implements View.OnClickListener, View.OnLongClickListener { - public void clear() { - mServers.clear(); - notifyDataSetChanged(); + final StatusImageView iconStatus; + final TextView textName; + final TextView textInterval; + final TextView textUrl; + final TextView textStatus; + final ServerAdapter adapter; + + public ServerVH(View itemView, ServerAdapter adapter) { + super(itemView); + iconStatus = (StatusImageView) itemView.findViewById(R.id.iconStatus); + textName = (TextView) itemView.findViewById(R.id.textName); + textInterval = (TextView) itemView.findViewById(R.id.textInterval); + textUrl = (TextView) itemView.findViewById(R.id.textUrl); + textStatus = (TextView) itemView.findViewById(R.id.textStatus); + this.adapter = adapter; + + itemView.setOnClickListener(this); + itemView.setOnLongClickListener(this); } @Override - public ServerAdapter.ServerVH onCreateViewHolder(ViewGroup parent, int viewType) { - final View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_server, parent, false); - return new ServerVH(v, this); + public void onClick(View view) { + adapter.performClick(getAdapterPosition(), false); } @Override - public void onBindViewHolder(ServerAdapter.ServerVH holder, int position) { - final ServerModel model = mServers.get(position); - - holder.textName.setText(model.name); - holder.textUrl.setText(model.url); - holder.iconStatus.setStatus(model.status); - - switch (model.status) { - case ServerStatus.OK: - holder.textStatus.setText(R.string.everything_checks_out); - break; - case ServerStatus.WAITING: - holder.textStatus.setText(R.string.waiting); - break; - case ServerStatus.CHECKING: - holder.textStatus.setText(R.string.checking_status); - break; - case ServerStatus.ERROR: - holder.textStatus.setText(model.reason); - break; - } - - if (model.checkInterval <= 0) { - holder.textInterval.setText(""); - } else { - final long now = System.currentTimeMillis(); - final long nextCheck = model.lastCheck + model.checkInterval; - final long difference = nextCheck - now; - holder.textInterval.setText(TimeUtil.str(difference)); - } - } - - @Override - public int getItemCount() { - return mServers.size(); - } - - public static class ServerVH extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { - - final StatusImageView iconStatus; - final TextView textName; - final TextView textInterval; - final TextView textUrl; - final TextView textStatus; - final ServerAdapter adapter; - - public ServerVH(View itemView, ServerAdapter adapter) { - super(itemView); - iconStatus = (StatusImageView) itemView.findViewById(R.id.iconStatus); - textName = (TextView) itemView.findViewById(R.id.textName); - textInterval = (TextView) itemView.findViewById(R.id.textInterval); - textUrl = (TextView) itemView.findViewById(R.id.textUrl); - textStatus = (TextView) itemView.findViewById(R.id.textStatus); - this.adapter = adapter; - - itemView.setOnClickListener(this); - itemView.setOnLongClickListener(this); - } - - @Override - public void onClick(View view) { - adapter.performClick(getAdapterPosition(), false); - } - - @Override - public boolean onLongClick(View view) { - adapter.performClick(getAdapterPosition(), true); - return false; - } + public boolean onLongClick(View view) { + adapter.performClick(getAdapterPosition(), true); + return false; } + } } diff --git a/app/src/main/java/com/afollestad/nocknock/api/ServerModel.java b/app/src/main/java/com/afollestad/nocknock/api/ServerModel.java index 1e3b6df..6fe6bc3 100644 --- a/app/src/main/java/com/afollestad/nocknock/api/ServerModel.java +++ b/app/src/main/java/com/afollestad/nocknock/api/ServerModel.java @@ -1,36 +1,23 @@ package com.afollestad.nocknock.api; import com.afollestad.inquiry.annotations.Column; - import java.io.Serializable; -/** - * @author Aidan Follestad (afollestad) - */ +/** @author Aidan Follestad (afollestad) */ public class ServerModel implements Serializable { - public ServerModel() { - } + public ServerModel() {} - @Column(name = "_id", primaryKey = true, notNull = true, autoIncrement = true) - public long id; - @Column - public String name; - @Column - public String url; - @Column - @ServerStatus.Enum - public int status; - @Column - public long checkInterval; - @Column - public long lastCheck; - @Column - public String reason; + @Column(name = "_id", primaryKey = true, notNull = true, autoIncrement = true) + public long id; - @Column - @ValidationMode.Enum - public int validationMode; - @Column - public String validationContent; -} \ No newline at end of file + @Column public String name; + @Column public String url; + @Column @ServerStatus.Enum public int status; + @Column public long checkInterval; + @Column public long lastCheck; + @Column public String reason; + + @Column @ValidationMode.Enum public int validationMode; + @Column public String validationContent; +} diff --git a/app/src/main/java/com/afollestad/nocknock/api/ServerStatus.java b/app/src/main/java/com/afollestad/nocknock/api/ServerStatus.java index f7f98fe..93bf2c8 100644 --- a/app/src/main/java/com/afollestad/nocknock/api/ServerStatus.java +++ b/app/src/main/java/com/afollestad/nocknock/api/ServerStatus.java @@ -1,21 +1,18 @@ package com.afollestad.nocknock.api; import android.support.annotation.IntDef; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -/** - * @author Aidan Follestad (afollestad) - */ +/** @author Aidan Follestad (afollestad) */ public final class ServerStatus { - public final static int OK = 1; - public final static int WAITING = 2; - public final static int CHECKING = 3; - public final static int ERROR = 4; + public static final int OK = 1; + public static final int WAITING = 2; + public static final int CHECKING = 3; + public static final int ERROR = 4; - @Retention(RetentionPolicy.SOURCE) - @IntDef({OK, WAITING, CHECKING, ERROR}) - public @interface Enum {} + @Retention(RetentionPolicy.SOURCE) + @IntDef({OK, WAITING, CHECKING, ERROR}) + public @interface Enum {} } diff --git a/app/src/main/java/com/afollestad/nocknock/api/ValidationMode.java b/app/src/main/java/com/afollestad/nocknock/api/ValidationMode.java index 2606635..bf1a524 100644 --- a/app/src/main/java/com/afollestad/nocknock/api/ValidationMode.java +++ b/app/src/main/java/com/afollestad/nocknock/api/ValidationMode.java @@ -1,21 +1,17 @@ package com.afollestad.nocknock.api; import android.support.annotation.IntDef; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -/** - * @author Aidan Follestad (afollestad) - */ +/** @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; + public static final int STATUS_CODE = 1; + public static final int TERM_SEARCH = 2; + public static final int JAVASCRIPT = 3; - @Retention(RetentionPolicy.SOURCE) - @IntDef({STATUS_CODE, TERM_SEARCH, JAVASCRIPT}) - public @interface Enum { - } + @Retention(RetentionPolicy.SOURCE) + @IntDef({STATUS_CODE, TERM_SEARCH, JAVASCRIPT}) + public @interface Enum {} } diff --git a/app/src/main/java/com/afollestad/nocknock/dialogs/AboutDialog.java b/app/src/main/java/com/afollestad/nocknock/dialogs/AboutDialog.java index 3eeed80..e61ed75 100644 --- a/app/src/main/java/com/afollestad/nocknock/dialogs/AboutDialog.java +++ b/app/src/main/java/com/afollestad/nocknock/dialogs/AboutDialog.java @@ -6,28 +6,25 @@ import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.support.v7.app.AppCompatActivity; import android.text.Html; - import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.nocknock.R; -/** - * @author Aidan Follestad (afollestad) - */ +/** @author Aidan Follestad (afollestad) */ public class AboutDialog extends DialogFragment { - public static void show(AppCompatActivity context) { - AboutDialog dialog = new AboutDialog(); - dialog.show(context.getSupportFragmentManager(), "[ABOUT_DIALOG]"); - } + public static void show(AppCompatActivity context) { + AboutDialog dialog = new AboutDialog(); + dialog.show(context.getSupportFragmentManager(), "[ABOUT_DIALOG]"); + } - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new MaterialDialog.Builder(getActivity()) - .title(R.string.about) - .positiveText(R.string.dismiss) - .content(Html.fromHtml(getString(R.string.about_body))) - .contentLineSpacing(1.6f) - .build(); - } -} \ No newline at end of file + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new MaterialDialog.Builder(getActivity()) + .title(R.string.about) + .positiveText(R.string.dismiss) + .content(Html.fromHtml(getString(R.string.about_body))) + .contentLineSpacing(1.6f) + .build(); + } +} diff --git a/app/src/main/java/com/afollestad/nocknock/receivers/BootReceiver.java b/app/src/main/java/com/afollestad/nocknock/receivers/BootReceiver.java index 7bb96e5..31729e2 100644 --- a/app/src/main/java/com/afollestad/nocknock/receivers/BootReceiver.java +++ b/app/src/main/java/com/afollestad/nocknock/receivers/BootReceiver.java @@ -3,26 +3,21 @@ package com.afollestad.nocknock.receivers; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; - import com.afollestad.inquiry.Inquiry; import com.afollestad.nocknock.api.ServerModel; import com.afollestad.nocknock.ui.MainActivity; import com.afollestad.nocknock.util.AlarmUtil; -/** - * @author Aidan Follestad (afollestad) - */ +/** @author Aidan Follestad (afollestad) */ public class BootReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { - 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(); - } + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { + 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(); } + } } diff --git a/app/src/main/java/com/afollestad/nocknock/receivers/ConnectivityReceiver.java b/app/src/main/java/com/afollestad/nocknock/receivers/ConnectivityReceiver.java index 7ceed62..3417ce3 100644 --- a/app/src/main/java/com/afollestad/nocknock/receivers/ConnectivityReceiver.java +++ b/app/src/main/java/com/afollestad/nocknock/receivers/ConnectivityReceiver.java @@ -4,22 +4,19 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; - import com.afollestad.nocknock.services.CheckService; import com.afollestad.nocknock.util.NetworkUtil; -/** - * @author Aidan Follestad (afollestad) - */ +/** @author Aidan Follestad (afollestad) */ public class ConnectivityReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - final boolean hasInternet = NetworkUtil.hasInternet(context); - Log.v("ConnectivityReceiver", "Connectivity state changed... has internet? " + hasInternet); - if (hasInternet) { - context.startService(new Intent(context, CheckService.class) - .putExtra(CheckService.ONLY_WAITING, true)); - } + @Override + public void onReceive(Context context, Intent intent) { + final boolean hasInternet = NetworkUtil.hasInternet(context); + Log.v("ConnectivityReceiver", "Connectivity state changed... has internet? " + hasInternet); + if (hasInternet) { + context.startService( + new Intent(context, CheckService.class).putExtra(CheckService.ONLY_WAITING, true)); } + } } diff --git a/app/src/main/java/com/afollestad/nocknock/services/CheckService.java b/app/src/main/java/com/afollestad/nocknock/services/CheckService.java index 2b9ab94..ad87568 100644 --- a/app/src/main/java/com/afollestad/nocknock/services/CheckService.java +++ b/app/src/main/java/com/afollestad/nocknock/services/CheckService.java @@ -3,7 +3,6 @@ package com.afollestad.nocknock.services; import android.app.IntentService; import android.app.Notification; import android.app.PendingIntent; -import android.app.Service; import android.content.Context; import android.content.Intent; import android.graphics.BitmapFactory; @@ -13,8 +12,6 @@ import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; import android.util.Log; -import android.widget.Toast; - import com.afollestad.bridge.Bridge; import com.afollestad.bridge.BridgeException; import com.afollestad.bridge.Response; @@ -29,213 +26,210 @@ 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; -/** - * @author Aidan Follestad (afollestad) - */ +/** @author Aidan Follestad (afollestad) */ @SuppressWarnings("CheckResult") public class CheckService extends IntentService { - public static String ACTION_CHECK_UPDATE = BuildConfig.APPLICATION_ID + ".CHECK_UPDATE"; - public static String ACTION_RUNNING = BuildConfig.APPLICATION_ID + ".CHECK_RUNNING"; - public static String MODEL_ID = "model_id"; - public static String ONLY_WAITING = "only_waiting"; - public static int NOTI_ID = 3456; + public static String ACTION_CHECK_UPDATE = BuildConfig.APPLICATION_ID + ".CHECK_UPDATE"; + public static String ACTION_RUNNING = BuildConfig.APPLICATION_ID + ".CHECK_RUNNING"; + public static String MODEL_ID = "model_id"; + public static String ONLY_WAITING = "only_waiting"; + public static int NOTI_ID = 3456; - public CheckService() { - super("NockNockCheckService"); + public CheckService() { + super("NockNockCheckService"); + } + + private static void LOG(String msg, Object... format) { + if (format != null) msg = String.format(Locale.getDefault(), msg, format); + Log.v("NockNockService", msg); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + protected void onHandleIntent(Intent intent) { + Inquiry.newInstance(this, MainActivity.DB_NAME).build(); + isRunning(true); + Bridge.config().defaultHeader("User-Agent", getString(R.string.app_name) + " (Android)"); + + final Query 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)); + } else if (intent != null && intent.getBooleanExtra(ONLY_WAITING, false)) { + query.where("status = ?", ServerStatus.WAITING); + } + final ServerModel[] sites = query.all(); + + if (sites == null || sites.length == 0) { + LOG("No sites added to check, service will terminate."); + isRunning(false); + stopSelf(); + return; } - private static void LOG(String msg, Object... format) { - if (format != null) - msg = String.format(Locale.getDefault(), msg, format); - Log.v("NockNockService", msg); + LOG("Checking %d sites...", sites.length); + sendBroadcast(new Intent(ACTION_RUNNING)); + + for (ServerModel site : sites) { + LOG("Updating %s (%s) status to WAITING...", site.name, site.url); + site.status = ServerStatus.WAITING; + updateStatus(site); } - @Nullable - @Override - public IBinder onBind(Intent intent) { - return null; - } + if (NetworkUtil.hasInternet(this)) { + for (ServerModel site : sites) { + LOG("Checking %s (%s)...", site.name, site.url); + site.status = ServerStatus.CHECKING; + site.lastCheck = System.currentTimeMillis(); + updateStatus(site); - @Override - protected void onHandleIntent(Intent intent) { - Inquiry.newInstance(this, MainActivity.DB_NAME).build(); - isRunning(true); - Bridge.config() - .defaultHeader("User-Agent", getString(R.string.app_name) + " (Android)"); - - final Query 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)); - } else if (intent != null && intent.getBooleanExtra(ONLY_WAITING, false)) { - query.where("status = ?", ServerStatus.WAITING); - } - final ServerModel[] sites = query.all(); - - if (sites == null || sites.length == 0) { - LOG("No sites added to check, service will terminate."); - isRunning(false); - stopSelf(); - return; - } - - LOG("Checking %d sites...", sites.length); - sendBroadcast(new Intent(ACTION_RUNNING)); - - for (ServerModel site : sites) { - LOG("Updating %s (%s) status to WAITING...", site.name, site.url); - site.status = ServerStatus.WAITING; - updateStatus(site); - } - - if (NetworkUtil.hasInternet(this)) { - for (ServerModel site : sites) { - LOG("Checking %s (%s)...", site.name, site.url); - site.status = ServerStatus.CHECKING; - site.lastCheck = System.currentTimeMillis(); - updateStatus(site); - - try { - final Response response = Bridge.get(site.url) - .throwIfNotSuccess() - .cancellable(false) - .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; - } - - if (site.status == ServerStatus.ERROR) - showNotification(this, site); - } catch (BridgeException e) { - processError(e, site); - } - updateStatus(site); - } - } else { - LOG("No internet connection, waiting."); - } - - isRunning(false); - LOG("Service is finished!"); - } - - private void processError(BridgeException e, ServerModel site) { - site.status = ServerStatus.OK; - site.reason = null; - - switch (e.reason()) { - case BridgeException.REASON_REQUEST_CANCELLED: - // Shouldn't happen - break; - case BridgeException.REASON_REQUEST_FAILED: - case BridgeException.REASON_RESPONSE_UNPARSEABLE: - case BridgeException.REASON_RESPONSE_UNSUCCESSFUL: - case BridgeException.REASON_RESPONSE_IOERROR: - //noinspection ConstantConditions - if (e.response() != null && e.response().code() == 401) { - // Don't consider 401 unsuccessful here - site.reason = null; - } else { - site.status = ServerStatus.ERROR; - site.reason = e.getMessage(); - } - break; - case BridgeException.REASON_REQUEST_TIMEOUT: - site.status = ServerStatus.ERROR; - site.reason = getString(R.string.timeout); - break; - case BridgeException.REASON_RESPONSE_VALIDATOR_ERROR: - case BridgeException.REASON_RESPONSE_VALIDATOR_FALSE: - // Not used - break; - } - - if (site.status != ServerStatus.OK) { - LOG("%s error: %s", site.name, site.reason); - showNotification(this, site); - } - } - - private void updateStatus(ServerModel site) { - Inquiry.get(this) - .update(MainActivity.SITES_TABLE_NAME, ServerModel.class) - .where("_id = ?", site.id) - .values(site) - .run(); - sendBroadcast(new Intent(ACTION_CHECK_UPDATE) - .putExtra("model", site)); - } - - private void isRunning(boolean running) { - PreferenceManager.getDefaultSharedPreferences(this) - .edit().putBoolean("check_service_running", running).commit(); - } - - public static boolean isRunning(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context) - .getBoolean("check_service_running", false); - } - - public static void isAppOpen(Context context, boolean open) { - PreferenceManager.getDefaultSharedPreferences(context) - .edit().putBoolean("is_app_open", open).commit(); - } - - public static boolean isAppOpen(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context) - .getBoolean("is_app_open", false); - } - - private static void showNotification(Context context, ServerModel site) { - if (isAppOpen(context)) { - // Don't show notifications while the app is open - return; - } - - final NotificationManagerCompat nm = NotificationManagerCompat.from(context); - final PendingIntent openIntent = PendingIntent.getActivity(context, 9669, - new Intent(context, ViewSiteActivity.class) - .putExtra("model", site) - .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), - PendingIntent.FLAG_CANCEL_CURRENT); - final Notification noti = new NotificationCompat.Builder(context) - .setContentTitle(site.name) - .setContentText(context.getString(R.string.something_wrong)) - .setContentIntent(openIntent) - .setSmallIcon(R.drawable.ic_notification) - .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher)) - .setPriority(Notification.PRIORITY_HIGH) - .setAutoCancel(true) - .setDefaults(Notification.DEFAULT_VIBRATE) - .build(); - nm.notify(site.url, NOTI_ID, noti); - } - - @Override - public void onDestroy() { try { - Inquiry.destroy(this); - } catch (Throwable t2) { - t2.printStackTrace(); + final Response response = + Bridge.get(site.url).throwIfNotSuccess().cancellable(false).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; + } + + if (site.status == ServerStatus.ERROR) showNotification(this, site); + } catch (BridgeException e) { + processError(e, site); } - super.onDestroy(); + updateStatus(site); + } + } else { + LOG("No internet connection, waiting."); } + + isRunning(false); + LOG("Service is finished!"); + } + + private void processError(BridgeException e, ServerModel site) { + site.status = ServerStatus.OK; + site.reason = null; + + switch (e.reason()) { + case BridgeException.REASON_REQUEST_CANCELLED: + // Shouldn't happen + break; + case BridgeException.REASON_REQUEST_FAILED: + case BridgeException.REASON_RESPONSE_UNPARSEABLE: + case BridgeException.REASON_RESPONSE_UNSUCCESSFUL: + case BridgeException.REASON_RESPONSE_IOERROR: + //noinspection ConstantConditions + if (e.response() != null && e.response().code() == 401) { + // Don't consider 401 unsuccessful here + site.reason = null; + } else { + site.status = ServerStatus.ERROR; + site.reason = e.getMessage(); + } + break; + case BridgeException.REASON_REQUEST_TIMEOUT: + site.status = ServerStatus.ERROR; + site.reason = getString(R.string.timeout); + break; + case BridgeException.REASON_RESPONSE_VALIDATOR_ERROR: + case BridgeException.REASON_RESPONSE_VALIDATOR_FALSE: + // Not used + break; + } + + if (site.status != ServerStatus.OK) { + LOG("%s error: %s", site.name, site.reason); + showNotification(this, site); + } + } + + private void updateStatus(ServerModel site) { + Inquiry.get(this) + .update(MainActivity.SITES_TABLE_NAME, ServerModel.class) + .where("_id = ?", site.id) + .values(site) + .run(); + sendBroadcast(new Intent(ACTION_CHECK_UPDATE).putExtra("model", site)); + } + + private void isRunning(boolean running) { + PreferenceManager.getDefaultSharedPreferences(this) + .edit() + .putBoolean("check_service_running", running) + .commit(); + } + + public static boolean isRunning(Context context) { + return PreferenceManager.getDefaultSharedPreferences(context) + .getBoolean("check_service_running", false); + } + + public static void isAppOpen(Context context, boolean open) { + PreferenceManager.getDefaultSharedPreferences(context) + .edit() + .putBoolean("is_app_open", open) + .commit(); + } + + public static boolean isAppOpen(Context context) { + return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("is_app_open", false); + } + + private static void showNotification(Context context, ServerModel site) { + if (isAppOpen(context)) { + // Don't show notifications while the app is open + return; + } + + final NotificationManagerCompat nm = NotificationManagerCompat.from(context); + final PendingIntent openIntent = + PendingIntent.getActivity( + context, + 9669, + new Intent(context, ViewSiteActivity.class) + .putExtra("model", site) + .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), + PendingIntent.FLAG_CANCEL_CURRENT); + final Notification noti = + new NotificationCompat.Builder(context) + .setContentTitle(site.name) + .setContentText(context.getString(R.string.something_wrong)) + .setContentIntent(openIntent) + .setSmallIcon(R.drawable.ic_notification) + .setLargeIcon( + BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher)) + .setPriority(Notification.PRIORITY_HIGH) + .setAutoCancel(true) + .setDefaults(Notification.DEFAULT_VIBRATE) + .build(); + nm.notify(site.url, NOTI_ID, noti); + } + + @Override + public void onDestroy() { + try { + Inquiry.destroy(this); + } catch (Throwable t2) { + t2.printStackTrace(); + } + super.onDestroy(); + } } diff --git a/app/src/main/java/com/afollestad/nocknock/ui/AddSiteActivity.java b/app/src/main/java/com/afollestad/nocknock/ui/AddSiteActivity.java index cb54ece..ba1b7fd 100644 --- a/app/src/main/java/com/afollestad/nocknock/ui/AddSiteActivity.java +++ b/app/src/main/java/com/afollestad/nocknock/ui/AddSiteActivity.java @@ -20,236 +20,254 @@ import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.Spinner; 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) - */ +/** @author Aidan Follestad (afollestad) */ public class AddSiteActivity extends AppCompatActivity implements View.OnClickListener { - private View rootLayout; - private Toolbar toolbar; + private View rootLayout; + private Toolbar toolbar; - private TextInputLayout nameTiLayout; - private EditText inputName; - private TextInputLayout urlTiLayout; - private EditText inputUrl; - private EditText inputInterval; - private Spinner spinnerInterval; - private TextView textUrlWarning; - private Spinner responseValidationSpinner; + private TextInputLayout nameTiLayout; + private EditText inputName; + private TextInputLayout urlTiLayout; + private EditText inputUrl; + private EditText inputInterval; + private Spinner spinnerInterval; + private TextView textUrlWarning; + private Spinner responseValidationSpinner; - private boolean isClosing; + private boolean isClosing; - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_addsite); + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_addsite); - rootLayout = findViewById(R.id.rootView); - nameTiLayout = (TextInputLayout) findViewById(R.id.nameTiLayout); - inputName = (EditText) findViewById(R.id.inputName); - urlTiLayout = (TextInputLayout) findViewById(R.id.urlTiLayout); - inputUrl = (EditText) findViewById(R.id.inputUrl); - textUrlWarning = (TextView) findViewById(R.id.textUrlWarning); - inputInterval = (EditText) findViewById(R.id.checkIntervalInput); - spinnerInterval = (Spinner) findViewById(R.id.checkIntervalSpinner); - responseValidationSpinner = (Spinner) findViewById(R.id.responseValidationMode); + rootLayout = findViewById(R.id.rootView); + nameTiLayout = (TextInputLayout) findViewById(R.id.nameTiLayout); + inputName = (EditText) findViewById(R.id.inputName); + urlTiLayout = (TextInputLayout) findViewById(R.id.urlTiLayout); + inputUrl = (EditText) findViewById(R.id.inputUrl); + 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()); + toolbar = (Toolbar) findViewById(R.id.toolbar); + toolbar.setNavigationOnClickListener(view -> closeActivityWithReveal()); - if (savedInstanceState == null) { - rootLayout.setVisibility(View.INVISIBLE); - ViewTreeObserver viewTreeObserver = rootLayout.getViewTreeObserver(); - if (viewTreeObserver.isAlive()) { - viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - circularRevealActivity(); - rootLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); - } - }); - } - } - - ArrayAdapter 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) -> { - if (!hasFocus) { - final String inputStr = inputUrl.getText().toString().trim(); - if (inputStr.isEmpty()) return; - final Uri uri = Uri.parse(inputStr); - if (uri.getScheme() == null) { - inputUrl.setText("http://" + inputStr); - textUrlWarning.setVisibility(View.GONE); - } else if (!"http".equals(uri.getScheme()) && !"https".equals(uri.getScheme())) { - textUrlWarning.setVisibility(View.VISIBLE); - textUrlWarning.setText(R.string.warning_http_url); - } else { - textUrlWarning.setVisibility(View.GONE); - } - } - }); - - ArrayAdapter 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); + if (savedInstanceState == null) { + rootLayout.setVisibility(View.INVISIBLE); + ViewTreeObserver viewTreeObserver = rootLayout.getViewTreeObserver(); + if (viewTreeObserver.isAlive()) { + viewTreeObserver.addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + circularRevealActivity(); + rootLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + }); + } } - @Override - public void onBackPressed() { - closeActivityWithReveal(); - } + ArrayAdapter 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); - private void closeActivityWithReveal() { - if (isClosing) return; - isClosing = true; - final int fabSize = getIntent().getIntExtra("fab_size", toolbar.getMeasuredHeight()); - final int cx = (int) getIntent().getFloatExtra("fab_x", rootLayout.getMeasuredWidth() / 2) + (fabSize / 2); - final int cy = (int) getIntent().getFloatExtra("fab_y", rootLayout.getMeasuredHeight() / 2) + toolbar.getMeasuredHeight() + (fabSize / 2); - float initialRadius = Math.max(cx, cy); - - final Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootLayout, cx, cy, initialRadius, 0); - circularReveal.setDuration(300); - circularReveal.setInterpolator(new AccelerateInterpolator()); - circularReveal.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - rootLayout.setVisibility(View.INVISIBLE); - finish(); - overridePendingTransition(0, 0); - } - }); - - circularReveal.start(); - } - - private void circularRevealActivity() { - final int cx = rootLayout.getMeasuredWidth() / 2; - final int cy = rootLayout.getMeasuredHeight() / 2; - final float finalRadius = Math.max(cx, cy); - final Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootLayout, cx, cy, 0, finalRadius); - - circularReveal.setDuration(300); - circularReveal.setInterpolator(new DecelerateInterpolator()); - - rootLayout.setVisibility(View.VISIBLE); - circularReveal.start(); - } - - // Done button - @Override - public void onClick(View view) { - isClosing = true; - - ServerModel model = new ServerModel(); - model.name = inputName.getText().toString().trim(); - model.url = inputUrl.getText().toString().trim(); - model.status = ServerStatus.WAITING; - - if (model.name.isEmpty()) { - nameTiLayout.setError(getString(R.string.please_enter_name)); - isClosing = false; - return; - } else { - nameTiLayout.setError(null); - } - - if (model.url.isEmpty()) { - urlTiLayout.setError(getString(R.string.please_enter_url)); - isClosing = false; - return; - } else { - urlTiLayout.setError(null); - if (!Patterns.WEB_URL.matcher(model.url).find()) { - urlTiLayout.setError(getString(R.string.please_enter_valid_url)); - isClosing = false; - return; + inputUrl.setOnFocusChangeListener( + (view, hasFocus) -> { + if (!hasFocus) { + final String inputStr = inputUrl.getText().toString().trim(); + if (inputStr.isEmpty()) return; + final Uri uri = Uri.parse(inputStr); + if (uri.getScheme() == null) { + inputUrl.setText("http://" + inputStr); + textUrlWarning.setVisibility(View.GONE); + } else if (!"http".equals(uri.getScheme()) && !"https".equals(uri.getScheme())) { + textUrlWarning.setVisibility(View.VISIBLE); + textUrlWarning.setText(R.string.warning_http_url); } else { - final Uri uri = Uri.parse(model.url); - if (uri.getScheme() == null) - model.url = "http://" + model.url; + textUrlWarning.setVisibility(View.GONE); } - } + } + }); - String intervalStr = inputInterval.getText().toString().trim(); - if (intervalStr.isEmpty()) intervalStr = "0"; - model.checkInterval = Integer.parseInt(intervalStr); + ArrayAdapter 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); - switch (spinnerInterval.getSelectedItemPosition()) { - case 0: // minutes - model.checkInterval *= (60 * 1000); - break; - case 1: // hours - model.checkInterval *= (60 * 60 * 1000); - break; - case 2: // days - model.checkInterval *= (60 * 60 * 24 * 1000); - break; - default: // weeks - model.checkInterval *= (60 * 60 * 24 * 7 * 1000); - break; - } + searchTerm.setVisibility(i == 1 ? View.VISIBLE : View.GONE); + javascript.setVisibility(i == 2 ? View.VISIBLE : View.GONE); - model.lastCheck = System.currentTimeMillis() - model.checkInterval; + 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; + } + } - 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(); - break; - } + @Override + public void onNothingSelected(AdapterView adapterView) {} + }); - setResult(RESULT_OK, new Intent() - .putExtra("model", model)); - finish(); - overridePendingTransition(R.anim.fade_out, R.anim.fade_out); + findViewById(R.id.doneBtn).setOnClickListener(this); + } + + @Override + public void onBackPressed() { + closeActivityWithReveal(); + } + + private void closeActivityWithReveal() { + if (isClosing) return; + isClosing = true; + final int fabSize = getIntent().getIntExtra("fab_size", toolbar.getMeasuredHeight()); + final int cx = + (int) getIntent().getFloatExtra("fab_x", rootLayout.getMeasuredWidth() / 2) + (fabSize / 2); + final int cy = + (int) getIntent().getFloatExtra("fab_y", rootLayout.getMeasuredHeight() / 2) + + toolbar.getMeasuredHeight() + + (fabSize / 2); + float initialRadius = Math.max(cx, cy); + + final Animator circularReveal = + ViewAnimationUtils.createCircularReveal(rootLayout, cx, cy, initialRadius, 0); + circularReveal.setDuration(300); + circularReveal.setInterpolator(new AccelerateInterpolator()); + circularReveal.addListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + rootLayout.setVisibility(View.INVISIBLE); + finish(); + overridePendingTransition(0, 0); + } + }); + + circularReveal.start(); + } + + private void circularRevealActivity() { + final int cx = rootLayout.getMeasuredWidth() / 2; + final int cy = rootLayout.getMeasuredHeight() / 2; + final float finalRadius = Math.max(cx, cy); + final Animator circularReveal = + ViewAnimationUtils.createCircularReveal(rootLayout, cx, cy, 0, finalRadius); + + circularReveal.setDuration(300); + circularReveal.setInterpolator(new DecelerateInterpolator()); + + rootLayout.setVisibility(View.VISIBLE); + circularReveal.start(); + } + + // Done button + @Override + public void onClick(View view) { + isClosing = true; + + ServerModel model = new ServerModel(); + model.name = inputName.getText().toString().trim(); + model.url = inputUrl.getText().toString().trim(); + model.status = ServerStatus.WAITING; + + if (model.name.isEmpty()) { + nameTiLayout.setError(getString(R.string.please_enter_name)); + isClosing = false; + return; + } else { + nameTiLayout.setError(null); } -} \ No newline at end of file + + if (model.url.isEmpty()) { + urlTiLayout.setError(getString(R.string.please_enter_url)); + isClosing = false; + return; + } else { + urlTiLayout.setError(null); + if (!Patterns.WEB_URL.matcher(model.url).find()) { + urlTiLayout.setError(getString(R.string.please_enter_valid_url)); + isClosing = false; + return; + } else { + final Uri uri = Uri.parse(model.url); + if (uri.getScheme() == null) model.url = "http://" + model.url; + } + } + + String intervalStr = inputInterval.getText().toString().trim(); + if (intervalStr.isEmpty()) intervalStr = "0"; + model.checkInterval = Integer.parseInt(intervalStr); + + switch (spinnerInterval.getSelectedItemPosition()) { + case 0: // minutes + model.checkInterval *= (60 * 1000); + break; + case 1: // hours + model.checkInterval *= (60 * 60 * 1000); + break; + case 2: // days + model.checkInterval *= (60 * 60 * 24 * 1000); + break; + default: // weeks + model.checkInterval *= (60 * 60 * 24 * 7 * 1000); + break; + } + + 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(); + break; + } + + setResult(RESULT_OK, new Intent().putExtra("model", model)); + finish(); + overridePendingTransition(R.anim.fade_out, R.anim.fade_out); + } +} diff --git a/app/src/main/java/com/afollestad/nocknock/ui/MainActivity.java b/app/src/main/java/com/afollestad/nocknock/ui/MainActivity.java index 88f8ba8..1e84a40 100644 --- a/app/src/main/java/com/afollestad/nocknock/ui/MainActivity.java +++ b/app/src/main/java/com/afollestad/nocknock/ui/MainActivity.java @@ -27,7 +27,6 @@ import android.view.MenuItem; import android.view.View; import android.view.animation.PathInterpolator; import android.widget.TextView; - import com.afollestad.bridge.Bridge; import com.afollestad.inquiry.Inquiry; import com.afollestad.materialdialogs.MaterialDialog; @@ -41,286 +40,299 @@ import com.afollestad.nocknock.util.AlarmUtil; import com.afollestad.nocknock.util.MathUtil; import com.afollestad.nocknock.views.DividerItemDecoration; -public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener, View.OnClickListener, ServerAdapter.ClickListener { +public class MainActivity extends AppCompatActivity + implements SwipeRefreshLayout.OnRefreshListener, + View.OnClickListener, + ServerAdapter.ClickListener { - 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_OLD = "sites"; - public final static String SITES_TABLE_NAME = "site_models"; + private static final int ADD_SITE_RQ = 6969; + private static final int VIEW_SITE_RQ = 6923; + public static final String DB_NAME = "nock_nock"; + public static final String SITES_TABLE_NAME_OLD = "sites"; + public static final String SITES_TABLE_NAME = "site_models"; - private FloatingActionButton mFab; - private RecyclerView mList; - private ServerAdapter mAdapter; - private TextView mEmptyText; - private SwipeRefreshLayout mRefreshLayout; + private FloatingActionButton mFab; + private RecyclerView mList; + private ServerAdapter mAdapter; + private TextView mEmptyText; + private SwipeRefreshLayout mRefreshLayout; - private ObjectAnimator mFabAnimator; - private float mOrigFabX; - private float mOrigFabY; + private ObjectAnimator mFabAnimator; + private float mOrigFabX; + private float mOrigFabY; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mReceiver = + new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - Log.v("MainActivity", "Received " + intent.getAction()); - if (CheckService.ACTION_RUNNING.equals(intent.getAction())) { - if (mRefreshLayout != null) - mRefreshLayout.setRefreshing(false); - } else { - final ServerModel model = (ServerModel) intent.getSerializableExtra("model"); - if (mAdapter != null && mList != null && model != null) { - mList.post(() -> mAdapter.update(model)); - } + Log.v("MainActivity", "Received " + intent.getAction()); + if (CheckService.ACTION_RUNNING.equals(intent.getAction())) { + if (mRefreshLayout != null) mRefreshLayout.setRefreshing(false); + } else { + final ServerModel model = (ServerModel) intent.getSerializableExtra("model"); + if (mAdapter != null && mList != null && model != null) { + mList.post(() -> mAdapter.update(model)); } + } } - }; + }; - @SuppressLint("CommitPrefEdits") - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); + @SuppressLint("CommitPrefEdits") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); - mAdapter = new ServerAdapter(this); - mEmptyText = (TextView) findViewById(R.id.emptyText); + mAdapter = new ServerAdapter(this); + mEmptyText = (TextView) findViewById(R.id.emptyText); - mList = (RecyclerView) findViewById(R.id.list); - mList.setLayoutManager(new LinearLayoutManager(this)); - mList.setAdapter(mAdapter); - mList.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); + mList = (RecyclerView) findViewById(R.id.list); + mList.setLayoutManager(new LinearLayoutManager(this)); + mList.setAdapter(mAdapter); + mList.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); - mRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout); - mRefreshLayout.setOnRefreshListener(this); - mRefreshLayout.setColorSchemeColors(ContextCompat.getColor(this, R.color.md_green), - ContextCompat.getColor(this, R.color.md_yellow), - ContextCompat.getColor(this, R.color.md_red)); + mRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout); + mRefreshLayout.setOnRefreshListener(this); + mRefreshLayout.setColorSchemeColors( + ContextCompat.getColor(this, R.color.md_green), + ContextCompat.getColor(this, R.color.md_yellow), + ContextCompat.getColor(this, R.color.md_red)); - mFab = (FloatingActionButton) findViewById(R.id.fab); - mFab.setOnClickListener(this); + mFab = (FloatingActionButton) findViewById(R.id.fab); + mFab.setOnClickListener(this); - Inquiry.newInstance(this, DB_NAME).build(); - Bridge.config() - .defaultHeader("User-Agent", getString(R.string.app_name) + " (Android)"); + 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(); + 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() { + if (mAdapter.getItemCount() == 0) return; + final SharedPreferences pr = PreferenceManager.getDefaultSharedPreferences(this); + if (pr.getBoolean("shown_swipe_refresh_tutorial", false)) return; + + mFab.hide(); + final View tutorialView = findViewById(R.id.swipeRefreshTutorial); + tutorialView.setVisibility(View.VISIBLE); + tutorialView.setAlpha(0f); + tutorialView.animate().cancel(); + tutorialView.animate().setDuration(300).alpha(1f).start(); + + findViewById(R.id.understoodBtn) + .setOnClickListener( + view -> { + view.setOnClickListener(null); + findViewById(R.id.swipeRefreshTutorial).setVisibility(View.GONE); + pr.edit().putBoolean("shown_swipe_refresh_tutorial", true).commit(); + mFab.show(); + }); + } + + @Override + protected void onResume() { + super.onResume(); + CheckService.isAppOpen(this, true); + + try { + final IntentFilter filter = new IntentFilter(); + filter.addAction(CheckService.ACTION_CHECK_UPDATE); + filter.addAction(CheckService.ACTION_RUNNING); + registerReceiver(mReceiver, filter); + } catch (Throwable t) { + t.printStackTrace(); } - private void showRefreshTutorial() { - if (mAdapter.getItemCount() == 0) return; - final SharedPreferences pr = PreferenceManager.getDefaultSharedPreferences(this); - if (pr.getBoolean("shown_swipe_refresh_tutorial", false)) return; + refreshModels(); + } - mFab.hide(); - final View tutorialView = findViewById(R.id.swipeRefreshTutorial); - tutorialView.setVisibility(View.VISIBLE); - tutorialView.setAlpha(0f); - tutorialView.animate().cancel(); - tutorialView.animate().setDuration(300).alpha(1f).start(); + @Override + protected void onPause() { + super.onPause(); + CheckService.isAppOpen(this, false); - findViewById(R.id.understoodBtn).setOnClickListener(view -> { - view.setOnClickListener(null); - findViewById(R.id.swipeRefreshTutorial).setVisibility(View.GONE); - pr.edit().putBoolean("shown_swipe_refresh_tutorial", true).commit(); - mFab.show(); + if (isFinishing()) { + Inquiry.destroy(this); + } + + NotificationManagerCompat.from(this).cancel(CheckService.NOTI_ID); + try { + unregisterReceiver(mReceiver); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + private void refreshModels() { + mAdapter.clear(); + mEmptyText.setVisibility(View.VISIBLE); + Inquiry.get(this).selectFrom(SITES_TABLE_NAME, ServerModel.class).all(this::setModels); + } + + private void setModels(ServerModel[] models) { + mAdapter.set(models); + mEmptyText.setVisibility(mAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); + AlarmUtil.setSiteChecks(this, models); + showRefreshTutorial(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_main, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.about) { + AboutDialog.show(this); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onRefresh() { + if (CheckService.isRunning(this)) { + mRefreshLayout.setRefreshing(false); + return; + } + startService(new Intent(this, CheckService.class)); + } + + // FAB clicked + @Override + public void onClick(View view) { + mOrigFabX = mFab.getX(); + mOrigFabY = mFab.getY(); + final Path curve = MathUtil.bezierCurve(mFab, mList); + if (mFabAnimator != null) mFabAnimator.cancel(); + mFabAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, curve); + mFabAnimator.setInterpolator(new PathInterpolator(.5f, .5f)); + mFabAnimator.setDuration(300); + mFabAnimator.addListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + startActivityForResult( + new Intent(MainActivity.this, AddSiteActivity.class) + .putExtra("fab_x", mOrigFabX) + .putExtra("fab_y", mOrigFabY) + .putExtra("fab_size", mFab.getMeasuredWidth()) + .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION), + ADD_SITE_RQ); + mFab.postDelayed( + () -> { + mFab.setX(mOrigFabX); + mFab.setY(mOrigFabY); + }, + 600); + } }); - } + mFabAnimator.start(); + } - @Override - protected void onResume() { - super.onResume(); - CheckService.isAppOpen(this, true); - - try { - final IntentFilter filter = new IntentFilter(); - filter.addAction(CheckService.ACTION_CHECK_UPDATE); - filter.addAction(CheckService.ACTION_RUNNING); - registerReceiver(mReceiver, filter); - } catch (Throwable t) { - t.printStackTrace(); - } - - refreshModels(); - } - - @Override - protected void onPause() { - super.onPause(); - CheckService.isAppOpen(this, false); - - if (isFinishing()) { - Inquiry.destroy(this); - } - - NotificationManagerCompat.from(this).cancel(CheckService.NOTI_ID); - try { - unregisterReceiver(mReceiver); - } catch (Throwable t) { - t.printStackTrace(); - } - } - - private void refreshModels() { - mAdapter.clear(); - mEmptyText.setVisibility(View.VISIBLE); + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK) { + final ServerModel model = (ServerModel) data.getSerializableExtra("model"); + if (requestCode == ADD_SITE_RQ) { + mAdapter.add(model); + mEmptyText.setVisibility(View.GONE); Inquiry.get(this) - .selectFrom(SITES_TABLE_NAME, ServerModel.class) - .all(this::setModels); + .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) { + mAdapter.update(model); + AlarmUtil.setSiteChecks(MainActivity.this, model); + checkSite(MainActivity.this, model); + } } + } - private void setModels(ServerModel[] models) { - mAdapter.set(models); - mEmptyText.setVisibility(mAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); - AlarmUtil.setSiteChecks(this, models); - showRefreshTutorial(); - } + public static void removeSite( + final Context context, final ServerModel model, final Runnable onRemoved) { + new MaterialDialog.Builder(context) + .title(R.string.remove_site) + .content(Html.fromHtml(context.getString(R.string.remove_site_prompt, model.name))) + .positiveText(R.string.remove) + .negativeText(android.R.string.cancel) + .onPositive( + (dialog, which) -> { + AlarmUtil.cancelSiteChecks(context, model); + final NotificationManagerCompat nm = NotificationManagerCompat.from(context); + nm.cancel(model.url, CheckService.NOTI_ID); + //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(); + } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_main, menu); - return super.onCreateOptionsMenu(menu); - } + public static void checkSite(Context context, ServerModel model) { + context.startService( + new Intent(context, CheckService.class).putExtra(CheckService.MODEL_ID, model.id)); + } - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.about) { - AboutDialog.show(this); - return true; - } - return super.onOptionsItemSelected(item); + @Override + public void onSiteSelected(final int index, final ServerModel model, boolean longClick) { + if (longClick) { + new MaterialDialog.Builder(this) + .title(R.string.options) + .items(R.array.site_long_options) + .negativeText(android.R.string.cancel) + .itemsCallback( + (dialog, itemView, which, text) -> { + if (which == 0) { + checkSite(MainActivity.this, model); + } else { + removeSite( + MainActivity.this, + model, + () -> { + mAdapter.remove(index); + mEmptyText.setVisibility( + mAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); + }); + } + }) + .show(); + } else { + startActivityForResult( + new Intent(this, ViewSiteActivity.class).putExtra("model", model), + VIEW_SITE_RQ, + ActivityOptions.makeSceneTransitionAnimation(this).toBundle()); } - - @Override - public void onRefresh() { - if (CheckService.isRunning(this)) { - mRefreshLayout.setRefreshing(false); - return; - } - startService(new Intent(this, CheckService.class)); - } - - // FAB clicked - @Override - public void onClick(View view) { - mOrigFabX = mFab.getX(); - mOrigFabY = mFab.getY(); - final Path curve = MathUtil.bezierCurve(mFab, mList); - if (mFabAnimator != null) - mFabAnimator.cancel(); - mFabAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, curve); - mFabAnimator.setInterpolator(new PathInterpolator(.5f, .5f)); - mFabAnimator.setDuration(300); - mFabAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - startActivityForResult(new Intent(MainActivity.this, AddSiteActivity.class) - .putExtra("fab_x", mOrigFabX) - .putExtra("fab_y", mOrigFabY) - .putExtra("fab_size", mFab.getMeasuredWidth()) - .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION), ADD_SITE_RQ); - mFab.postDelayed(() -> { - mFab.setX(mOrigFabX); - mFab.setY(mOrigFabY); - }, 600); - } - }); - mFabAnimator.start(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == RESULT_OK) { - final ServerModel model = (ServerModel) data.getSerializableExtra("model"); - if (requestCode == ADD_SITE_RQ) { - mAdapter.add(model); - mEmptyText.setVisibility(View.GONE); - 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) { - 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) { - new MaterialDialog.Builder(context) - .title(R.string.remove_site) - .content(Html.fromHtml(context.getString(R.string.remove_site_prompt, model.name))) - .positiveText(R.string.remove) - .negativeText(android.R.string.cancel) - .onPositive((dialog, which) -> { - AlarmUtil.cancelSiteChecks(context, model); - final NotificationManagerCompat nm = NotificationManagerCompat.from(context); - nm.cancel(model.url, CheckService.NOTI_ID); - //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(); - } - - public static void checkSite(Context context, ServerModel model) { - context.startService(new Intent(context, CheckService.class) - .putExtra(CheckService.MODEL_ID, model.id)); - } - - @Override - public void onSiteSelected(final int index, final ServerModel model, boolean longClick) { - if (longClick) { - new MaterialDialog.Builder(this) - .title(R.string.options) - .items(R.array.site_long_options) - .negativeText(android.R.string.cancel) - .itemsCallback((dialog, itemView, which, text) -> { - if (which == 0) { - checkSite(MainActivity.this, model); - } else { - removeSite(MainActivity.this, model, () -> { - mAdapter.remove(index); - mEmptyText.setVisibility(mAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); - }); - } - }).show(); - } else { - startActivityForResult(new Intent(this, ViewSiteActivity.class) - .putExtra("model", model), VIEW_SITE_RQ, - ActivityOptions.makeSceneTransitionAnimation(this).toBundle()); - } - } -} \ No newline at end of file + } +} diff --git a/app/src/main/java/com/afollestad/nocknock/ui/ViewSiteActivity.java b/app/src/main/java/com/afollestad/nocknock/ui/ViewSiteActivity.java index 5edbef3..71d4bc5 100644 --- a/app/src/main/java/com/afollestad/nocknock/ui/ViewSiteActivity.java +++ b/app/src/main/java/com/afollestad/nocknock/ui/ViewSiteActivity.java @@ -19,7 +19,6 @@ 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; @@ -29,312 +28,333 @@ import com.afollestad.nocknock.api.ValidationMode; import com.afollestad.nocknock.services.CheckService; import com.afollestad.nocknock.util.TimeUtil; import com.afollestad.nocknock.views.StatusImageView; - import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -/** - * @author Aidan Follestad (afollestad) - */ -public class ViewSiteActivity extends AppCompatActivity implements View.OnClickListener, Toolbar.OnMenuItemClickListener { +/** @author Aidan Follestad (afollestad) */ +public class ViewSiteActivity extends AppCompatActivity + implements View.OnClickListener, Toolbar.OnMenuItemClickListener { - private StatusImageView iconStatus; - private EditText inputName; - private EditText inputUrl; - private EditText inputCheckInterval; - private Spinner checkIntervalSpinner; - private TextView textLastCheckResult; - private TextView textNextCheck; - private TextView textUrlWarning; - private Spinner responseValidationSpinner; + private StatusImageView iconStatus; + private EditText inputName; + private EditText inputUrl; + private EditText inputCheckInterval; + private Spinner checkIntervalSpinner; + private TextView textLastCheckResult; + private TextView textNextCheck; + private TextView textUrlWarning; + private Spinner responseValidationSpinner; - private ServerModel mModel; + private ServerModel mModel; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mReceiver = + new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - Log.v("ViewSiteActivity", "Received " + intent.getAction()); - final ServerModel model = (ServerModel) intent.getSerializableExtra("model"); - if (model != null) { - mModel = model; - update(); - } - } - }; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_viewsite); - - final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); - toolbar.setNavigationOnClickListener(view -> finish()); - toolbar.inflateMenu(R.menu.menu_viewsite); - toolbar.setOnMenuItemClickListener(this); - - iconStatus = (StatusImageView) findViewById(R.id.iconStatus); - inputName = (EditText) findViewById(R.id.inputName); - inputUrl = (EditText) findViewById(R.id.inputUrl); - textUrlWarning = (TextView) findViewById(R.id.textUrlWarning); - inputCheckInterval = (EditText) findViewById(R.id.checkIntervalInput); - 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 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) -> { - if (!hasFocus) { - final String inputStr = inputUrl.getText().toString().trim(); - if (inputStr.isEmpty()) return; - final Uri uri = Uri.parse(inputStr); - if (uri.getScheme() == null) { - inputUrl.setText("http://" + inputStr); - textUrlWarning.setVisibility(View.GONE); - } else if (!"http".equals(uri.getScheme()) && !"https".equals(uri.getScheme())) { - textUrlWarning.setVisibility(View.VISIBLE); - textUrlWarning.setText(R.string.warning_http_url); - } else { - textUrlWarning.setVisibility(View.GONE); - } - } - }); - - ArrayAdapter 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(); - - Bridge.config() - .defaultHeader("User-Agent", getString(R.string.app_name) + " (Android)"); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - if (intent != null && intent.hasExtra("model")) { - mModel = (ServerModel) intent.getSerializableExtra("model"); + Log.v("ViewSiteActivity", "Received " + intent.getAction()); + final ServerModel model = (ServerModel) intent.getSerializableExtra("model"); + if (model != null) { + mModel = model; update(); + } } - } + }; - @SuppressLint({"SetTextI18n", "SwitchIntDef"}) - private void update() { - final SimpleDateFormat df = new SimpleDateFormat("MMMM dd, hh:mm:ss a", Locale.getDefault()); + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_viewsite); - iconStatus.setStatus(mModel.status); - inputName.setText(mModel.name); - inputUrl.setText(mModel.url); + final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + toolbar.setNavigationOnClickListener(view -> finish()); + toolbar.inflateMenu(R.menu.menu_viewsite); + toolbar.setOnMenuItemClickListener(this); - if (mModel.lastCheck == 0) { - textLastCheckResult.setText(R.string.none); - } else { - switch (mModel.status) { - case ServerStatus.CHECKING: - textLastCheckResult.setText(R.string.checking_status); - break; - case ServerStatus.ERROR: - textLastCheckResult.setText(mModel.reason); - break; - case ServerStatus.OK: - textLastCheckResult.setText(R.string.everything_checks_out); - break; - case ServerStatus.WAITING: - textLastCheckResult.setText(R.string.waiting); - break; - } - } + iconStatus = (StatusImageView) findViewById(R.id.iconStatus); + inputName = (EditText) findViewById(R.id.inputName); + inputUrl = (EditText) findViewById(R.id.inputUrl); + textUrlWarning = (TextView) findViewById(R.id.textUrlWarning); + inputCheckInterval = (EditText) findViewById(R.id.checkIntervalInput); + checkIntervalSpinner = (Spinner) findViewById(R.id.checkIntervalSpinner); + textLastCheckResult = (TextView) findViewById(R.id.textLastCheckResult); + textNextCheck = (TextView) findViewById(R.id.textNextCheck); + responseValidationSpinner = (Spinner) findViewById(R.id.responseValidationMode); - if (mModel.checkInterval == 0) { - textNextCheck.setText(R.string.none_turned_off); - inputCheckInterval.setText(""); - checkIntervalSpinner.setSelection(0); - } else { - long lastCheck = mModel.lastCheck; - if (lastCheck == 0) lastCheck = System.currentTimeMillis(); - textNextCheck.setText(df.format(new Date(lastCheck + mModel.checkInterval))); + ArrayAdapter 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); - if (mModel.checkInterval >= TimeUtil.WEEK) { - inputCheckInterval.setText(Integer.toString((int) Math.ceil(((float) mModel.checkInterval / (float) TimeUtil.WEEK)))); - checkIntervalSpinner.setSelection(3); - } else if (mModel.checkInterval >= TimeUtil.DAY) { - inputCheckInterval.setText(Integer.toString((int) Math.ceil(((float) mModel.checkInterval / (float) TimeUtil.DAY)))); - checkIntervalSpinner.setSelection(2); - } else if (mModel.checkInterval >= TimeUtil.HOUR) { - inputCheckInterval.setText(Integer.toString((int) Math.ceil(((float) mModel.checkInterval / (float) TimeUtil.HOUR)))); - checkIntervalSpinner.setSelection(1); - } else if (mModel.checkInterval >= TimeUtil.MINUTE) { - inputCheckInterval.setText(Integer.toString((int) Math.ceil(((float) mModel.checkInterval / (float) TimeUtil.MINUTE)))); - checkIntervalSpinner.setSelection(0); + inputUrl.setOnFocusChangeListener( + (view, hasFocus) -> { + if (!hasFocus) { + final String inputStr = inputUrl.getText().toString().trim(); + if (inputStr.isEmpty()) return; + final Uri uri = Uri.parse(inputStr); + if (uri.getScheme() == null) { + inputUrl.setText("http://" + inputStr); + textUrlWarning.setVisibility(View.GONE); + } else if (!"http".equals(uri.getScheme()) && !"https".equals(uri.getScheme())) { + textUrlWarning.setVisibility(View.VISIBLE); + textUrlWarning.setText(R.string.warning_http_url); } else { - inputCheckInterval.setText("0"); - checkIntervalSpinner.setSelection(0); + textUrlWarning.setVisibility(View.GONE); } - } + } + }); - responseValidationSpinner.setSelection(mModel.validationMode - 1); - switch (mModel.validationMode) { - case ValidationMode.TERM_SEARCH: - ((TextView) findViewById(R.id.responseValidationSearchTerm)).setText(mModel.validationContent); + ArrayAdapter 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 ValidationMode.JAVASCRIPT: - ((TextView) findViewById(R.id.responseValidationScriptInput)).setText(mModel.validationContent); + case 1: + modeDesc.setText(R.string.validation_mode_term_desc); + break; + case 2: + modeDesc.setText(R.string.validation_mode_javascript_desc); break; - } - - findViewById(R.id.doneBtn).setOnClickListener(this); - } - - @Override - protected void onResume() { - super.onResume(); - try { - final IntentFilter filter = new IntentFilter(); - filter.addAction(CheckService.ACTION_CHECK_UPDATE); - // filter.addAction(CheckService.ACTION_RUNNING); - registerReceiver(mReceiver, filter); - } catch (Throwable t) { - t.printStackTrace(); - } - } - - @Override - protected void onPause() { - super.onPause(); - try { - unregisterReceiver(mReceiver); - } catch (Throwable t) { - t.printStackTrace(); - } - } - - private void performSave(boolean withValidation) { - mModel.name = inputName.getText().toString().trim(); - mModel.url = inputUrl.getText().toString().trim(); - mModel.status = ServerStatus.WAITING; - - if (withValidation && mModel.name.isEmpty()) { - inputName.setError(getString(R.string.please_enter_name)); - return; - } else { - inputName.setError(null); - } - - if (withValidation && mModel.url.isEmpty()) { - inputUrl.setError(getString(R.string.please_enter_url)); - return; - } else { - inputUrl.setError(null); - if (withValidation && !Patterns.WEB_URL.matcher(mModel.url).find()) { - inputUrl.setError(getString(R.string.please_enter_valid_url)); - return; - } else { - final Uri uri = Uri.parse(mModel.url); - if (uri.getScheme() == null) - mModel.url = "http://" + mModel.url; } - } + } - String intervalStr = inputCheckInterval.getText().toString().trim(); - if (intervalStr.isEmpty()) intervalStr = "0"; - mModel.checkInterval = Integer.parseInt(intervalStr); + @Override + public void onNothingSelected(AdapterView adapterView) {} + }); - switch (checkIntervalSpinner.getSelectedItemPosition()) { - case 0: // minutes - mModel.checkInterval *= (60 * 1000); - break; - case 1: // hours - mModel.checkInterval *= (60 * 60 * 1000); - break; - case 2: // days - mModel.checkInterval *= (60 * 60 * 24 * 1000); - break; - default: // weeks - mModel.checkInterval *= (60 * 60 * 24 * 7 * 1000); - break; - } + mModel = (ServerModel) getIntent().getSerializableExtra("model"); + update(); - mModel.lastCheck = System.currentTimeMillis() - mModel.checkInterval; + Bridge.config().defaultHeader("User-Agent", getString(R.string.app_name) + " (Android)"); + } - 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(); - break; - } + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + if (intent != null && intent.hasExtra("model")) { + mModel = (ServerModel) intent.getSerializableExtra("model"); + update(); + } + } - 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(); + @SuppressLint({"SetTextI18n", "SwitchIntDef"}) + private void update() { + final SimpleDateFormat df = new SimpleDateFormat("MMMM dd, hh:mm:ss a", Locale.getDefault()); + + iconStatus.setStatus(mModel.status); + inputName.setText(mModel.name); + inputUrl.setText(mModel.url); + + if (mModel.lastCheck == 0) { + textLastCheckResult.setText(R.string.none); + } else { + switch (mModel.status) { + case ServerStatus.CHECKING: + textLastCheckResult.setText(R.string.checking_status); + break; + case ServerStatus.ERROR: + textLastCheckResult.setText(mModel.reason); + break; + case ServerStatus.OK: + textLastCheckResult.setText(R.string.everything_checks_out); + break; + case ServerStatus.WAITING: + textLastCheckResult.setText(R.string.waiting); + break; + } } - // Save button - @Override - public void onClick(View view) { - performSave(true); - setResult(RESULT_OK, new Intent().putExtra("model", mModel)); - finish(); + if (mModel.checkInterval == 0) { + textNextCheck.setText(R.string.none_turned_off); + inputCheckInterval.setText(""); + checkIntervalSpinner.setSelection(0); + } else { + long lastCheck = mModel.lastCheck; + if (lastCheck == 0) lastCheck = System.currentTimeMillis(); + textNextCheck.setText(df.format(new Date(lastCheck + mModel.checkInterval))); + + if (mModel.checkInterval >= TimeUtil.WEEK) { + inputCheckInterval.setText( + Integer.toString( + (int) Math.ceil(((float) mModel.checkInterval / (float) TimeUtil.WEEK)))); + checkIntervalSpinner.setSelection(3); + } else if (mModel.checkInterval >= TimeUtil.DAY) { + inputCheckInterval.setText( + Integer.toString( + (int) Math.ceil(((float) mModel.checkInterval / (float) TimeUtil.DAY)))); + checkIntervalSpinner.setSelection(2); + } else if (mModel.checkInterval >= TimeUtil.HOUR) { + inputCheckInterval.setText( + Integer.toString( + (int) Math.ceil(((float) mModel.checkInterval / (float) TimeUtil.HOUR)))); + checkIntervalSpinner.setSelection(1); + } else if (mModel.checkInterval >= TimeUtil.MINUTE) { + inputCheckInterval.setText( + Integer.toString( + (int) Math.ceil(((float) mModel.checkInterval / (float) TimeUtil.MINUTE)))); + checkIntervalSpinner.setSelection(0); + } else { + inputCheckInterval.setText("0"); + checkIntervalSpinner.setSelection(0); + } } - @Override - 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, this::finish); - return true; - } - return false; + 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); + } + + @Override + protected void onResume() { + super.onResume(); + try { + final IntentFilter filter = new IntentFilter(); + filter.addAction(CheckService.ACTION_CHECK_UPDATE); + // filter.addAction(CheckService.ACTION_RUNNING); + registerReceiver(mReceiver, filter); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + @Override + protected void onPause() { + super.onPause(); + try { + unregisterReceiver(mReceiver); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + private void performSave(boolean withValidation) { + mModel.name = inputName.getText().toString().trim(); + mModel.url = inputUrl.getText().toString().trim(); + mModel.status = ServerStatus.WAITING; + + if (withValidation && mModel.name.isEmpty()) { + inputName.setError(getString(R.string.please_enter_name)); + return; + } else { + inputName.setError(null); + } + + if (withValidation && mModel.url.isEmpty()) { + inputUrl.setError(getString(R.string.please_enter_url)); + return; + } else { + inputUrl.setError(null); + if (withValidation && !Patterns.WEB_URL.matcher(mModel.url).find()) { + inputUrl.setError(getString(R.string.please_enter_valid_url)); + return; + } else { + final Uri uri = Uri.parse(mModel.url); + if (uri.getScheme() == null) mModel.url = "http://" + mModel.url; + } + } + + String intervalStr = inputCheckInterval.getText().toString().trim(); + if (intervalStr.isEmpty()) intervalStr = "0"; + mModel.checkInterval = Integer.parseInt(intervalStr); + + switch (checkIntervalSpinner.getSelectedItemPosition()) { + case 0: // minutes + mModel.checkInterval *= (60 * 1000); + break; + case 1: // hours + mModel.checkInterval *= (60 * 60 * 1000); + break; + case 2: // days + mModel.checkInterval *= (60 * 60 * 24 * 1000); + break; + default: // weeks + mModel.checkInterval *= (60 * 60 * 24 * 7 * 1000); + break; + } + + 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(); + 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(); + } + + @Override + 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, this::finish); + return true; + } + return false; + } } diff --git a/app/src/main/java/com/afollestad/nocknock/util/AlarmUtil.java b/app/src/main/java/com/afollestad/nocknock/util/AlarmUtil.java index 7effdb4..a527898 100644 --- a/app/src/main/java/com/afollestad/nocknock/util/AlarmUtil.java +++ b/app/src/main/java/com/afollestad/nocknock/util/AlarmUtil.java @@ -5,55 +5,57 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.util.Log; - import com.afollestad.nocknock.api.ServerModel; import com.afollestad.nocknock.services.CheckService; - import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -/** - * @author Aidan Follestad (afollestad) - */ +/** @author Aidan Follestad (afollestad) */ public class AlarmUtil { - private final static int BASE_RQC = 69; + private static final int BASE_RQC = 69; - public static PendingIntent getSiteIntent(Context context, ServerModel site) { - return PendingIntent.getService(context, - BASE_RQC + (int) site.id, - new Intent(context, CheckService.class) - .putExtra(CheckService.MODEL_ID, site.id), - PendingIntent.FLAG_UPDATE_CURRENT); - } + public static PendingIntent getSiteIntent(Context context, ServerModel site) { + return PendingIntent.getService( + context, + BASE_RQC + (int) site.id, + new Intent(context, CheckService.class).putExtra(CheckService.MODEL_ID, site.id), + PendingIntent.FLAG_UPDATE_CURRENT); + } - private static AlarmManager am(Context context) { - return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - } + private static AlarmManager am(Context context) { + return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + } - public static void cancelSiteChecks(Context context, ServerModel site) { - PendingIntent pi = getSiteIntent(context, site); - am(context).cancel(pi); - } + public static void cancelSiteChecks(Context context, ServerModel site) { + PendingIntent pi = getSiteIntent(context, site); + am(context).cancel(pi); + } - public static void setSiteChecks(Context context, ServerModel site) { - cancelSiteChecks(context, site); - if (site.checkInterval <= 0) return; - if (site.lastCheck <= 0) - site.lastCheck = System.currentTimeMillis(); - final long nextCheck = site.lastCheck + site.checkInterval; - final AlarmManager aMgr = am(context); - final PendingIntent serviceIntent = getSiteIntent(context, site); - aMgr.setRepeating(AlarmManager.RTC_WAKEUP, nextCheck, site.checkInterval, serviceIntent); - final SimpleDateFormat df = new SimpleDateFormat("EEE MMM dd hh:mm:ssa z yyyy", Locale.getDefault()); - Log.d("AlarmUtil", String.format(Locale.getDefault(), "Set site check alarm for %s (%s), check interval: %d, next check: %s", - site.name, site.url, site.checkInterval, df.format(new Date(nextCheck)))); - } + public static void setSiteChecks(Context context, ServerModel site) { + cancelSiteChecks(context, site); + if (site.checkInterval <= 0) return; + if (site.lastCheck <= 0) site.lastCheck = System.currentTimeMillis(); + final long nextCheck = site.lastCheck + site.checkInterval; + final AlarmManager aMgr = am(context); + final PendingIntent serviceIntent = getSiteIntent(context, site); + aMgr.setRepeating(AlarmManager.RTC_WAKEUP, nextCheck, site.checkInterval, serviceIntent); + final SimpleDateFormat df = + new SimpleDateFormat("EEE MMM dd hh:mm:ssa z yyyy", Locale.getDefault()); + Log.d( + "AlarmUtil", + String.format( + Locale.getDefault(), + "Set site check alarm for %s (%s), check interval: %d, next check: %s", + site.name, + site.url, + site.checkInterval, + df.format(new Date(nextCheck)))); + } - public static void setSiteChecks(Context context, ServerModel[] sites) { - if (sites == null || sites.length == 0) return; - for (ServerModel site : sites) - setSiteChecks(context, site); - } -} \ No newline at end of file + public static void setSiteChecks(Context context, ServerModel[] sites) { + if (sites == null || sites.length == 0) return; + for (ServerModel site : sites) setSiteChecks(context, site); + } +} diff --git a/app/src/main/java/com/afollestad/nocknock/util/JsUtil.java b/app/src/main/java/com/afollestad/nocknock/util/JsUtil.java index 160927b..3c7c462 100644 --- a/app/src/main/java/com/afollestad/nocknock/util/JsUtil.java +++ b/app/src/main/java/com/afollestad/nocknock/util/JsUtil.java @@ -1,72 +1,68 @@ 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) - */ +/** @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", " ")); + 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(); + // 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(); + // 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); + // 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); + // 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(); + // 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; + } } - } - private JsUtil() { + Log.d("JsUtil", "Evaluated to " + message + " (" + success + "): " + code); + return !success ? message : null; + } finally { + Context.exit(); + } + } catch (EvaluatorException e) { + return e.getMessage(); } + } + + private JsUtil() {} } diff --git a/app/src/main/java/com/afollestad/nocknock/util/MathUtil.java b/app/src/main/java/com/afollestad/nocknock/util/MathUtil.java index 6cb885b..efe418b 100644 --- a/app/src/main/java/com/afollestad/nocknock/util/MathUtil.java +++ b/app/src/main/java/com/afollestad/nocknock/util/MathUtil.java @@ -4,29 +4,27 @@ import android.graphics.Path; import android.support.design.widget.FloatingActionButton; import android.view.View; -/** - * @author Aidan Follestad (afollestad) - */ +/** @author Aidan Follestad (afollestad) */ public final class MathUtil { - public static Path bezierCurve(FloatingActionButton fab, View rootView) { - final int fabCenterX = (int) (fab.getX() + fab.getMeasuredWidth() / 2); - final int fabCenterY = (int) (fab.getY() + fab.getMeasuredHeight() / 2); + public static Path bezierCurve(FloatingActionButton fab, View rootView) { + final int fabCenterX = (int) (fab.getX() + fab.getMeasuredWidth() / 2); + final int fabCenterY = (int) (fab.getY() + fab.getMeasuredHeight() / 2); - final int endCenterX = (rootView.getMeasuredWidth() / 2) - (fab.getMeasuredWidth() / 2); - final int endCenterY = (rootView.getMeasuredHeight() / 2) - (fab.getMeasuredHeight() / 2); + final int endCenterX = (rootView.getMeasuredWidth() / 2) - (fab.getMeasuredWidth() / 2); + final int endCenterY = (rootView.getMeasuredHeight() / 2) - (fab.getMeasuredHeight() / 2); - final int halfX = (fabCenterX - endCenterX) / 2; - final int halfY = (fabCenterY - endCenterY) / 2; - int mControlX = endCenterX + halfX; - int mControlY = endCenterY + halfY; - mControlY -= halfY; - mControlX += halfX; + final int halfX = (fabCenterX - endCenterX) / 2; + final int halfY = (fabCenterY - endCenterY) / 2; + int mControlX = endCenterX + halfX; + int mControlY = endCenterY + halfY; + mControlY -= halfY; + mControlX += halfX; - Path path = new Path(); - path.moveTo(fab.getX(), fab.getY()); - path.quadTo(mControlX, mControlY, endCenterX, endCenterY); + Path path = new Path(); + path.moveTo(fab.getX(), fab.getY()); + path.quadTo(mControlX, mControlY, endCenterX, endCenterY); - return path; - } -} \ No newline at end of file + return path; + } +} diff --git a/app/src/main/java/com/afollestad/nocknock/util/NetworkUtil.java b/app/src/main/java/com/afollestad/nocknock/util/NetworkUtil.java index 3680f26..c67e57a 100644 --- a/app/src/main/java/com/afollestad/nocknock/util/NetworkUtil.java +++ b/app/src/main/java/com/afollestad/nocknock/util/NetworkUtil.java @@ -4,15 +4,13 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; -/** - * @author Aidan Follestad (afollestad) - */ +/** @author Aidan Follestad (afollestad) */ public class NetworkUtil { - public static boolean hasInternet(Context context) { - final ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - final NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); - return activeNetwork != null && - activeNetwork.isConnectedOrConnecting(); - } -} \ No newline at end of file + public static boolean hasInternet(Context context) { + final ConnectivityManager cm = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + final NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); + return activeNetwork != null && activeNetwork.isConnectedOrConnecting(); + } +} diff --git a/app/src/main/java/com/afollestad/nocknock/util/TimeUtil.java b/app/src/main/java/com/afollestad/nocknock/util/TimeUtil.java index 3a65b73..bc0b604 100644 --- a/app/src/main/java/com/afollestad/nocknock/util/TimeUtil.java +++ b/app/src/main/java/com/afollestad/nocknock/util/TimeUtil.java @@ -1,32 +1,30 @@ package com.afollestad.nocknock.util; -/** - * @author Aidan Follestad (afollestad) - */ +/** @author Aidan Follestad (afollestad) */ public class TimeUtil { - public final static long SECOND = 1000; - public final static long MINUTE = SECOND * 60; - public final static long HOUR = MINUTE * 60; - public final static long DAY = HOUR * 24; - public final static long WEEK = DAY * 7; - public final static long MONTH = WEEK * 4; + public static final long SECOND = 1000; + public static final long MINUTE = SECOND * 60; + public static final long HOUR = MINUTE * 60; + public static final long DAY = HOUR * 24; + public static final long WEEK = DAY * 7; + public static final long MONTH = WEEK * 4; - public static String str(long duration) { - if (duration <= 0) { - return ""; - } else if (duration >= MONTH) { - return (int) Math.ceil(((float) duration / (float) MONTH)) + "mo"; - } else if (duration >= WEEK) { - return (int) Math.ceil(((float) duration / (float) WEEK)) + "w"; - } else if (duration >= DAY) { - return (int) Math.ceil(((float) duration / (float) DAY)) + "d"; - } else if (duration >= HOUR) { - return (int) Math.ceil(((float) duration / (float) HOUR)) + "h"; - } else if (duration >= MINUTE) { - return (int) Math.ceil(((float) duration / (float) MINUTE)) + "m"; - } else { - return "<1m"; - } + public static String str(long duration) { + if (duration <= 0) { + return ""; + } else if (duration >= MONTH) { + return (int) Math.ceil(((float) duration / (float) MONTH)) + "mo"; + } else if (duration >= WEEK) { + return (int) Math.ceil(((float) duration / (float) WEEK)) + "w"; + } else if (duration >= DAY) { + return (int) Math.ceil(((float) duration / (float) DAY)) + "d"; + } else if (duration >= HOUR) { + return (int) Math.ceil(((float) duration / (float) HOUR)) + "h"; + } else if (duration >= MINUTE) { + return (int) Math.ceil(((float) duration / (float) MINUTE)) + "m"; + } else { + return "<1m"; } + } } diff --git a/app/src/main/java/com/afollestad/nocknock/views/DividerItemDecoration.java b/app/src/main/java/com/afollestad/nocknock/views/DividerItemDecoration.java index cc4396a..5000d4c 100644 --- a/app/src/main/java/com/afollestad/nocknock/views/DividerItemDecoration.java +++ b/app/src/main/java/com/afollestad/nocknock/views/DividerItemDecoration.java @@ -26,79 +26,75 @@ import android.view.View; */ public class DividerItemDecoration extends RecyclerView.ItemDecoration { - private static final int[] ATTRS = new int[]{ - android.R.attr.listDivider - }; + private static final int[] ATTRS = new int[] {android.R.attr.listDivider}; - public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; + public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; - public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; + public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; - private Drawable mDivider; + private Drawable mDivider; - private int mOrientation; + private int mOrientation; - public DividerItemDecoration(Context context, int orientation) { - final TypedArray a = context.obtainStyledAttributes(ATTRS); - mDivider = a.getDrawable(0); - a.recycle(); - setOrientation(orientation); + public DividerItemDecoration(Context context, int orientation) { + final TypedArray a = context.obtainStyledAttributes(ATTRS); + mDivider = a.getDrawable(0); + a.recycle(); + setOrientation(orientation); + } + + public void setOrientation(int orientation) { + if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { + throw new IllegalArgumentException("invalid orientation"); } + mOrientation = orientation; + } - public void setOrientation(int orientation) { - if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { - throw new IllegalArgumentException("invalid orientation"); - } - mOrientation = orientation; + @Override + public void onDraw(Canvas c, RecyclerView parent) { + if (mOrientation == VERTICAL_LIST) { + drawVertical(c, parent); + } else { + drawHorizontal(c, parent); } + } - @Override - public void onDraw(Canvas c, RecyclerView parent) { - if (mOrientation == VERTICAL_LIST) { - drawVertical(c, parent); - } else { - drawHorizontal(c, parent); - } + public void drawVertical(Canvas c, RecyclerView parent) { + final int left = parent.getPaddingLeft(); + final int right = parent.getWidth() - parent.getPaddingRight(); + + final int childCount = parent.getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = parent.getChildAt(i); + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); + final int top = child.getBottom() + params.bottomMargin; + final int bottom = top + mDivider.getIntrinsicHeight(); + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(c); } + } - public void drawVertical(Canvas c, RecyclerView parent) { - final int left = parent.getPaddingLeft(); - final int right = parent.getWidth() - parent.getPaddingRight(); + public void drawHorizontal(Canvas c, RecyclerView parent) { + final int top = parent.getPaddingTop(); + final int bottom = parent.getHeight() - parent.getPaddingBottom(); - final int childCount = parent.getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = parent.getChildAt(i); - final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child - .getLayoutParams(); - final int top = child.getBottom() + params.bottomMargin; - final int bottom = top + mDivider.getIntrinsicHeight(); - mDivider.setBounds(left, top, right, bottom); - mDivider.draw(c); - } + final int childCount = parent.getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = parent.getChildAt(i); + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); + final int left = child.getRight() + params.rightMargin; + final int right = left + mDivider.getIntrinsicHeight(); + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(c); } + } - public void drawHorizontal(Canvas c, RecyclerView parent) { - final int top = parent.getPaddingTop(); - final int bottom = parent.getHeight() - parent.getPaddingBottom(); - - final int childCount = parent.getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = parent.getChildAt(i); - final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child - .getLayoutParams(); - final int left = child.getRight() + params.rightMargin; - final int right = left + mDivider.getIntrinsicHeight(); - mDivider.setBounds(left, top, right, bottom); - mDivider.draw(c); - } + @Override + public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { + if (mOrientation == VERTICAL_LIST) { + outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); + } else { + outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } - - @Override - public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { - if (mOrientation == VERTICAL_LIST) { - outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); - } else { - outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); - } - } -} \ No newline at end of file + } +} diff --git a/app/src/main/java/com/afollestad/nocknock/views/StatusImageView.java b/app/src/main/java/com/afollestad/nocknock/views/StatusImageView.java index ac8cf13..4aa41a7 100644 --- a/app/src/main/java/com/afollestad/nocknock/views/StatusImageView.java +++ b/app/src/main/java/com/afollestad/nocknock/views/StatusImageView.java @@ -3,45 +3,42 @@ package com.afollestad.nocknock.views; import android.content.Context; import android.util.AttributeSet; import android.widget.ImageView; - import com.afollestad.nocknock.R; import com.afollestad.nocknock.api.ServerStatus; -/** - * @author Aidan Follestad (afollestad) - */ +/** @author Aidan Follestad (afollestad) */ public class StatusImageView extends ImageView { - public StatusImageView(Context context) { - super(context); - setStatus(ServerStatus.OK); - } + public StatusImageView(Context context) { + super(context); + setStatus(ServerStatus.OK); + } - public StatusImageView(Context context, AttributeSet attrs) { - super(context, attrs); - setStatus(ServerStatus.OK); - } + public StatusImageView(Context context, AttributeSet attrs) { + super(context, attrs); + setStatus(ServerStatus.OK); + } - public StatusImageView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - setStatus(ServerStatus.OK); - } + public StatusImageView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setStatus(ServerStatus.OK); + } - public void setStatus(@ServerStatus.Enum int status) { - switch (status) { - case ServerStatus.CHECKING: - case ServerStatus.WAITING: - setImageResource(R.drawable.status_progress); - setBackgroundResource(R.drawable.yellow_circle); - break; - case ServerStatus.ERROR: - setImageResource(R.drawable.status_error); - setBackgroundResource(R.drawable.red_circle); - break; - case ServerStatus.OK: - setImageResource(R.drawable.status_ok); - setBackgroundResource(R.drawable.green_circle); - break; - } + public void setStatus(@ServerStatus.Enum int status) { + switch (status) { + case ServerStatus.CHECKING: + case ServerStatus.WAITING: + setImageResource(R.drawable.status_progress); + setBackgroundResource(R.drawable.yellow_circle); + break; + case ServerStatus.ERROR: + setImageResource(R.drawable.status_error); + setBackgroundResource(R.drawable.red_circle); + break; + case ServerStatus.OK: + setImageResource(R.drawable.status_ok); + setBackgroundResource(R.drawable.green_circle); + break; } + } } diff --git a/build.gradle b/build.gradle index 75c86f6..d68c028 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,14 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. +apply from: './dependencies.gradle' buildscript { + apply from: './dependencies.gradle' + repositories { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.3' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files + classpath 'com.android.tools.build:gradle:' + versions.gradlePlugin + classpath "com.diffplug.spotless:spotless-plugin-gradle:" + versions.spotlessPlugin } } @@ -17,6 +17,22 @@ allprojects { jcenter() maven { url "https://jitpack.io" } } + + buildscript { + repositories { + maven { url "https://plugins.gradle.org/m2/" } + } + } + apply plugin: "com.diffplug.gradle.spotless" + spotless { + java { + target "**/*.java" + trimTrailingWhitespace() + removeUnusedImports() + googleJavaFormat() + endWithNewline() + } + } } task clean(type: Delete) { diff --git a/dependencies.gradle b/dependencies.gradle new file mode 100644 index 0000000..2ddd7c7 --- /dev/null +++ b/dependencies.gradle @@ -0,0 +1,13 @@ +ext.versions = [ + minSdk : 21, + compileSdk : 26, + buildTools : '26.0.0', + publishVersion : '0.1.3.1', + publishVersionCode: 14, + gradlePlugin : '2.3.2', + spotlessPlugin : '3.4.0', + supportLib : '25.3.1', + materialDialogs : '0.9.4.5', + bridge : '5.1.2', + inquiry : '5.0.0' +] \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cf2d737..41f2737 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip