diff --git a/app/src/main/java/com/robobunny/SeekBarPreference.kt b/app/src/main/java/com/robobunny/SeekBarPreference.kt new file mode 100644 index 0000000000000000000000000000000000000000..c8489446782c62174d98d60ae30a06b2565c34cb --- /dev/null +++ b/app/src/main/java/com/robobunny/SeekBarPreference.kt @@ -0,0 +1,164 @@ +package com.robobunny + +import android.content.Context +import android.content.res.TypedArray +import android.support.v7.preference.Preference +import android.support.v7.preference.PreferenceViewHolder +import android.support.v7.widget.AppCompatSeekBar +import android.util.AttributeSet +import android.util.Log +import android.widget.SeekBar +import android.widget.TextView +import butterknife.BindView +import butterknife.ButterKnife +import de.kuschku.quasseldroid_ng.R + +/* + * Copyright (c) 2015 IRCCloud, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +class SeekBarPreference : Preference, SeekBar.OnSeekBarChangeListener { + + private val TAG = javaClass.name + + private var maxValue = 100 + private var minValue = 0 + private var interval = 1 + private var currentValue: Int = 0 + + private var unitsLeftText = "" + private var unitsRightText = "" + + @BindView(R.id.seekBarPrefSeekBar) + @JvmField + var seekBar: AppCompatSeekBar? = null + + @BindView(R.id.seekBarPrefValue) + @JvmField + var statusText: TextView? = null + + @BindView(R.id.seekBarPrefUnitsLeft) + @JvmField + var unitsLeft: TextView? = null + + @BindView(R.id.seekBarPrefUnitsRight) + @JvmField + var unitsRight: TextView? = null + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : + super(context, attrs, defStyleAttr) { + initPreference(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet) : + super(context, attrs) { + initPreference(context, attrs) + } + + private fun initPreference(context: Context, attrs: AttributeSet) { + setValuesFromXml(attrs) + layoutResource = R.layout.preference_vertical + widgetLayoutResource = R.layout.preference_seekbar + } + + private fun setValuesFromXml(attrs: AttributeSet) { + maxValue = attrs.getAttributeIntValue(NAMESPACE_ANDROID, "max", 100) + minValue = attrs.getAttributeIntValue(NAMESPACE_ROBOBUNNY, "min", 0) + unitsLeftText = getAttributeStringValue(attrs, NAMESPACE_ROBOBUNNY, "unitsLeft", "") + val units = getAttributeStringValue(attrs, NAMESPACE_ROBOBUNNY, "units", "") + unitsRightText = getAttributeStringValue(attrs, NAMESPACE_ROBOBUNNY, "unitsRight", units) + try { + val newInterval = attrs.getAttributeValue(NAMESPACE_ROBOBUNNY, "interval") + if (newInterval != null) + interval = Integer.parseInt(newInterval) + } catch (e: Exception) { + Log.e(TAG, "Invalid interval value", e) + } + } + + private fun getAttributeStringValue(attrs: AttributeSet, namespace: String, name: String, + defaultValue: String) = + attrs.getAttributeValue(namespace, name) ?: defaultValue + + override fun onBindViewHolder(holder: PreferenceViewHolder?) { + super.onBindViewHolder(holder) + holder?.itemView?.let { view -> + ButterKnife.bind(this, view) + seekBar?.max = maxValue - minValue + seekBar?.setOnSeekBarChangeListener(this) + statusText?.text = currentValue.toString() + statusText?.minimumWidth = 30 + seekBar?.progress = currentValue - minValue + unitsRight?.text = this.unitsRightText + unitsLeft?.text = this.unitsLeftText + } + } + + override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { + var newValue = progress + minValue + if (newValue > maxValue) + newValue = maxValue + else if (newValue < minValue) + newValue = minValue + else if (interval != 1 && newValue % interval != 0) + newValue = Math.round(newValue.toFloat() / interval) * interval + // change rejected, revert to the previous value + if (!callChangeListener(newValue)) { + seekBar.progress = currentValue - minValue + return + } + // change accepted, store it + currentValue = newValue + statusText?.text = newValue.toString() + persistInt(newValue) + } + + override fun onStartTrackingTouch(seekBar: SeekBar) = Unit + override fun onStopTrackingTouch(seekBar: SeekBar) = notifyChanged() + override fun onGetDefaultValue(ta: TypedArray, index: Int) = ta.getInt(index, DEFAULT_VALUE) + override fun onSetInitialValue(restoreValue: Boolean, defaultValue: Any?) { + if (restoreValue) { + currentValue = getPersistedInt(currentValue) + } else { + var temp = 0 + try { + temp = defaultValue as Int + } catch (ex: Exception) { + Log.e(TAG, "Invalid default value: " + defaultValue.toString()) + } + persistInt(temp) + currentValue = temp + } + } + + /** + * make sure that the seekbar is disabled if the preference is disabled + */ + override fun setEnabled(enabled: Boolean) { + super.setEnabled(enabled) + seekBar?.isEnabled = enabled + } + + override fun onDependencyChanged(dependency: Preference, disableDependent: Boolean) { + super.onDependencyChanged(dependency, disableDependent) + //Disable movement of seek bar when dependency is false + seekBar?.isEnabled = !disableDependent + } + + companion object { + private const val NAMESPACE_ANDROID = "http://schemas.android.com/apk/res/android" + private const val NAMESPACE_ROBOBUNNY = "http://robobunny.com" + private const val DEFAULT_VALUE = 50 + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/settings/AppearanceSettings.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/AppearanceSettings.kt index b0b4e5f00424178671b81f53f7befa9db0e6f95d..4facddae802851a32ee428d2c668fcb0a03fb83d 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/settings/AppearanceSettings.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/AppearanceSettings.kt @@ -9,6 +9,7 @@ data class AppearanceSettings( val inputEnter: InputEnterMode = InputEnterMode.EMOJI, val colorizeMirc: Boolean = true, val useMonospace: Boolean = false, + val textSize: Int = 14, val showSeconds: Boolean = false, val use24hClock: Boolean = true, val showAutocomplete: Boolean = true, diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/settings/Settings.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/Settings.kt index f78f23cd82ccff4fc710d8de8531db38b70fdea1..175afcd6729f78a7c9572fc374c2849629c81435 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/settings/Settings.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/Settings.kt @@ -18,6 +18,10 @@ object Settings { context.getString(R.string.preference_monospace_key), AppearanceSettings.DEFAULT.useMonospace ), + textSize = getInt( + context.getString(R.string.preference_textsize_key), + AppearanceSettings.DEFAULT.textSize + ), showSeconds = getBoolean( context.getString(R.string.preference_show_seconds_key), AppearanceSettings.DEFAULT.showSeconds diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/QuasselMessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/QuasselMessageRenderer.kt index e61e8c882969399cb5bc94615270a6bb338b674b..99c5e96133425ef196d79e3ec6d7e535dae4abab 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/QuasselMessageRenderer.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/QuasselMessageRenderer.kt @@ -8,6 +8,7 @@ import android.text.TextPaint import android.text.style.ForegroundColorSpan import android.text.style.StyleSpan import android.text.style.URLSpan +import android.util.TypedValue import de.kuschku.libquassel.protocol.Message.MessageType.* import de.kuschku.libquassel.protocol.Message_Flag import de.kuschku.libquassel.protocol.Message_Type @@ -89,6 +90,9 @@ class QuasselMessageRenderer( if (appearanceSettings.useMonospace) { viewHolder.content.typeface = Typeface.MONOSPACE } + val textSize = appearanceSettings.textSize.toFloat() + viewHolder.time.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize) + viewHolder.content.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize) } override fun bind(holder: QuasselMessageViewHolder, message: FormattedMessage) { diff --git a/app/src/main/res/layout/preference_seekbar.xml b/app/src/main/res/layout/preference_seekbar.xml new file mode 100644 index 0000000000000000000000000000000000000000..2041b1339c4a9440489819be64a189f4294cf910 --- /dev/null +++ b/app/src/main/res/layout/preference_seekbar.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (c) 2015 IRCCloud, Ltd. + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@android:id/widget_frame" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:orientation="horizontal" + android:paddingBottom="5dp" + android:paddingEnd="10dp" + android:paddingLeft="15dp" + android:paddingRight="10dp" + android:paddingStart="15dp" + android:paddingTop="5dp"> + + <android.support.v7.widget.AppCompatSeekBar + android:id="@+id/seekBarPrefSeekBar" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:layout_weight="1" /> + + <TextView + android:id="@+id/seekBarPrefUnitsRight" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="%" /> + + <TextView + android:id="@+id/seekBarPrefValue" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="100" /> + + <TextView + android:id="@+id/seekBarPrefUnitsLeft" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="$" /> +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/preference_vertical.xml b/app/src/main/res/layout/preference_vertical.xml new file mode 100644 index 0000000000000000000000000000000000000000..fd5c40f8209b917d92ccc714a54b9d6d2b624ad1 --- /dev/null +++ b/app/src/main/res/layout/preference_vertical.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (c) 2015 IRCCloud, Ltd. + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<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:background="?android:attr/selectableItemBackground" + android:clipToPadding="false" + android:focusable="true" + android:gravity="center_vertical" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:paddingEnd="?android:attr/listPreferredItemPaddingRight" + android:paddingLeft="?android:attr/listPreferredItemPaddingLeft" + android:paddingRight="?android:attr/listPreferredItemPaddingRight" + android:paddingStart="?android:attr/listPreferredItemPaddingLeft"> + + <FrameLayout + android:id="@+id/icon_frame" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="-4dp" + android:layout_marginStart="-4dp" + android:gravity="start|center_vertical" + android:minWidth="60dp" + android:orientation="horizontal" + android:paddingBottom="4dp" + android:paddingEnd="12dp" + android:paddingRight="12dp" + android:paddingTop="4dp"> + + <android.support.v7.internal.widget.PreferenceImageView + android:id="@android:id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:maxHeight="48dp" + app:maxWidth="48dp" /> + </FrameLayout> + + <LinearLayout + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="vertical" + android:paddingBottom="16dp" + android:paddingTop="16dp"> + + <TextView + android:id="@android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="marquee" + android:singleLine="true" + android:textSize="16sp" + tools:text="Font Size" /> + + <TextView + android:id="@android:id/summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:maxLines="10" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:attr/textColorSecondary" /> + + <LinearLayout + android:id="@android:id/widget_frame" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + </LinearLayout> +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index 1bd4d825c86d92115886d3647d2e0986043c6a16..f38fcf4b41832598338e5c4a1dda5d484be62199 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_recents.png b/app/src/main/res/mipmap-hdpi/ic_launcher_recents.png index 704b703466300312afef5183f4815c87b853a6a8..3aa420b7594005b212e8d47098eb1d9cac93f081 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_recents.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_recents.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png index 4ecb43845f86b0db882badf94e69d29fff6c0dff..bfbb5bec79527a8a12b22b711e3b77a098987359 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png index 5f17520e2db9b5f47898a7381e2188d4bd195d4f..f9e9bc74159bb1bb26a46de14af37e3a8278c7b5 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_recents.png b/app/src/main/res/mipmap-mdpi/ic_launcher_recents.png index aa6768589fdc17dc9615ccd9d9a72202a63ed2f6..a160a6bab6a5b658b7f8d22e5af6084f136529e7 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_recents.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_recents.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 4e05140cba78c57ef638b8447fdd0f3154818bb7..c467548ffc085b72f2514bea9989ec554dcc80b0 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_recents.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_recents.png index b602349062aab9c0f7b44b347d9400177b0da5f3..bec27ec68fca34d0f21f6789439e35cfa299816a 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_recents.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_recents.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index acef6e44a5484b18c6f031f655dda670937e65cf..0d6d70aaa5c29bf01c84ba9da62de289341a933e 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_recents.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_recents.png index d4b4622fcf9b571ce307740c5f9335daed3f99c6..2cd62c04fb0d5e86ef736e6f60e3bcf665d24a9e 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_recents.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_recents.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index bbccb73c804dc280e522aa997e895f4fc09c5d39..366142e9b7b379249e49bb3184429fad132a89fb 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_recents.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_recents.png index aada01932a343ad3cf2e5afe2767c22f21dddbb1..f208b7051960432c4ac5cb26150340d6f3f59912 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_recents.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_recents.png differ diff --git a/app/src/main/res/values/strings_preferences.xml b/app/src/main/res/values/strings_preferences.xml index 1d111f867451dc552693ecdf162ba47e63d82be9..d9d856e155f04d55da5850d063ad73e16e659793 100644 --- a/app/src/main/res/values/strings_preferences.xml +++ b/app/src/main/res/values/strings_preferences.xml @@ -33,6 +33,9 @@ <string name="preference_monospace_key" translatable="false">monospace</string> <string name="preference_monospace_title">Use Monospace Font</string> + <string name="preference_textsize_key" translatable="false">fontsize</string> + <string name="preference_textsize_title">Text Size</string> + <string name="preference_show_seconds_key" translatable="false">show_seconds</string> <string name="preference_show_seconds_title">Show Seconds</string> diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 52f4a061c05472d820269c41d283ad4e06955e6d..c9747aaabd10a690a7f0dc6fa1659505788a717c 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:robobunny="http://robobunny.com"> <PreferenceCategory android:title="@string/preference_appearance_title"> <ListPreference android:defaultValue="QUASSEL_LIGHT" @@ -13,6 +14,13 @@ android:key="@string/preference_monospace_key" android:title="@string/preference_monospace_title" /> + <com.robobunny.SeekBarPreference + android:defaultValue="14" + android:key="@string/preference_textsize_key" + android:max="24" + android:title="@string/preference_textsize_title" + robobunny:min="12" /> + <SwitchPreference android:defaultValue="false" android:key="@string/preference_show_seconds_key" diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/QVariant.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/QVariant.kt index 933c3d2c025c572ba2e78fe7cdd64488b999dfca..b0eeac79123bf06a9133d23ca78b392ddcd8bc6e 100644 --- a/lib/src/main/java/de/kuschku/libquassel/protocol/QVariant.kt +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/QVariant.kt @@ -14,26 +14,15 @@ class QVariant<T>(val data: T?, val type: MetaType<T>) { } } -@PublishedApi -internal inline fun <reified U> QVariant_?.coerce(): QVariant<U>? { - return if (this?.data is U) { - this as QVariant<U> - } else { - null - } -} - inline fun <reified U> QVariant_?.value(): U? = this?.value<U?>(null) -inline fun <reified U> QVariant_?.value(defValue: U): U - = this.coerce<U>()?.data ?: defValue +inline fun <reified U> QVariant_?.value(defValue: U): U = this?.data as? U ?: defValue -inline fun <reified U> QVariant_?.valueOr(f: () -> U): U - = this.coerce<U>()?.data ?: f() +inline fun <reified U> QVariant_?.valueOr(f: () -> U): U = this?.data as? U ?: f() -inline fun <reified U> QVariant_?.valueOrThrow(e: Throwable = NullPointerException()): U - = this.coerce<U>()?.data ?: throw e +inline fun <reified U> QVariant_?.valueOrThrow(e: Throwable = NullPointerException()): U = + this?.data as? U ?: throw e -inline fun <reified U> QVariant_?.valueOrThrow(e: () -> Throwable): U - = this.coerce<U>()?.data ?: throw e() +inline fun <reified U> QVariant_?.valueOrThrow(e: () -> Throwable): U = + this?.data as? U ?: throw e()