mirror of
https://github.com/afollestad/nock-nock.git
synced 2025-04-20 19:45:17 +00:00
WIP use custom fonts, cleanup layouts, etc.
This commit is contained in:
parent
77a98b161b
commit
ef73245831
32 changed files with 336 additions and 270 deletions
|
@ -52,6 +52,9 @@
|
|||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<meta-data
|
||||
android:name="preloaded_fonts"
|
||||
android:resource="@array/preloaded_fonts"/>
|
||||
|
||||
</application>
|
||||
|
||||
|
|
|
@ -20,9 +20,11 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import com.afollestad.nocknock.R
|
||||
import com.afollestad.nocknock.data.ServerModel
|
||||
import com.afollestad.nocknock.data.ServerStatus.WAITING
|
||||
import com.afollestad.nocknock.data.ValidationMode
|
||||
import com.afollestad.nocknock.data.ValidationMode.JAVASCRIPT
|
||||
import com.afollestad.nocknock.data.ValidationMode.STATUS_CODE
|
||||
import com.afollestad.nocknock.data.ValidationMode.TERM_SEARCH
|
||||
import com.afollestad.nocknock.data.indexToValidationMode
|
||||
import com.afollestad.nocknock.engine.db.ServerModelStore
|
||||
import com.afollestad.nocknock.engine.statuscheck.CheckStatusManager
|
||||
import com.afollestad.nocknock.utilities.ext.injector
|
||||
|
@ -56,6 +58,7 @@ import kotlinx.coroutines.launch
|
|||
import java.lang.System.currentTimeMillis
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.max
|
||||
import kotlin.properties.Delegates.notNull
|
||||
|
||||
private const val KEY_FAB_X = "fab_x"
|
||||
private const val KEY_FAB_Y = "fab_y"
|
||||
|
@ -76,11 +79,19 @@ fun MainActivity.intentToAdd(
|
|||
/** @author Aidan Follestad (afollestad) */
|
||||
class AddSiteActivity : AppCompatActivity(), View.OnClickListener {
|
||||
|
||||
companion object {
|
||||
private const val REVEAL_DURATION = 300L
|
||||
}
|
||||
|
||||
private var isClosing: Boolean = false
|
||||
|
||||
@Inject lateinit var serverModelStore: ServerModelStore
|
||||
@Inject lateinit var checkStatusManager: CheckStatusManager
|
||||
|
||||
private var revealCx by notNull<Int>()
|
||||
private var revealCy by notNull<Int>()
|
||||
private var revealRadius by notNull<Float>()
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -91,7 +102,19 @@ class AddSiteActivity : AppCompatActivity(), View.OnClickListener {
|
|||
|
||||
if (savedInstanceState == null) {
|
||||
rootView.conceal()
|
||||
rootView.onLayout { circularRevealActivity() }
|
||||
rootView.onLayout {
|
||||
val fabSize = intent.getIntExtra(KEY_FAB_SIZE, 0)
|
||||
val fabX = intent.getFloatExtra(KEY_FAB_X, 0f)
|
||||
.toInt()
|
||||
val fabY = intent.getFloatExtra(KEY_FAB_Y, 0f)
|
||||
.toInt()
|
||||
|
||||
revealCx = fabX + fabSize / 2
|
||||
revealCy = (fabY + toolbar.measuredHeight + fabSize / 2)
|
||||
revealRadius = max(revealCx, revealCy).toFloat()
|
||||
|
||||
circularRevealActivity()
|
||||
}
|
||||
}
|
||||
|
||||
inputUrl.setOnFocusChangeListener { _, hasFocus ->
|
||||
|
@ -141,27 +164,23 @@ class AddSiteActivity : AppCompatActivity(), View.OnClickListener {
|
|||
doneBtn.setOnClickListener(this)
|
||||
}
|
||||
|
||||
private fun circularRevealActivity() {
|
||||
val circularReveal =
|
||||
createCircularReveal(rootView, revealCx, revealCy, 0f, revealRadius)
|
||||
.apply {
|
||||
duration = REVEAL_DURATION
|
||||
interpolator = DecelerateInterpolator()
|
||||
}
|
||||
rootView.show()
|
||||
circularReveal.start()
|
||||
}
|
||||
|
||||
private fun closeActivityWithReveal() {
|
||||
if (isClosing) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isClosing) return
|
||||
isClosing = true
|
||||
val fabSize = intent.getIntExtra(KEY_FAB_SIZE, toolbar!!.measuredHeight)
|
||||
|
||||
val defaultCx = rootView.measuredWidth / 2f
|
||||
val cx =
|
||||
intent.getFloatExtra(KEY_FAB_X, defaultCx).toInt() + fabSize / 2
|
||||
|
||||
val defaultCy = rootView.measuredHeight / 2f
|
||||
val cy = (intent.getFloatExtra(KEY_FAB_Y, defaultCy).toInt() +
|
||||
toolbar!!.measuredHeight +
|
||||
fabSize / 2)
|
||||
|
||||
val initialRadius = max(cx, cy).toFloat()
|
||||
createCircularReveal(rootView, cx, cy, initialRadius, 0f)
|
||||
createCircularReveal(rootView, revealCx, revealCy, revealRadius, 0f)
|
||||
.apply {
|
||||
duration = 300
|
||||
duration = REVEAL_DURATION
|
||||
interpolator = AccelerateInterpolator()
|
||||
onEnd {
|
||||
rootView.conceal()
|
||||
|
@ -172,20 +191,6 @@ class AddSiteActivity : AppCompatActivity(), View.OnClickListener {
|
|||
}
|
||||
}
|
||||
|
||||
private fun circularRevealActivity() {
|
||||
val cx = rootView.measuredWidth / 2
|
||||
val cy = rootView.measuredHeight / 2
|
||||
val finalRadius = Math.max(cx, cy)
|
||||
.toFloat()
|
||||
val circularReveal = createCircularReveal(rootView, cx, cy, 0f, finalRadius)
|
||||
.apply {
|
||||
duration = 300
|
||||
interpolator = DecelerateInterpolator()
|
||||
}
|
||||
rootView.show()
|
||||
circularReveal.start()
|
||||
}
|
||||
|
||||
// Done button
|
||||
override fun onClick(view: View) {
|
||||
isClosing = true
|
||||
|
@ -223,14 +228,14 @@ class AddSiteActivity : AppCompatActivity(), View.OnClickListener {
|
|||
}
|
||||
|
||||
val selectedCheckInterval = checkIntervalLayout.getSelectedCheckInterval()
|
||||
val selectedValidationMode = getSelectedValidationMode()
|
||||
val selectedValidationContent = getSelectedValidationContent()
|
||||
val selectedValidationMode =
|
||||
responseValidationMode.selectedItemPosition.indexToValidationMode()
|
||||
|
||||
newModel = newModel.copy(
|
||||
checkInterval = selectedCheckInterval,
|
||||
lastCheck = currentTimeMillis() - selectedCheckInterval,
|
||||
validationMode = selectedValidationMode,
|
||||
validationContent = selectedValidationContent
|
||||
validationContent = selectedValidationMode.validationContent()
|
||||
)
|
||||
|
||||
rootView.scopeWhileAttached(Main) {
|
||||
|
@ -250,25 +255,9 @@ class AddSiteActivity : AppCompatActivity(), View.OnClickListener {
|
|||
|
||||
override fun onBackPressed() = closeActivityWithReveal()
|
||||
|
||||
private fun getSelectedValidationMode() = when (responseValidationMode.selectedItemPosition) {
|
||||
0 -> STATUS_CODE
|
||||
1 -> TERM_SEARCH
|
||||
2 -> JAVASCRIPT
|
||||
else -> {
|
||||
throw IllegalStateException(
|
||||
"Unexpected validation mode index: ${responseValidationMode.selectedItemPosition}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSelectedValidationContent() = when (responseValidationMode.selectedItemPosition) {
|
||||
0 -> null
|
||||
1 -> responseValidationSearchTerm.trimmedText()
|
||||
2 -> scriptInputLayout.getCode()
|
||||
else -> {
|
||||
throw IllegalStateException(
|
||||
"Unexpected validation mode index: ${responseValidationMode.selectedItemPosition}"
|
||||
)
|
||||
}
|
||||
private fun ValidationMode.validationContent() = when (this) {
|
||||
STATUS_CODE -> null
|
||||
TERM_SEARCH -> responseValidationSearchTerm.trimmedText()
|
||||
JAVASCRIPT -> scriptInputLayout.getCode()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
*/
|
||||
package com.afollestad.nocknock.ui
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.animation.ObjectAnimator.ofFloat
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ActivityOptions.makeSceneTransitionAnimation
|
||||
import android.content.BroadcastReceiver
|
||||
|
@ -15,12 +13,6 @@ import android.content.Intent
|
|||
import android.content.IntentFilter
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.View.X
|
||||
import android.view.View.Y
|
||||
import android.view.animation.PathInterpolator
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||
|
@ -40,17 +32,16 @@ import com.afollestad.nocknock.engine.statuscheck.CheckStatusJob.Companion.KEY_U
|
|||
import com.afollestad.nocknock.engine.statuscheck.CheckStatusManager
|
||||
import com.afollestad.nocknock.notifications.NockNotificationManager
|
||||
import com.afollestad.nocknock.utilities.ext.injector
|
||||
import com.afollestad.nocknock.utilities.ext.onEnd
|
||||
import com.afollestad.nocknock.utilities.ext.safeRegisterReceiver
|
||||
import com.afollestad.nocknock.utilities.ext.safeUnregisterReceiver
|
||||
import com.afollestad.nocknock.utilities.ext.scopeWhileAttached
|
||||
import com.afollestad.nocknock.viewcomponents.ext.show
|
||||
import com.afollestad.nocknock.viewcomponents.ext.showOrHide
|
||||
import com.afollestad.nocknock.utilities.util.MathUtil.bezierCurve
|
||||
import kotlinx.android.synthetic.main.activity_main.emptyText
|
||||
import kotlinx.android.synthetic.main.activity_main.fab
|
||||
import kotlinx.android.synthetic.main.activity_main.list
|
||||
import kotlinx.android.synthetic.main.activity_main.rootView
|
||||
import kotlinx.android.synthetic.main.activity_main.toolbar
|
||||
import kotlinx.android.synthetic.main.include_empty_view.emptyText
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.async
|
||||
|
@ -58,12 +49,11 @@ import kotlinx.coroutines.launch
|
|||
import javax.inject.Inject
|
||||
|
||||
/** @author Aidan Follestad (afollestad) */
|
||||
class MainActivity : AppCompatActivity(), View.OnClickListener {
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
companion object {
|
||||
private const val ADD_SITE_RQ = 6969
|
||||
private const val VIEW_SITE_RQ = 6923
|
||||
private const val REVEAL_DURATION = 250L
|
||||
|
||||
private fun log(message: String) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
|
@ -72,10 +62,6 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
|
|||
}
|
||||
}
|
||||
|
||||
private var fabAnimator: ObjectAnimator? = null
|
||||
private var originalFabX: Float = 0.toFloat()
|
||||
private var originalFabY: Float = 0.toFloat()
|
||||
|
||||
private val intentReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(
|
||||
context: Context,
|
||||
|
@ -105,13 +91,26 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
|
|||
injector().injectInto(this)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
toolbar.inflateMenu(R.menu.menu_main)
|
||||
toolbar.setOnMenuItemClickListener { item ->
|
||||
if (item.itemId == R.id.about) {
|
||||
AboutDialog.show(this)
|
||||
}
|
||||
return@setOnMenuItemClickListener true
|
||||
}
|
||||
|
||||
adapter = ServerAdapter(this::onSiteSelected)
|
||||
|
||||
list.layoutManager = LinearLayoutManager(this)
|
||||
list.adapter = adapter
|
||||
list.addItemDecoration(DividerItemDecoration(this, VERTICAL))
|
||||
|
||||
fab.setOnClickListener(this)
|
||||
fab.setOnClickListener {
|
||||
startActivityForResult(
|
||||
intentToAdd(fab.x, fab.y, fab.measuredWidth),
|
||||
ADD_SITE_RQ
|
||||
)
|
||||
}
|
||||
|
||||
notificationManager.createChannels()
|
||||
ensureCheckJobs()
|
||||
|
@ -152,46 +151,6 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
|
|||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_main, menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == R.id.about) {
|
||||
AboutDialog.show(this)
|
||||
return true
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
// FAB clicked
|
||||
override fun onClick(view: View) {
|
||||
originalFabX = fab.x
|
||||
originalFabY = fab.y
|
||||
|
||||
fabAnimator?.cancel()
|
||||
fabAnimator = ofFloat(view, X, Y, bezierCurve(fab, list))
|
||||
.apply {
|
||||
interpolator = PathInterpolator(.5f, .5f)
|
||||
duration = REVEAL_DURATION
|
||||
onEnd {
|
||||
startActivityForResult(
|
||||
intentToAdd(originalFabX, originalFabY, fab.measuredWidth),
|
||||
ADD_SITE_RQ
|
||||
)
|
||||
fab.postDelayed(
|
||||
{
|
||||
fab.x = originalFabX
|
||||
fab.y = originalFabY
|
||||
},
|
||||
REVEAL_DURATION * 2
|
||||
)
|
||||
}
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(
|
||||
requestCode: Int,
|
||||
resultCode: Int,
|
||||
|
|
|
@ -24,12 +24,15 @@ import androidx.core.text.HtmlCompat
|
|||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.nocknock.BuildConfig
|
||||
import com.afollestad.nocknock.R
|
||||
import com.afollestad.nocknock.data.LAST_CHECK_NONE
|
||||
import com.afollestad.nocknock.data.ServerModel
|
||||
import com.afollestad.nocknock.data.ServerStatus.CHECKING
|
||||
import com.afollestad.nocknock.data.ServerStatus.WAITING
|
||||
import com.afollestad.nocknock.data.ValidationMode
|
||||
import com.afollestad.nocknock.data.ValidationMode.JAVASCRIPT
|
||||
import com.afollestad.nocknock.data.ValidationMode.STATUS_CODE
|
||||
import com.afollestad.nocknock.data.ValidationMode.TERM_SEARCH
|
||||
import com.afollestad.nocknock.data.indexToValidationMode
|
||||
import com.afollestad.nocknock.data.textRes
|
||||
import com.afollestad.nocknock.engine.db.ServerModelStore
|
||||
import com.afollestad.nocknock.engine.statuscheck.CheckStatusJob.Companion.ACTION_STATUS_UPDATE
|
||||
|
@ -41,12 +44,17 @@ import com.afollestad.nocknock.utilities.ext.isHttpOrHttps
|
|||
import com.afollestad.nocknock.utilities.ext.safeRegisterReceiver
|
||||
import com.afollestad.nocknock.utilities.ext.safeUnregisterReceiver
|
||||
import com.afollestad.nocknock.utilities.ext.scopeWhileAttached
|
||||
import com.afollestad.nocknock.viewcomponents.ext.dimenFloat
|
||||
import com.afollestad.nocknock.viewcomponents.ext.disable
|
||||
import com.afollestad.nocknock.viewcomponents.ext.enable
|
||||
import com.afollestad.nocknock.viewcomponents.ext.hide
|
||||
import com.afollestad.nocknock.viewcomponents.ext.onItemSelected
|
||||
import com.afollestad.nocknock.viewcomponents.ext.onScroll
|
||||
import com.afollestad.nocknock.viewcomponents.ext.show
|
||||
import com.afollestad.nocknock.viewcomponents.ext.showOrHide
|
||||
import com.afollestad.nocknock.viewcomponents.ext.trimmedText
|
||||
import kotlinx.android.synthetic.main.activity_viewsite.checkIntervalLayout
|
||||
import kotlinx.android.synthetic.main.activity_viewsite.disableChecksButton
|
||||
import kotlinx.android.synthetic.main.activity_viewsite.doneBtn
|
||||
import kotlinx.android.synthetic.main.activity_viewsite.iconStatus
|
||||
import kotlinx.android.synthetic.main.activity_viewsite.inputName
|
||||
|
@ -56,6 +64,7 @@ import kotlinx.android.synthetic.main.activity_viewsite.responseValidationMode
|
|||
import kotlinx.android.synthetic.main.activity_viewsite.responseValidationSearchTerm
|
||||
import kotlinx.android.synthetic.main.activity_viewsite.rootView
|
||||
import kotlinx.android.synthetic.main.activity_viewsite.scriptInputLayout
|
||||
import kotlinx.android.synthetic.main.activity_viewsite.scrollView
|
||||
import kotlinx.android.synthetic.main.activity_viewsite.textLastCheckResult
|
||||
import kotlinx.android.synthetic.main.activity_viewsite.textNextCheck
|
||||
import kotlinx.android.synthetic.main.activity_viewsite.textUrlWarning
|
||||
|
@ -122,6 +131,14 @@ class ViewSiteActivity : AppCompatActivity(),
|
|||
setOnMenuItemClickListener(this@ViewSiteActivity)
|
||||
}
|
||||
|
||||
scrollView.onScroll {
|
||||
toolbar.elevation = if (it > toolbar.height / 4) {
|
||||
toolbar.dimenFloat(R.dimen.default_elevation)
|
||||
} else {
|
||||
0f
|
||||
}
|
||||
}
|
||||
|
||||
inputUrl.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) {
|
||||
val inputStr = inputUrl.text
|
||||
|
@ -184,7 +201,7 @@ class ViewSiteActivity : AppCompatActivity(),
|
|||
inputName.setText(this.name)
|
||||
inputUrl.setText(this.url)
|
||||
|
||||
if (this.lastCheck == 0L) {
|
||||
if (this.lastCheck == LAST_CHECK_NONE) {
|
||||
textLastCheckResult.setText(R.string.none)
|
||||
} else {
|
||||
val statusText = this.status.textRes()
|
||||
|
@ -195,16 +212,8 @@ class ViewSiteActivity : AppCompatActivity(),
|
|||
}
|
||||
}
|
||||
|
||||
if (this.checkInterval == 0L) {
|
||||
textNextCheck.setText(R.string.none_turned_off)
|
||||
checkIntervalLayout.clear()
|
||||
} else {
|
||||
var lastCheck = this.lastCheck
|
||||
if (lastCheck == 0L) {
|
||||
lastCheck = currentTimeMillis()
|
||||
}
|
||||
textNextCheck.text = (lastCheck + this.checkInterval).formatDate()
|
||||
}
|
||||
textNextCheck.text = (this.lastCheck + this.checkInterval).formatDate()
|
||||
checkIntervalLayout.set(this.checkInterval)
|
||||
|
||||
responseValidationMode.setSelection(validationMode.value - 1)
|
||||
|
||||
|
@ -267,14 +276,14 @@ class ViewSiteActivity : AppCompatActivity(),
|
|||
}
|
||||
|
||||
val selectedCheckInterval = checkIntervalLayout.getSelectedCheckInterval()
|
||||
val selectedValidationMode = getSelectedValidationMode()
|
||||
val selectedValidationContent = getSelectedValidationContent()
|
||||
val selectedValidationMode =
|
||||
responseValidationMode.selectedItemPosition.indexToValidationMode()
|
||||
|
||||
currentModel = currentModel.copy(
|
||||
checkInterval = selectedCheckInterval,
|
||||
lastCheck = currentTimeMillis() - selectedCheckInterval,
|
||||
validationMode = selectedValidationMode,
|
||||
validationContent = selectedValidationContent
|
||||
validationContent = selectedValidationMode.validationContent()
|
||||
)
|
||||
|
||||
return true
|
||||
|
@ -307,6 +316,7 @@ class ViewSiteActivity : AppCompatActivity(),
|
|||
R.id.refresh -> {
|
||||
rootView.scopeWhileAttached(Main) {
|
||||
launch(coroutineContext) {
|
||||
disableChecksButton.disable()
|
||||
loadingProgress.setLoading()
|
||||
updateModelFromInput(false)
|
||||
currentModel = currentModel.copy(status = WAITING)
|
||||
|
@ -317,6 +327,7 @@ class ViewSiteActivity : AppCompatActivity(),
|
|||
checkStatusManager.cancelCheck(currentModel)
|
||||
checkStatusManager.scheduleCheck(currentModel, rightNow = true)
|
||||
loadingProgress.setDone()
|
||||
disableChecksButton.enable()
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
@ -363,25 +374,9 @@ class ViewSiteActivity : AppCompatActivity(),
|
|||
item.isEnabled = currentModel.status != CHECKING && currentModel.status != WAITING
|
||||
}
|
||||
|
||||
private fun getSelectedValidationMode() = when (responseValidationMode.selectedItemPosition) {
|
||||
0 -> STATUS_CODE
|
||||
1 -> TERM_SEARCH
|
||||
2 -> JAVASCRIPT
|
||||
else -> {
|
||||
throw IllegalStateException(
|
||||
"Unexpected validation mode index: ${responseValidationMode.selectedItemPosition}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSelectedValidationContent() = when (responseValidationMode.selectedItemPosition) {
|
||||
0 -> null
|
||||
1 -> responseValidationSearchTerm.trimmedText()
|
||||
2 -> scriptInputLayout.getCode()
|
||||
else -> {
|
||||
throw IllegalStateException(
|
||||
"Unexpected validation mode index: ${responseValidationMode.selectedItemPosition}"
|
||||
)
|
||||
}
|
||||
private fun ValidationMode.validationContent() = when (this) {
|
||||
STATUS_CODE -> null
|
||||
TERM_SEARCH -> responseValidationSearchTerm.trimmedText()
|
||||
JAVASCRIPT -> scriptInputLayout.getCode()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/FlatToolbarTheme"
|
||||
app:navigationIcon="@drawable/ic_action_close"
|
||||
app:title="@string/add_site"
|
||||
app:titleTextColor="?android:textColorPrimary"
|
||||
app:titleTextColor="#FFFFFF"
|
||||
/>
|
||||
|
||||
<ScrollView
|
||||
|
@ -51,7 +52,7 @@
|
|||
android:id="@+id/inputName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato"
|
||||
android:hint="@string/site_name"
|
||||
android:inputType="textPersonName|textCapWords|textAutoCorrect"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
|
@ -74,7 +75,7 @@
|
|||
android:id="@+id/inputUrl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato"
|
||||
android:hint="@string/site_url"
|
||||
android:inputType="textUri"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
|
@ -89,7 +90,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/list_text_spacing"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato_light"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/caption_font_size"
|
||||
android:visibility="gone"
|
||||
|
@ -106,11 +107,11 @@
|
|||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/responseValidation"
|
||||
android:id="@+id/responseValidationLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/content_inset"
|
||||
android:fontFamily="sans-serif"
|
||||
android:fontFamily="@font/lato"
|
||||
android:text="@string/response_validation_mode"
|
||||
android:textColor="?colorAccent"
|
||||
android:textSize="@dimen/caption_font_size"
|
||||
|
@ -130,11 +131,11 @@
|
|||
android:layout_marginLeft="-4dp"
|
||||
android:layout_marginRight="-4dp"
|
||||
android:layout_marginTop="-4dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato_light"
|
||||
android:hint="@string/search_term"
|
||||
android:textSize="@dimen/body_font_size"
|
||||
android:visibility="gone"
|
||||
tools:ignore="Autofill"
|
||||
tools:ignore="Autofill,TextFields"
|
||||
/>
|
||||
|
||||
<com.afollestad.nocknock.viewcomponents.JavaScriptInputLayout
|
||||
|
@ -151,7 +152,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/content_inset_half"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato_light"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:text="@string/validation_mode_status_desc"
|
||||
android:textSize="@dimen/body_font_size"
|
||||
|
@ -161,7 +162,7 @@
|
|||
android:id="@+id/doneBtn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/content_inset"
|
||||
android:layout_marginTop="@dimen/content_inset_double"
|
||||
android:text="@string/done"
|
||||
style="@style/AccentButton"
|
||||
/>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/rootView"
|
||||
|
@ -8,38 +9,43 @@
|
|||
tools:context=".ui.MainActivity"
|
||||
>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/list"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
/>
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/emptyText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="@dimen/content_inset"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:gravity="center"
|
||||
android:text="@string/no_sites_added"
|
||||
android:textSize="@dimen/empty_text_size"
|
||||
android:textStyle="italic"
|
||||
/>
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/MainToolbarTheme"
|
||||
style="@style/MainToolbarStyle"
|
||||
/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/include_empty_view"/>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|bottom"
|
||||
android:layout_margin="@dimen/content_inset"
|
||||
android:src="@drawable/ic_add"
|
||||
app:backgroundTint="?colorAccent"
|
||||
app:elevation="@dimen/fab_elevation"
|
||||
app:fabSize="normal"
|
||||
app:pressedTranslationZ="@dimen/fab_elevation_pressed"
|
||||
app:rippleColor="#40ffffff"
|
||||
app:useCompatPadding="true"
|
||||
/>
|
||||
|
||||
</FrameLayout>
|
||||
|
|
|
@ -15,16 +15,20 @@
|
|||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
<!-- Background is applied again here so programmatic elevation works -->
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?colorPrimary"
|
||||
android:theme="@style/FlatToolbarTheme"
|
||||
app:navigationIcon="@drawable/ic_action_close"
|
||||
app:title="@string/view_site"
|
||||
app:titleTextColor="?android:textColorPrimary"
|
||||
/>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scrollView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
>
|
||||
|
@ -66,7 +70,7 @@
|
|||
android:id="@+id/inputName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato"
|
||||
android:hint="@string/site_name"
|
||||
android:inputType="textPersonName|textCapWords|textAutoCorrect"
|
||||
android:singleLine="true"
|
||||
|
@ -74,14 +78,14 @@
|
|||
android:textColorHint="?android:textColorSecondary"
|
||||
android:textSize="@dimen/body_font_size"
|
||||
android:transitionName="site_name"
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:ignore="Autofill,UnusedAttribute"
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/inputUrl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato"
|
||||
android:hint="@string/site_url"
|
||||
android:inputType="textUri"
|
||||
android:singleLine="true"
|
||||
|
@ -89,7 +93,7 @@
|
|||
android:textColorHint="?android:textColorSecondary"
|
||||
android:textSize="@dimen/body_font_size"
|
||||
android:transitionName="site_url"
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:ignore="Autofill,UnusedAttribute"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
|
@ -99,7 +103,7 @@
|
|||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="@dimen/list_text_spacing"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato_light"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/caption_font_size"
|
||||
android:visibility="gone"
|
||||
|
@ -132,11 +136,11 @@
|
|||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/responseValidation"
|
||||
android:id="@+id/responseValidationLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/content_inset"
|
||||
android:fontFamily="sans-serif"
|
||||
android:fontFamily="@font/lato"
|
||||
android:text="@string/response_validation_mode"
|
||||
android:textColor="?colorAccent"
|
||||
android:textSize="@dimen/caption_font_size"
|
||||
|
@ -156,7 +160,7 @@
|
|||
android:layout_marginLeft="-4dp"
|
||||
android:layout_marginRight="-4dp"
|
||||
android:layout_marginTop="-4dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato_light"
|
||||
android:hint="@string/search_term"
|
||||
android:textSize="@dimen/body_font_size"
|
||||
android:visibility="gone"
|
||||
|
@ -177,7 +181,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/content_inset_half"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:text="@string/validation_mode_status_desc"
|
||||
android:textSize="@dimen/body_font_size"
|
||||
|
@ -199,7 +203,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/list_text_spacing"
|
||||
android:fontFamily="sans-serif"
|
||||
android:fontFamily="@font/lato"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/medium_text_size"
|
||||
tools:text="Everything checks out!"
|
||||
|
@ -219,7 +223,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/list_text_spacing"
|
||||
android:fontFamily="sans-serif"
|
||||
android:fontFamily="@font/lato"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/medium_text_size"
|
||||
tools:text="In 2 hours"
|
||||
|
@ -229,11 +233,20 @@
|
|||
android:id="@+id/doneBtn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/content_inset_more"
|
||||
android:text="@string/save"
|
||||
android:layout_marginTop="@dimen/content_inset_double"
|
||||
android:text="@string/save_changes"
|
||||
style="@style/AccentButton"
|
||||
/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/disableChecksButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/content_inset_half"
|
||||
android:text="@string/disable_automatic_checks"
|
||||
style="@style/PrimaryDarkButton"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
|
14
app/src/main/res/layout/include_empty_view.xml
Normal file
14
app/src/main/res/layout/include_empty_view.xml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/emptyText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="@dimen/content_inset"
|
||||
android:fontFamily="@font/lato_light"
|
||||
android:gravity="center"
|
||||
android:text="@string/no_sites_added"
|
||||
android:textSize="@dimen/empty_text_size"
|
||||
android:textStyle="italic"
|
||||
/>
|
|
@ -43,7 +43,7 @@
|
|||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="@dimen/content_inset_half"
|
||||
android:layout_toStartOf="@+id/textInterval"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:fontFamily="@font/lato"
|
||||
android:singleLine="true"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/title_font_size"
|
||||
|
@ -57,7 +57,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato_light"
|
||||
android:singleLine="true"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="@dimen/caption_font_size"
|
||||
|
@ -71,7 +71,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/list_text_spacing"
|
||||
android:fontFamily="sans-serif"
|
||||
android:fontFamily="@font/lato"
|
||||
android:singleLine="true"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="@dimen/body_font_size"
|
||||
|
@ -84,7 +84,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/list_text_spacing"
|
||||
android:fontFamily="sans-serif"
|
||||
android:fontFamily="@font/lato"
|
||||
android:singleLine="true"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="@dimen/body_font_size"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<resources>
|
||||
|
||||
<string name="app_name" tools:ignore="Typos">Nock Nock (BETA)</string>
|
||||
<string name="app_name">Nock Nock</string>
|
||||
|
||||
<string name="no_sites_added">No sites added!</string>
|
||||
|
||||
|
@ -29,7 +29,8 @@
|
|||
<string name="remove_site">Remove Site</string>
|
||||
<string name="remove_site_prompt"><![CDATA[Remove <b>%1$s</b> from your sites?]]></string>
|
||||
<string name="remove">Remove</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="save_changes">Save Changes</string>
|
||||
<string name="disable_automatic_checks">Disable Automatic Checks</string>
|
||||
<string name="view_site">View Site</string>
|
||||
<string name="last_check_result">Last Check Result</string>
|
||||
<string name="next_check">Next Check</string>
|
||||
|
@ -39,13 +40,23 @@
|
|||
<string name="refresh_status">Refresh Status</string>
|
||||
|
||||
<string name="warning_http_url">
|
||||
Warning: this app checks for server availability with HTTP requests. It\'s recommended that you use an HTTP URL.
|
||||
</string>
|
||||
Warning: this app checks for server availability with HTTP requests. It\'s recommended that you
|
||||
use an HTTP URL.
|
||||
</string>
|
||||
<string name="response_validation_mode">Response Validation Mode</string>
|
||||
<string name="search_term">Search term…</string>
|
||||
|
||||
<string name="validation_mode_status_desc">The HTTP status code is checked. If it\'s a successful status code, the site passes the check.</string>
|
||||
<string name="validation_mode_term_desc">The status code check is done first. If it\'s successful, the response body is checked. If it contains your search term, the site passes the check.</string>
|
||||
<string name="validation_mode_javascript_desc">The status code check is done first. If it\'s successful, the response body is passed to the JavaScript function above. If the function returns true, the site passes the check. Throw an exception to pass custom error messages to Nock Nock.</string>
|
||||
<string name="validation_mode_status_desc">
|
||||
The HTTP status code is checked. If it\'s a successful status code, the site passes the check.
|
||||
</string>
|
||||
<string name="validation_mode_term_desc">
|
||||
The status code check is done first. If it\'s successful, the response body is checked.
|
||||
If it contains your search term, the site passes the check.
|
||||
</string>
|
||||
<string name="validation_mode_javascript_desc">
|
||||
The status code check is done first. If it\'s successful, the response body is passed to the
|
||||
JavaScript function above. If the function returns true, the site passes the check. Throw an
|
||||
exception to pass custom error messages to Nock Nock.
|
||||
</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<resources>
|
||||
|
||||
<style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar">
|
||||
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
|
@ -27,9 +27,38 @@
|
|||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<style name="MainToolbarTheme" parent="@style/Theme.MaterialComponents">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="android:fontFamily">@font/lato_black</item>
|
||||
</style>
|
||||
|
||||
<style name="MainToolbarStyle" parent="@style/Widget.MaterialComponents.Toolbar">
|
||||
<item name="android:background">?colorPrimary</item>
|
||||
<item name="android:elevation">@dimen/default_elevation</item>
|
||||
<item name="title">@string/app_name</item>
|
||||
<item name="titleTextColor">#FFFFFF</item>
|
||||
<item name="popupTheme">@style/Theme.MaterialComponents.Light.DarkActionBar</item>
|
||||
</style>
|
||||
|
||||
<style name="FlatToolbarTheme" parent="@style/Theme.MaterialComponents">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="android:fontFamily">@font/lato_black</item>
|
||||
</style>
|
||||
|
||||
<style name="AccentButton" parent="Widget.MaterialComponents.Button">
|
||||
<item name="android:textColor">#fff</item>
|
||||
<item name="android:colorButtonNormal">@color/colorAccent</item>
|
||||
<item name="backgroundTint">@color/colorAccent</item>
|
||||
<item name="android:fontFamily">@font/lato</item>
|
||||
</style>
|
||||
|
||||
<style name="PrimaryDarkButton" parent="Widget.MaterialComponents.Button">
|
||||
<item name="android:textColor">#fff</item>
|
||||
<item name="backgroundTint">@color/colorPrimaryDark</item>
|
||||
<item name="android:fontFamily">@font/lato</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -12,17 +12,21 @@ import com.afollestad.nocknock.utilities.ext.timeString
|
|||
import java.io.Serializable
|
||||
import java.lang.System.currentTimeMillis
|
||||
|
||||
const val CHECK_INTERVAL_UNSET = -1L
|
||||
const val LAST_CHECK_NONE = -1L
|
||||
|
||||
/** @author Aidan Follestad (afollestad)*/
|
||||
data class ServerModel(
|
||||
var id: Int = 0,
|
||||
val name: String = "Unknown",
|
||||
val url: String = "Unknown",
|
||||
val name: String,
|
||||
val url: String,
|
||||
val status: ServerStatus = OK,
|
||||
val checkInterval: Long = 0,
|
||||
val lastCheck: Long = 0,
|
||||
val checkInterval: Long = CHECK_INTERVAL_UNSET,
|
||||
val lastCheck: Long = LAST_CHECK_NONE,
|
||||
val reason: String? = null,
|
||||
val validationMode: ValidationMode,
|
||||
val validationContent: String? = null
|
||||
val validationContent: String? = null,
|
||||
val disabled: Boolean = false
|
||||
) : Serializable {
|
||||
|
||||
companion object {
|
||||
|
@ -36,8 +40,9 @@ data class ServerModel(
|
|||
const val COLUMN_REASON = "reason"
|
||||
const val COLUMN_VALIDATION_MODE = "validation_mode"
|
||||
const val COLUMN_VALIDATION_CONTENT = "validation_content"
|
||||
const val COLUMN_DISABLED = "disabled"
|
||||
|
||||
const val DEFAULT_SORT_ORDER = "$COLUMN_NAME ASC"
|
||||
const val DEFAULT_SORT_ORDER = "$COLUMN_NAME ASC, $COLUMN_DISABLED DESC"
|
||||
|
||||
fun pull(cursor: Cursor): ServerModel {
|
||||
return ServerModel(
|
||||
|
@ -51,7 +56,8 @@ data class ServerModel(
|
|||
validationMode = cursor.getInt(
|
||||
cursor.getColumnIndex(COLUMN_VALIDATION_MODE)
|
||||
).toValidationMode(),
|
||||
validationContent = cursor.getString(cursor.getColumnIndex(COLUMN_VALIDATION_CONTENT))
|
||||
validationContent = cursor.getString(cursor.getColumnIndex(COLUMN_VALIDATION_CONTENT)),
|
||||
disabled = cursor.getInt(cursor.getColumnIndex(COLUMN_DISABLED)) == 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -73,5 +79,6 @@ data class ServerModel(
|
|||
put(COLUMN_REASON, reason)
|
||||
put(COLUMN_VALIDATION_MODE, validationMode.value)
|
||||
put(COLUMN_VALIDATION_CONTENT, validationContent)
|
||||
put(COLUMN_DISABLED, disabled)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,16 @@ enum class ValidationMode(val value: Int) {
|
|||
JAVASCRIPT.value -> JAVASCRIPT
|
||||
else -> throw IllegalArgumentException("Unknown validationMode: $value")
|
||||
}
|
||||
|
||||
fun fromIndex(index: Int) = when (index) {
|
||||
0 -> STATUS_CODE
|
||||
1 -> TERM_SEARCH
|
||||
2 -> JAVASCRIPT
|
||||
else -> throw IllegalArgumentException("Index out of range: $index")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Int.toValidationMode() = ValidationMode.fromValue(this)
|
||||
|
||||
fun Int.indexToValidationMode() = ValidationMode.fromIndex(this)
|
||||
|
|
|
@ -20,7 +20,8 @@ private const val SQL_CREATE_ENTRIES =
|
|||
"${ServerModel.COLUMN_LAST_CHECK} INTEGER," +
|
||||
"${ServerModel.COLUMN_REASON} TEXT," +
|
||||
"${ServerModel.COLUMN_VALIDATION_MODE} INTEGER," +
|
||||
"${ServerModel.COLUMN_VALIDATION_CONTENT} TEXT)"
|
||||
"${ServerModel.COLUMN_VALIDATION_CONTENT} TEXT," +
|
||||
"${ServerModel.COLUMN_DISABLED} INTEGER)"
|
||||
|
||||
private const val SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS ${ServerModel.TABLE_NAME}"
|
||||
|
||||
|
@ -29,7 +30,7 @@ class ServerModelDbHelper(context: Context) : SQLiteOpenHelper(
|
|||
context, DATABASE_NAME, null, DATABASE_VERSION
|
||||
) {
|
||||
companion object {
|
||||
const val DATABASE_VERSION = 1
|
||||
const val DATABASE_VERSION = 2
|
||||
const val DATABASE_NAME = "ServerModels.db"
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@ import java.util.Date
|
|||
import java.util.Locale
|
||||
|
||||
fun Long.formatDate(): String {
|
||||
if (this <= 0) {
|
||||
return "(None)"
|
||||
}
|
||||
val df = SimpleDateFormat("MMMM dd, hh:mm:ss a", Locale.getDefault())
|
||||
return df.format(Date(this))
|
||||
}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Licensed under Apache-2.0
|
||||
*
|
||||
* Designed and developed by Aidan Follestad (@afollestad)
|
||||
*/
|
||||
package com.afollestad.nocknock.utilities.util
|
||||
|
||||
import android.graphics.Path
|
||||
import android.view.View
|
||||
|
||||
/** @author Aidan Follestad (afollestad) */
|
||||
object MathUtil {
|
||||
|
||||
fun bezierCurve(
|
||||
targetView: View,
|
||||
rootView: View
|
||||
): Path {
|
||||
val fabCenterX = (targetView.x + targetView.measuredWidth / 2).toInt()
|
||||
val fabCenterY = (targetView.y + targetView.measuredHeight / 2).toInt()
|
||||
|
||||
val endCenterX = rootView.measuredWidth / 2 - targetView.measuredWidth / 2
|
||||
val endCenterY = rootView.measuredHeight / 2 - targetView.measuredHeight / 2
|
||||
|
||||
val halfX = (fabCenterX - endCenterX) / 2
|
||||
val halfY = (fabCenterY - endCenterY) / 2
|
||||
|
||||
var controlX = endCenterX + halfX
|
||||
var controlY = endCenterY + halfY
|
||||
|
||||
controlY -= halfY
|
||||
controlX += halfX
|
||||
|
||||
val path = Path()
|
||||
path.moveTo(targetView.x, targetView.y)
|
||||
path.quadTo(
|
||||
controlX.toFloat(),
|
||||
controlY.toFloat(),
|
||||
endCenterX.toFloat(),
|
||||
endCenterY.toFloat()
|
||||
)
|
||||
|
||||
return path
|
||||
}
|
||||
}
|
|
@ -74,11 +74,6 @@ class CheckIntervalLayout(
|
|||
}
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
input.setText("")
|
||||
spinner.setSelection(0)
|
||||
}
|
||||
|
||||
@CheckResult fun getSelectedCheckInterval(): Long {
|
||||
val intervalInput = input.textAsLong()
|
||||
val spinnerPos = spinner.selectedItemPosition
|
||||
|
|
|
@ -27,6 +27,8 @@ class LoadingIndicatorFrame(
|
|||
setBackgroundColor(ContextCompat.getColor(context, R.color.loading_indicator_frame_background))
|
||||
hide() // hide self by default
|
||||
inflate(context, R.layout.loading_indicator_frame, this)
|
||||
isClickable = true
|
||||
isFocusable = true
|
||||
}
|
||||
|
||||
fun setLoading() {
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* Licensed under Apache-2.0
|
||||
*
|
||||
* Designed and developed by Aidan Follestad (@afollestad)
|
||||
*/
|
||||
package com.afollestad.nocknock.viewcomponents.ext
|
||||
|
||||
import android.widget.ScrollView
|
||||
|
||||
fun ScrollView.onScroll(cb: (y: Int) -> Unit) =
|
||||
viewTreeObserver.addOnScrollChangedListener { cb(scrollY) }
|
|
@ -24,6 +24,14 @@ fun View.hide() {
|
|||
visibility = GONE
|
||||
}
|
||||
|
||||
fun View.enable() {
|
||||
isEnabled = true
|
||||
}
|
||||
|
||||
fun View.disable() {
|
||||
isEnabled = false
|
||||
}
|
||||
|
||||
fun View.showOrHide(show: Boolean) = if (show) show() else hide()
|
||||
|
||||
fun View.onLayout(cb: () -> Unit) {
|
||||
|
|
7
viewcomponents/src/main/res/font/fira_mono.xml
Normal file
7
viewcomponents/src/main/res/font/fira_mono.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
app:fontProviderAuthority="com.google.android.gms.fonts"
|
||||
app:fontProviderPackage="com.google.android.gms"
|
||||
app:fontProviderQuery="Fira Mono"
|
||||
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
||||
</font-family>
|
7
viewcomponents/src/main/res/font/lato.xml
Normal file
7
viewcomponents/src/main/res/font/lato.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
app:fontProviderAuthority="com.google.android.gms.fonts"
|
||||
app:fontProviderPackage="com.google.android.gms"
|
||||
app:fontProviderQuery="Lato"
|
||||
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
||||
</font-family>
|
7
viewcomponents/src/main/res/font/lato_black.xml
Normal file
7
viewcomponents/src/main/res/font/lato_black.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
app:fontProviderAuthority="com.google.android.gms.fonts"
|
||||
app:fontProviderPackage="com.google.android.gms"
|
||||
app:fontProviderQuery="name=Lato&weight=900"
|
||||
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
||||
</font-family>
|
7
viewcomponents/src/main/res/font/lato_light.xml
Normal file
7
viewcomponents/src/main/res/font/lato_light.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
app:fontProviderAuthority="com.google.android.gms.fonts"
|
||||
app:fontProviderPackage="com.google.android.gms"
|
||||
app:fontProviderQuery="name=Lato&weight=300"
|
||||
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
||||
</font-family>
|
|
@ -5,13 +5,14 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
tools:parentTag="android.widget.LinearLayout"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif"
|
||||
android:fontFamily="@font/lato"
|
||||
android:text="@string/check_interval"
|
||||
android:textColor="?colorAccent"
|
||||
android:textSize="@dimen/caption_font_size"
|
||||
|
@ -32,7 +33,7 @@
|
|||
android:layout_marginEnd="@dimen/content_inset_half"
|
||||
android:layout_marginStart="-4dp"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato_light"
|
||||
android:hint="0"
|
||||
android:inputType="number"
|
||||
android:maxLength="6"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="serif-monospace"
|
||||
android:fontFamily="@font/fira_mono"
|
||||
android:lineSpacingMultiplier="1.4"
|
||||
android:singleLine="true"
|
||||
android:text="@string/function_declaration"
|
||||
|
@ -28,7 +28,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:fontFamily="serif-monospace"
|
||||
android:fontFamily="@font/fira_mono"
|
||||
android:gravity="top"
|
||||
android:inputType="textMultiLine"
|
||||
android:lineSpacingMultiplier="1.6"
|
||||
|
@ -45,7 +45,7 @@
|
|||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="serif-monospace"
|
||||
android:fontFamily="@font/fira_mono"
|
||||
android:text="@string/function_end"
|
||||
android:textSize="@dimen/code_font_size"
|
||||
/>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/button_height"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato"
|
||||
android:gravity="center_vertical|start"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/body_font_size"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/button_height"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:fontFamily="@font/lato"
|
||||
android:gravity="center_vertical|start"
|
||||
android:paddingLeft="@dimen/content_inset"
|
||||
android:paddingRight="@dimen/content_inset"
|
||||
|
|
|
@ -4,12 +4,10 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
>
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
style="?android:progressBarStyleLarge"
|
||||
/>
|
||||
|
||||
</merge>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<dimen name="content_inset_less">12dp</dimen>
|
||||
<dimen name="content_inset">16dp</dimen>
|
||||
<dimen name="content_inset_more">24dp</dimen>
|
||||
<dimen name="content_inset_double">32dp</dimen>
|
||||
|
||||
<dimen name="code_font_size">14sp</dimen>
|
||||
<dimen name="body_font_size">14sp</dimen>
|
||||
|
|
17
viewcomponents/src/main/res/values/font_certs.xml
Normal file
17
viewcomponents/src/main/res/values/font_certs.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<array name="com_google_android_gms_fonts_certs">
|
||||
<item>@array/com_google_android_gms_fonts_certs_dev</item>
|
||||
<item>@array/com_google_android_gms_fonts_certs_prod</item>
|
||||
</array>
|
||||
<string-array name="com_google_android_gms_fonts_certs_dev">
|
||||
<item>
|
||||
MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
|
||||
</item>
|
||||
</string-array>
|
||||
<string-array name="com_google_android_gms_fonts_certs_prod">
|
||||
<item>
|
||||
MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
|
||||
</item>
|
||||
</string-array>
|
||||
</resources>
|
9
viewcomponents/src/main/res/values/preloaded_fonts.xml
Normal file
9
viewcomponents/src/main/res/values/preloaded_fonts.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<array name="preloaded_fonts" translatable="false">
|
||||
<item>@font/fira_mono</item>
|
||||
<item>@font/lato</item>
|
||||
<item>@font/lato_black</item>
|
||||
<item>@font/lato_light</item>
|
||||
</array>
|
||||
</resources>
|
Loading…
Add table
Reference in a new issue