diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e644d7cb882f94f34ed4942cea096605fdbaf943..92cc546479348cdbe3334281f982c3bef720128b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -71,7 +71,6 @@ android { getByName("debug") { applicationIdSuffix = "debug" - /* isZipAlignEnabled = true isMinifyEnabled = true @@ -81,7 +80,6 @@ android { getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" ) - */ } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 09ec17e0b4adcd0c95c4c499e9143b2a05909369..49809b1aab2c9f2648d4abb2f5c8ed7768b58fc5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -137,8 +137,20 @@ android:name=".ui.coresettings.highlightrule.HighlightRuleActivity" android:exported="false" android:label="@string/settings_highlightrule_title" + android:parentActivityName=".ui.coresettings.highlightlist.HighlightListActivity" + android:windowSoftInputMode="adjustResize" /> + <activity + android:name=".ui.coresettings.aliaslist.AliasListActivity" + android:exported="false" + android:label="@string/settings_aliaslist_title" android:parentActivityName=".ui.coresettings.CoreSettingsActivity" android:windowSoftInputMode="adjustResize" /> + <activity + android:name=".ui.coresettings.aliasitem.AliasItemActivity" + android:exported="false" + android:label="@string/settings_aliasitem_title" + android:parentActivityName=".ui.coresettings.aliaslist.AliasListActivity" + android:windowSoftInputMode="adjustResize" /> <activity android:name=".ui.coresettings.networkconfig.NetworkConfigActivity" 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 bf66c799ff059f1414c8ada3e8cd7f70a594143f..62aa64020aab3fb005ce530b68a2a0b5ff475c1c 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/dagger/ActivityModule.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/dagger/ActivityModule.kt @@ -22,6 +22,10 @@ import de.kuschku.quasseldroid.ui.clientsettings.license.LicenseSettingsActivity import de.kuschku.quasseldroid.ui.clientsettings.license.LicenseSettingsFragmentProvider import de.kuschku.quasseldroid.ui.coresettings.CoreSettingsActivity import de.kuschku.quasseldroid.ui.coresettings.CoreSettingsFragmentProvider +import de.kuschku.quasseldroid.ui.coresettings.aliasitem.AliasItemActivity +import de.kuschku.quasseldroid.ui.coresettings.aliasitem.AliasItemFragmentProvider +import de.kuschku.quasseldroid.ui.coresettings.aliaslist.AliasListActivity +import de.kuschku.quasseldroid.ui.coresettings.aliaslist.AliasListFragmentProvider import de.kuschku.quasseldroid.ui.coresettings.chatlist.ChatlistCreateActivity import de.kuschku.quasseldroid.ui.coresettings.chatlist.ChatlistCreateFragmentProvider import de.kuschku.quasseldroid.ui.coresettings.chatlist.ChatlistEditActivity @@ -105,14 +109,20 @@ abstract class ActivityModule { @ContributesAndroidInjector(modules = [IgnoreListFragmentProvider::class]) abstract fun bindIgnoreListActivity(): IgnoreListActivity + @ContributesAndroidInjector(modules = [IgnoreItemFragmentProvider::class]) + abstract fun bindIgnoreItemActivity(): IgnoreItemActivity + @ContributesAndroidInjector(modules = [HighlightListFragmentProvider::class]) abstract fun bindHighlightListActivity(): HighlightListActivity @ContributesAndroidInjector(modules = [HighlightRuleFragmentProvider::class]) abstract fun bindHighlightRuleActivity(): HighlightRuleActivity - @ContributesAndroidInjector(modules = [IgnoreItemFragmentProvider::class]) - abstract fun bindIgnoreItemActivity(): IgnoreItemActivity + @ContributesAndroidInjector(modules = [AliasListFragmentProvider::class]) + abstract fun bindAliasListActivity(): AliasListActivity + + @ContributesAndroidInjector(modules = [AliasItemFragmentProvider::class]) + abstract fun bindAliasItemActivity(): AliasItemActivity @ContributesAndroidInjector(modules = [NetworkConfigFragmentProvider::class]) abstract fun bindNetworkConfigActivity(): NetworkConfigActivity 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 238ed903201bfc28822562516675df2bdbc63db0..0881512c234722ce93a509ef860c06bbabb28c2d 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 @@ -16,6 +16,7 @@ import de.kuschku.libquassel.quassel.syncables.BufferViewConfig import de.kuschku.libquassel.quassel.syncables.Identity import de.kuschku.libquassel.quassel.syncables.Network import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.ui.coresettings.aliaslist.AliasListActivity import de.kuschku.quasseldroid.ui.coresettings.chatlist.ChatlistCreateActivity import de.kuschku.quasseldroid.ui.coresettings.chatlist.ChatlistEditActivity import de.kuschku.quasseldroid.ui.coresettings.highlightlist.HighlightListActivity @@ -136,6 +137,10 @@ class CoreSettingsFragment : ServiceBoundFragment() { HighlightListActivity.launch(requireContext()) } + aliaslist.setOnClickListener { + AliasListActivity.launch(requireContext()) + } + newNetwork.setOnClickListener { NetworkCreateActivity.launch(requireContext()) } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..58311483b6f2097985c4ce5a7764ef1baef13c0a --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemActivity.kt @@ -0,0 +1,24 @@ +package de.kuschku.quasseldroid.ui.coresettings.aliasitem + +import android.content.Context +import android.content.Intent +import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager +import de.kuschku.quasseldroid.util.ui.SettingsActivity + +class AliasItemActivity : SettingsActivity(AliasItemFragment()) { + companion object { + fun launch( + context: Context, + item: IAliasManager.Alias? = null + ) = context.startActivity(intent(context, item)) + + fun intent( + context: Context, + item: IAliasManager.Alias? = null + ) = Intent(context, AliasItemActivity::class.java).apply { + if (item != null) { + putExtra("item", item) + } + } + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..891fc0e301a018bb23d0cf1531afaf266ec1433b --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemFragment.kt @@ -0,0 +1,177 @@ +package de.kuschku.quasseldroid.ui.coresettings.aliasitem + +import android.app.Activity +import android.arch.lifecycle.ViewModelProviders +import android.content.Intent +import android.os.Bundle +import android.support.v7.widget.DefaultItemAnimator +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.EditText +import butterknife.BindView +import butterknife.ButterKnife +import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager +import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.settings.AppearanceSettings +import de.kuschku.quasseldroid.settings.AutoCompleteSettings +import de.kuschku.quasseldroid.settings.MessageSettings +import de.kuschku.quasseldroid.ui.chat.input.* +import de.kuschku.quasseldroid.ui.coresettings.SettingsFragment +import de.kuschku.quasseldroid.util.helper.styledAttributes +import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer +import de.kuschku.quasseldroid.util.irc.format.IrcFormatSerializer +import de.kuschku.quasseldroid.viewmodel.EditorViewModel +import javax.inject.Inject + +class AliasItemFragment : SettingsFragment(), SettingsFragment.Savable, + SettingsFragment.Changeable { + + @BindView(R.id.name) + lateinit var name: EditText + + @BindView(R.id.expansion) + lateinit var expansion: RichEditText + + @BindView(R.id.formatting_toolbar) + lateinit var toolbar: RichToolbar + + @BindView(R.id.autocomplete_list) + lateinit var autoCompleteList: RecyclerView + + @Inject + lateinit var autoCompleteSettings: AutoCompleteSettings + + @Inject + lateinit var messageSettings: MessageSettings + + @Inject + lateinit var appearanceSettings: AppearanceSettings + + @Inject + lateinit var formatDeserializer: IrcFormatDeserializer + + @Inject + lateinit var formatSerializer: IrcFormatSerializer + + @Inject + lateinit var autoCompleteAdapter: AutoCompleteAdapter + + private lateinit var editorHelper: EditorHelper + + private lateinit var mircColorMap: Map<Int, Int> + + private var colorForegroundMirc: Int = 0 + + private var rule: IAliasManager.Alias? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + + val view = inflater.inflate(R.layout.settings_aliasitem, container, false) + ButterKnife.bind(this, view) + + (arguments?.getSerializable("item") as? IAliasManager.Alias)?.let { + rule = it + } + + val mircColors = requireContext().theme.styledAttributes( + R.attr.mircColor00, R.attr.mircColor01, R.attr.mircColor02, R.attr.mircColor03, + R.attr.mircColor04, R.attr.mircColor05, R.attr.mircColor06, R.attr.mircColor07, + R.attr.mircColor08, R.attr.mircColor09, R.attr.mircColor10, R.attr.mircColor11, + R.attr.mircColor12, R.attr.mircColor13, R.attr.mircColor14, R.attr.mircColor15, + R.attr.mircColor16, R.attr.mircColor17, R.attr.mircColor18, R.attr.mircColor19, + R.attr.mircColor20, R.attr.mircColor21, R.attr.mircColor22, R.attr.mircColor23, + R.attr.mircColor24, R.attr.mircColor25, R.attr.mircColor26, R.attr.mircColor27, + R.attr.mircColor28, R.attr.mircColor29, R.attr.mircColor30, R.attr.mircColor31, + R.attr.mircColor32, R.attr.mircColor33, R.attr.mircColor34, R.attr.mircColor35, + R.attr.mircColor36, R.attr.mircColor37, R.attr.mircColor38, R.attr.mircColor39, + R.attr.mircColor40, R.attr.mircColor41, R.attr.mircColor42, R.attr.mircColor43, + R.attr.mircColor44, R.attr.mircColor45, R.attr.mircColor46, R.attr.mircColor47, + R.attr.mircColor48, R.attr.mircColor49, R.attr.mircColor50, R.attr.mircColor51, + R.attr.mircColor52, R.attr.mircColor53, R.attr.mircColor54, R.attr.mircColor55, + R.attr.mircColor56, R.attr.mircColor57, R.attr.mircColor58, R.attr.mircColor59, + R.attr.mircColor60, R.attr.mircColor61, R.attr.mircColor62, R.attr.mircColor63, + R.attr.mircColor64, R.attr.mircColor65, R.attr.mircColor66, R.attr.mircColor67, + R.attr.mircColor68, R.attr.mircColor69, R.attr.mircColor70, R.attr.mircColor71, + R.attr.mircColor72, R.attr.mircColor73, R.attr.mircColor74, R.attr.mircColor75, + R.attr.mircColor76, R.attr.mircColor77, R.attr.mircColor78, R.attr.mircColor79, + R.attr.mircColor80, R.attr.mircColor81, R.attr.mircColor82, R.attr.mircColor83, + R.attr.mircColor84, R.attr.mircColor85, R.attr.mircColor86, R.attr.mircColor87, + R.attr.mircColor88, R.attr.mircColor89, R.attr.mircColor90, R.attr.mircColor91, + R.attr.mircColor92, R.attr.mircColor93, R.attr.mircColor94, R.attr.mircColor95, + R.attr.mircColor96, R.attr.mircColor97, R.attr.mircColor98 + ) { + IntArray(99) { + getColor(it, 0) + } + } + + mircColorMap = mircColors.take(16).mapIndexed { index: Int, color: Int -> + color to index + }.toMap() + + colorForegroundMirc = requireContext().theme.styledAttributes(R.attr.colorForegroundMirc) { + getColor(0, 0) + } + + val editorViewModel = ViewModelProviders.of(this).get(EditorViewModel::class.java) + editorViewModel.quasselViewModel.onNext(viewModel) + + val autoCompleteHelper = AutoCompleteHelper( + requireActivity(), + autoCompleteSettings, + messageSettings, + formatDeserializer, + editorViewModel + ) + + editorHelper = EditorHelper( + requireActivity(), + expansion, + toolbar, + autoCompleteHelper, + autoCompleteSettings, + appearanceSettings + ) + + editorViewModel.lastWord.onNext(editorHelper.lastWord) + + if (autoCompleteSettings.prefix || autoCompleteSettings.auto) { + autoCompleteAdapter.setOnClickListener(expansion::autoComplete) + autoCompleteList.layoutManager = LinearLayoutManager(activity) + autoCompleteList.itemAnimator = DefaultItemAnimator() + autoCompleteList.adapter = autoCompleteAdapter + autoCompleteHelper.setDataListener { + autoCompleteAdapter.submitList(it) + } + } + + rule?.let { data -> + name.setText(data.name) + expansion.setText(formatDeserializer.formatString(mircColors, data.expansion, true)) + } + + return view + } + + private fun applyChanges() = IAliasManager.Alias( + name = name.text.toString(), + expansion = formatSerializer.toEscapeCodes(colorForegroundMirc, mircColorMap, expansion.text) + ) + + override fun onSave() = rule.let { data -> + requireActivity().setResult( + Activity.RESULT_OK, + Intent().also { + it.putExtra("old", data) + it.putExtra("new", applyChanges()) + } + ) + true + } + + override fun hasChanged() = rule != applyChanges() +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemFragmentProvider.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemFragmentProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..079201779779d3bfdba2b0b6ff4d5eae00e7c232 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemFragmentProvider.kt @@ -0,0 +1,10 @@ +package de.kuschku.quasseldroid.ui.coresettings.aliasitem + +import dagger.Module +import dagger.android.ContributesAndroidInjector + +@Module +abstract class AliasItemFragmentProvider { + @ContributesAndroidInjector + abstract fun bindAliasItemFragment(): AliasItemFragment +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..c55e49397c386130fbc9952b60ee3c08898d059c --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListActivity.kt @@ -0,0 +1,12 @@ +package de.kuschku.quasseldroid.ui.coresettings.aliaslist + +import android.content.Context +import android.content.Intent +import de.kuschku.quasseldroid.util.ui.SettingsActivity + +class AliasListActivity : SettingsActivity(AliasListFragment()) { + companion object { + fun launch(context: Context) = context.startActivity(intent(context)) + fun intent(context: Context) = Intent(context, AliasListActivity::class.java) + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..45133fedce34c902233eeb7a8ed2040ba0884b6f --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListAdapter.kt @@ -0,0 +1,156 @@ +package de.kuschku.quasseldroid.ui.coresettings.aliaslist + +import android.content.Context +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.TextView +import butterknife.BindView +import butterknife.ButterKnife +import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager +import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.util.helper.styledAttributes +import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer +import java.util.* +import javax.inject.Inject + +class AliasListAdapter @Inject constructor( + private val formatDeserializer: IrcFormatDeserializer +) : RecyclerView.Adapter<AliasListAdapter.AliasItemViewHolder>() { + private var clickListener: ((IAliasManager.Alias) -> Unit)? = null + private var dragListener: ((AliasItemViewHolder) -> Unit)? = null + + fun setOnClickListener(listener: ((IAliasManager.Alias) -> Unit)?) { + clickListener = listener + } + + fun setOnDragListener(listener: ((AliasItemViewHolder) -> Unit)?) { + dragListener = listener + } + + private val data = mutableListOf<IAliasManager.Alias>() + var list: List<IAliasManager.Alias> + get() = data + set(value) { + val length = data.size + data.clear() + notifyItemRangeRemoved(0, length) + data.addAll(value) + notifyItemRangeInserted(0, list.size) + } + + fun add(item: IAliasManager.Alias) { + val index = data.size + data.add(item) + notifyItemInserted(index) + } + + fun replace(index: Int, item: IAliasManager.Alias) { + data[index] = item + notifyItemChanged(index) + } + + fun indexOf(name: String) = data.map(IAliasManager.Alias::name).indexOf(name) + + fun remove(index: Int) { + data.removeAt(index) + notifyItemRemoved(index) + } + + fun move(from: Int, to: Int) { + Collections.swap(data, from, to) + notifyItemMoved(from, to) + } + + private lateinit var mircColors: IntArray + + fun updateColors(context: Context) { + mircColors = context.theme.styledAttributes( + R.attr.mircColor00, R.attr.mircColor01, R.attr.mircColor02, R.attr.mircColor03, + R.attr.mircColor04, R.attr.mircColor05, R.attr.mircColor06, R.attr.mircColor07, + R.attr.mircColor08, R.attr.mircColor09, R.attr.mircColor10, R.attr.mircColor11, + R.attr.mircColor12, R.attr.mircColor13, R.attr.mircColor14, R.attr.mircColor15, + R.attr.mircColor16, R.attr.mircColor17, R.attr.mircColor18, R.attr.mircColor19, + R.attr.mircColor20, R.attr.mircColor21, R.attr.mircColor22, R.attr.mircColor23, + R.attr.mircColor24, R.attr.mircColor25, R.attr.mircColor26, R.attr.mircColor27, + R.attr.mircColor28, R.attr.mircColor29, R.attr.mircColor30, R.attr.mircColor31, + R.attr.mircColor32, R.attr.mircColor33, R.attr.mircColor34, R.attr.mircColor35, + R.attr.mircColor36, R.attr.mircColor37, R.attr.mircColor38, R.attr.mircColor39, + R.attr.mircColor40, R.attr.mircColor41, R.attr.mircColor42, R.attr.mircColor43, + R.attr.mircColor44, R.attr.mircColor45, R.attr.mircColor46, R.attr.mircColor47, + R.attr.mircColor48, R.attr.mircColor49, R.attr.mircColor50, R.attr.mircColor51, + R.attr.mircColor52, R.attr.mircColor53, R.attr.mircColor54, R.attr.mircColor55, + R.attr.mircColor56, R.attr.mircColor57, R.attr.mircColor58, R.attr.mircColor59, + R.attr.mircColor60, R.attr.mircColor61, R.attr.mircColor62, R.attr.mircColor63, + R.attr.mircColor64, R.attr.mircColor65, R.attr.mircColor66, R.attr.mircColor67, + R.attr.mircColor68, R.attr.mircColor69, R.attr.mircColor70, R.attr.mircColor71, + R.attr.mircColor72, R.attr.mircColor73, R.attr.mircColor74, R.attr.mircColor75, + R.attr.mircColor76, R.attr.mircColor77, R.attr.mircColor78, R.attr.mircColor79, + R.attr.mircColor80, R.attr.mircColor81, R.attr.mircColor82, R.attr.mircColor83, + R.attr.mircColor84, R.attr.mircColor85, R.attr.mircColor86, R.attr.mircColor87, + R.attr.mircColor88, R.attr.mircColor89, R.attr.mircColor90, R.attr.mircColor91, + R.attr.mircColor92, R.attr.mircColor93, R.attr.mircColor94, R.attr.mircColor95, + R.attr.mircColor96, R.attr.mircColor97, R.attr.mircColor98 + ) { + IntArray(99) { + getColor(it, 0) + } + } + } + + override fun getItemCount() = data.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = AliasItemViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.settings_aliaslist_item, parent, false), + formatDeserializer, + mircColors, + clickListener, + dragListener + ) + + override fun onBindViewHolder(holder: AliasItemViewHolder, position: Int) { + holder.bind(data[position]) + } + + class AliasItemViewHolder( + itemView: View, + private val formatDeserializer: IrcFormatDeserializer, + private val mircColors: IntArray, + clickListener: ((IAliasManager.Alias) -> Unit)?, + dragListener: ((AliasItemViewHolder) -> Unit)? + ) : RecyclerView.ViewHolder(itemView) { + @BindView(R.id.name) + lateinit var name: TextView + + @BindView(R.id.expansion) + lateinit var expansion: TextView + + @BindView(R.id.handle) + lateinit var handle: View + + private var item: IAliasManager.Alias? = null + + init { + ButterKnife.bind(this, itemView) + itemView.setOnClickListener { + item?.let { + clickListener?.invoke(it) + } + } + handle.setOnTouchListener { _, event -> + if (event.action == MotionEvent.ACTION_DOWN) { + dragListener?.invoke(this) + } + false + } + } + + fun bind(item: IAliasManager.Alias) { + this.item = item + name.text = item.name + expansion.text = formatDeserializer.formatString(mircColors, item.expansion, true) + } + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..4cfb13990b9ffb4069d3816039aafaff4496d5e8 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListFragment.kt @@ -0,0 +1,128 @@ +package de.kuschku.quasseldroid.ui.coresettings.aliaslist + +import android.app.Activity +import android.arch.lifecycle.Observer +import android.content.Intent +import android.os.Bundle +import android.support.design.widget.FloatingActionButton +import android.support.v7.widget.DefaultItemAnimator +import android.support.v7.widget.DividerItemDecoration +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.support.v7.widget.helper.ItemTouchHelper +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import butterknife.BindView +import butterknife.ButterKnife +import de.kuschku.libquassel.quassel.syncables.AliasManager +import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager +import de.kuschku.libquassel.util.Optional +import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.ui.coresettings.SettingsFragment +import de.kuschku.quasseldroid.ui.coresettings.aliasitem.AliasItemActivity +import de.kuschku.quasseldroid.util.helper.toLiveData +import javax.inject.Inject + +class AliasListFragment : SettingsFragment(), SettingsFragment.Savable, + SettingsFragment.Changeable { + @BindView(R.id.list) + lateinit var list: RecyclerView + + @BindView(R.id.add) + lateinit var add: FloatingActionButton + + @Inject + lateinit var adapter: AliasListAdapter + + private var aliasManager: Pair<AliasManager, AliasManager>? = null + + private lateinit var helper: ItemTouchHelper + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + val view = inflater.inflate(R.layout.settings_ignorelist, container, false) + ButterKnife.bind(this, view) + + adapter.updateColors(requireContext()) + adapter.setOnClickListener(::itemClick) + adapter.setOnDragListener(::startDrag) + + list.adapter = adapter + list.layoutManager = LinearLayoutManager(requireContext()) + list.itemAnimator = DefaultItemAnimator() + list.addItemDecoration(DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL)) + + val callback = DragSortItemTouchHelperCallback(adapter) + helper = ItemTouchHelper(callback) + helper.attachToRecyclerView(list) + + add.setOnClickListener { + startActivityForResult(AliasItemActivity.intent(requireContext()), REQUEST_CREATE_ITEM) + } + + viewModel.aliasManager + .filter(Optional<AliasManager>::isPresent) + .map(Optional<AliasManager>::get) + .toLiveData().observe(this, Observer { + if (it != null) { + if (this.aliasManager == null) { + this.aliasManager = Pair(it, it.copy()) + this.aliasManager?.let { (_, data) -> + adapter.list = data.aliasList() + } + } + } + }) + + return view + } + + private fun itemClick(item: IAliasManager.Alias) { + startActivityForResult(AliasItemActivity.intent(requireContext(), item), REQUEST_UPDATE_ITEM) + } + + private fun startDrag(holder: AliasListAdapter.AliasItemViewHolder) = helper.startDrag(holder) + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + if (resultCode == Activity.RESULT_OK && data != null) { + when (requestCode) { + REQUEST_UPDATE_ITEM -> { + val oldRule = data.getSerializableExtra("old") as? IAliasManager.Alias + val newRule = data.getSerializableExtra("new") as? IAliasManager.Alias + + if (oldRule != null && newRule != null) { + adapter.replace(adapter.indexOf(oldRule.name), newRule) + } + } + REQUEST_CREATE_ITEM -> { + val newRule = data.getSerializableExtra("new") as? IAliasManager.Alias + + if (newRule != null) { + adapter.add(newRule) + } + } + } + } + } + + override fun onSave() = aliasManager?.let { (it, data) -> + applyChanges(data) + it.requestUpdate(data.toVariantMap()) + true + } ?: false + + override fun hasChanged() = aliasManager?.let { (it, data) -> + applyChanges(data) + data.aliasList() != it.aliasList() + } ?: false + + private fun applyChanges(data: AliasManager) { + data.setAliasList(adapter.list) + } + + companion object { + private const val REQUEST_UPDATE_ITEM = 1 + private const val REQUEST_CREATE_ITEM = 2 + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListFragmentProvider.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListFragmentProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..fa745903fc43c16d05706e747cafb8c56fbc0252 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListFragmentProvider.kt @@ -0,0 +1,10 @@ +package de.kuschku.quasseldroid.ui.coresettings.aliaslist + +import dagger.Module +import dagger.android.ContributesAndroidInjector + +@Module +abstract class AliasListFragmentProvider { + @ContributesAndroidInjector + abstract fun bindAliasListFragment(): AliasListFragment +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/DragSortItemTouchHelperCallback.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/DragSortItemTouchHelperCallback.kt new file mode 100644 index 0000000000000000000000000000000000000000..049bd8e750f6160d5ece70c3497666aab95f12e5 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/DragSortItemTouchHelperCallback.kt @@ -0,0 +1,28 @@ +package de.kuschku.quasseldroid.ui.coresettings.aliaslist + +import android.support.v7.widget.RecyclerView +import android.support.v7.widget.helper.ItemTouchHelper + +class DragSortItemTouchHelperCallback(private val adapter: AliasListAdapter) : + 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/util/ui/SettingsActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/SettingsActivity.kt index 91725f7df7e34539e04f7122e4e13201e9fc717c..9f52b3f5cb16e0b59eea1e9c45502de9d4732684 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/ui/SettingsActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/SettingsActivity.kt @@ -64,11 +64,11 @@ abstract class SettingsActivity(private val fragment: Fragment? = null) : Servic override fun onOptionsItemSelected(item: MenuItem?) = when (item?.itemId) { android.R.id.home -> { shouldNavigateAway { - if (supportParentActivityIntent == null) { - super.onBackPressed() - } else { + if (supportParentActivityIntent != null) { startActivity(supportParentActivityIntent) finish() + } else { + super.onBackPressed() } } true diff --git a/app/src/main/res/layout/fragment_topic.xml b/app/src/main/res/layout/fragment_topic.xml index dedaeaddadaecf745ba7f45ae4714d151207588b..a97be3cb72836849ce212ed6f76e7793cc52a5ff 100644 --- a/app/src/main/res/layout/fragment_topic.xml +++ b/app/src/main/res/layout/fragment_topic.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <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:minHeight="240dp" @@ -33,7 +34,8 @@ <de.kuschku.quasseldroid.util.ui.AutoCompleteRecyclerView android:id="@+id/autocomplete_list" android:layout_width="match_parent" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content" + tools:listitem="@layout/widget_nick" /> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" diff --git a/app/src/main/res/layout/settings_aliasitem.xml b/app/src/main/res/layout/settings_aliasitem.xml new file mode 100644 index 0000000000000000000000000000000000000000..a771b054bd5ba00cdc33e1e184716a536fc88708 --- /dev/null +++ b/app/src/main/res/layout/settings_aliasitem.xml @@ -0,0 +1,74 @@ +<?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:fillViewport="true" + android:scrollbars="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout style="@style/Widget.CoreSettings.Wrapper"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp"> + + <android.support.design.widget.TextInputLayout + style="@style/Widget.CoreSettings.PrimaryItemSwitch" + android:hint="@string/settings_aliasitem_name"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/name" + style="@style/Widget.CoreSettings.EditText" + tools:text="back" /> + </android.support.design.widget.TextInputLayout> + </LinearLayout> + </LinearLayout> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="0dip" + android:layout_weight="1"> + + <LinearLayout style="@style/Widget.CoreSettings.Wrapper"> + + <android.support.design.widget.TextInputLayout + style="@style/Widget.CoreSettings.PrimaryItemSwitch" + android:hint="@string/settings_aliasitem_expansion"> + + <de.kuschku.quasseldroid.ui.chat.input.RichEditText + android:id="@+id/expansion" + style="@style/Widget.CoreSettings.EditText" + android:imeOptions="flagNoExtractUi" + android:inputType="textMultiLine" + android:textColor="?attr/colorForeground" + android:textSize="16sp" /> + </android.support.design.widget.TextInputLayout> + </LinearLayout> + </ScrollView> + + <de.kuschku.quasseldroid.util.ui.AutoCompleteRecyclerView + android:id="@+id/autocomplete_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:listitem="@layout/widget_nick" /> + + <android.support.design.widget.AppBarLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/colorBackgroundCard"> + + <de.kuschku.quasseldroid.ui.chat.input.RichToolbar + android:id="@+id/formatting_toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + app:contentInsetStart="0dip" /> + </android.support.design.widget.AppBarLayout> + </LinearLayout> +</android.support.v4.widget.NestedScrollView> diff --git a/app/src/main/res/layout/settings_aliaslist.xml b/app/src/main/res/layout/settings_aliaslist.xml new file mode 100644 index 0000000000000000000000000000000000000000..2b5a5e0eeb73ef36c607aa74f7e6709b22abf9e0 --- /dev/null +++ b/app/src/main/res/layout/settings_aliaslist.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <android.support.v7.widget.RecyclerView + android:id="@+id/list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingLeft="2dp" + android:paddingRight="2dp" + tools:listitem="@layout/settings_aliaslist_item" /> + + <android.support.design.widget.FloatingActionButton + android:id="@+id/add" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end|bottom" + android:layout_margin="16dp" + app:fabSize="normal" + app:srcCompat="@drawable/ic_add" + app:tint="?colorTextPrimaryInverse" /> + +</FrameLayout> diff --git a/app/src/main/res/layout/settings_aliaslist_item.xml b/app/src/main/res/layout/settings_aliaslist_item.xml new file mode 100644 index 0000000000000000000000000000000000000000..147ec9e941334644adefd738c2cf503195d6ad61 --- /dev/null +++ b/app/src/main/res/layout/settings_aliaslist_item.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<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="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:orientation="horizontal" + tools:showIn="@layout/settings_aliaslist"> + + <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="32dp" + android:paddingLeft="?listPreferredItemPaddingLeft" + android:paddingRight="32dp" + android:paddingStart="?listPreferredItemPaddingLeft" + app:srcCompat="@drawable/ic_reorder" + app:tint="?colorTextSecondary" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:orientation="vertical" + android:paddingBottom="16dp" + android:paddingEnd="?listPreferredItemPaddingRight" + android:paddingLeft="0dip" + android:paddingRight="?listPreferredItemPaddingRight" + android:paddingStart="0dip" + android:paddingTop="16dp"> + + <TextView + android:id="@+id/name" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="marquee" + android:orientation="vertical" + android:singleLine="true" + android:textAppearance="?android:textAppearanceMedium" + android:textColor="?colorTextPrimary" + android:textSize="16sp" + tools:text="back" /> + + <TextView + android:id="@+id/expansion" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="marquee" + android:singleLine="true" + android:textAppearance="?textAppearanceListItemSecondary" + android:textColor="?colorTextSecondary" + tools:text="/quote away" /> + + </LinearLayout> +</LinearLayout> diff --git a/app/src/main/res/layout/settings_ignorelist.xml b/app/src/main/res/layout/settings_ignorelist.xml index 183923f7f8b79db8ed228278618779771719ffff..988af7b5cdadf1823c1a01f9d4dc5449efc34912 100644 --- a/app/src/main/res/layout/settings_ignorelist.xml +++ b/app/src/main/res/layout/settings_ignorelist.xml @@ -11,7 +11,7 @@ android:layout_height="match_parent" android:paddingLeft="2dp" android:paddingRight="2dp" - tools:listitem="@layout/settings_item" /> + tools:listitem="@layout/settings_ignorelist_item" /> <android.support.design.widget.FloatingActionButton android:id="@+id/add" diff --git a/app/src/main/res/layout/settings_ignorelist_item.xml b/app/src/main/res/layout/settings_ignorelist_item.xml index c1cc3a59b9cc524c75e03d05bdb6e406f45cd0ff..b7e24b75a92982d6a33639b9e42c1a7c975146e1 100644 --- a/app/src/main/res/layout/settings_ignorelist_item.xml +++ b/app/src/main/res/layout/settings_ignorelist_item.xml @@ -61,21 +61,6 @@ </LinearLayout> - <TextView - android:id="@+id/title" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1" - android:ellipsize="marquee" - android:orientation="vertical" - android:paddingBottom="16dp" - android:paddingTop="16dp" - android:singleLine="true" - android:textAppearance="?android:textAppearanceMedium" - android:textColor="?colorTextPrimary" - android:textSize="16sp" - tools:text="https://clbin.com/*.jpg*" /> - <android.support.v7.widget.SwitchCompat android:id="@+id/toggle" android:layout_width="wrap_content" diff --git a/app/src/main/res/values-de/strings_settings.xml b/app/src/main/res/values-de/strings_settings.xml index 0e748aa91da1af77cec29c80a1c907a2361f00a9..b14d6f74725766a279a991d888b2dff256fe7780 100644 --- a/app/src/main/res/values-de/strings_settings.xml +++ b/app/src/main/res/values-de/strings_settings.xml @@ -114,6 +114,10 @@ <string name="settings_aliaslist_title">Aliase</string> + <string name="settings_aliasitem_title">Alias</string> + <string name="settings_aliasitem_name">Name</string> + <string name="settings_aliasitem_expansion">Ersetzungstext</string> + <string name="settings_networkconfig_title">IRC Konfiguration</string> <string name="settings_networkconfig_ping_timeout">Erkennung von Ping-Zeitüberschreitungen</string> <string name="settings_networkconfig_ping_interval">Ping-Intervall</string> diff --git a/app/src/main/res/values/strings_settings.xml b/app/src/main/res/values/strings_settings.xml index 11a0943a3aa2d325f26d3d93c379f24c0eb2ccaa..78203fc305154b9d09a7ef566092fa01fdd30396 100644 --- a/app/src/main/res/values/strings_settings.xml +++ b/app/src/main/res/values/strings_settings.xml @@ -114,6 +114,10 @@ <string name="settings_aliaslist_title">Aliases</string> + <string name="settings_aliasitem_title">Alias</string> + <string name="settings_aliasitem_name">Name</string> + <string name="settings_aliasitem_expansion">Expansion</string> + <string name="settings_networkconfig_title">IRC Config</string> <string name="settings_networkconfig_ping_timeout">Ping Timeout Detection</string> <string name="settings_networkconfig_ping_interval">Ping Interval</string> diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4571f45064146299054a8044b637f0814a053510..91309ff2c89af4723d0a89a36a1f481f877ff63a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,5 +2,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https://services.gradle.org/distributions/gradle-4.6-all.zip +distributionUrl=https://services.gradle.org/distributions/gradle-4.7-all.zip diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/AliasManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/AliasManager.kt index b1c8c7f106b7df499fde927d531e05108c736f7a..c618c7a74c70b310031916f912bcda31b80975c1 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/AliasManager.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/AliasManager.kt @@ -36,8 +36,7 @@ class AliasManager constructor( "Sizes do not match: names=${names.size}, expansions=${expansions.size}" ) - _aliases.clear() - _aliases.addAll(names.zip(expansions, ::Alias)) + _aliases = names.zip(expansions, ::Alias).toList() } override fun addAlias(name: String, expansion: String) { @@ -45,7 +44,7 @@ class AliasManager constructor( return } - _aliases.add(Alias(name, expansion)) + _aliases += Alias(name, expansion) super.addAlias(name, expansion) } @@ -70,6 +69,16 @@ class AliasManager constructor( Alias("sysinfo", "/exec inxi -d") ) + fun aliasList() = _aliases + + fun setAliasList(list: List<Alias>) { + _aliases = list + } + + fun copy() = AliasManager(proxy).also { + it.fromVariantMap(toVariantMap()) + } + fun processInput(info: BufferInfo, message: String, previousCommands: MutableList<IAliasManager.Command>) { var msg = message @@ -160,5 +169,5 @@ class AliasManager constructor( } } - private val _aliases = mutableListOf<IAliasManager.Alias>() + private var _aliases = listOf<IAliasManager.Alias>() } diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IAliasManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IAliasManager.kt index 854b3ed0422e2d9bbbfeacc38ca2577de4a8b347..2922470accf137b1cc36b1c897173b5c34a0219c 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IAliasManager.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IAliasManager.kt @@ -6,6 +6,7 @@ import de.kuschku.libquassel.protocol.ARG import de.kuschku.libquassel.protocol.QVariantMap import de.kuschku.libquassel.protocol.Type import de.kuschku.libquassel.quassel.BufferInfo +import java.io.Serializable @Syncable(name = "AliasManager") interface IAliasManager : ISyncableObject { @@ -24,7 +25,7 @@ interface IAliasManager : ISyncableObject { data class Alias( val name: String, val expansion: String - ) + ) : Serializable data class Command( val buffer: BufferInfo, diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt index d9a4ce4e9f65de3662810da34f380a88405e163b..623d7e6668633ff7e21e3b42aa28d6416e3ae0ff 100644 --- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt +++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt @@ -73,6 +73,8 @@ class QuasselViewModel : ViewModel() { val highlightRuleManager = session.mapMapNullable(ISession::highlightRuleManager) + val aliasManager = session.mapMapNullable(ISession::aliasManager) + val networks = session.switchMap { it.map(ISession::liveNetworks).orElse(Observable.just(emptyMap())) }