Re-organize some UI, hook up SSL certificate selection, etc. Resolves #42.

This commit is contained in:
Aidan Follestad 2019-01-11 18:50:04 -08:00
commit 26d6d9abf8
14 changed files with 238 additions and 62 deletions

View file

@ -16,13 +16,20 @@
package com.afollestad.nocknock.ui.addsite
import android.annotation.SuppressLint
import android.content.Intent
import android.content.Intent.ACTION_OPEN_DOCUMENT
import android.content.Intent.CATEGORY_OPENABLE
import android.os.Bundle
import android.widget.ArrayAdapter
import androidx.lifecycle.Observer
import com.afollestad.nocknock.R
import com.afollestad.nocknock.data.model.Site
import com.afollestad.nocknock.data.model.ValidationMode
import com.afollestad.nocknock.ui.DarkModeSwitchActivity
import com.afollestad.nocknock.ui.viewsite.KEY_SITE
import com.afollestad.nocknock.utilities.ext.onTextChanged
import com.afollestad.nocknock.utilities.ext.toUri
import com.afollestad.nocknock.utilities.livedata.distinct
import com.afollestad.nocknock.viewcomponents.ext.dimenFloat
import com.afollestad.nocknock.viewcomponents.ext.onScroll
import com.afollestad.nocknock.viewcomponents.livedata.attachLiveData
@ -41,6 +48,8 @@ import kotlinx.android.synthetic.main.activity_addsite.responseValidationSearchT
import kotlinx.android.synthetic.main.activity_addsite.retryPolicyLayout
import kotlinx.android.synthetic.main.activity_addsite.scriptInputLayout
import kotlinx.android.synthetic.main.activity_addsite.scrollView
import kotlinx.android.synthetic.main.activity_addsite.sslCertificateBrowse
import kotlinx.android.synthetic.main.activity_addsite.sslCertificateInput
import kotlinx.android.synthetic.main.activity_addsite.textUrlWarning
import kotlinx.android.synthetic.main.activity_addsite.validationModeDescription
import kotlinx.android.synthetic.main.include_app_bar.toolbar
@ -50,6 +59,9 @@ import kotlinx.android.synthetic.main.include_app_bar.toolbar_title as toolbarTi
/** @author Aidan Follestad (@afollestad) */
class AddSiteActivity : DarkModeSwitchActivity() {
companion object {
private const val SELECT_CERT_FILE_RQ = 23
}
private val viewModel by viewModel<AddSiteViewModel>()
@ -165,5 +177,38 @@ class AddSiteActivity : DarkModeSwitchActivity() {
0f
}
}
// SSL certificate
sslCertificateInput.onTextChanged { viewModel.certificateUri.value = it.toUri() }
viewModel.certificateUri.distinct()
.observe(this, Observer { sslCertificateInput.setText(it.toString()) })
sslCertificateBrowse.setOnClickListener {
val intent = Intent(ACTION_OPEN_DOCUMENT).apply {
addCategory(CATEGORY_OPENABLE)
type = "*/*"
}
startActivityForResult(intent, SELECT_CERT_FILE_RQ)
}
}
override fun onResume() {
super.onResume()
appToolbar.elevation =
if (scrollView.scrollY > appToolbar.measuredHeight / 2) {
appToolbar.dimenFloat(R.dimen.default_elevation)
} else {
0f
}
}
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
resultData: Intent?
) {
super.onActivityResult(requestCode, resultCode, resultData)
if (requestCode == SELECT_CERT_FILE_RQ && resultCode == RESULT_OK) {
sslCertificateInput.setText(resultData?.data?.toString() ?: "")
}
}
}

View file

@ -15,6 +15,7 @@
*/
package com.afollestad.nocknock.ui.addsite
import android.net.Uri
import androidx.annotation.CheckResult
import androidx.annotation.VisibleForTesting
import androidx.annotation.VisibleForTesting.PRIVATE
@ -68,6 +69,7 @@ class AddSiteViewModel(
val retryPolicyTimes = MutableLiveData<Int>()
val retryPolicyMinutes = MutableLiveData<Int>()
val headers = MutableLiveData<List<Header>>()
val certificateUri = MutableLiveData<Uri>()
@OnLifecycleEvent(ON_START)
fun setDefaults() {
@ -237,7 +239,8 @@ class AddSiteViewModel(
validationMode = validationMode.value!!,
validationArgs = getValidationArgs(),
networkTimeout = timeout,
disabled = false
disabled = false,
certificate = certificateUri.value.toString()
)
val newLastResult = ValidationResult(

View file

@ -17,6 +17,8 @@ package com.afollestad.nocknock.ui.viewsite
import android.annotation.SuppressLint
import android.content.Intent
import android.content.Intent.ACTION_OPEN_DOCUMENT
import android.content.Intent.CATEGORY_OPENABLE
import android.os.Bundle
import android.widget.ArrayAdapter
import androidx.lifecycle.Observer
@ -25,6 +27,9 @@ import com.afollestad.nocknock.broadcasts.StatusUpdateIntentReceiver
import com.afollestad.nocknock.data.model.Site
import com.afollestad.nocknock.data.model.ValidationMode
import com.afollestad.nocknock.ui.DarkModeSwitchActivity
import com.afollestad.nocknock.utilities.ext.onTextChanged
import com.afollestad.nocknock.utilities.ext.toUri
import com.afollestad.nocknock.utilities.livedata.distinct
import com.afollestad.nocknock.utilities.providers.IntentProvider
import com.afollestad.nocknock.viewcomponents.ext.dimenFloat
import com.afollestad.nocknock.viewcomponents.ext.onScroll
@ -45,18 +50,23 @@ import kotlinx.android.synthetic.main.activity_viewsite.responseValidationSearch
import kotlinx.android.synthetic.main.activity_viewsite.retryPolicyLayout
import kotlinx.android.synthetic.main.activity_viewsite.scriptInputLayout
import kotlinx.android.synthetic.main.activity_viewsite.scrollView
import kotlinx.android.synthetic.main.activity_viewsite.sslCertificateBrowse
import kotlinx.android.synthetic.main.activity_viewsite.sslCertificateInput
import kotlinx.android.synthetic.main.activity_viewsite.textLastCheckResult
import kotlinx.android.synthetic.main.activity_viewsite.textNextCheck
import kotlinx.android.synthetic.main.activity_viewsite.textUrlWarning
import kotlinx.android.synthetic.main.activity_viewsite.validationModeDescription
import kotlinx.android.synthetic.main.include_app_bar.app_toolbar as appToolbar
import kotlinx.android.synthetic.main.include_app_bar.toolbar
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import kotlinx.android.synthetic.main.include_app_bar.app_toolbar as appToolbar
import kotlinx.android.synthetic.main.include_app_bar.toolbar_title as toolbarTitle
/** @author Aidan Follestad (@afollestad) */
class ViewSiteActivity : DarkModeSwitchActivity() {
companion object {
private const val SELECT_CERT_FILE_RQ = 23
}
internal val viewModel by viewModel<ViewSiteViewModel>()
@ -210,6 +220,39 @@ class ViewSiteActivity : DarkModeSwitchActivity() {
toolbar.menu.findItem(R.id.commit)
.setTitle(it)
})
// SSL certificate
sslCertificateInput.onTextChanged { viewModel.certificateUri.value = it.toUri() }
viewModel.certificateUri.distinct()
.observe(this, Observer { sslCertificateInput.setText(it.toString()) })
sslCertificateBrowse.setOnClickListener {
val intent = Intent(ACTION_OPEN_DOCUMENT).apply {
addCategory(CATEGORY_OPENABLE)
type = "*/*"
}
startActivityForResult(intent, SELECT_CERT_FILE_RQ)
}
}
override fun onResume() {
super.onResume()
appToolbar.elevation =
if (scrollView.scrollY > appToolbar.measuredHeight / 2) {
appToolbar.dimenFloat(R.dimen.default_elevation)
} else {
0f
}
}
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
resultData: Intent?
) {
super.onActivityResult(requestCode, resultCode, resultData)
if (requestCode == SELECT_CERT_FILE_RQ && resultCode == RESULT_OK) {
sslCertificateInput.setText(resultData?.data?.toString() ?: "")
}
}
override fun onNewIntent(intent: Intent?) {

View file

@ -15,6 +15,7 @@
*/
package com.afollestad.nocknock.ui.viewsite
import android.net.Uri
import androidx.annotation.CheckResult
import androidx.annotation.VisibleForTesting
import androidx.annotation.VisibleForTesting.PRIVATE
@ -76,6 +77,7 @@ class ViewSiteViewModel(
val retryPolicyTimes = MutableLiveData<Int>()
val retryPolicyMinutes = MutableLiveData<Int>()
val headers = MutableLiveData<List<Header>>()
val certificateUri = MutableLiveData<Uri>()
internal val disabled = MutableLiveData<Boolean>()
internal val lastResult = MutableLiveData<ValidationResult?>()
@ -316,7 +318,8 @@ class ViewSiteViewModel(
validationMode = validationMode.value!!,
validationArgs = getValidationArgs(),
networkTimeout = timeout,
disabled = false
disabled = false,
certificate = certificateUri.value.toString()
)
val retryPolicyTimes = retryPolicyTimes.value ?: 0

View file

@ -24,6 +24,7 @@ import com.afollestad.nocknock.utilities.ext.DAY
import com.afollestad.nocknock.utilities.ext.HOUR
import com.afollestad.nocknock.utilities.ext.MINUTE
import com.afollestad.nocknock.utilities.ext.WEEK
import com.afollestad.nocknock.utilities.ext.toUri
import kotlin.math.ceil
fun ViewSiteViewModel.setModel(site: Site) {
@ -55,6 +56,9 @@ fun ViewSiteViewModel.setModel(site: Site) {
setCheckInterval(settings.validationIntervalMs)
setRetryPolicy(site.retryPolicy)
headers.value = site.headers
if (settings.certificate != null) {
certificateUri.value = settings.certificate!!.toUri()
}
this.disabled.value = settings.disabled
this.lastResult.value = site.lastResult

View file

@ -91,20 +91,6 @@
android:layout_marginTop="@dimen/content_inset"
/>
<TextView
android:text="@string/response_timeout"
style="@style/InputForm.Header"
/>
<EditText
android:id="@+id/responseTimeoutInput"
android:hint="@string/response_timeout_default"
android:inputType="number"
android:maxLength="8"
tools:ignore="Autofill"
style="@style/InputForm.Field"
/>
<TextView
android:id="@+id/responseValidationLabel"
android:text="@string/response_validation_mode"
@ -159,6 +145,59 @@
android:layout_marginTop="@dimen/content_inset_more"
/>
<TextView
android:layout_marginTop="@dimen/content_inset"
android:text="@string/response_timeout"
style="@style/InputForm.Header"
/>
<EditText
android:id="@+id/responseTimeoutInput"
android:hint="@string/response_timeout_default"
android:inputType="number"
android:maxLength="8"
tools:ignore="Autofill"
style="@style/InputForm.Field"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/content_inset"
android:text="@string/ssl_certificate"
style="@style/NockText.SectionHeader"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<EditText
android:id="@+id/sslCertificateInput"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="-4dp"
android:layout_weight="1"
android:hint="@string/ssl_certificate_automatic"
android:inputType="textUri"
tools:ignore="Autofill,HardcodedText,LabelFor"
style="@style/NockText.Body"
/>
<Button
android:id="@+id/sslCertificateBrowse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:text="@string/ssl_certificate_browse"
style="@style/AccentTextButton"
/>
</LinearLayout>
<include layout="@layout/include_divider"/>
<com.afollestad.nocknock.viewcomponents.headers.HeaderStackLayout

View file

@ -26,7 +26,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/content_inset"
android:paddingBottom="@dimen/content_inset_double"
android:paddingLeft="@dimen/content_inset"
android:paddingRight="@dimen/content_inset"
android:paddingTop="@dimen/content_inset_less"
@ -126,35 +126,6 @@
android:layout_marginTop="@dimen/content_inset"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/content_inset_less"
android:text="@string/response_timeout"
style="@style/NockText.SectionHeader"
/>
<EditText
android:id="@+id/responseTimeoutInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="-4dp"
android:layout_marginStart="-4dp"
android:layout_marginTop="@dimen/content_inset_quarter"
android:hint="@string/response_timeout_default"
android:inputType="number"
android:maxLength="8"
tools:ignore="Autofill,HardcodedText,LabelFor"
style="@style/NockText.Body"
/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="@dimen/content_inset_less"
android:background="?dividerColor"
/>
<TextView
android:id="@+id/responseValidationLabel"
android:layout_width="wrap_content"
@ -217,6 +188,66 @@
android:layout_marginTop="@dimen/content_inset"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/content_inset"
android:text="@string/response_timeout"
style="@style/NockText.SectionHeader"
/>
<EditText
android:id="@+id/responseTimeoutInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="-4dp"
android:layout_marginStart="-4dp"
android:layout_marginTop="@dimen/content_inset_quarter"
android:hint="@string/response_timeout_default"
android:inputType="number"
android:maxLength="8"
tools:ignore="Autofill,HardcodedText,LabelFor"
style="@style/NockText.Body"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/content_inset"
android:text="@string/ssl_certificate"
style="@style/NockText.SectionHeader"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<EditText
android:id="@+id/sslCertificateInput"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="-4dp"
android:layout_weight="1"
android:hint="@string/ssl_certificate_automatic"
android:inputType="textUri"
tools:ignore="Autofill,HardcodedText,LabelFor"
style="@style/NockText.Body"
/>
<Button
android:id="@+id/sslCertificateBrowse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:text="@string/ssl_certificate_browse"
style="@style/AccentTextButton"
/>
</LinearLayout>
<include layout="@layout/include_divider"/>
<com.afollestad.nocknock.viewcomponents.headers.HeaderStackLayout

View file

@ -59,6 +59,10 @@
<string name="response_timeout">Network Response Timeout (ms)</string>
<string name="response_timeout_default">10000</string>
<string name="ssl_certificate">SSL Certificate</string>
<string name="ssl_certificate_automatic">(Automatic)</string>
<string name="ssl_certificate_browse">Browse</string>
<string name="refresh_status">Refresh Status</string>
<string name="warning_http_url">

View file

@ -4,20 +4,10 @@
<style name="AppTheme.Dark" parent="AppThemeParent.Dark"/>
<style name="AccentButton" parent="Widget.MaterialComponents.Button">
<item name="android:textColor">#fff</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/lighterGray</item>
<item name="android:fontFamily">@font/lato</item>
</style>
<style name="AccentTextButton" parent="Widget.MaterialComponents.Button.TextButton">
<item name="android:fontFamily">@font/lato</item>
</style>
</resources>

View file

@ -66,6 +66,6 @@ class Database3to4Migration : Migration(3, 4) {
class Database4to5Migration : Migration(4, 5) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE `site_settings` ADD COLUMN certificatePath TEXT")
database.execSQL("ALTER TABLE `site_settings` ADD COLUMN certificate TEXT")
}
}

View file

@ -74,6 +74,10 @@ class RealSslManager(
log("Loaded successfully!")
return client.newBuilder()
.sslSocketFactory(sslContext.socketFactory, trustManager)
.hostnameVerifier { hostname, _ ->
log("Verifying hostname $hostname")
hostname == host
}
.build()
}
}

View file

@ -12,7 +12,7 @@
android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/check_interval"
android:text="@string/validation_interval"
style="@style/NockText.SectionHeader"
/>
@ -27,7 +27,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/check_interval_every"
android:text="@string/validation_interval_every"
style="@style/NockText.Body"
/>

View file

@ -5,8 +5,8 @@
<string name="function_declaration">function validate(response) {</string>
<string name="function_end">}</string>
<string name="check_interval">Check Interval</string>
<string name="check_interval_every">Every</string>
<string name="validation_interval">Validation Interval</string>
<string name="validation_interval_every">Every</string>
<string name="retry_policy">Retry Policy</string>
<string name="retry_policy_retry">Retry</string>

View file

@ -52,4 +52,14 @@
<item name="android:textColor">@color/md_red</item>
</style>
<style name="AccentButton" parent="Widget.MaterialComponents.Button">
<item name="android:textColor">#fff</item>
<item name="backgroundTint">?colorAccent</item>
<item name="android:fontFamily">@font/lato</item>
</style>
<style name="AccentTextButton" parent="Widget.MaterialComponents.Button.TextButton">
<item name="android:fontFamily">@font/lato</item>
</style>
</resources>