Skip to content
Snippets Groups Projects
Verified Commit f6fc0748 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Implemented support for irc:// and ircs:// links

parent 28ea2b31
No related branches found
No related tags found
No related merge requests found
Showing
with 775 additions and 14 deletions
...@@ -66,6 +66,15 @@ ...@@ -66,6 +66,15 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" /> <data android:mimeType="text/plain" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="irc" />
<data android:scheme="ircs" />
</intent-filter>
</activity> </activity>
<activity <activity
android:name=".ui.chat.info.user.UserInfoActivity" android:name=".ui.chat.info.user.UserInfoActivity"
...@@ -234,7 +243,13 @@ ...@@ -234,7 +243,13 @@
<activity <activity
android:name=".ui.setup.user.UserSetupActivity" android:name=".ui.setup.user.UserSetupActivity"
android:exported="false" android:exported="false"
android:label="@string/settings_identity_title" android:label="@string/setup_user_title"
android:parentActivityName=".ui.chat.ChatActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".ui.setup.network.NetworkSetupActivity"
android:exported="false"
android:label="@string/setup_network_title"
android:parentActivityName=".ui.chat.ChatActivity" android:parentActivityName=".ui.chat.ChatActivity"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
......
...@@ -80,6 +80,8 @@ import de.kuschku.quasseldroid.ui.setup.accounts.selection.AccountSelectionActiv ...@@ -80,6 +80,8 @@ import de.kuschku.quasseldroid.ui.setup.accounts.selection.AccountSelectionActiv
import de.kuschku.quasseldroid.ui.setup.accounts.selection.AccountSelectionFragmentProvider import de.kuschku.quasseldroid.ui.setup.accounts.selection.AccountSelectionFragmentProvider
import de.kuschku.quasseldroid.ui.setup.accounts.setup.AccountSetupActivity import de.kuschku.quasseldroid.ui.setup.accounts.setup.AccountSetupActivity
import de.kuschku.quasseldroid.ui.setup.accounts.setup.AccountSetupFragmentProvider import de.kuschku.quasseldroid.ui.setup.accounts.setup.AccountSetupFragmentProvider
import de.kuschku.quasseldroid.ui.setup.network.NetworkSetupActivity
import de.kuschku.quasseldroid.ui.setup.network.NetworkSetupFragmentProvider
import de.kuschku.quasseldroid.ui.setup.user.UserSetupActivity import de.kuschku.quasseldroid.ui.setup.user.UserSetupActivity
import de.kuschku.quasseldroid.ui.setup.user.UserSetupFragmentProvider import de.kuschku.quasseldroid.ui.setup.user.UserSetupFragmentProvider
...@@ -201,6 +203,10 @@ abstract class ActivityModule { ...@@ -201,6 +203,10 @@ abstract class ActivityModule {
@ContributesAndroidInjector(modules = [UserSetupFragmentProvider::class, SettingsModule::class, DatabaseModule::class, ActivityBaseModule::class]) @ContributesAndroidInjector(modules = [UserSetupFragmentProvider::class, SettingsModule::class, DatabaseModule::class, ActivityBaseModule::class])
abstract fun bindUserSetupActivity(): UserSetupActivity abstract fun bindUserSetupActivity(): UserSetupActivity
@ActivityScope
@ContributesAndroidInjector(modules = [NetworkSetupFragmentProvider::class, SettingsModule::class, DatabaseModule::class, ActivityBaseModule::class])
abstract fun bindNetworkSetupActivity(): NetworkSetupActivity
@ActivityScope @ActivityScope
@ContributesAndroidInjector(modules = [QuasselServiceModule::class, SettingsModule::class, DatabaseModule::class]) @ContributesAndroidInjector(modules = [QuasselServiceModule::class, SettingsModule::class, DatabaseModule::class])
abstract fun bindQuasselService(): QuasselService abstract fun bindQuasselService(): QuasselService
......
...@@ -67,11 +67,13 @@ import de.kuschku.libquassel.util.Optional ...@@ -67,11 +67,13 @@ import de.kuschku.libquassel.util.Optional
import de.kuschku.libquassel.util.flag.and import de.kuschku.libquassel.util.flag.and
import de.kuschku.libquassel.util.flag.hasFlag import de.kuschku.libquassel.util.flag.hasFlag
import de.kuschku.libquassel.util.flag.or import de.kuschku.libquassel.util.flag.or
import de.kuschku.libquassel.util.helpers.nullIf
import de.kuschku.libquassel.util.helpers.value import de.kuschku.libquassel.util.helpers.value
import de.kuschku.libquassel.util.irc.SenderColorUtil import de.kuschku.libquassel.util.irc.SenderColorUtil
import de.kuschku.quasseldroid.GlideApp import de.kuschku.quasseldroid.GlideApp
import de.kuschku.quasseldroid.Keys import de.kuschku.quasseldroid.Keys
import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.defaults.DefaultNetworkServer
import de.kuschku.quasseldroid.persistence.AccountDatabase import de.kuschku.quasseldroid.persistence.AccountDatabase
import de.kuschku.quasseldroid.persistence.QuasselDatabase import de.kuschku.quasseldroid.persistence.QuasselDatabase
import de.kuschku.quasseldroid.settings.AutoCompleteSettings import de.kuschku.quasseldroid.settings.AutoCompleteSettings
...@@ -82,11 +84,14 @@ import de.kuschku.quasseldroid.ui.chat.input.ChatlineFragment ...@@ -82,11 +84,14 @@ import de.kuschku.quasseldroid.ui.chat.input.ChatlineFragment
import de.kuschku.quasseldroid.ui.clientsettings.client.ClientSettingsActivity import de.kuschku.quasseldroid.ui.clientsettings.client.ClientSettingsActivity
import de.kuschku.quasseldroid.ui.coresettings.CoreSettingsActivity import de.kuschku.quasseldroid.ui.coresettings.CoreSettingsActivity
import de.kuschku.quasseldroid.ui.setup.accounts.selection.AccountSelectionActivity import de.kuschku.quasseldroid.ui.setup.accounts.selection.AccountSelectionActivity
import de.kuschku.quasseldroid.ui.setup.network.LinkNetwork
import de.kuschku.quasseldroid.ui.setup.network.NetworkSetupActivity
import de.kuschku.quasseldroid.ui.setup.user.UserSetupActivity import de.kuschku.quasseldroid.ui.setup.user.UserSetupActivity
import de.kuschku.quasseldroid.util.ColorContext import de.kuschku.quasseldroid.util.ColorContext
import de.kuschku.quasseldroid.util.avatars.AvatarHelper import de.kuschku.quasseldroid.util.avatars.AvatarHelper
import de.kuschku.quasseldroid.util.backport.OsConstants import de.kuschku.quasseldroid.util.backport.OsConstants
import de.kuschku.quasseldroid.util.helper.* import de.kuschku.quasseldroid.util.helper.*
import de.kuschku.quasseldroid.util.irc.IrcPorts
import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer
import de.kuschku.quasseldroid.util.missingfeatures.MissingFeaturesDialog import de.kuschku.quasseldroid.util.missingfeatures.MissingFeaturesDialog
import de.kuschku.quasseldroid.util.missingfeatures.RequiredFeatures import de.kuschku.quasseldroid.util.missingfeatures.RequiredFeatures
...@@ -228,6 +233,28 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc ...@@ -228,6 +233,28 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
} }
} }
} }
intent.scheme == "irc" ||
intent.scheme == "ircs" -> {
val uri = intent.data
if (uri != null) {
val channelString = (uri.path.let { it ?: "" }.trimStart('/')) +
(uri.fragment?.let { "#$it" }.let { it ?: "" })
NetworkSetupActivity.launch(
this,
network = LinkNetwork(
name = "",
server = DefaultNetworkServer(
host = uri.host ?: "",
port = uri.port.nullIf { it == -1 }
?: if (uri.scheme == "irc") IrcPorts.normal
else IrcPorts.secure,
secure = uri.scheme == "ircs"
)
),
channels = channelString.split(",").toTypedArray()
)
}
}
} }
} }
} }
......
...@@ -165,7 +165,7 @@ abstract class NetworkBaseFragment(private val initDefault: Boolean) : ...@@ -165,7 +165,7 @@ abstract class NetworkBaseFragment(private val initDefault: Boolean) :
identityAdapter.submitList(it) identityAdapter.submitList(it)
if (selectOriginal) { if (selectOriginal) {
this.network?.let { (_, data) -> this.network?.let { (_, data) ->
identityAdapter.indexOf(data.networkId())?.let(identity::setSelection) identityAdapter.indexOf(data.identity())?.let(identity::setSelection)
} }
} }
} }
......
...@@ -116,10 +116,10 @@ class NetworkServerFragment : SettingsFragment(), SettingsFragment.Savable, ...@@ -116,10 +116,10 @@ class NetworkServerFragment : SettingsFragment(), SettingsFragment.Savable,
sslEnabled.setOnCheckedChangeListener { _, isChecked -> sslEnabled.setOnCheckedChangeListener { _, isChecked ->
sslVerify.isEnabled = isChecked sslVerify.isEnabled = isChecked
val portValue = port.text.trim().toString() val portValue = port.text.trim().toString()
if (isChecked && portValue == IrcPorts.normal) { if (isChecked && portValue == IrcPorts.normal.toString()) {
port.setText(IrcPorts.secure) port.setText(IrcPorts.secure.toString())
} else if (!isChecked && portValue == IrcPorts.secure) { } else if (!isChecked && portValue == IrcPorts.secure.toString()) {
port.setText(IrcPorts.normal) port.setText(IrcPorts.normal.toString())
} }
} }
sslVerify.isEnabled = sslEnabled.isChecked sslVerify.isEnabled = sslEnabled.isChecked
......
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.ui.setup
import android.content.Context
import android.os.Bundle
import de.kuschku.libquassel.session.Backend
import de.kuschku.libquassel.util.Optional
import de.kuschku.quasseldroid.Keys
import de.kuschku.quasseldroid.util.service.BackendServiceConnection
import de.kuschku.quasseldroid.viewmodel.QuasselViewModel
import io.reactivex.subjects.BehaviorSubject
import javax.inject.Inject
abstract class ServiceBoundSlideFragment : SlideFragment() {
@Inject
lateinit var viewModel: QuasselViewModel
private val connection = BackendServiceConnection()
protected val backend: BehaviorSubject<Optional<Backend>>
get() = connection.backend
protected fun runInBackground(f: () -> Unit) {
connection.backend.value.ifPresent {
it.sessionManager().handlerService.backend(f)
}
}
protected fun runInBackgroundDelayed(delayMillis: Long, f: () -> Unit) {
connection.backend.value.ifPresent {
it.sessionManager().handlerService.backendDelayed(delayMillis, f)
}
}
protected var accountId: Long = -1
override fun onCreate(savedInstanceState: Bundle?) {
accountId = context?.getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE)
?.getLong(Keys.Status.selectedAccount, -1) ?: -1
connection.context = context
lifecycle.addObserver(connection)
super.onCreate(savedInstanceState)
}
override fun onStart() {
super.onStart()
accountId = context?.getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE)
?.getLong(Keys.Status.selectedAccount, -1) ?: -1
}
override fun onDestroy() {
lifecycle.removeObserver(connection)
super.onDestroy()
}
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.ui.setup.network
import de.kuschku.quasseldroid.defaults.DefaultNetworkServer
import java.io.Serializable
data class LinkNetwork(
val name: String,
val defaultChannels: List<String> = emptyList(),
val server: DefaultNetworkServer
) : Serializable
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.ui.setup.network
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import de.kuschku.libquassel.protocol.Buffer_Type
import de.kuschku.libquassel.protocol.IdentityId
import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
import de.kuschku.libquassel.util.helpers.value
import de.kuschku.quasseldroid.ui.setup.ServiceBoundSetupActivity
class NetworkSetupActivity : ServiceBoundSetupActivity() {
private lateinit var arguments: Bundle
override val initData: Bundle
get() = arguments
override fun onCreate(savedInstanceState: Bundle?) {
arguments = intent.getBundleExtra("link")
super.onCreate(savedInstanceState)
}
override fun onDone(data: Bundle) {
val network = data.getSerializable("network") as? LinkNetwork
val networkId = data.getInt("network_id", -1)
val identity = data.getInt("identity", -1)
if (networkId != -1 || (network != null && identity != -1)) {
viewModel.backend?.value?.ifPresent { backend ->
val session = viewModel.session.value?.orNull()
session?.apply {
rpcHandler?.apply {
when {
networkId != -1 -> {
val buffer = bufferSyncer?.find(networkId = networkId,
type = Buffer_Type.of(Buffer_Type.StatusBuffer))
if (buffer != null) {
data.getStringArray("channels")?.toList().orEmpty().forEach {
sendInput(buffer, "/join $it")
}
}
}
network != null &&
network.name.isNotBlank() &&
network.server.host.isNotBlank() -> {
createNetwork(INetwork.NetworkInfo(
networkName = network.name,
identity = identity,
serverList = listOf(INetwork.Server(
host = network.server.host,
port = network.server.port,
useSsl = network.server.secure
))
), data.getStringArray("channels")?.toList().orEmpty())
backend.requestConnectNewNetwork()
}
}
}
}
}
}
setResult(Activity.RESULT_OK)
finish()
}
override val fragments = listOf(
NetworkSetupNetworkSlide(),
NetworkSetupChannelsSlide()
)
companion object {
fun launch(
context: Context,
network: LinkNetwork? = null,
identity: IdentityId? = null,
channels: Array<String>? = null
) = context.startActivity(intent(context, network, identity, channels))
fun intent(
context: Context,
network: LinkNetwork? = null,
identity: IdentityId? = null,
channels: Array<String>? = null
) = Intent(context, NetworkSetupActivity::class.java).apply {
if (network != null || identity != null || channels != null) {
val bundle = Bundle()
if (network != null) {
bundle.putSerializable("network", network)
}
if (identity != null) {
bundle.putInt("identity", identity)
}
if (channels != null) {
bundle.putStringArray("channels", channels)
}
putExtra("link", bundle)
}
}
}
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.ui.setup.network
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import butterknife.BindView
import butterknife.ButterKnife
import com.google.android.material.textfield.TextInputLayout
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.ui.setup.SlideFragment
class NetworkSetupChannelsSlide : SlideFragment() {
@BindView(R.id.channelsWrapper)
lateinit var channelsWrapper: TextInputLayout
@BindView(R.id.channels)
lateinit var channelsField: EditText
override fun isValid() = true
override val title = R.string.slide_user_channels_title
override val description = R.string.slide_user_channels_description
override fun setData(data: Bundle) {
if (data.containsKey("channels"))
channelsField.setText(data.getStringArray("channels")?.joinToString("\n"))
updateValidity()
}
override fun getData(data: Bundle) {
data.putStringArray("channels",
channelsField.text.toString()
.split('\n', ' ', ',', ';')
.map(String::trim)
.filter(String::isNotBlank)
.toTypedArray()
)
}
override fun onCreateContent(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
val view = inflater.inflate(R.layout.setup_user_channels, container, false)
ButterKnife.bind(this, view)
return view
}
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.ui.setup.network
import androidx.fragment.app.FragmentActivity
import dagger.Binds
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class NetworkSetupFragmentProvider {
@Binds
abstract fun bindFragmentActivity(activity: NetworkSetupActivity): FragmentActivity
@ContributesAndroidInjector
abstract fun bindNetworkSetupNetworkSlide(): NetworkSetupNetworkSlide
@ContributesAndroidInjector
abstract fun bindNetworkSetupChannelsSlide(): NetworkSetupChannelsSlide
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.ui.setup.network
import android.os.Bundle
import android.text.Editable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.EditText
import android.widget.Spinner
import androidx.appcompat.widget.SwitchCompat
import androidx.lifecycle.Observer
import butterknife.BindView
import butterknife.ButterKnife
import com.google.android.material.textfield.TextInputLayout
import de.kuschku.libquassel.quassel.syncables.Identity
import de.kuschku.libquassel.quassel.syncables.Network
import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.defaults.DefaultNetworkServer
import de.kuschku.quasseldroid.ui.coresettings.chatlist.NetworkAdapter
import de.kuschku.quasseldroid.ui.coresettings.network.IdentityAdapter
import de.kuschku.quasseldroid.ui.setup.ServiceBoundSlideFragment
import de.kuschku.quasseldroid.util.Patterns
import de.kuschku.quasseldroid.util.TextValidator
import de.kuschku.quasseldroid.util.helper.combineLatest
import de.kuschku.quasseldroid.util.helper.toLiveData
import de.kuschku.quasseldroid.util.irc.IrcPorts
import de.kuschku.quasseldroid.util.ui.AnimationHelper
class NetworkSetupNetworkSlide : ServiceBoundSlideFragment() {
@BindView(R.id.identity)
lateinit var identity: Spinner
@BindView(R.id.network)
lateinit var network: Spinner
@BindView(R.id.network_group)
lateinit var networkGroup: ViewGroup
@BindView(R.id.nameWrapper)
lateinit var nameWrapper: TextInputLayout
@BindView(R.id.name)
lateinit var nameField: EditText
@BindView(R.id.hostWrapper)
lateinit var hostWrapper: TextInputLayout
@BindView(R.id.host)
lateinit var hostField: EditText
@BindView(R.id.portWrapper)
lateinit var portWrapper: TextInputLayout
@BindView(R.id.port)
lateinit var portField: EditText
@BindView(R.id.ssl_enabled)
lateinit var sslEnabled: SwitchCompat
private val identityAdapter = IdentityAdapter()
private val networkAdapter = NetworkAdapter()
override fun isValid(): Boolean {
return (this.network.selectedItemPosition != -1 &&
networkAdapter.getItemId(this.network.selectedItemPosition) != -1L) ||
((this.identity.selectedItemPosition != -1 &&
identityAdapter.getItemId(this.identity.selectedItemPosition) != -1L) &&
(nameValidator.isValid && hostValidator.isValid && portValidator.isValid))
}
override val title = R.string.slide_user_network_title
override val description = R.string.slide_user_network_description
private var data: Bundle? = null
private var networks: List<INetwork.NetworkInfo>? = null
override fun setData(data: Bundle) {
this.data = data
update()
}
override fun getData(data: Bundle) {
data.putSerializable(
"identity",
identityAdapter.getItemId(this.identity.selectedItemPosition)
)
val networkId = (network.selectedItem as? INetwork.NetworkInfo)?.networkId
if (networkId != null) {
data.putInt("network_id", networkId)
} else {
data.putSerializable(
"network",
LinkNetwork(
name = nameField.text.toString(),
server = DefaultNetworkServer(
host = hostField.text.toString(),
port = portField.text.toString().toIntOrNull()
?: if (sslEnabled.isChecked) 6697
else 6667,
secure = sslEnabled.isChecked
)
)
)
}
}
override fun onCreateContent(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
val view = inflater.inflate(R.layout.setup_network_network, container, false)
ButterKnife.bind(this, view)
nameValidator = object : TextValidator(
requireActivity(), nameWrapper::setError, resources.getString(R.string.hint_invalid_name)
) {
override fun validate(text: Editable) = text.isNotBlank()
override fun onChanged() = updateValidity()
}
hostValidator = object : TextValidator(
requireActivity(), hostWrapper::setError, resources.getString(R.string.hint_invalid_host)
) {
override fun validate(text: Editable) =
text.toString().matches(Patterns.DOMAIN_NAME)
override fun onChanged() = updateValidity()
}
portValidator = object : TextValidator(
requireActivity(), portWrapper::setError, resources.getString(R.string.hint_invalid_port)
) {
override fun validate(text: Editable) = text.toString().toIntOrNull() in (0 until 65536)
override fun onChanged() = updateValidity()
}
nameField.addTextChangedListener(nameValidator)
hostField.addTextChangedListener(hostValidator)
portField.addTextChangedListener(portValidator)
nameValidator.afterTextChanged(nameField.text)
hostValidator.afterTextChanged(hostField.text)
portValidator.afterTextChanged(portField.text)
network.adapter = networkAdapter
network.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
fun selected(item: INetwork.NetworkInfo?) {
if (item == null) {
AnimationHelper.expand(networkGroup)
} else {
AnimationHelper.collapse(networkGroup)
}
updateValidity()
}
override fun onNothingSelected(parent: AdapterView<*>?) = selected(null)
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) =
selected(networkAdapter.getItem(position))
}
identity.adapter = identityAdapter
viewModel.identities.switchMap {
combineLatest(it.values.map(Identity::liveUpdates)).map {
it.sortedBy(Identity::identityName)
}
}.toLiveData().observe(this, Observer {
if (it != null) {
identityAdapter.submitList(it)
}
})
viewModel.networks.toLiveData().observe(this, Observer {
if (it != null) {
this.networks = it.values.map(Network::networkInfo)
update()
}
})
identity.adapter = identityAdapter
sslEnabled.setOnCheckedChangeListener { _, isChecked ->
val portValue = portField.text.trim().toString()
if (isChecked && portValue == IrcPorts.normal.toString()) {
portField.setText(IrcPorts.secure.toString())
} else if (!isChecked && portValue == IrcPorts.secure.toString()) {
portField.setText(IrcPorts.normal.toString())
}
}
return view
}
private var hasSetUi = false
private var hasSetNetwork = false
private fun update() {
val data = this.data
val networks = this.networks
if (data != null && networks != null) {
networkAdapter.submitList(listOf(null) + networks)
val linkNetwork = data.getSerializable("network") as? LinkNetwork
val existingNetwork = networks.firstOrNull {
it.serverList.any {
it.host == linkNetwork?.server?.host
}
}
if (!hasSetNetwork) {
val networkPosition = networkAdapter.indexOf(existingNetwork?.networkId ?: -1) ?: -1
if (networkPosition != -1) {
network.setSelection(networkPosition)
hasSetNetwork = true
}
}
if (!hasSetUi) {
if (linkNetwork != null && !hasSetUi) {
nameField.setText(linkNetwork.name)
hostField.setText(linkNetwork.server.host)
portField.setText("${linkNetwork.server.port}")
sslEnabled.isChecked = linkNetwork.server.secure
}
if (data.containsKey("identity")) {
val identity = data.getInt("identity", -1)
if (identity != -1) {
val position = identityAdapter.indexOf(identity)
if (position == -1) {
this.identity.setSelection(-1)
}
}
}
}
updateValidity()
}
}
private lateinit var nameValidator: TextValidator
private lateinit var hostValidator: TextValidator
private lateinit var portValidator: TextValidator
}
...@@ -79,8 +79,8 @@ class UserSetupNetworkSlide : SlideFragment() { ...@@ -79,8 +79,8 @@ class UserSetupNetworkSlide : SlideFragment() {
(nameValidator.isValid && hostValidator.isValid && portValidator.isValid) (nameValidator.isValid && hostValidator.isValid && portValidator.isValid)
} }
override val title = R.string.slide_account_connection_title override val title = R.string.slide_user_network_title
override val description = R.string.slide_account_connection_description override val description = R.string.slide_user_network_description
override fun setData(data: Bundle) { override fun setData(data: Bundle) {
if (data.containsKey("network")) { if (data.containsKey("network")) {
...@@ -162,6 +162,7 @@ class UserSetupNetworkSlide : SlideFragment() { ...@@ -162,6 +162,7 @@ class UserSetupNetworkSlide : SlideFragment() {
} else { } else {
AnimationHelper.collapse(networkGroup) AnimationHelper.collapse(networkGroup)
} }
updateValidity()
} }
override fun onNothingSelected(parent: AdapterView<*>?) = selected(null) override fun onNothingSelected(parent: AdapterView<*>?) = selected(null)
...@@ -177,10 +178,10 @@ class UserSetupNetworkSlide : SlideFragment() { ...@@ -177,10 +178,10 @@ class UserSetupNetworkSlide : SlideFragment() {
sslEnabled.setOnCheckedChangeListener { _, isChecked -> sslEnabled.setOnCheckedChangeListener { _, isChecked ->
val portValue = portField.text.trim().toString() val portValue = portField.text.trim().toString()
if (isChecked && portValue == IrcPorts.normal) { if (isChecked && portValue == IrcPorts.normal.toString()) {
portField.setText(IrcPorts.secure) portField.setText(IrcPorts.secure.toString())
} else if (!isChecked && portValue == IrcPorts.secure) { } else if (!isChecked && portValue == IrcPorts.secure.toString()) {
portField.setText(IrcPorts.normal) portField.setText(IrcPorts.normal.toString())
} }
} }
......
...@@ -20,6 +20,6 @@ ...@@ -20,6 +20,6 @@
package de.kuschku.quasseldroid.util.irc package de.kuschku.quasseldroid.util.irc
object IrcPorts { object IrcPorts {
const val normal = "6667" const val normal = 6667
const val secure = "6697" const val secure = 6697
} }
<!--
Quasseldroid - Quassel client for Android
Copyright (c) 2019 Janne Koschinski
Copyright (c) 2019 The Quassel Project
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License version 3 as published
by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="32dp">
<TextView
style="@style/Widget.CoreSettings.EditTextHeader"
android:text="@string/settings_network_title" />
<Spinner
android:id="@+id/network"
style="@style/Widget.FullWidthSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/widget_spinner_item_inline" />
<LinearLayout
android:id="@+id/network_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
style="@style/Widget.CoreSettings.EditTextHeader"
android:text="@string/settings_identity_title" />
<Spinner
android:id="@+id/identity"
style="@style/Widget.FullWidthSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/widget_spinner_item_inline" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/nameWrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/settings_network_network_name"
tools:ignore="LabelFor">
<EditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textUri|textNoSuggestions"
app:errorEnabled="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/hostWrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/settings_networkserver_host"
tools:ignore="LabelFor">
<EditText
android:id="@+id/host"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textUri|textNoSuggestions"
app:errorEnabled="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/portWrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/settings_networkserver_port"
app:passwordToggleEnabled="true"
tools:ignore="LabelFor">
<EditText
android:id="@+id/port"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:text="6667"
app:errorEnabled="true"
tools:ignore="HardcodedText" />
</com.google.android.material.textfield.TextInputLayout>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/ssl_enabled"
style="@style/Widget.CoreSettings.PrimaryItemSwitch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_networkserver_ssl_enabled" />
</LinearLayout>
</LinearLayout>
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
<string name="slide_account_select_description">Please select an account from the list or add one</string> <string name="slide_account_select_description">Please select an account from the list or add one</string>
<string name="label_user_on_host">%1$s on %2$s:%3$d</string> <string name="label_user_on_host">%1$s on %2$s:%3$d</string>
<!-- Account Setup -->
<!-- Account Connection --> <!-- Account Connection -->
<string name="slide_account_connection_title">Connection</string> <string name="slide_account_connection_title">Connection</string>
<string name="slide_account_connection_description">First, please choose which server your core is hosted on.</string> <string name="slide_account_connection_description">First, please choose which server your core is hosted on.</string>
...@@ -50,6 +52,8 @@ ...@@ -50,6 +52,8 @@
<string name="hint_invalid_name">Name can not be empty</string> <string name="hint_invalid_name">Name can not be empty</string>
<!-- Core Setup -->
<!-- Core Authenticator Select --> <!-- Core Authenticator Select -->
<string name="slide_core_authenticator_select_title">Select Authentication Backend</string> <string name="slide_core_authenticator_select_title">Select Authentication Backend</string>
<string name="slide_core_authenticator_select_description">Please select an authentication backend for the Quassel Core to use for authenticating users.</string> <string name="slide_core_authenticator_select_description">Please select an authentication backend for the Quassel Core to use for authenticating users.</string>
...@@ -62,6 +66,10 @@ ...@@ -62,6 +66,10 @@
<string name="slide_core_backend_setup_title">Configure Storage Backend</string> <string name="slide_core_backend_setup_title">Configure Storage Backend</string>
<string name="slide_core_backend_setup_description">Please configure the selected database backend.</string> <string name="slide_core_backend_setup_description">Please configure the selected database backend.</string>
<!-- User Setup -->
<string name="setup_user_title">Setup User</string>
<!-- User Identity --> <!-- User Identity -->
<string name="slide_user_identity_title">Setup Identity</string> <string name="slide_user_identity_title">Setup Identity</string>
<string name="slide_user_identity_description">Please choose a nickname</string> <string name="slide_user_identity_description">Please choose a nickname</string>
...@@ -79,4 +87,8 @@ ...@@ -79,4 +87,8 @@
<string name="slide_user_channels_description">Select what channels to join.</string> <string name="slide_user_channels_description">Select what channels to join.</string>
<string name="label_channels">Channels</string> <string name="label_channels">Channels</string>
<!-- Network Setup -->
<string name="setup_network_title">Setup Network</string>
</resources> </resources>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment