diff --git a/app/sampledata/networks.json b/app/sampledata/networks.json new file mode 100644 index 0000000000000000000000000000000000000000..079e43fe6343cf43c149bb58915d2944ecf32240 --- /dev/null +++ b/app/sampledata/networks.json @@ -0,0 +1,24 @@ +{ + "data": [ + { + "host": "ipv6-irc.snoonet.org", + "port": "6697" + }, + { + "host": "irc.snoonet.org", + "port": "6697" + }, + { + "host": "eu-irc.snoonet.org", + "port": "6697" + }, + { + "host": "alt-irc.snoonet.org", + "port": "6697" + }, + { + "host": "asiapac-irc.snoonet.org", + "port": "6697" + } + ] +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 353a7e6903a4d048921ae72ee4807e4dc23855b7..5afc1e446e7866f3e1636b616bb44d53072d4966 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -61,6 +61,18 @@ android:label="@string/label_settings_core" android:parentActivityName=".ui.chat.ChatActivity" android:windowSoftInputMode="adjustResize" /> + <activity + android:name=".ui.coresettings.network.NetworkCreateActivity" + android:exported="false" + android:label="@string/settings_network_title" + android:parentActivityName=".ui.coresettings.CoreSettingsActivity" + android:windowSoftInputMode="adjustResize" /> + <activity + android:name=".ui.coresettings.network.NetworkEditActivity" + android:exported="false" + android:label="@string/settings_network_title" + android:parentActivityName=".ui.coresettings.CoreSettingsActivity" + android:windowSoftInputMode="adjustResize" /> <activity android:name=".ui.coresettings.identity.IdentityCreateActivity" android:exported="false" diff --git a/app/src/main/java/de/kuschku/quasseldroid/dagger/ActivityModule.kt b/app/src/main/java/de/kuschku/quasseldroid/dagger/ActivityModule.kt index 50e08e1553d125c79d9c8547990eab1daf839443..422f9fbd367d3154802e6d340d1789a623602546 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/dagger/ActivityModule.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/dagger/ActivityModule.kt @@ -34,6 +34,10 @@ import de.kuschku.quasseldroid.ui.coresettings.ignoreitem.IgnoreItemActivity import de.kuschku.quasseldroid.ui.coresettings.ignoreitem.IgnoreItemFragmentProvider import de.kuschku.quasseldroid.ui.coresettings.ignorelist.IgnoreListActivity import de.kuschku.quasseldroid.ui.coresettings.ignorelist.IgnoreListFragmentProvider +import de.kuschku.quasseldroid.ui.coresettings.network.NetworkCreateActivity +import de.kuschku.quasseldroid.ui.coresettings.network.NetworkCreateFragmentProvider +import de.kuschku.quasseldroid.ui.coresettings.network.NetworkEditActivity +import de.kuschku.quasseldroid.ui.coresettings.network.NetworkEditFragmentProvider import de.kuschku.quasseldroid.ui.coresettings.networkconfig.NetworkConfigActivity import de.kuschku.quasseldroid.ui.coresettings.networkconfig.NetworkConfigFragmentProvider import de.kuschku.quasseldroid.ui.setup.accounts.edit.AccountEditActivity @@ -71,6 +75,12 @@ abstract class ActivityModule { @ContributesAndroidInjector(modules = [CoreSettingsFragmentProvider::class]) abstract fun bindCoreSettingsActivity(): CoreSettingsActivity + @ContributesAndroidInjector(modules = [NetworkCreateFragmentProvider::class]) + abstract fun bindNetworkCreateActivity(): NetworkCreateActivity + + @ContributesAndroidInjector(modules = [NetworkEditFragmentProvider::class]) + abstract fun bindNetworkEditActivity(): NetworkEditActivity + @ContributesAndroidInjector(modules = [IdentityCreateFragmentProvider::class]) abstract fun bindIdentityCreateActivity(): IdentityCreateActivity diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/CoreSettingsFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/CoreSettingsFragment.kt index f9f6d54e0e09e338914022d47ea6c7a7ca7c2595..9e8ff65448c6a75d6ccf5fb8dc48be498de904d7 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/CoreSettingsFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/CoreSettingsFragment.kt @@ -21,6 +21,7 @@ import de.kuschku.quasseldroid.ui.coresettings.chatlist.ChatlistEditActivity import de.kuschku.quasseldroid.ui.coresettings.identity.IdentityCreateActivity import de.kuschku.quasseldroid.ui.coresettings.identity.IdentityEditActivity import de.kuschku.quasseldroid.ui.coresettings.ignorelist.IgnoreListActivity +import de.kuschku.quasseldroid.ui.coresettings.network.NetworkEditActivity import de.kuschku.quasseldroid.ui.coresettings.networkconfig.NetworkConfigActivity import de.kuschku.quasseldroid.util.helper.combineLatest import de.kuschku.quasseldroid.util.helper.toLiveData @@ -63,11 +64,7 @@ class CoreSettingsFragment : ServiceBoundFragment() { ButterKnife.bind(this, view) val networkAdapter = SettingsItemAdapter { - /* - val intent = Intent(requireContext(), NetworkActivity::class.java) - intent.putExtra("network", it) - startActivity(intent) - */ + NetworkEditActivity.launch(requireContext(), network = it) } val identityAdapter = SettingsItemAdapter { diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatListBaseFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatListBaseFragment.kt index cffea51bdae43bba1f04782d3b681b1d4783fbbf..d964fcfd37c3960ba219035964bbf9995505a70f 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatListBaseFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatListBaseFragment.kt @@ -7,8 +7,8 @@ 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 android.widget.TextView import butterknife.BindView import butterknife.ButterKnife import de.kuschku.libquassel.protocol.Buffer_Activity @@ -16,6 +16,7 @@ import de.kuschku.libquassel.protocol.Buffer_Type import de.kuschku.libquassel.quassel.syncables.BufferViewConfig import de.kuschku.libquassel.quassel.syncables.Network import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork +import de.kuschku.libquassel.util.Optional import de.kuschku.libquassel.util.flag.hasFlag import de.kuschku.libquassel.util.flag.minus import de.kuschku.libquassel.util.flag.plus @@ -23,14 +24,13 @@ import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.ui.coresettings.SettingsFragment import de.kuschku.quasseldroid.util.helper.combineLatest import de.kuschku.quasseldroid.util.helper.toLiveData -import io.reactivex.Observable abstract class ChatListBaseFragment : SettingsFragment(), SettingsFragment.Savable, SettingsFragment.Changeable { protected var chatlist: Pair<BufferViewConfig?, BufferViewConfig>? = null @BindView(R.id.buffer_view_name) - lateinit var bufferViewName: TextView + lateinit var bufferViewName: EditText @BindView(R.id.show_search) lateinit var showSearch: SwitchCompat @@ -108,32 +108,34 @@ abstract class ChatListBaseFragment : SettingsFragment(), SettingsFragment.Savab } }) - viewModel.bufferViewConfigMap.switchMap { - it[chatlistId]?.liveUpdates() ?: Observable.empty() - }.firstElement().toLiveData().observe(this, Observer { - if (it != null) { - this.chatlist = Pair(it, it.copy()) - this.chatlist?.let { (_, data) -> - bufferViewName.text = data.bufferViewName() - showSearch.isChecked = data.showSearch() - sortAlphabetically.isChecked = data.sortAlphabetically() - addNewBuffersAutomatically.isChecked = data.addNewBuffersAutomatically() - showStatusBuffer.isChecked = data.allowedBufferTypes().hasFlag(Buffer_Type.StatusBuffer) + viewModel.bufferViewConfigMap.map { Optional.ofNullable(it[chatlistId]) } + .filter(Optional<BufferViewConfig>::isPresent) + .map(Optional<BufferViewConfig>::get) + .firstElement() + .toLiveData().observe(this, Observer { + it?.let { + this.chatlist = Pair(it, it.copy()) + this.chatlist?.let { (_, data) -> + bufferViewName.setText(data.bufferViewName()) + showSearch.isChecked = data.showSearch() + sortAlphabetically.isChecked = data.sortAlphabetically() + addNewBuffersAutomatically.isChecked = data.addNewBuffersAutomatically() + showStatusBuffer.isChecked = data.allowedBufferTypes().hasFlag(Buffer_Type.StatusBuffer) - minimumActivity.setSelection( - minimumActivityAdapter.indexOf(data.minimumActivity()) ?: 0 - ) + minimumActivity.setSelection( + minimumActivityAdapter.indexOf(data.minimumActivity()) ?: 0 + ) - networkAdapter.indexOf(data.networkId())?.let(networkId::setSelection) + networkAdapter.indexOf(data.networkId())?.let(networkId::setSelection) - hideInactiveBuffers.isChecked = data.hideInactiveBuffers() - hideInactiveNetworks.isChecked = data.hideInactiveNetworks() + hideInactiveBuffers.isChecked = data.hideInactiveBuffers() + hideInactiveNetworks.isChecked = data.hideInactiveNetworks() - showQueries.isChecked = data.allowedBufferTypes().hasFlag(Buffer_Type.QueryBuffer) - showChannels.isChecked = data.allowedBufferTypes().hasFlag(Buffer_Type.ChannelBuffer) + showQueries.isChecked = data.allowedBufferTypes().hasFlag(Buffer_Type.QueryBuffer) + showChannels.isChecked = data.allowedBufferTypes().hasFlag(Buffer_Type.ChannelBuffer) + } } - } - }) + }) networkId.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onNothingSelected(parent: AdapterView<*>?) { showStatusBuffer.isChecked = true @@ -166,7 +168,7 @@ abstract class ChatListBaseFragment : SettingsFragment(), SettingsFragment.Savab data.allowedBufferTypes() != it.allowedBufferTypes() || data.networkId() != it.networkId() || data.minimumActivity() != it.minimumActivity() - } ?: false + } ?: true protected fun applyChanges(data: BufferViewConfig, old: BufferViewConfig?) { data.setBufferViewName(bufferViewName.text.toString()) diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityBaseFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityBaseFragment.kt index 1c57031734162537d0e264510eb1d1f508b7cf53..4cca29dbfaecbc5364b22f7a958f2055eec8a70b 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityBaseFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityBaseFragment.kt @@ -11,31 +11,29 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button -import android.widget.TextView +import android.widget.EditText import butterknife.BindView import butterknife.ButterKnife import com.afollestad.materialdialogs.MaterialDialog import de.kuschku.libquassel.quassel.syncables.Identity +import de.kuschku.libquassel.util.Optional import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.ui.coresettings.SettingsFragment import de.kuschku.quasseldroid.util.helper.setDependent import de.kuschku.quasseldroid.util.helper.toLiveData -import io.reactivex.Observable abstract class IdentityBaseFragment : SettingsFragment(), SettingsFragment.Savable, SettingsFragment.Changeable { - protected var identity: Pair<Identity?, Identity>? = null - @BindView(R.id.identity_name) - lateinit var identityName: TextView + lateinit var identityName: EditText @BindView(R.id.real_name) - lateinit var realName: TextView + lateinit var realName: EditText @BindView(R.id.ident) - lateinit var ident: TextView + lateinit var ident: EditText @BindView(R.id.nicks) lateinit var nicks: RecyclerView @@ -44,16 +42,16 @@ abstract class IdentityBaseFragment : SettingsFragment(), SettingsFragment.Savab lateinit var newNick: Button @BindView(R.id.kick_reason) - lateinit var kickReason: TextView + lateinit var kickReason: EditText @BindView(R.id.part_reason) - lateinit var partReason: TextView + lateinit var partReason: EditText @BindView(R.id.quit_reason) - lateinit var quitReason: TextView + lateinit var quitReason: EditText @BindView(R.id.away_reason) - lateinit var awayReason: TextView + lateinit var awayReason: EditText @BindView(R.id.detach_away) lateinit var detachAway: SwitchCompat @@ -62,7 +60,9 @@ abstract class IdentityBaseFragment : SettingsFragment(), SettingsFragment.Savab lateinit var detachAwayGroup: ViewGroup @BindView(R.id.detach_away_reason) - lateinit var detachAwayReason: TextView + lateinit var detachAwayReason: EditText + + protected var identity: Pair<Identity?, Identity>? = null private lateinit var adapter: IdentityNicksAdapter private lateinit var helper: ItemTouchHelper @@ -98,22 +98,23 @@ abstract class IdentityBaseFragment : SettingsFragment(), SettingsFragment.Savab }.build().show() } - viewModel.identities.switchMap { - it[identityId]?.liveUpdates() ?: Observable.empty() - }.firstElement() + viewModel.identities.map { Optional.ofNullable(it[identityId]) } + .filter(Optional<Identity>::isPresent) + .map(Optional<Identity>::get) + .firstElement() .toLiveData().observe(this, Observer { - if (it != null) { + it?.let { this.identity = Pair(it, it.copy()) this.identity?.let { (_, data) -> - identityName.text = data.identityName() - realName.text = data.realName() - ident.text = data.ident() - kickReason.text = data.kickReason() - partReason.text = data.partReason() - quitReason.text = data.quitReason() - awayReason.text = data.awayReason() + identityName.setText(data.identityName()) + realName.setText(data.realName()) + ident.setText(data.ident()) + kickReason.setText(data.kickReason()) + partReason.setText(data.partReason()) + quitReason.setText(data.quitReason()) + awayReason.setText(data.awayReason()) detachAway.isChecked = data.detachAwayEnabled() - detachAwayReason.text = data.detachAwayReason() + detachAwayReason.setText(data.detachAwayReason()) adapter.nicks = data.nicks() } } @@ -124,9 +125,10 @@ abstract class IdentityBaseFragment : SettingsFragment(), SettingsFragment.Savab return view } - fun startDrag(holder: IdentityNicksAdapter.IdentityNickViewHolder) = helper.startDrag(holder) + private fun startDrag(holder: IdentityNicksAdapter.IdentityNickViewHolder) = helper.startDrag( + holder) - fun nickClick(index: Int, nick: String) { + private fun nickClick(index: Int, nick: String) { MaterialDialog.Builder(requireContext()) .input(null, nick, false) { _, _ -> } .title(R.string.label_edit_nick) @@ -155,7 +157,7 @@ abstract class IdentityBaseFragment : SettingsFragment(), SettingsFragment.Savab data.detachAwayEnabled() != it.detachAwayEnabled() || data.detachAwayReason() != it.detachAwayReason() || data.nicks() != it.nicks() - } ?: false + } ?: true protected fun applyChanges(data: Identity) { data.setIdentityName(identityName.text.toString()) diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityCreateFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityCreateFragment.kt index e2d5432b4ea34e6ca3a56ec6fadc3a563a2f20d9..d7a0bfde0d57cb9e8d579e645ca640fd64fcaed0 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityCreateFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityCreateFragment.kt @@ -8,7 +8,7 @@ class IdentityCreateFragment : IdentityBaseFragment() { override fun onSave() = viewModel.session.value?.orNull()?.let { session -> Identity(session.proxy).let { data -> applyChanges(data) - session.rpcHandler?.createIdentity(data.toVariantMap(), mapOf()) + session.rpcHandler?.createIdentity(data, mapOf()) true } } ?: false diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListFragment.kt index 08b5f5d17754e10fde0618cc4044f938850ece89..bbdfad785f7373c0cf6cb26e8c734493932049cc 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListFragment.kt @@ -67,11 +67,11 @@ class IgnoreListFragment : SettingsFragment(), SettingsFragment.Savable, return view } - fun itemClick(item: IgnoreListManager.IgnoreListItem) { + private fun itemClick(item: IgnoreListManager.IgnoreListItem) { startActivityForResult(IgnoreItemActivity.intent(requireContext(), item), REQUEST_UPDATE_RULE) } - fun startDrag(holder: IgnoreListAdapter.IgnoreItemViewHolder) = helper.startDrag(holder) + private fun startDrag(holder: IgnoreListAdapter.IgnoreItemViewHolder) = helper.startDrag(holder) override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK && data != null) { diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/DragSortItemTouchHelperCallback.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/DragSortItemTouchHelperCallback.kt new file mode 100644 index 0000000000000000000000000000000000000000..dbfeb4a72de1425eec68b40b8238304ccde4169b --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/DragSortItemTouchHelperCallback.kt @@ -0,0 +1,28 @@ +package de.kuschku.quasseldroid.ui.coresettings.network + +import android.support.v7.widget.RecyclerView +import android.support.v7.widget.helper.ItemTouchHelper + +class DragSortItemTouchHelperCallback(private val adapter: NetworkServerAdapter) : + ItemTouchHelper.Callback() { + override fun isLongPressDragEnabled() = true + + override fun isItemViewSwipeEnabled() = true + + override fun getMovementFlags(recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder): Int { + val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN + val swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END + return makeMovementFlags(dragFlags, swipeFlags) + } + + override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder): Boolean { + adapter.move(viewHolder.adapterPosition, target.adapterPosition) + return true + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + adapter.remove(viewHolder.adapterPosition) + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/IdentityAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/IdentityAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..385c9e3fd533a77f4c0548c871f9f3cef70c4a59 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/IdentityAdapter.kt @@ -0,0 +1,68 @@ +package de.kuschku.quasseldroid.ui.coresettings.network + +import android.support.v7.widget.RecyclerView +import android.support.v7.widget.ThemedSpinnerAdapter +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import butterknife.BindView +import butterknife.ButterKnife +import de.kuschku.libquassel.protocol.NetworkId +import de.kuschku.libquassel.quassel.syncables.Identity +import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.util.ui.ContextThemeWrapper +import de.kuschku.quasseldroid.util.ui.RecyclerSpinnerAdapter + +class IdentityAdapter : RecyclerSpinnerAdapter<IdentityAdapter.NetworkViewHolder>(), + ThemedSpinnerAdapter { + var data = emptyList<Identity>() + + fun submitList(list: List<Identity>) { + data = list + notifyDataSetChanged() + } + + override fun isEmpty() = data.isEmpty() + + override fun onBindViewHolder(holder: NetworkViewHolder, position: Int) = + holder.bind(getItem(position)) + + override fun onCreateViewHolder(parent: ViewGroup, dropDown: Boolean) + : NetworkViewHolder { + val inflater = LayoutInflater.from( + if (dropDown) ContextThemeWrapper(parent.context, dropDownViewTheme) else parent.context + ) + return NetworkViewHolder(inflater.inflate(R.layout.widget_spinner_item_toolbar, parent, false)) + } + + fun indexOf(id: NetworkId): Int? { + for ((key, item) in data.withIndex()) { + if (item.id() == id) { + return key + } + } + return null + } + + override fun getItem(position: Int): Identity? = data[position] + + override fun getItemId(position: Int) = getItem(position)?.id()?.toLong() ?: -1 + + override fun hasStableIds() = true + + override fun getCount() = data.size + + class NetworkViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + @BindView(android.R.id.text1) + lateinit var text: TextView + + init { + ButterKnife.bind(this, itemView) + } + + fun bind(network: Identity?) { + text.text = network?.identityName() + } + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkBaseFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkBaseFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..4ac703d0908f81fcc6e67bd37958d05c6f5bc342 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkBaseFragment.kt @@ -0,0 +1,260 @@ +package de.kuschku.quasseldroid.ui.coresettings.network + +import android.arch.lifecycle.Observer +import android.os.Bundle +import android.support.v4.view.ViewCompat +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.support.v7.widget.SwitchCompat +import android.support.v7.widget.helper.ItemTouchHelper +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.EditText +import android.widget.Spinner +import butterknife.BindView +import butterknife.ButterKnife +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.libquassel.util.Optional +import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.ui.coresettings.SettingsFragment +import de.kuschku.quasseldroid.util.helper.combineLatest +import de.kuschku.quasseldroid.util.helper.setDependent +import de.kuschku.quasseldroid.util.helper.toLiveData +import kotlin.math.roundToInt + +abstract class NetworkBaseFragment : SettingsFragment(), SettingsFragment.Savable, + SettingsFragment.Changeable { + + @BindView(R.id.network_name) + lateinit var networkName: EditText + + @BindView(R.id.identity) + lateinit var identity: Spinner + + @BindView(R.id.servers) + lateinit var servers: RecyclerView + + @BindView(R.id.new_server) + lateinit var newServer: Button + + @BindView(R.id.sasl_enabled) + lateinit var saslEnabled: SwitchCompat + + @BindView(R.id.sasl_group) + lateinit var saslGroup: ViewGroup + + @BindView(R.id.sasl_account) + lateinit var saslAccount: EditText + + @BindView(R.id.sasl_password) + lateinit var saslPassword: EditText + + @BindView(R.id.autoidentify_enabled) + lateinit var autoidentifyEnabled: SwitchCompat + + @BindView(R.id.autoidentify_group) + lateinit var autoidentifyGroup: ViewGroup + + @BindView(R.id.autoidentify_service) + lateinit var autoidentifyService: EditText + + @BindView(R.id.autoidentify_password) + lateinit var autoidentifyPassword: EditText + + @BindView(R.id.autoreconnect_enabled) + lateinit var autoreconnectEnabled: SwitchCompat + + @BindView(R.id.autoreconnect_group) + lateinit var autoreconnectGroup: ViewGroup + + @BindView(R.id.autoreconnect_interval) + lateinit var autoreconnectInterval: EditText + + @BindView(R.id.autoreconnect_attempts) + lateinit var autoreconnectRetries: EditText + + @BindView(R.id.autoreconnect_unlimited) + lateinit var autoreconnectUnlimited: SwitchCompat + + @BindView(R.id.rejoin_channels) + lateinit var rejoinChannels: SwitchCompat + + @BindView(R.id.customratelimits_enabled) + lateinit var customratelimitsEnabled: SwitchCompat + + @BindView(R.id.customratelimits_group) + lateinit var customratelimitsGroup: ViewGroup + + @BindView(R.id.customratelimits_burstsize) + lateinit var customratelimitsBurstSize: EditText + + @BindView(R.id.customratelimits_unlimited) + lateinit var customratelimitsUnlimited: SwitchCompat + + @BindView(R.id.customratelimits_delay) + lateinit var customratelimitsDelay: EditText + + protected var network: Pair<Network?, Network>? = null + + private lateinit var adapter: NetworkServerAdapter + private lateinit var helper: ItemTouchHelper + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + val view = inflater.inflate(R.layout.settings_network, container, false) + ButterKnife.bind(this, view) + + val networkId = arguments?.getInt("network", -1) ?: -1 + + adapter = NetworkServerAdapter(::serverClick, ::startDrag) + servers.layoutManager = LinearLayoutManager(requireContext()) + servers.adapter = adapter + ViewCompat.setNestedScrollingEnabled(servers, false) + + val callback = DragSortItemTouchHelperCallback(adapter) + helper = ItemTouchHelper(callback) + helper.attachToRecyclerView(servers) + + newServer.setOnClickListener { + // TODO: Add server screen + } + + val identityAdapter = IdentityAdapter() + identity.adapter = identityAdapter + + viewModel.identities.switchMap { + combineLatest(it.values.map(Identity::liveUpdates)).map { + it.sortedBy(Identity::identityName) + } + }.toLiveData().observe(this, Observer { + if (it != null) { + val selectOriginal = identity.selectedItemId == Spinner.INVALID_ROW_ID + identityAdapter.submitList(it) + if (selectOriginal) { + this.network?.let { (_, data) -> + identityAdapter.indexOf(data.networkId())?.let(identity::setSelection) + } + } + } + }) + + viewModel.networks.map { Optional.ofNullable(it[networkId]) } + .filter(Optional<Network>::isPresent) + .map(Optional<Network>::get) + .firstElement() + .toLiveData().observe(this, Observer { + it?.let { + this.network = Pair(it, it.copy()) + this.network?.let { (_, data) -> + networkName.setText(data.networkName()) + + identityAdapter.indexOf(data.identity())?.let(identity::setSelection) + + adapter.list = data.serverList() + + saslEnabled.isChecked = data.useSasl() + saslAccount.setText(data.saslAccount()) + saslPassword.setText(data.saslPassword()) + + autoidentifyEnabled.isChecked = data.useAutoIdentify() + autoidentifyService.setText(data.autoIdentifyService()) + autoidentifyPassword.setText(data.autoIdentifyPassword()) + + autoreconnectEnabled.isChecked = data.useAutoReconnect() + autoreconnectInterval.setText(data.autoReconnectInterval().toString()) + autoreconnectRetries.setText(data.autoReconnectRetries().toString()) + autoreconnectUnlimited.isChecked = data.unlimitedReconnectRetries() + + rejoinChannels.isChecked = data.rejoinChannels() + + customratelimitsEnabled.isChecked = data.useCustomMessageRate() + customratelimitsBurstSize.setText(data.messageRateBurstSize().toString()) + customratelimitsUnlimited.isChecked = data.unlimitedMessageRate() + customratelimitsDelay.setText("${data.messageRateDelay() / 1000.0}") + } + } + }) + + saslEnabled.setDependent(saslGroup) + autoidentifyEnabled.setDependent(autoidentifyGroup) + autoreconnectEnabled.setDependent(autoreconnectGroup) + autoreconnectUnlimited.setOnCheckedChangeListener { _, isChecked -> + autoreconnectRetries.isEnabled = !isChecked + } + customratelimitsEnabled.setDependent(customratelimitsGroup) + customratelimitsUnlimited.setOnCheckedChangeListener { _, isChecked -> + customratelimitsBurstSize.isEnabled = !isChecked + } + + return view + } + + private fun serverClick(index: Int, server: INetwork.Server) { + // TODO: Add server screen + } + + private fun startDrag(holder: RecyclerView.ViewHolder) { + helper.startDrag(holder) + } + + override fun hasChanged() = network?.let { (it, data) -> + applyChanges(data) + + it == null || + data.networkName() != it.networkName() || + data.identity() != it.identity() || + data.serverList() != it.serverList() || + data.useSasl() != it.useSasl() || + data.saslAccount() != it.saslAccount() || + data.saslPassword() != it.saslPassword() || + data.useAutoIdentify() != it.useAutoIdentify() || + data.autoIdentifyService() != it.autoIdentifyService() || + data.autoIdentifyPassword() != it.autoIdentifyPassword() || + data.useAutoReconnect() != it.useAutoReconnect() || + data.autoReconnectInterval() != it.autoReconnectInterval() || + data.autoReconnectRetries() != it.autoReconnectRetries() || + data.unlimitedReconnectRetries() != it.unlimitedReconnectRetries() || + data.rejoinChannels() != it.rejoinChannels() || + data.useCustomMessageRate() != it.useCustomMessageRate() || + data.messageRateBurstSize() != it.messageRateBurstSize() || + data.unlimitedMessageRate() != it.unlimitedMessageRate() || + data.messageRateDelay() != it.messageRateDelay() + } ?: true + + protected fun applyChanges(data: Network) { + data.setNetworkName(networkName.text.toString()) + + data.setIdentity(identity.selectedItemId.toInt()) + + data.setActualServerList(adapter.list) + + data.setUseSasl(saslEnabled.isChecked) + data.setSaslAccount(saslAccount.text.toString()) + data.setSaslPassword(saslPassword.text.toString()) + + data.setUseAutoIdentify(autoidentifyEnabled.isChecked) + data.setAutoIdentifyService(autoidentifyService.text.toString()) + data.setAutoIdentifyPassword(autoidentifyPassword.text.toString()) + + data.setUseAutoReconnect(autoreconnectEnabled.isChecked) + data.setAutoReconnectInterval(autoreconnectInterval.text.toString().toIntOrNull() + ?: data.autoReconnectInterval()) + data.setAutoReconnectRetries(autoreconnectRetries.text.toString().toShortOrNull() + ?: data.autoReconnectRetries()) + data.setUnlimitedReconnectRetries(autoreconnectUnlimited.isChecked) + + data.setRejoinChannels(rejoinChannels.isChecked) + + data.setUseCustomMessageRate(customratelimitsEnabled.isChecked) + data.setMessageRateBurstSize(customratelimitsBurstSize.text.toString().toIntOrNull() + ?: data.messageRateBurstSize()) + data.setUnlimitedMessageRate(customratelimitsUnlimited.isChecked) + data.setMessageRateDelay(customratelimitsDelay.toString().toFloatOrNull() + ?.let { (it * 1000).roundToInt() } + ?: data.messageRateDelay()) + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..a8b204e840757026c1cfdd6b2da347ac6289ce94 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateActivity.kt @@ -0,0 +1,12 @@ +package de.kuschku.quasseldroid.ui.coresettings.network + +import android.content.Context +import android.content.Intent +import de.kuschku.quasseldroid.util.ui.SettingsActivity + +class NetworkCreateActivity : SettingsActivity(NetworkCreateFragment()) { + companion object { + fun launch(context: Context) = context.startActivity(intent(context)) + fun intent(context: Context) = Intent(context, NetworkEditActivity::class.java) + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..1591023ba750adbac050cd5268d06bbe9b24165f --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateFragment.kt @@ -0,0 +1,14 @@ +package de.kuschku.quasseldroid.ui.coresettings.network + +import de.kuschku.libquassel.quassel.syncables.Network +import de.kuschku.libquassel.util.helpers.value + +class NetworkCreateFragment : NetworkBaseFragment() { + override fun onSave() = viewModel.session.value?.orNull()?.let { session -> + Network(-1, session.proxy).let { data -> + applyChanges(data) + session.rpcHandler?.createNetwork(data.networkInfo(), emptyList()) + true + } + } ?: false +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateFragmentProvider.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateFragmentProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..df321c97acfd6e9931782609ba8033cad208c20f --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateFragmentProvider.kt @@ -0,0 +1,10 @@ +package de.kuschku.quasseldroid.ui.coresettings.network + +import dagger.Module +import dagger.android.ContributesAndroidInjector + +@Module +abstract class NetworkCreateFragmentProvider { + @ContributesAndroidInjector + abstract fun bindNetworkCreateFragment(): NetworkCreateFragment +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..f813c0565c06d86079e38aba3067897ae21710a4 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditActivity.kt @@ -0,0 +1,22 @@ +package de.kuschku.quasseldroid.ui.coresettings.network + +import android.content.Context +import android.content.Intent +import de.kuschku.libquassel.protocol.NetworkId +import de.kuschku.quasseldroid.util.ui.SettingsActivity + +class NetworkEditActivity : SettingsActivity(NetworkEditFragment()) { + companion object { + fun launch( + context: Context, + network: NetworkId + ) = context.startActivity(intent(context, network)) + + fun intent( + context: Context, + network: NetworkId + ) = Intent(context, NetworkEditActivity::class.java).apply { + putExtra("network", network) + } + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..3af4fdf6944e5898ac4388a7822f4f1ce4868178 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditFragment.kt @@ -0,0 +1,20 @@ +package de.kuschku.quasseldroid.ui.coresettings.network + +import de.kuschku.libquassel.util.helpers.value +import de.kuschku.quasseldroid.ui.coresettings.SettingsFragment + +class NetworkEditFragment : NetworkBaseFragment(), SettingsFragment.Deletable { + override fun onSave() = network?.let { (it, data) -> + applyChanges(data) + it?.requestUpdate(data.toVariantMap()) + true + } ?: false + + override fun onDelete() { + network?.let { (it, _) -> + it?.let { + viewModel.session.value?.orNull()?.rpcHandler?.removeNetwork(it.networkId()) + } + } + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditFragmentProvider.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditFragmentProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..b59c47ab68dc2a1341f90684ee1b76fc810b506b --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditFragmentProvider.kt @@ -0,0 +1,10 @@ +package de.kuschku.quasseldroid.ui.coresettings.network + +import dagger.Module +import dagger.android.ContributesAndroidInjector + +@Module +abstract class NetworkEditFragmentProvider { + @ContributesAndroidInjector + abstract fun bindNetworkEditFragment(): NetworkEditFragment +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkServerAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkServerAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..e91a705702380e3e6bea20385dd0762f1ab0102b --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkServerAdapter.kt @@ -0,0 +1,134 @@ +package de.kuschku.quasseldroid.ui.coresettings.network + +import android.graphics.drawable.Drawable +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import butterknife.BindView +import butterknife.ButterKnife +import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork +import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.util.helper.getVectorDrawableCompat +import de.kuschku.quasseldroid.util.helper.styledAttributes +import de.kuschku.quasseldroid.util.helper.tint +import java.util.* + +class NetworkServerAdapter( + private val clickListener: (Int, INetwork.Server) -> Unit, + private val dragListener: (NetworkServerViewHolder) -> Unit +) : RecyclerView.Adapter<NetworkServerAdapter.NetworkServerViewHolder>() { + private val data = mutableListOf<INetwork.Server>() + var list: List<INetwork.Server> + get() = data + set(value) { + val length = data.size + data.clear() + notifyItemRangeRemoved(0, length) + data.addAll(value) + notifyItemRangeInserted(0, list.size) + } + + fun add(item: INetwork.Server) { + val index = data.size + data.add(item) + notifyItemInserted(index) + } + + fun replace(index: Int, item: INetwork.Server) { + data[index] = item + notifyItemChanged(index) + } + + fun remove(index: Int) { + data.removeAt(index) + notifyItemRemoved(index) + } + + fun move(from: Int, to: Int) { + Collections.swap(data, from, to) + notifyItemMoved(from, to) + } + + override fun getItemCount() = data.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = NetworkServerViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.settings_network_server, parent, false), + clickListener, + dragListener + ) + + override fun onBindViewHolder(holder: NetworkServerViewHolder, position: Int) { + holder.bind(data[position]) + } + + class NetworkServerViewHolder( + itemView: View, + clickListener: (Int, INetwork.Server) -> Unit, + dragListener: (NetworkServerViewHolder) -> Unit + ) : RecyclerView.ViewHolder(itemView) { + @BindView(R.id.host) + lateinit var host: TextView + + @BindView(R.id.port) + lateinit var port: TextView + + @BindView(R.id.ssl_enabled) + lateinit var sslEnabled: ImageView + + @BindView(R.id.handle) + lateinit var handle: View + + private var item: INetwork.Server? = null + + private val secure: Drawable? + private val partiallySecure: Drawable? + private val insecure: Drawable? + + init { + ButterKnife.bind(this, itemView) + itemView.setOnClickListener { + item?.let { + clickListener(adapterPosition, it) + } + } + handle.setOnTouchListener { _, event -> + if (event.action == MotionEvent.ACTION_DOWN) { + dragListener.invoke(this) + } + false + } + + secure = itemView.context.getVectorDrawableCompat(R.drawable.ic_lock)?.mutate() + partiallySecure = itemView.context.getVectorDrawableCompat(R.drawable.ic_lock)?.mutate() + insecure = itemView.context.getVectorDrawableCompat(R.drawable.ic_lock_open)?.mutate() + + itemView.context.theme.styledAttributes( + R.attr.colorTintSecure, + R.attr.colorTintPartiallySecure, + R.attr.colorTintInsecure + ) { + secure?.tint(getColor(0, 0)) + partiallySecure?.tint(getColor(1, 0)) + insecure?.tint(getColor(2, 0)) + } + } + + fun bind(item: INetwork.Server) { + this.item = item + host.text = item.host + port.text = item.port.toString() + + sslEnabled.setImageDrawable( + when { + item.useSsl && item.sslVerify -> secure + item.useSsl -> partiallySecure + else -> insecure + } + ) + } + } +} diff --git a/app/src/main/res/drawable/ic_key_variant.xml b/app/src/main/res/drawable/ic_key_variant.xml new file mode 100644 index 0000000000000000000000000000000000000000..e13ff652f24287ccb6dcf008cbbafff20a4c7053 --- /dev/null +++ b/app/src/main/res/drawable/ic_key_variant.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + <path + android:fillColor="#000" + android:pathData="M22,18V22H18V19H15V16H12L9.74,13.74C9.19,13.91 8.61,14 8,14A6,6 0 0,1 2,8A6,6 0 0,1 8,2A6,6 0 0,1 14,8C14,8.61 13.91,9.19 13.74,9.74L22,18M7,5A2,2 0 0,0 5,7A2,2 0 0,0 7,9A2,2 0 0,0 9,7A2,2 0 0,0 7,5Z" /> +</vector> diff --git a/app/src/main/res/layout/settings_chatlist.xml b/app/src/main/res/layout/settings_chatlist.xml index 773b90fd7c00c15a8db386b3c0276246a0e8f4d3..96d3cf5b929bc4d331b9a8128e9d4b7a629ff012 100644 --- a/app/src/main/res/layout/settings_chatlist.xml +++ b/app/src/main/res/layout/settings_chatlist.xml @@ -73,7 +73,8 @@ <Spinner android:id="@+id/network_id" android:layout_width="match_parent" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content" + tools:listitem="@layout/widget_spinner_item_toolbar" /> <android.support.v7.widget.SwitchCompat android:id="@+id/show_status_buffer" @@ -131,7 +132,8 @@ <Spinner android:id="@+id/minimum_activity" android:layout_width="match_parent" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content" + tools:listitem="@layout/widget_spinner_item_toolbar" /> <android.support.v7.widget.SwitchCompat android:id="@+id/hide_inactive_buffers" diff --git a/app/src/main/res/layout/settings_identity_nick.xml b/app/src/main/res/layout/settings_identity_nick.xml index ab343f9161d5ee3aa83172c0ac92d7063da0cc59..1a017a4de712260a91fde07b7c15a45be7d6b77a 100644 --- a/app/src/main/res/layout/settings_identity_nick.xml +++ b/app/src/main/res/layout/settings_identity_nick.xml @@ -5,7 +5,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="2dp" - app:cardElevation="2dp"> + app:cardBackgroundColor="?colorBackgroundCard" + app:cardElevation="2dp" + tools:showIn="@layout/settings_identity"> <LinearLayout android:layout_width="match_parent" @@ -36,4 +38,4 @@ app:srcCompat="@drawable/ic_reorder" app:tint="?colorTextSecondary" /> </LinearLayout> -</android.support.v7.widget.CardView> \ No newline at end of file +</android.support.v7.widget.CardView> diff --git a/app/src/main/res/layout/settings_ignorelist_item.xml b/app/src/main/res/layout/settings_ignorelist_item.xml index e38964f532e1d655a92868f595f895d17094078b..0f716b7f8a0ffa063fc125c2237f866e592f6077 100644 --- a/app/src/main/res/layout/settings_ignorelist_item.xml +++ b/app/src/main/res/layout/settings_ignorelist_item.xml @@ -5,7 +5,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="2dp" - app:cardElevation="2dp"> + app:cardBackgroundColor="?colorBackgroundCard" + app:cardElevation="2dp" + tools:showIn="@layout/settings_ignorelist"> <LinearLayout android:layout_width="match_parent" diff --git a/app/src/main/res/layout/settings_network.xml b/app/src/main/res/layout/settings_network.xml new file mode 100644 index 0000000000000000000000000000000000000000..4154566b732902c0a7a0a3db53eb365e8795ea20 --- /dev/null +++ b/app/src/main/res/layout/settings_network.xml @@ -0,0 +1,322 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.v4.widget.NestedScrollView 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:scrollbars="vertical"> + + <LinearLayout style="@style/Widget.CoreSettings.Wrapper"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp"> + + <android.support.v7.widget.AppCompatImageView + style="@style/Widget.CoreSettings.PrimaryItemIcon" + app:srcCompat="@drawable/ic_message_bulleted" /> + + <TextView + style="@style/Widget.CoreSettings.PrimaryItemSwitch" + android:text="@string/settings_network_title" /> + </LinearLayout> + + <LinearLayout + style="@style/Widget.CoreSettings.DependentGroup" + android:visibility="visible"> + + <android.support.design.widget.TextInputLayout + style="@style/Widget.CoreSettings.EditTextLayout" + android:hint="@string/settings_network_network_name"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/network_name" + style="@style/Widget.CoreSettings.EditText" + tools:text="Snoonet" /> + </android.support.design.widget.TextInputLayout> + </LinearLayout> + + <LinearLayout + style="@style/Widget.CoreSettings.DependentGroup" + android:orientation="vertical" + android:visibility="visible"> + + <android.support.v7.widget.RecyclerView + android:id="@+id/servers" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:itemCount="4" + tools:listitem="@layout/settings_network_server" /> + + <LinearLayout + style="@style/Widget.CoreSettings.EditTextLayout" + android:orientation="horizontal"> + + <Button + android:id="@+id/new_server" + style="@style/Widget.Button.Borderless.Colored" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/label_new_server" /> + </LinearLayout> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp"> + + <android.support.v7.widget.AppCompatImageView + style="@style/Widget.CoreSettings.PrimaryItemIcon" + app:srcCompat="@drawable/ic_account_card" /> + + <TextView + style="@style/Widget.CoreSettings.PrimaryItemSwitch" + android:text="@string/settings_network_identity" /> + </LinearLayout> + + <LinearLayout + style="@style/Widget.CoreSettings.DependentGroup" + android:visibility="visible"> + + <Spinner + android:id="@+id/identity" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:listitem="@layout/widget_spinner_item_toolbar" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp"> + + <android.support.v7.widget.AppCompatImageView + style="@style/Widget.CoreSettings.PrimaryItemIcon" + app:srcCompat="@drawable/ic_key_variant" /> + + <android.support.v7.widget.SwitchCompat + android:id="@+id/sasl_enabled" + style="@style/Widget.CoreSettings.PrimaryItemSwitch" + android:text="@string/settings_network_sasl_enabled" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/sasl_group" + style="@style/Widget.CoreSettings.DependentGroup" + tools:visibility="gone"> + + <android.support.design.widget.TextInputLayout + style="@style/Widget.CoreSettings.EditTextLayout" + android:hint="@string/settings_network_sasl_account"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/sasl_account" + style="@style/Widget.CoreSettings.EditText" + tools:text="justjanne" /> + </android.support.design.widget.TextInputLayout> + + <android.support.design.widget.TextInputLayout + style="@style/Widget.CoreSettings.EditTextLayout" + android:hint="@string/settings_network_sasl_password" + app:passwordToggleEnabled="true"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/sasl_password" + style="@style/Widget.CoreSettings.EditText" + android:inputType="textPassword" + tools:text="thisisasecurepassword" /> + </android.support.design.widget.TextInputLayout> + + <!-- TODO: Add info box to show if network supports SASL when connected --> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp"> + + <android.support.v7.widget.AppCompatImageView + style="@style/Widget.CoreSettings.PrimaryItemIcon" + app:srcCompat="@drawable/ic_key_variant" /> + + <android.support.v7.widget.SwitchCompat + android:id="@+id/autoidentify_enabled" + style="@style/Widget.CoreSettings.PrimaryItemSwitch" + android:text="@string/settings_network_autoidentify_enabled" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/autoidentify_group" + style="@style/Widget.CoreSettings.DependentGroup" + tools:visibility="gone"> + + <android.support.design.widget.TextInputLayout + style="@style/Widget.CoreSettings.EditTextLayout" + android:hint="@string/settings_network_autoidentify_service"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/autoidentify_service" + style="@style/Widget.CoreSettings.EditText" + tools:text="NickServ" /> + </android.support.design.widget.TextInputLayout> + + <android.support.design.widget.TextInputLayout + style="@style/Widget.CoreSettings.EditTextLayout" + android:hint="@string/settings_network_autoidentify_password" + app:passwordToggleEnabled="true"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/autoidentify_password" + style="@style/Widget.CoreSettings.EditText" + android:inputType="textPassword" + tools:text="thisisasecurepassword" /> + </android.support.design.widget.TextInputLayout> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp"> + + <android.support.v7.widget.AppCompatImageView + style="@style/Widget.CoreSettings.PrimaryItemIcon" + app:srcCompat="@drawable/ic_server_network" /> + + <TextView + style="@style/Widget.CoreSettings.PrimaryItemSwitch" + android:text="@string/settings_network_connection" /> + </LinearLayout> + + <LinearLayout + style="@style/Widget.CoreSettings.DependentGroup" + android:visibility="visible"> + + <android.support.design.widget.TextInputLayout + style="@style/Widget.CoreSettings.EditTextLayout" + android:hint="@string/settings_network_perform"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/perform" + style="@style/Widget.CoreSettings.EditText" + tools:text="/mode -x" /> + </android.support.design.widget.TextInputLayout> + + <android.support.v7.widget.SwitchCompat + android:id="@+id/rejoin_channels" + style="@style/Widget.CoreSettings.PrimaryItemSwitch" + android:text="@string/settings_network_rejoin_channels" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp"> + + <android.support.v7.widget.AppCompatImageView + style="@style/Widget.CoreSettings.PrimaryItemIcon" + app:srcCompat="@drawable/ic_clock" /> + + <android.support.v7.widget.SwitchCompat + android:id="@+id/autoreconnect_enabled" + style="@style/Widget.CoreSettings.PrimaryItemSwitch" + android:text="@string/settings_network_autoreconnect_enabled" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/autoreconnect_group" + style="@style/Widget.CoreSettings.DependentGroup" + tools:visibility="visible"> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <android.support.design.widget.TextInputLayout + style="@style/Widget.CoreSettings.EditTextLayout" + android:hint="@string/settings_network_autoreconnect_interval"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/autoreconnect_interval" + style="@style/Widget.CoreSettings.EditText" + tools:text="60" /> + </android.support.design.widget.TextInputLayout> + + <TextView + style="@style/Widget.CoreSettings.EditTextSuffix" + android:text="@string/settings_network_autoreconnect_interval_unit" /> + </FrameLayout> + + <android.support.design.widget.TextInputLayout + style="@style/Widget.CoreSettings.EditTextLayout" + android:hint="@string/settings_network_autoreconnect_attempts"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/autoreconnect_attempts" + style="@style/Widget.CoreSettings.EditText" + tools:text="20" /> + </android.support.design.widget.TextInputLayout> + + <android.support.v7.widget.SwitchCompat + android:id="@+id/autoreconnect_unlimited" + style="@style/Widget.CoreSettings.PrimaryItemSwitch" + android:text="@string/settings_network_autoreconnect_unlimited" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp"> + + <android.support.v7.widget.AppCompatImageView + style="@style/Widget.CoreSettings.PrimaryItemIcon" + app:srcCompat="@drawable/ic_settings" /> + + <android.support.v7.widget.SwitchCompat + android:id="@+id/customratelimits_enabled" + style="@style/Widget.CoreSettings.PrimaryItemSwitch" + android:text="@string/settings_network_customratelimits_enabled" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/customratelimits_group" + style="@style/Widget.CoreSettings.DependentGroup" + tools:visibility="visible"> + + <android.support.design.widget.TextInputLayout + style="@style/Widget.CoreSettings.EditTextLayout" + android:hint="@string/settings_network_customratelimits_burstsize"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/customratelimits_burstsize" + style="@style/Widget.CoreSettings.EditText" + tools:text="5" /> + </android.support.design.widget.TextInputLayout> + + <android.support.v7.widget.SwitchCompat + android:id="@+id/customratelimits_unlimited" + style="@style/Widget.CoreSettings.PrimaryItemSwitch" + android:text="@string/settings_network_customratelimits_unlimited" /> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <android.support.design.widget.TextInputLayout + style="@style/Widget.CoreSettings.EditTextLayout" + android:hint="@string/settings_network_customratelimits_delay"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/customratelimits_delay" + style="@style/Widget.CoreSettings.EditText" + tools:text="2.20" /> + </android.support.design.widget.TextInputLayout> + + <TextView + style="@style/Widget.CoreSettings.EditTextSuffix" + android:text="@string/settings_network_customratelimits_interval_unit" /> + </FrameLayout> + </LinearLayout> + </LinearLayout> +</android.support.v4.widget.NestedScrollView> diff --git a/app/src/main/res/layout/settings_network_server.xml b/app/src/main/res/layout/settings_network_server.xml new file mode 100644 index 0000000000000000000000000000000000000000..aec7f169df14b7c5347d5dbb04c4315ab257d475 --- /dev/null +++ b/app/src/main/res/layout/settings_network_server.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.v7.widget.CardView 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="wrap_content" + android:layout_margin="2dp" + app:cardBackgroundColor="?colorBackgroundCard" + app:cardElevation="2dp" + tools:showIn="@layout/settings_network"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:orientation="horizontal" + android:paddingBottom="10dp" + android:paddingTop="10dp"> + + <android.support.v7.widget.AppCompatImageView + android:id="@+id/ssl_enabled" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="center_vertical" + android:paddingEnd="32dp" + android:paddingLeft="?listPreferredItemPaddingLeft" + android:paddingRight="32dp" + android:paddingStart="?listPreferredItemPaddingLeft" + tools:srcCompat="@drawable/ic_lock" + tools:tint="?colorTintSecure" /> + + <LinearLayout + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:orientation="vertical"> + + <TextView + android:id="@+id/host" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="marquee" + android:singleLine="true" + android:textAppearance="?textAppearanceListItemSmall" + tools:text="@sample/networks.json/data/host" /> + + <TextView + android:id="@+id/port" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="marquee" + android:singleLine="true" + android:textAppearance="?textAppearanceListItemSecondary" + android:textColor="?colorTextSecondary" + tools:text="@sample/networks.json/data/port" /> + </LinearLayout> + + <android.support.v7.widget.AppCompatImageView + android:id="@+id/handle" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="center_vertical" + android:paddingEnd="?listPreferredItemPaddingRight" + android:paddingLeft="32dp" + android:paddingRight="?listPreferredItemPaddingRight" + android:paddingStart="32dp" + app:srcCompat="@drawable/ic_reorder" + app:tint="?colorTextSecondary" /> + </LinearLayout> +</android.support.v7.widget.CardView> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 3b0edec4009489c88d130537a5f8439a713b3cf7..3024c896eee54e59cdc19a904fd218b6b54be7da 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -45,6 +45,7 @@ <string name="label_new_identity">Identität hinzufügen</string> <string name="label_new_network">Netzwerk hinzufügen</string> <string name="label_new_nick">Spitzname hinzufügen</string> + <string name="label_new_server">Server hinzufügen</string> <string name="label_nicklist">Benutzerliste</string> <string name="label_no">Nein</string> <string name="label_reset">Zurücksetzen</string> diff --git a/app/src/main/res/values-de/strings_settings.xml b/app/src/main/res/values-de/strings_settings.xml index e2f2eaa834fea60b03f01652e9e091169bd55158..a19c1bbcf6dafda6ec1f54abecb4eb242fa27f66 100644 --- a/app/src/main/res/values-de/strings_settings.xml +++ b/app/src/main/res/values-de/strings_settings.xml @@ -2,6 +2,27 @@ <resources> <string name="settings_networks_title">Netzwerke</string> <string name="settings_network_title">Netzwerk</string> + <string name="settings_network_network_name">Netzwerkname</string> + <string name="settings_network_identity">Identität</string> + <string name="settings_network_sasl_enabled">SASL</string> + <string name="settings_network_sasl_account">Kontoname</string> + <string name="settings_network_sasl_password">Passwort</string> + <string name="settings_network_autoidentify_enabled">Auto-Identifizieren</string> + <string name="settings_network_autoidentify_service">Service</string> + <string name="settings_network_autoidentify_password">Passwort</string> + <string name="settings_network_connection">Verbindung</string> + <string name="settings_network_perform">Befehle</string> + <string name="settings_network_rejoin_channels">Beim Verbinden Kanäle wieder betreten</string> + <string name="settings_network_autoreconnect_enabled">Automatisches Wiederverbinden</string> + <string name="settings_network_autoreconnect_interval">Zeit zwischen Verbindungsversuchen</string> + <string name="settings_network_autoreconnect_interval_unit">Sekunden</string> + <string name="settings_network_autoreconnect_attempts">Maximale Anzahl an Verbindungsversuchen</string> + <string name="settings_network_autoreconnect_unlimited">Unbegrenzt</string> + <string name="settings_network_customratelimits_enabled">Benutzerdefinierte Nachrichtenrate</string> + <string name="settings_network_customratelimits_burstsize">Anzahl Nachrichten pro Übertragung</string> + <string name="settings_network_customratelimits_unlimited">Unbegrenzt</string> + <string name="settings_network_customratelimits_delay">Zeit zwischen Übertragungen</string> + <string name="settings_network_customratelimits_interval_unit">Sekunden</string> <string name="settings_identities_title">Identitäten</string> <string name="settings_identity_title">Identität</string> diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index b178dcda03b0f30e4fd6f0dc1c087a24b442b34f..79a9a0a37ec877bc4166821a0f8f3713635f69c3 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -156,6 +156,10 @@ <attr name="buttonThemeColored" format="reference" /> <attr name="cardStyle" format="reference" /> + <attr name="colorTintSecure" format="color" /> + <attr name="colorTintPartiallySecure" format="color" /> + <attr name="colorTintInsecure" format="color" /> + <!-- Menu Items --> <attr name="backgroundMenuItem" format="reference" /> <attr name="backgroundMenuItemRounded" format="reference" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d78395b56f723f85d483441912597ca37c2f72f0..74d3af40c78606f2baa143f456f3f6bb064836a7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -45,6 +45,7 @@ <string name="label_new_identity">New Identity</string> <string name="label_new_network">New Network</string> <string name="label_new_nick">New Nick</string> + <string name="label_new_server">New Server</string> <string name="label_nicklist">Nick List</string> <string name="label_no">No</string> <string name="label_reset">Reset</string> diff --git a/app/src/main/res/values/strings_settings.xml b/app/src/main/res/values/strings_settings.xml index c124cb405f554512a19a827e060ce019a85c1e3e..6a69c073622df04242069df04cb9d53423a1b7a3 100644 --- a/app/src/main/res/values/strings_settings.xml +++ b/app/src/main/res/values/strings_settings.xml @@ -2,6 +2,27 @@ <resources> <string name="settings_networks_title">Networks</string> <string name="settings_network_title">Network</string> + <string name="settings_network_network_name">Network Name</string> + <string name="settings_network_identity">Identity</string> + <string name="settings_network_sasl_enabled">SASL</string> + <string name="settings_network_sasl_account">Account</string> + <string name="settings_network_sasl_password">Password</string> + <string name="settings_network_autoidentify_enabled">Auto Identify</string> + <string name="settings_network_autoidentify_service">Service</string> + <string name="settings_network_autoidentify_password">Password</string> + <string name="settings_network_connection">Connection</string> + <string name="settings_network_perform">Perform</string> + <string name="settings_network_rejoin_channels">Rejoin Channels</string> + <string name="settings_network_autoreconnect_enabled">Autoreconnect</string> + <string name="settings_network_autoreconnect_interval">Interval</string> + <string name="settings_network_autoreconnect_interval_unit">seconds</string> + <string name="settings_network_autoreconnect_attempts">Maximum Attempts</string> + <string name="settings_network_autoreconnect_unlimited">Unlimited Attempts</string> + <string name="settings_network_customratelimits_enabled">Custom Rate Limits</string> + <string name="settings_network_customratelimits_burstsize">Burst Size</string> + <string name="settings_network_customratelimits_unlimited">Unlimited</string> + <string name="settings_network_customratelimits_delay">Delay</string> + <string name="settings_network_customratelimits_interval_unit">seconds</string> <string name="settings_identities_title">Identities</string> <string name="settings_identity_title">Identity</string> diff --git a/app/src/main/res/values/themes_amoled.xml b/app/src/main/res/values/themes_amoled.xml index af6d2c3f0a69b20d3a4c075e19db8fbcfc6b80c7..39b57fc9b4889e52dcee41dcf089b1b315a4ffa8 100644 --- a/app/src/main/res/values/themes_amoled.xml +++ b/app/src/main/res/values/themes_amoled.xml @@ -48,5 +48,9 @@ <item name="colorTintActivity">#88cc33</item> <item name="colorTintMessage">#2277dd</item> <item name="colorTintHighlight">#ff8811</item> + + <item name="colorTintSecure">#88cc33</item> + <item name="colorTintPartiallySecure">#ffaf3b</item> + <item name="colorTintInsecure">#BB2222</item> </style> </resources> diff --git a/app/src/main/res/values/themes_gruvbox.xml b/app/src/main/res/values/themes_gruvbox.xml index d9fc8ffb3b63a18084d0e19a6da51d21795d0af8..feb2fe12aaa24da2a5394da33997fbc39985fa1f 100644 --- a/app/src/main/res/values/themes_gruvbox.xml +++ b/app/src/main/res/values/themes_gruvbox.xml @@ -54,6 +54,10 @@ <item name="colorTintActivity">#98971a</item> <item name="colorTintMessage">#458588</item> <item name="colorTintHighlight">#d65d0e</item> + + <item name="colorTintSecure">#98971a</item> + <item name="colorTintPartiallySecure">#d79921</item> + <item name="colorTintInsecure">#9d0006</item> </style> <color name="gruvbox_dark_background">#282828</color> @@ -109,5 +113,9 @@ <item name="colorTintActivity">#98971a</item> <item name="colorTintMessage">#458588</item> <item name="colorTintHighlight">#d65d0e</item> + + <item name="colorTintSecure">#98971a</item> + <item name="colorTintPartiallySecure">#d79921</item> + <item name="colorTintInsecure">#cc241d</item> </style> </resources> diff --git a/app/src/main/res/values/themes_quassel.xml b/app/src/main/res/values/themes_quassel.xml index 49784f16cab7161632a1aac9e206349751ed2677..3bf2a6e1f1572b406dbd61c007d71b4662d646ad 100644 --- a/app/src/main/res/values/themes_quassel.xml +++ b/app/src/main/res/values/themes_quassel.xml @@ -42,6 +42,10 @@ <item name="colorTintActivity">#88cc33</item> <item name="colorTintMessage">#2277dd</item> <item name="colorTintHighlight">#ff8811</item> + + <item name="colorTintSecure">#88cc33</item> + <item name="colorTintPartiallySecure">#ffaf3b</item> + <item name="colorTintInsecure">#BB2222</item> </style> <color name="quassel_dark_background">#303030</color> @@ -85,5 +89,9 @@ <item name="colorTintActivity">#88cc33</item> <item name="colorTintMessage">#2277dd</item> <item name="colorTintHighlight">#ff8811</item> + + <item name="colorTintSecure">#88cc33</item> + <item name="colorTintPartiallySecure">#ffaf3b</item> + <item name="colorTintInsecure">#BB2222</item> </style> </resources> diff --git a/app/src/main/res/values/themes_solarized.xml b/app/src/main/res/values/themes_solarized.xml index 2a10005900774983d27c3c41c74b1c2dd3a18d06..e5f72d234582f7731b3ffa5718f1d4831c568db7 100644 --- a/app/src/main/res/values/themes_solarized.xml +++ b/app/src/main/res/values/themes_solarized.xml @@ -54,6 +54,10 @@ <item name="colorTintActivity">#859900</item> <item name="colorTintMessage">#268BD2</item> <item name="colorTintHighlight">#EB6B36</item> + + <item name="colorTintSecure">#859900</item> + <item name="colorTintPartiallySecure">#D5A920</item> + <item name="colorTintInsecure">#CB4B16</item> </style> <color name="solarized_dark_background">#002B36</color> @@ -109,5 +113,9 @@ <item name="colorTintActivity">#859900</item> <item name="colorTintMessage">#268BD2</item> <item name="colorTintHighlight">#EB6B36</item> + + <item name="colorTintSecure">#859900</item> + <item name="colorTintPartiallySecure">#B58900</item> + <item name="colorTintInsecure">#CB4B16</item> </style> </resources>