mirror of
https://github.com/afollestad/nock-nock.git
synced 2025-08-09 09:28:38 +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>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="preloaded_fonts"
|
||||||
|
android:resource="@array/preloaded_fonts"/>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,11 @@ import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.afollestad.nocknock.R
|
import com.afollestad.nocknock.R
|
||||||
import com.afollestad.nocknock.data.ServerModel
|
import com.afollestad.nocknock.data.ServerModel
|
||||||
import com.afollestad.nocknock.data.ServerStatus.WAITING
|
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.JAVASCRIPT
|
||||||
import com.afollestad.nocknock.data.ValidationMode.STATUS_CODE
|
import com.afollestad.nocknock.data.ValidationMode.STATUS_CODE
|
||||||
import com.afollestad.nocknock.data.ValidationMode.TERM_SEARCH
|
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.db.ServerModelStore
|
||||||
import com.afollestad.nocknock.engine.statuscheck.CheckStatusManager
|
import com.afollestad.nocknock.engine.statuscheck.CheckStatusManager
|
||||||
import com.afollestad.nocknock.utilities.ext.injector
|
import com.afollestad.nocknock.utilities.ext.injector
|
||||||
|
@ -56,6 +58,7 @@ import kotlinx.coroutines.launch
|
||||||
import java.lang.System.currentTimeMillis
|
import java.lang.System.currentTimeMillis
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
import kotlin.properties.Delegates.notNull
|
||||||
|
|
||||||
private const val KEY_FAB_X = "fab_x"
|
private const val KEY_FAB_X = "fab_x"
|
||||||
private const val KEY_FAB_Y = "fab_y"
|
private const val KEY_FAB_Y = "fab_y"
|
||||||
|
@ -76,11 +79,19 @@ fun MainActivity.intentToAdd(
|
||||||
/** @author Aidan Follestad (afollestad) */
|
/** @author Aidan Follestad (afollestad) */
|
||||||
class AddSiteActivity : AppCompatActivity(), View.OnClickListener {
|
class AddSiteActivity : AppCompatActivity(), View.OnClickListener {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val REVEAL_DURATION = 300L
|
||||||
|
}
|
||||||
|
|
||||||
private var isClosing: Boolean = false
|
private var isClosing: Boolean = false
|
||||||
|
|
||||||
@Inject lateinit var serverModelStore: ServerModelStore
|
@Inject lateinit var serverModelStore: ServerModelStore
|
||||||
@Inject lateinit var checkStatusManager: CheckStatusManager
|
@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")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
@ -91,7 +102,19 @@ class AddSiteActivity : AppCompatActivity(), View.OnClickListener {
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
rootView.conceal()
|
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 ->
|
inputUrl.setOnFocusChangeListener { _, hasFocus ->
|
||||||
|
@ -141,27 +164,23 @@ class AddSiteActivity : AppCompatActivity(), View.OnClickListener {
|
||||||
doneBtn.setOnClickListener(this)
|
doneBtn.setOnClickListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun closeActivityWithReveal() {
|
private fun circularRevealActivity() {
|
||||||
if (isClosing) {
|
val circularReveal =
|
||||||
return
|
createCircularReveal(rootView, revealCx, revealCy, 0f, revealRadius)
|
||||||
|
.apply {
|
||||||
|
duration = REVEAL_DURATION
|
||||||
|
interpolator = DecelerateInterpolator()
|
||||||
|
}
|
||||||
|
rootView.show()
|
||||||
|
circularReveal.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun closeActivityWithReveal() {
|
||||||
|
if (isClosing) return
|
||||||
isClosing = true
|
isClosing = true
|
||||||
val fabSize = intent.getIntExtra(KEY_FAB_SIZE, toolbar!!.measuredHeight)
|
createCircularReveal(rootView, revealCx, revealCy, revealRadius, 0f)
|
||||||
|
|
||||||
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)
|
|
||||||
.apply {
|
.apply {
|
||||||
duration = 300
|
duration = REVEAL_DURATION
|
||||||
interpolator = AccelerateInterpolator()
|
interpolator = AccelerateInterpolator()
|
||||||
onEnd {
|
onEnd {
|
||||||
rootView.conceal()
|
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
|
// Done button
|
||||||
override fun onClick(view: View) {
|
override fun onClick(view: View) {
|
||||||
isClosing = true
|
isClosing = true
|
||||||
|
@ -223,14 +228,14 @@ class AddSiteActivity : AppCompatActivity(), View.OnClickListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
val selectedCheckInterval = checkIntervalLayout.getSelectedCheckInterval()
|
val selectedCheckInterval = checkIntervalLayout.getSelectedCheckInterval()
|
||||||
val selectedValidationMode = getSelectedValidationMode()
|
val selectedValidationMode =
|
||||||
val selectedValidationContent = getSelectedValidationContent()
|
responseValidationMode.selectedItemPosition.indexToValidationMode()
|
||||||
|
|
||||||
newModel = newModel.copy(
|
newModel = newModel.copy(
|
||||||
checkInterval = selectedCheckInterval,
|
checkInterval = selectedCheckInterval,
|
||||||
lastCheck = currentTimeMillis() - selectedCheckInterval,
|
lastCheck = currentTimeMillis() - selectedCheckInterval,
|
||||||
validationMode = selectedValidationMode,
|
validationMode = selectedValidationMode,
|
||||||
validationContent = selectedValidationContent
|
validationContent = selectedValidationMode.validationContent()
|
||||||
)
|
)
|
||||||
|
|
||||||
rootView.scopeWhileAttached(Main) {
|
rootView.scopeWhileAttached(Main) {
|
||||||
|
@ -250,25 +255,9 @@ class AddSiteActivity : AppCompatActivity(), View.OnClickListener {
|
||||||
|
|
||||||
override fun onBackPressed() = closeActivityWithReveal()
|
override fun onBackPressed() = closeActivityWithReveal()
|
||||||
|
|
||||||
private fun getSelectedValidationMode() = when (responseValidationMode.selectedItemPosition) {
|
private fun ValidationMode.validationContent() = when (this) {
|
||||||
0 -> STATUS_CODE
|
STATUS_CODE -> null
|
||||||
1 -> TERM_SEARCH
|
TERM_SEARCH -> responseValidationSearchTerm.trimmedText()
|
||||||
2 -> JAVASCRIPT
|
JAVASCRIPT -> scriptInputLayout.getCode()
|
||||||
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}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock.ui
|
package com.afollestad.nocknock.ui
|
||||||
|
|
||||||
import android.animation.ObjectAnimator
|
|
||||||
import android.animation.ObjectAnimator.ofFloat
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.ActivityOptions.makeSceneTransitionAnimation
|
import android.app.ActivityOptions.makeSceneTransitionAnimation
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
|
@ -15,12 +13,6 @@ import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
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.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY
|
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.engine.statuscheck.CheckStatusManager
|
||||||
import com.afollestad.nocknock.notifications.NockNotificationManager
|
import com.afollestad.nocknock.notifications.NockNotificationManager
|
||||||
import com.afollestad.nocknock.utilities.ext.injector
|
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.safeRegisterReceiver
|
||||||
import com.afollestad.nocknock.utilities.ext.safeUnregisterReceiver
|
import com.afollestad.nocknock.utilities.ext.safeUnregisterReceiver
|
||||||
import com.afollestad.nocknock.utilities.ext.scopeWhileAttached
|
import com.afollestad.nocknock.utilities.ext.scopeWhileAttached
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.show
|
import com.afollestad.nocknock.viewcomponents.ext.show
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.showOrHide
|
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.fab
|
||||||
import kotlinx.android.synthetic.main.activity_main.list
|
import kotlinx.android.synthetic.main.activity_main.list
|
||||||
import kotlinx.android.synthetic.main.activity_main.rootView
|
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.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
|
@ -58,12 +49,11 @@ import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/** @author Aidan Follestad (afollestad) */
|
/** @author Aidan Follestad (afollestad) */
|
||||||
class MainActivity : AppCompatActivity(), View.OnClickListener {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val ADD_SITE_RQ = 6969
|
private const val ADD_SITE_RQ = 6969
|
||||||
private const val VIEW_SITE_RQ = 6923
|
private const val VIEW_SITE_RQ = 6923
|
||||||
private const val REVEAL_DURATION = 250L
|
|
||||||
|
|
||||||
private fun log(message: String) {
|
private fun log(message: String) {
|
||||||
if (BuildConfig.DEBUG) {
|
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() {
|
private val intentReceiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(
|
override fun onReceive(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@ -105,13 +91,26 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
|
||||||
injector().injectInto(this)
|
injector().injectInto(this)
|
||||||
setContentView(R.layout.activity_main)
|
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)
|
adapter = ServerAdapter(this::onSiteSelected)
|
||||||
|
|
||||||
list.layoutManager = LinearLayoutManager(this)
|
list.layoutManager = LinearLayoutManager(this)
|
||||||
list.adapter = adapter
|
list.adapter = adapter
|
||||||
list.addItemDecoration(DividerItemDecoration(this, VERTICAL))
|
list.addItemDecoration(DividerItemDecoration(this, VERTICAL))
|
||||||
|
|
||||||
fab.setOnClickListener(this)
|
fab.setOnClickListener {
|
||||||
|
startActivityForResult(
|
||||||
|
intentToAdd(fab.x, fab.y, fab.measuredWidth),
|
||||||
|
ADD_SITE_RQ
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
notificationManager.createChannels()
|
notificationManager.createChannels()
|
||||||
ensureCheckJobs()
|
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(
|
override fun onActivityResult(
|
||||||
requestCode: Int,
|
requestCode: Int,
|
||||||
resultCode: Int,
|
resultCode: Int,
|
||||||
|
|
|
@ -24,12 +24,15 @@ import androidx.core.text.HtmlCompat
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.afollestad.nocknock.BuildConfig
|
import com.afollestad.nocknock.BuildConfig
|
||||||
import com.afollestad.nocknock.R
|
import com.afollestad.nocknock.R
|
||||||
|
import com.afollestad.nocknock.data.LAST_CHECK_NONE
|
||||||
import com.afollestad.nocknock.data.ServerModel
|
import com.afollestad.nocknock.data.ServerModel
|
||||||
import com.afollestad.nocknock.data.ServerStatus.CHECKING
|
import com.afollestad.nocknock.data.ServerStatus.CHECKING
|
||||||
import com.afollestad.nocknock.data.ServerStatus.WAITING
|
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.JAVASCRIPT
|
||||||
import com.afollestad.nocknock.data.ValidationMode.STATUS_CODE
|
import com.afollestad.nocknock.data.ValidationMode.STATUS_CODE
|
||||||
import com.afollestad.nocknock.data.ValidationMode.TERM_SEARCH
|
import com.afollestad.nocknock.data.ValidationMode.TERM_SEARCH
|
||||||
|
import com.afollestad.nocknock.data.indexToValidationMode
|
||||||
import com.afollestad.nocknock.data.textRes
|
import com.afollestad.nocknock.data.textRes
|
||||||
import com.afollestad.nocknock.engine.db.ServerModelStore
|
import com.afollestad.nocknock.engine.db.ServerModelStore
|
||||||
import com.afollestad.nocknock.engine.statuscheck.CheckStatusJob.Companion.ACTION_STATUS_UPDATE
|
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.safeRegisterReceiver
|
||||||
import com.afollestad.nocknock.utilities.ext.safeUnregisterReceiver
|
import com.afollestad.nocknock.utilities.ext.safeUnregisterReceiver
|
||||||
import com.afollestad.nocknock.utilities.ext.scopeWhileAttached
|
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.hide
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.onItemSelected
|
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.show
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.showOrHide
|
import com.afollestad.nocknock.viewcomponents.ext.showOrHide
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.trimmedText
|
import com.afollestad.nocknock.viewcomponents.ext.trimmedText
|
||||||
import kotlinx.android.synthetic.main.activity_viewsite.checkIntervalLayout
|
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.doneBtn
|
||||||
import kotlinx.android.synthetic.main.activity_viewsite.iconStatus
|
import kotlinx.android.synthetic.main.activity_viewsite.iconStatus
|
||||||
import kotlinx.android.synthetic.main.activity_viewsite.inputName
|
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.responseValidationSearchTerm
|
||||||
import kotlinx.android.synthetic.main.activity_viewsite.rootView
|
import kotlinx.android.synthetic.main.activity_viewsite.rootView
|
||||||
import kotlinx.android.synthetic.main.activity_viewsite.scriptInputLayout
|
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.textLastCheckResult
|
||||||
import kotlinx.android.synthetic.main.activity_viewsite.textNextCheck
|
import kotlinx.android.synthetic.main.activity_viewsite.textNextCheck
|
||||||
import kotlinx.android.synthetic.main.activity_viewsite.textUrlWarning
|
import kotlinx.android.synthetic.main.activity_viewsite.textUrlWarning
|
||||||
|
@ -122,6 +131,14 @@ class ViewSiteActivity : AppCompatActivity(),
|
||||||
setOnMenuItemClickListener(this@ViewSiteActivity)
|
setOnMenuItemClickListener(this@ViewSiteActivity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scrollView.onScroll {
|
||||||
|
toolbar.elevation = if (it > toolbar.height / 4) {
|
||||||
|
toolbar.dimenFloat(R.dimen.default_elevation)
|
||||||
|
} else {
|
||||||
|
0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inputUrl.setOnFocusChangeListener { _, hasFocus ->
|
inputUrl.setOnFocusChangeListener { _, hasFocus ->
|
||||||
if (!hasFocus) {
|
if (!hasFocus) {
|
||||||
val inputStr = inputUrl.text
|
val inputStr = inputUrl.text
|
||||||
|
@ -184,7 +201,7 @@ class ViewSiteActivity : AppCompatActivity(),
|
||||||
inputName.setText(this.name)
|
inputName.setText(this.name)
|
||||||
inputUrl.setText(this.url)
|
inputUrl.setText(this.url)
|
||||||
|
|
||||||
if (this.lastCheck == 0L) {
|
if (this.lastCheck == LAST_CHECK_NONE) {
|
||||||
textLastCheckResult.setText(R.string.none)
|
textLastCheckResult.setText(R.string.none)
|
||||||
} else {
|
} else {
|
||||||
val statusText = this.status.textRes()
|
val statusText = this.status.textRes()
|
||||||
|
@ -195,16 +212,8 @@ class ViewSiteActivity : AppCompatActivity(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.checkInterval == 0L) {
|
textNextCheck.text = (this.lastCheck + this.checkInterval).formatDate()
|
||||||
textNextCheck.setText(R.string.none_turned_off)
|
checkIntervalLayout.set(this.checkInterval)
|
||||||
checkIntervalLayout.clear()
|
|
||||||
} else {
|
|
||||||
var lastCheck = this.lastCheck
|
|
||||||
if (lastCheck == 0L) {
|
|
||||||
lastCheck = currentTimeMillis()
|
|
||||||
}
|
|
||||||
textNextCheck.text = (lastCheck + this.checkInterval).formatDate()
|
|
||||||
}
|
|
||||||
|
|
||||||
responseValidationMode.setSelection(validationMode.value - 1)
|
responseValidationMode.setSelection(validationMode.value - 1)
|
||||||
|
|
||||||
|
@ -267,14 +276,14 @@ class ViewSiteActivity : AppCompatActivity(),
|
||||||
}
|
}
|
||||||
|
|
||||||
val selectedCheckInterval = checkIntervalLayout.getSelectedCheckInterval()
|
val selectedCheckInterval = checkIntervalLayout.getSelectedCheckInterval()
|
||||||
val selectedValidationMode = getSelectedValidationMode()
|
val selectedValidationMode =
|
||||||
val selectedValidationContent = getSelectedValidationContent()
|
responseValidationMode.selectedItemPosition.indexToValidationMode()
|
||||||
|
|
||||||
currentModel = currentModel.copy(
|
currentModel = currentModel.copy(
|
||||||
checkInterval = selectedCheckInterval,
|
checkInterval = selectedCheckInterval,
|
||||||
lastCheck = currentTimeMillis() - selectedCheckInterval,
|
lastCheck = currentTimeMillis() - selectedCheckInterval,
|
||||||
validationMode = selectedValidationMode,
|
validationMode = selectedValidationMode,
|
||||||
validationContent = selectedValidationContent
|
validationContent = selectedValidationMode.validationContent()
|
||||||
)
|
)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -307,6 +316,7 @@ class ViewSiteActivity : AppCompatActivity(),
|
||||||
R.id.refresh -> {
|
R.id.refresh -> {
|
||||||
rootView.scopeWhileAttached(Main) {
|
rootView.scopeWhileAttached(Main) {
|
||||||
launch(coroutineContext) {
|
launch(coroutineContext) {
|
||||||
|
disableChecksButton.disable()
|
||||||
loadingProgress.setLoading()
|
loadingProgress.setLoading()
|
||||||
updateModelFromInput(false)
|
updateModelFromInput(false)
|
||||||
currentModel = currentModel.copy(status = WAITING)
|
currentModel = currentModel.copy(status = WAITING)
|
||||||
|
@ -317,6 +327,7 @@ class ViewSiteActivity : AppCompatActivity(),
|
||||||
checkStatusManager.cancelCheck(currentModel)
|
checkStatusManager.cancelCheck(currentModel)
|
||||||
checkStatusManager.scheduleCheck(currentModel, rightNow = true)
|
checkStatusManager.scheduleCheck(currentModel, rightNow = true)
|
||||||
loadingProgress.setDone()
|
loadingProgress.setDone()
|
||||||
|
disableChecksButton.enable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -363,25 +374,9 @@ class ViewSiteActivity : AppCompatActivity(),
|
||||||
item.isEnabled = currentModel.status != CHECKING && currentModel.status != WAITING
|
item.isEnabled = currentModel.status != CHECKING && currentModel.status != WAITING
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSelectedValidationMode() = when (responseValidationMode.selectedItemPosition) {
|
private fun ValidationMode.validationContent() = when (this) {
|
||||||
0 -> STATUS_CODE
|
STATUS_CODE -> null
|
||||||
1 -> TERM_SEARCH
|
TERM_SEARCH -> responseValidationSearchTerm.trimmedText()
|
||||||
2 -> JAVASCRIPT
|
JAVASCRIPT -> scriptInputLayout.getCode()
|
||||||
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}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,10 @@
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:theme="@style/FlatToolbarTheme"
|
||||||
app:navigationIcon="@drawable/ic_action_close"
|
app:navigationIcon="@drawable/ic_action_close"
|
||||||
app:title="@string/add_site"
|
app:title="@string/add_site"
|
||||||
app:titleTextColor="?android:textColorPrimary"
|
app:titleTextColor="#FFFFFF"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
|
@ -51,7 +52,7 @@
|
||||||
android:id="@+id/inputName"
|
android:id="@+id/inputName"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato"
|
||||||
android:hint="@string/site_name"
|
android:hint="@string/site_name"
|
||||||
android:inputType="textPersonName|textCapWords|textAutoCorrect"
|
android:inputType="textPersonName|textCapWords|textAutoCorrect"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
|
@ -74,7 +75,7 @@
|
||||||
android:id="@+id/inputUrl"
|
android:id="@+id/inputUrl"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato"
|
||||||
android:hint="@string/site_url"
|
android:hint="@string/site_url"
|
||||||
android:inputType="textUri"
|
android:inputType="textUri"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
|
@ -89,7 +90,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/list_text_spacing"
|
android:layout_marginTop="@dimen/list_text_spacing"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato_light"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
android:textSize="@dimen/caption_font_size"
|
android:textSize="@dimen/caption_font_size"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
|
@ -106,11 +107,11 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/responseValidation"
|
android:id="@+id/responseValidationLabel"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/content_inset"
|
android:layout_marginTop="@dimen/content_inset"
|
||||||
android:fontFamily="sans-serif"
|
android:fontFamily="@font/lato"
|
||||||
android:text="@string/response_validation_mode"
|
android:text="@string/response_validation_mode"
|
||||||
android:textColor="?colorAccent"
|
android:textColor="?colorAccent"
|
||||||
android:textSize="@dimen/caption_font_size"
|
android:textSize="@dimen/caption_font_size"
|
||||||
|
@ -130,11 +131,11 @@
|
||||||
android:layout_marginLeft="-4dp"
|
android:layout_marginLeft="-4dp"
|
||||||
android:layout_marginRight="-4dp"
|
android:layout_marginRight="-4dp"
|
||||||
android:layout_marginTop="-4dp"
|
android:layout_marginTop="-4dp"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato_light"
|
||||||
android:hint="@string/search_term"
|
android:hint="@string/search_term"
|
||||||
android:textSize="@dimen/body_font_size"
|
android:textSize="@dimen/body_font_size"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:ignore="Autofill"
|
tools:ignore="Autofill,TextFields"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<com.afollestad.nocknock.viewcomponents.JavaScriptInputLayout
|
<com.afollestad.nocknock.viewcomponents.JavaScriptInputLayout
|
||||||
|
@ -151,7 +152,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="@dimen/content_inset_half"
|
android:layout_marginBottom="@dimen/content_inset_half"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato_light"
|
||||||
android:lineSpacingMultiplier="1.2"
|
android:lineSpacingMultiplier="1.2"
|
||||||
android:text="@string/validation_mode_status_desc"
|
android:text="@string/validation_mode_status_desc"
|
||||||
android:textSize="@dimen/body_font_size"
|
android:textSize="@dimen/body_font_size"
|
||||||
|
@ -161,7 +162,7 @@
|
||||||
android:id="@+id/doneBtn"
|
android:id="@+id/doneBtn"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/content_inset"
|
android:layout_marginTop="@dimen/content_inset_double"
|
||||||
android:text="@string/done"
|
android:text="@string/done"
|
||||||
style="@style/AccentButton"
|
style="@style/AccentButton"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/rootView"
|
android:id="@+id/rootView"
|
||||||
|
@ -8,6 +9,20 @@
|
||||||
tools:context=".ui.MainActivity"
|
tools:context=".ui.MainActivity"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
>
|
||||||
|
|
||||||
|
<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
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/list"
|
android:id="@+id/list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -15,31 +30,22 @@
|
||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextView
|
</LinearLayout>
|
||||||
android:id="@+id/emptyText"
|
|
||||||
android:layout_width="match_parent"
|
<include layout="@layout/include_empty_view"/>
|
||||||
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"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/fab"
|
android:id="@+id/fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="end|bottom"
|
android:layout_gravity="end|bottom"
|
||||||
|
android:layout_margin="@dimen/content_inset"
|
||||||
android:src="@drawable/ic_add"
|
android:src="@drawable/ic_add"
|
||||||
app:backgroundTint="?colorAccent"
|
app:backgroundTint="?colorAccent"
|
||||||
app:elevation="@dimen/fab_elevation"
|
app:elevation="@dimen/fab_elevation"
|
||||||
app:fabSize="normal"
|
app:fabSize="normal"
|
||||||
app:pressedTranslationZ="@dimen/fab_elevation_pressed"
|
app:pressedTranslationZ="@dimen/fab_elevation_pressed"
|
||||||
app:rippleColor="#40ffffff"
|
app:rippleColor="#40ffffff"
|
||||||
app:useCompatPadding="true"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
|
@ -15,16 +15,20 @@
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<!-- Background is applied again here so programmatic elevation works -->
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?colorPrimary"
|
||||||
|
android:theme="@style/FlatToolbarTheme"
|
||||||
app:navigationIcon="@drawable/ic_action_close"
|
app:navigationIcon="@drawable/ic_action_close"
|
||||||
app:title="@string/view_site"
|
app:title="@string/view_site"
|
||||||
app:titleTextColor="?android:textColorPrimary"
|
app:titleTextColor="?android:textColorPrimary"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
|
android:id="@+id/scrollView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
>
|
>
|
||||||
|
@ -66,7 +70,7 @@
|
||||||
android:id="@+id/inputName"
|
android:id="@+id/inputName"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato"
|
||||||
android:hint="@string/site_name"
|
android:hint="@string/site_name"
|
||||||
android:inputType="textPersonName|textCapWords|textAutoCorrect"
|
android:inputType="textPersonName|textCapWords|textAutoCorrect"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
|
@ -74,14 +78,14 @@
|
||||||
android:textColorHint="?android:textColorSecondary"
|
android:textColorHint="?android:textColorSecondary"
|
||||||
android:textSize="@dimen/body_font_size"
|
android:textSize="@dimen/body_font_size"
|
||||||
android:transitionName="site_name"
|
android:transitionName="site_name"
|
||||||
tools:ignore="UnusedAttribute"
|
tools:ignore="Autofill,UnusedAttribute"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/inputUrl"
|
android:id="@+id/inputUrl"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato"
|
||||||
android:hint="@string/site_url"
|
android:hint="@string/site_url"
|
||||||
android:inputType="textUri"
|
android:inputType="textUri"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
|
@ -89,7 +93,7 @@
|
||||||
android:textColorHint="?android:textColorSecondary"
|
android:textColorHint="?android:textColorSecondary"
|
||||||
android:textSize="@dimen/body_font_size"
|
android:textSize="@dimen/body_font_size"
|
||||||
android:transitionName="site_url"
|
android:transitionName="site_url"
|
||||||
tools:ignore="UnusedAttribute"
|
tools:ignore="Autofill,UnusedAttribute"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -99,7 +103,7 @@
|
||||||
android:layout_marginEnd="4dp"
|
android:layout_marginEnd="4dp"
|
||||||
android:layout_marginStart="4dp"
|
android:layout_marginStart="4dp"
|
||||||
android:layout_marginTop="@dimen/list_text_spacing"
|
android:layout_marginTop="@dimen/list_text_spacing"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato_light"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
android:textSize="@dimen/caption_font_size"
|
android:textSize="@dimen/caption_font_size"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
|
@ -132,11 +136,11 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/responseValidation"
|
android:id="@+id/responseValidationLabel"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/content_inset"
|
android:layout_marginTop="@dimen/content_inset"
|
||||||
android:fontFamily="sans-serif"
|
android:fontFamily="@font/lato"
|
||||||
android:text="@string/response_validation_mode"
|
android:text="@string/response_validation_mode"
|
||||||
android:textColor="?colorAccent"
|
android:textColor="?colorAccent"
|
||||||
android:textSize="@dimen/caption_font_size"
|
android:textSize="@dimen/caption_font_size"
|
||||||
|
@ -156,7 +160,7 @@
|
||||||
android:layout_marginLeft="-4dp"
|
android:layout_marginLeft="-4dp"
|
||||||
android:layout_marginRight="-4dp"
|
android:layout_marginRight="-4dp"
|
||||||
android:layout_marginTop="-4dp"
|
android:layout_marginTop="-4dp"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato_light"
|
||||||
android:hint="@string/search_term"
|
android:hint="@string/search_term"
|
||||||
android:textSize="@dimen/body_font_size"
|
android:textSize="@dimen/body_font_size"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
|
@ -177,7 +181,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="@dimen/content_inset_half"
|
android:layout_marginBottom="@dimen/content_inset_half"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato"
|
||||||
android:lineSpacingMultiplier="1.2"
|
android:lineSpacingMultiplier="1.2"
|
||||||
android:text="@string/validation_mode_status_desc"
|
android:text="@string/validation_mode_status_desc"
|
||||||
android:textSize="@dimen/body_font_size"
|
android:textSize="@dimen/body_font_size"
|
||||||
|
@ -199,7 +203,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/list_text_spacing"
|
android:layout_marginTop="@dimen/list_text_spacing"
|
||||||
android:fontFamily="sans-serif"
|
android:fontFamily="@font/lato"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
android:textSize="@dimen/medium_text_size"
|
android:textSize="@dimen/medium_text_size"
|
||||||
tools:text="Everything checks out!"
|
tools:text="Everything checks out!"
|
||||||
|
@ -219,7 +223,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/list_text_spacing"
|
android:layout_marginTop="@dimen/list_text_spacing"
|
||||||
android:fontFamily="sans-serif"
|
android:fontFamily="@font/lato"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
android:textSize="@dimen/medium_text_size"
|
android:textSize="@dimen/medium_text_size"
|
||||||
tools:text="In 2 hours"
|
tools:text="In 2 hours"
|
||||||
|
@ -229,11 +233,20 @@
|
||||||
android:id="@+id/doneBtn"
|
android:id="@+id/doneBtn"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/content_inset_more"
|
android:layout_marginTop="@dimen/content_inset_double"
|
||||||
android:text="@string/save"
|
android:text="@string/save_changes"
|
||||||
style="@style/AccentButton"
|
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>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</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_centerVertical="true"
|
||||||
android:layout_marginEnd="@dimen/content_inset_half"
|
android:layout_marginEnd="@dimen/content_inset_half"
|
||||||
android:layout_toStartOf="@+id/textInterval"
|
android:layout_toStartOf="@+id/textInterval"
|
||||||
android:fontFamily="sans-serif-medium"
|
android:fontFamily="@font/lato"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
android:textSize="@dimen/title_font_size"
|
android:textSize="@dimen/title_font_size"
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato_light"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="@dimen/caption_font_size"
|
android:textSize="@dimen/caption_font_size"
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/list_text_spacing"
|
android:layout_marginTop="@dimen/list_text_spacing"
|
||||||
android:fontFamily="sans-serif"
|
android:fontFamily="@font/lato"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="@dimen/body_font_size"
|
android:textSize="@dimen/body_font_size"
|
||||||
|
@ -84,7 +84,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/list_text_spacing"
|
android:layout_marginTop="@dimen/list_text_spacing"
|
||||||
android:fontFamily="sans-serif"
|
android:fontFamily="@font/lato"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="@dimen/body_font_size"
|
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>
|
<string name="no_sites_added">No sites added!</string>
|
||||||
|
|
||||||
|
@ -29,7 +29,8 @@
|
||||||
<string name="remove_site">Remove Site</string>
|
<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_site_prompt"><![CDATA[Remove <b>%1$s</b> from your sites?]]></string>
|
||||||
<string name="remove">Remove</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="view_site">View Site</string>
|
||||||
<string name="last_check_result">Last Check Result</string>
|
<string name="last_check_result">Last Check Result</string>
|
||||||
<string name="next_check">Next Check</string>
|
<string name="next_check">Next Check</string>
|
||||||
|
@ -39,13 +40,23 @@
|
||||||
<string name="refresh_status">Refresh Status</string>
|
<string name="refresh_status">Refresh Status</string>
|
||||||
|
|
||||||
<string name="warning_http_url">
|
<string name="warning_http_url">
|
||||||
Warning: this app checks for server availability with HTTP requests. It\'s recommended that you use an HTTP URL.
|
Warning: this app checks for server availability with HTTP requests. It\'s recommended that you
|
||||||
|
use an HTTP URL.
|
||||||
</string>
|
</string>
|
||||||
<string name="response_validation_mode">Response Validation Mode</string>
|
<string name="response_validation_mode">Response Validation Mode</string>
|
||||||
<string name="search_term">Search term…</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_status_desc">
|
||||||
<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>
|
The HTTP status code is checked. If it\'s a successful status code, the site passes the check.
|
||||||
<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>
|
||||||
|
<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>
|
</resources>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<resources>
|
<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="colorPrimary">@color/colorPrimary</item>
|
||||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
<item name="colorAccent">@color/colorAccent</item>
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
@ -27,9 +27,38 @@
|
||||||
<item name="android:windowBackground">@android:color/transparent</item>
|
<item name="android:windowBackground">@android:color/transparent</item>
|
||||||
</style>
|
</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">
|
<style name="AccentButton" parent="Widget.MaterialComponents.Button">
|
||||||
<item name="android:textColor">#fff</item>
|
<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>
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -12,17 +12,21 @@ import com.afollestad.nocknock.utilities.ext.timeString
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.lang.System.currentTimeMillis
|
import java.lang.System.currentTimeMillis
|
||||||
|
|
||||||
|
const val CHECK_INTERVAL_UNSET = -1L
|
||||||
|
const val LAST_CHECK_NONE = -1L
|
||||||
|
|
||||||
/** @author Aidan Follestad (afollestad)*/
|
/** @author Aidan Follestad (afollestad)*/
|
||||||
data class ServerModel(
|
data class ServerModel(
|
||||||
var id: Int = 0,
|
var id: Int = 0,
|
||||||
val name: String = "Unknown",
|
val name: String,
|
||||||
val url: String = "Unknown",
|
val url: String,
|
||||||
val status: ServerStatus = OK,
|
val status: ServerStatus = OK,
|
||||||
val checkInterval: Long = 0,
|
val checkInterval: Long = CHECK_INTERVAL_UNSET,
|
||||||
val lastCheck: Long = 0,
|
val lastCheck: Long = LAST_CHECK_NONE,
|
||||||
val reason: String? = null,
|
val reason: String? = null,
|
||||||
val validationMode: ValidationMode,
|
val validationMode: ValidationMode,
|
||||||
val validationContent: String? = null
|
val validationContent: String? = null,
|
||||||
|
val disabled: Boolean = false
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -36,8 +40,9 @@ data class ServerModel(
|
||||||
const val COLUMN_REASON = "reason"
|
const val COLUMN_REASON = "reason"
|
||||||
const val COLUMN_VALIDATION_MODE = "validation_mode"
|
const val COLUMN_VALIDATION_MODE = "validation_mode"
|
||||||
const val COLUMN_VALIDATION_CONTENT = "validation_content"
|
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 {
|
fun pull(cursor: Cursor): ServerModel {
|
||||||
return ServerModel(
|
return ServerModel(
|
||||||
|
@ -51,7 +56,8 @@ data class ServerModel(
|
||||||
validationMode = cursor.getInt(
|
validationMode = cursor.getInt(
|
||||||
cursor.getColumnIndex(COLUMN_VALIDATION_MODE)
|
cursor.getColumnIndex(COLUMN_VALIDATION_MODE)
|
||||||
).toValidationMode(),
|
).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_REASON, reason)
|
||||||
put(COLUMN_VALIDATION_MODE, validationMode.value)
|
put(COLUMN_VALIDATION_MODE, validationMode.value)
|
||||||
put(COLUMN_VALIDATION_CONTENT, validationContent)
|
put(COLUMN_VALIDATION_CONTENT, validationContent)
|
||||||
|
put(COLUMN_DISABLED, disabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,16 @@ enum class ValidationMode(val value: Int) {
|
||||||
JAVASCRIPT.value -> JAVASCRIPT
|
JAVASCRIPT.value -> JAVASCRIPT
|
||||||
else -> throw IllegalArgumentException("Unknown validationMode: $value")
|
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.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_LAST_CHECK} INTEGER," +
|
||||||
"${ServerModel.COLUMN_REASON} TEXT," +
|
"${ServerModel.COLUMN_REASON} TEXT," +
|
||||||
"${ServerModel.COLUMN_VALIDATION_MODE} INTEGER," +
|
"${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}"
|
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
|
context, DATABASE_NAME, null, DATABASE_VERSION
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
const val DATABASE_VERSION = 1
|
const val DATABASE_VERSION = 2
|
||||||
const val DATABASE_NAME = "ServerModels.db"
|
const val DATABASE_NAME = "ServerModels.db"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,9 @@ import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
fun Long.formatDate(): String {
|
fun Long.formatDate(): String {
|
||||||
|
if (this <= 0) {
|
||||||
|
return "(None)"
|
||||||
|
}
|
||||||
val df = SimpleDateFormat("MMMM dd, hh:mm:ss a", Locale.getDefault())
|
val df = SimpleDateFormat("MMMM dd, hh:mm:ss a", Locale.getDefault())
|
||||||
return df.format(Date(this))
|
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 {
|
@CheckResult fun getSelectedCheckInterval(): Long {
|
||||||
val intervalInput = input.textAsLong()
|
val intervalInput = input.textAsLong()
|
||||||
val spinnerPos = spinner.selectedItemPosition
|
val spinnerPos = spinner.selectedItemPosition
|
||||||
|
|
|
@ -27,6 +27,8 @@ class LoadingIndicatorFrame(
|
||||||
setBackgroundColor(ContextCompat.getColor(context, R.color.loading_indicator_frame_background))
|
setBackgroundColor(ContextCompat.getColor(context, R.color.loading_indicator_frame_background))
|
||||||
hide() // hide self by default
|
hide() // hide self by default
|
||||||
inflate(context, R.layout.loading_indicator_frame, this)
|
inflate(context, R.layout.loading_indicator_frame, this)
|
||||||
|
isClickable = true
|
||||||
|
isFocusable = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setLoading() {
|
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
|
visibility = GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun View.enable() {
|
||||||
|
isEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun View.disable() {
|
||||||
|
isEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
fun View.showOrHide(show: Boolean) = if (show) show() else hide()
|
fun View.showOrHide(show: Boolean) = if (show) show() else hide()
|
||||||
|
|
||||||
fun View.onLayout(cb: () -> Unit) {
|
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_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
tools:parentTag="android.widget.LinearLayout"
|
||||||
>
|
>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/label"
|
android:id="@+id/label"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="sans-serif"
|
android:fontFamily="@font/lato"
|
||||||
android:text="@string/check_interval"
|
android:text="@string/check_interval"
|
||||||
android:textColor="?colorAccent"
|
android:textColor="?colorAccent"
|
||||||
android:textSize="@dimen/caption_font_size"
|
android:textSize="@dimen/caption_font_size"
|
||||||
|
@ -32,7 +33,7 @@
|
||||||
android:layout_marginEnd="@dimen/content_inset_half"
|
android:layout_marginEnd="@dimen/content_inset_half"
|
||||||
android:layout_marginStart="-4dp"
|
android:layout_marginStart="-4dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato_light"
|
||||||
android:hint="0"
|
android:hint="0"
|
||||||
android:inputType="number"
|
android:inputType="number"
|
||||||
android:maxLength="6"
|
android:maxLength="6"
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="serif-monospace"
|
android:fontFamily="@font/fira_mono"
|
||||||
android:lineSpacingMultiplier="1.4"
|
android:lineSpacingMultiplier="1.4"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="@string/function_declaration"
|
android:text="@string/function_declaration"
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@null"
|
android:background="@null"
|
||||||
android:fontFamily="serif-monospace"
|
android:fontFamily="@font/fira_mono"
|
||||||
android:gravity="top"
|
android:gravity="top"
|
||||||
android:inputType="textMultiLine"
|
android:inputType="textMultiLine"
|
||||||
android:lineSpacingMultiplier="1.6"
|
android:lineSpacingMultiplier="1.6"
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="serif-monospace"
|
android:fontFamily="@font/fira_mono"
|
||||||
android:text="@string/function_end"
|
android:text="@string/function_end"
|
||||||
android:textSize="@dimen/code_font_size"
|
android:textSize="@dimen/code_font_size"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/button_height"
|
android:layout_height="@dimen/button_height"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato"
|
||||||
android:gravity="center_vertical|start"
|
android:gravity="center_vertical|start"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
android:textSize="@dimen/body_font_size"
|
android:textSize="@dimen/body_font_size"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/button_height"
|
android:layout_height="@dimen/button_height"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="@font/lato"
|
||||||
android:gravity="center_vertical|start"
|
android:gravity="center_vertical|start"
|
||||||
android:paddingLeft="@dimen/content_inset"
|
android:paddingLeft="@dimen/content_inset"
|
||||||
android:paddingRight="@dimen/content_inset"
|
android:paddingRight="@dimen/content_inset"
|
||||||
|
|
|
@ -4,12 +4,10 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
>
|
>
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
style="?android:progressBarStyleLarge"
|
style="?android:progressBarStyleLarge"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</merge>
|
</merge>
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
<dimen name="content_inset_less">12dp</dimen>
|
<dimen name="content_inset_less">12dp</dimen>
|
||||||
<dimen name="content_inset">16dp</dimen>
|
<dimen name="content_inset">16dp</dimen>
|
||||||
<dimen name="content_inset_more">24dp</dimen>
|
<dimen name="content_inset_more">24dp</dimen>
|
||||||
|
<dimen name="content_inset_double">32dp</dimen>
|
||||||
|
|
||||||
<dimen name="code_font_size">14sp</dimen>
|
<dimen name="code_font_size">14sp</dimen>
|
||||||
<dimen name="body_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
Add a link
Reference in a new issue