diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bce3a7a922f0b9926fadb4be8b117029f7a6508f..c3df58fe4c7ed3ba89f2fbf80724bb5988251fac 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -16,7 +16,7 @@ plugins { android { compileSdkVersion(26) - buildToolsVersion("26.0.2") + buildToolsVersion("27.0.2") signingConfigs { val signing = project.rootProject.properties("signing.properties") @@ -88,21 +88,21 @@ android { } } -val appCompatVersion = "26.1.0" -val appArchVersion = "1.0.0-rc1" +val appCompatVersion = "27.0.2" +val appArchVersion = "1.0.0" dependencies { - implementation(kotlin("stdlib", "1.1.61")) + implementation(kotlin("stdlib", "1.2.0")) implementation(appCompat("appcompat-v7")) implementation(appCompat("design")) implementation(appCompat("customtabs")) implementation(appCompat("cardview-v7")) implementation(appCompat("recyclerview-v7")) - implementation("com.android.support.constraint:constraint-layout:1.0.2") + implementation(appCompat("constraint", "constraint-layout", version = "1.0.2")) - implementation("com.github.StephenVinouze.AdvancedRecyclerView:core:1.1.6") + implementation("com.github.StephenVinouze.AdvancedRecyclerView", "core", "1.1.6") - implementation("io.reactivex.rxjava2:rxjava:2.1.3") + implementation("io.reactivex.rxjava2", "rxjava", "2.1.3") implementation(appArch("lifecycle", "extensions")) implementation(appArch("lifecycle", "reactivestreams")) @@ -115,21 +115,25 @@ dependencies { exclude(group = "junit", module = "junit") } - implementation("org.threeten:threetenbp:1.3.6") + implementation("org.threeten", "threetenbp", "1.3.6", classifier = "no-tzdb") - implementation("com.jakewharton:butterknife:8.8.1") - kapt("com.jakewharton:butterknife-compiler:8.8.1") + implementation("com.jakewharton", "butterknife", "8.8.1") + kapt("com.jakewharton", "butterknife-compiler", "8.8.1") - implementation(project(":lib")) + implementation(project(":lib")) { + exclude(group = "org.threeten", module = "threetenbp") + } implementation(project(":malheur")) + debugImplementation("com.squareup.leakcanary", "leakcanary-android", "1.5.1") + testImplementation(appArch("persistence.room", "testing")) - testImplementation("junit:junit:4.12") + testImplementation("junit", "junit", "4.12") - androidTestImplementation("com.android.support.test:runner:1.0.1") - androidTestImplementation("com.android.support.test:rules:1.0.1") + androidTestImplementation("com.android.support.test", "runner", "1.0.1") + androidTestImplementation("com.android.support.test", "rules", "1.0.1") - androidTestImplementation("com.android.support.test.espresso:espresso-core:3.0.1") + androidTestImplementation("com.android.support.test.espresso", "espresso-core", "3.0.1") } tasks.withType(KotlinCompile::class.java) { @@ -168,8 +172,12 @@ fun Project.properties(fileName: String): Properties? { * @param module simple name of the AppCompat module, for example "cardview-v7". * @param version optional desired version, null implies [appCompatVersion]. */ -fun appCompat(module: String, version: String? = null) - = "com.android.support:$module:${version ?: appCompatVersion}" +fun appCompat(module: String, submodule: String? = null, version: String? = null) + = if (submodule != null) { + "com.android.support.$module:$submodule:${version ?: appCompatVersion}" +} else { + "com.android.support:$module:${version ?: appCompatVersion}" +} /** * Builds the dependency notation for the named AppArch [module] at the given [version]. diff --git a/app/src/main/assets/org/threeten/bp/TZDB.dat b/app/src/main/assets/org/threeten/bp/TZDB.dat new file mode 100644 index 0000000000000000000000000000000000000000..5677059dc8b992b60ae88f75a82f14e80a1cbf70 Binary files /dev/null and b/app/src/main/assets/org/threeten/bp/TZDB.dat differ diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt index f03aecc1fa6e3e7f99ea3cb73a5eb69efc5c4548..6395cd02568f858bba7c46edab6c0197f8ff6da1 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt @@ -5,7 +5,9 @@ import android.content.pm.ShortcutInfo import android.content.pm.ShortcutManager import android.graphics.drawable.Icon import android.os.Build +import com.squareup.leakcanary.LeakCanary import de.kuschku.malheur.CrashHandler +import de.kuschku.quasseldroid_ng.util.backport.AndroidThreeTenBackport import de.kuschku.quasseldroid_ng.util.compatibility.AndroidCompatibilityUtils import de.kuschku.quasseldroid_ng.util.compatibility.AndroidLoggingHandler import de.kuschku.quasseldroid_ng.util.compatibility.AndroidStreamChannelFactory @@ -13,7 +15,12 @@ import de.kuschku.quasseldroid_ng.util.helper.systemService class QuasseldroidNG : Application() { override fun onCreate() { - println("QuasseldroidNG::onCreate") + if (LeakCanary.isInAnalyzerProcess(this)) { + // This process is dedicated to LeakCanary for heap analysis. + // You should not init your app in this process. + return + } + LeakCanary.install(this) CrashHandler.init( application = this, @@ -26,6 +33,8 @@ class QuasseldroidNG : Application() { AndroidLoggingHandler.inject() AndroidStreamChannelFactory.inject() + AndroidThreeTenBackport.init(this) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { systemService<ShortcutManager>().dynamicShortcuts = listOf( ShortcutInfo.Builder(this, "id1") diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt index 89d9c7a8e09c5ffdb3422dc9822f0fb5d9cf3ab6..205530597579b0935401da396200fabbd4236ceb 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt @@ -4,6 +4,7 @@ import android.arch.paging.LivePagedListProvider import android.arch.persistence.room.* import android.content.Context import android.support.annotation.IntRange +import android.support.v7.recyclerview.extensions.DiffCallback import de.kuschku.libquassel.protocol.Message_Flag import de.kuschku.libquassel.protocol.Message_Type import org.threeten.bp.Instant @@ -37,6 +38,14 @@ abstract class QuasselDatabase : RoomDatabase() { type)}, flag=${Message_Flag.of( flag)}, bufferId=$bufferId, sender='$sender', senderPrefixes='$senderPrefixes', content='$content')" } + + object MessageDiffCallback : DiffCallback<DatabaseMessage>() { + override fun areContentsTheSame(oldItem: QuasselDatabase.DatabaseMessage, newItem: QuasselDatabase.DatabaseMessage) + = oldItem == newItem + + override fun areItemsTheSame(oldItem: QuasselDatabase.DatabaseMessage, newItem: QuasselDatabase.DatabaseMessage) + = oldItem.messageId == newItem.messageId + } } @Dao diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigFragment.kt index bcb8e99ed04b6f9f9a085921c12cab136f20d35e..5867f9f7418b3aa96bc1a8704573b54885ef6023 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigFragment.kt @@ -92,7 +92,7 @@ class BufferViewConfigFragment : ServiceBoundFragment() { chatListSpinner.adapter = adapter chatListSpinner.onItemSelectedListener = itemSelectedListener - chatList.adapter = BufferListAdapter(this, bufferList, handlerThread::post, activity::runOnUiThread, clickListener) + chatList.adapter = BufferListAdapter(this, bufferList, handlerThread::post, activity!!::runOnUiThread, clickListener) chatList.layoutManager = LinearLayoutManager(context) chatList.itemAnimator = DefaultItemAnimator() return view diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt index 17638610cfceeb6839614da6bd6bfac630ac3776..9b40316e0e8eed4a658023e8512ccbdd2589bec8 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt @@ -62,7 +62,6 @@ class ChatActivity : ServiceBoundActivity() { private lateinit var database: QuasselDatabase override fun onCreate(savedInstanceState: Bundle?) { - println("ChatActivity::onCreate") handler.onCreate() super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) @@ -128,7 +127,7 @@ class ChatActivity : ServiceBoundActivity() { val status = it ?: ConnectionState.DISCONNECTED snackbar?.dismiss() - snackbar = Snackbar.make(window.decorView.rootView, status.name, Snackbar.LENGTH_SHORT) + snackbar = Snackbar.make(findViewById(R.id.contentMessages), status.name, Snackbar.LENGTH_SHORT) snackbar?.show() }) } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..7422ad5079b8e760a1f6862a2f31304a0bd44911 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageAdapter.kt @@ -0,0 +1,36 @@ +package de.kuschku.quasseldroid_ng.ui.chat + +import android.arch.paging.PagedListAdapter +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import de.kuschku.libquassel.protocol.Message_Flags +import de.kuschku.libquassel.protocol.Message_Type +import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase + +class MessageAdapter(context: Context) : PagedListAdapter<QuasselDatabase.DatabaseMessage, QuasselMessageViewHolder>(QuasselDatabase.DatabaseMessage.MessageDiffCallback) { + val messageRenderer: MessageRenderer = QuasselMessageRenderer(context) + + override fun onBindViewHolder(holder: QuasselMessageViewHolder, position: Int) { + getItem(position)?.let { messageRenderer.bind(holder, it) } + } + + override fun getItemViewType(position: Int): Int { + return getItem(position)?.type ?: 0 + } + + private fun messageType(viewType: Int): Message_Type? + = Message_Type.of(viewType).enabledValues().firstOrNull() + + private fun messageFlags(viewType: Int): Message_Flags + = Message_Flags.of() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuasselMessageViewHolder { + return QuasselMessageViewHolder(LayoutInflater.from(parent.context).inflate( + messageRenderer.layout(messageType(viewType), messageFlags(viewType)), + parent, + false + )) + } +} + diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageListFragment.kt index 3e98bb186f298b1b7272ad92fe01703b18134b5c..7007b536ff5b4f106bf3538d9c6b35412395c82b 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageListFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageListFragment.kt @@ -4,16 +4,13 @@ import android.arch.lifecycle.LiveData import android.arch.lifecycle.MutableLiveData import android.arch.lifecycle.Observer import android.arch.paging.PagedList -import android.arch.paging.PagedListAdapter import android.os.Bundle -import android.support.v7.recyclerview.extensions.DiffCallback 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.TextView import butterknife.BindView import butterknife.ButterKnife import de.kuschku.libquassel.protocol.BufferId @@ -27,8 +24,6 @@ class MessageListFragment : ServiceBoundFragment() { private lateinit var database: QuasselDatabase - private val adapter = MessageAdapter() - @BindView(R.id.messageList) lateinit var messageList: RecyclerView @@ -36,7 +31,7 @@ class MessageListFragment : ServiceBoundFragment() { val view = inflater.inflate(R.layout.content_messages, container, false) ButterKnife.bind(this, view) - database = QuasselDatabase.Creator.init(context.applicationContext) + database = QuasselDatabase.Creator.init(context!!.applicationContext) val data = currentBuffer.switchMap { it.switchMap { database.message().findByBufferIdPaged(it).create(Int.MAX_VALUE, @@ -49,6 +44,8 @@ class MessageListFragment : ServiceBoundFragment() { } } + val adapter = MessageAdapter(context!!) + data.observe(this, Observer { list -> adapter.setList(list) }) @@ -59,33 +56,4 @@ class MessageListFragment : ServiceBoundFragment() { return view } -} - -class MessageAdapter : PagedListAdapter<QuasselDatabase.DatabaseMessage, MessageViewHolder>(MessageDiffCallback) { - override fun onBindViewHolder(holder: MessageViewHolder?, position: Int) { - holder?.bind(getItem(position)) - } - - override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MessageViewHolder { - return MessageViewHolder(LayoutInflater.from(parent?.context).inflate(android.R.layout.simple_list_item_1, parent, false)) - } -} - -object MessageDiffCallback : DiffCallback<QuasselDatabase.DatabaseMessage>() { - override fun areContentsTheSame(oldItem: QuasselDatabase.DatabaseMessage, newItem: QuasselDatabase.DatabaseMessage) - = oldItem == newItem - - override fun areItemsTheSame(oldItem: QuasselDatabase.DatabaseMessage, newItem: QuasselDatabase.DatabaseMessage) - = oldItem.messageId == newItem.messageId -} - -class MessageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - fun bind(message: QuasselDatabase.DatabaseMessage?) { - val text = (itemView as TextView) - if (message == null) { - text.text = "null" - } else { - text.text = "[${message.time}] <${message.senderPrefixes}${message.sender}> ${message.content}" - } - } } \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageRenderer.kt new file mode 100644 index 0000000000000000000000000000000000000000..4ca12c9faffb9d73cdfc7115d9b6f91af702bf97 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageRenderer.kt @@ -0,0 +1,13 @@ +package de.kuschku.quasseldroid_ng.ui.chat + +import android.support.annotation.LayoutRes +import de.kuschku.libquassel.protocol.Message_Flags +import de.kuschku.libquassel.protocol.Message_Type +import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase + +interface MessageRenderer { + @LayoutRes + fun layout(type: Message_Type?, flags: Message_Flags): Int + + fun bind(holder: QuasselMessageViewHolder, message: QuasselDatabase.DatabaseMessage) +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageRenderer.kt new file mode 100644 index 0000000000000000000000000000000000000000..751e67e353f08a6349fcb8772529cfccc036d81b --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageRenderer.kt @@ -0,0 +1,74 @@ +package de.kuschku.quasseldroid_ng.ui.chat + +import android.content.Context +import android.graphics.Typeface +import android.text.SpannableString +import android.text.format.DateFormat +import android.text.style.ForegroundColorSpan +import android.text.style.StyleSpan +import de.kuschku.libquassel.protocol.Message.MessageType.* +import de.kuschku.libquassel.protocol.Message_Flags +import de.kuschku.libquassel.protocol.Message_Type +import de.kuschku.quasseldroid_ng.R +import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase +import de.kuschku.quasseldroid_ng.util.quassel.IrcUserUtils +import de.kuschku.quasseldroid_ng.util.ui.SpanFormatter +import org.threeten.bp.ZoneId +import org.threeten.bp.format.DateTimeFormatter +import java.text.SimpleDateFormat + +class QuasselMessageRenderer(context: Context) : MessageRenderer { + val timeFormatter = DateTimeFormatter.ofPattern((DateFormat.getTimeFormat(context) as SimpleDateFormat).toLocalizedPattern()) + val senderColors: IntArray + + init { + val typedArray = context.obtainStyledAttributes(intArrayOf( + R.attr.senderColor0, R.attr.senderColor1, R.attr.senderColor2, R.attr.senderColor3, + R.attr.senderColor4, R.attr.senderColor5, R.attr.senderColor6, R.attr.senderColor7, + R.attr.senderColor8, R.attr.senderColor9, R.attr.senderColorA, R.attr.senderColorB, + R.attr.senderColorC, R.attr.senderColorD, R.attr.senderColorE, R.attr.senderColorF + )) + senderColors = IntArray(16) { + typedArray.getColor(it, 0) + } + typedArray.recycle() + } + + override fun layout(type: Message_Type?, flags: Message_Flags) + = when (type) { + Nick, Notice, Mode, Join, Part, Quit, Kick, Kill, Server, Info, DayChange, Topic, NetsplitJoin, + NetsplitQuit, Invite -> R.layout.widget_chatmessage_server + Error -> R.layout.widget_chatmessage_error + Action -> R.layout.widget_chatmessage_action + Plain -> R.layout.widget_chatmessage_plain + else -> R.layout.widget_chatmessage_plain + } + + override fun bind(holder: QuasselMessageViewHolder, message: QuasselDatabase.DatabaseMessage) { + holder.time.text = timeFormatter.format(message.time.atZone(ZoneId.systemDefault())) + holder.content.text = SpanFormatter.format( + "%s: %s", + formatNick(message.sender), + message.content + ) + } + + private fun formatNick(sender: String): CharSequence { + val nick = IrcUserUtils.nick(sender) + val senderColor = IrcUserUtils.senderColor(nick) + val spannableString = SpannableString(nick) + spannableString.setSpan( + ForegroundColorSpan(senderColors[senderColor % senderColors.size]), + 0, + nick.length, + SpannableString.SPAN_INCLUSIVE_EXCLUSIVE + ) + spannableString.setSpan( + StyleSpan(Typeface.BOLD), + 0, + nick.length, + SpannableString.SPAN_INCLUSIVE_EXCLUSIVE + ) + return spannableString + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageViewHolder.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageViewHolder.kt new file mode 100644 index 0000000000000000000000000000000000000000..cf54d42c9a66edf32cdc43eee9178c64b1ee5aa4 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageViewHolder.kt @@ -0,0 +1,22 @@ +package de.kuschku.quasseldroid_ng.ui.chat + +import android.support.v7.widget.RecyclerView +import android.text.method.LinkMovementMethod +import android.view.View +import android.widget.TextView +import butterknife.BindView +import butterknife.ButterKnife +import de.kuschku.quasseldroid_ng.R + +class QuasselMessageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + @BindView(R.id.time) + lateinit var time: TextView + + @BindView(R.id.content) + lateinit var content: TextView + + init { + ButterKnife.bind(this, itemView) + content.movementMethod = LinkMovementMethod.getInstance() + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt index 5465c59950e162e1edffc5708fe05d9d2614c3d1..9a943d1eb390accff12ecd4d879a870a6e853460 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt @@ -160,13 +160,13 @@ abstract class SetupActivity : AppCompatActivity() { list.add(fragment) } - override fun instantiateItem(container: ViewGroup?, position: Int): Any { + override fun instantiateItem(container: ViewGroup, position: Int): Any { val fragment = super.instantiateItem(container, position) storeNewFragment(position, fragment as SlideFragment) return fragment } - override fun destroyItem(container: ViewGroup?, position: Int, `object`: Any?) { + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { retainedFragments.get(position)?.getData(result) retainedFragments.remove(position) super.destroyItem(container, position, `object`) diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt index ec5e12e1cc664ea2d12ebfffb2c1920e0655690c..cb6891877f190de016e533effed7cfb945ef35d5 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt @@ -8,7 +8,7 @@ import android.os.Bundle import de.kuschku.quasseldroid_ng.Keys import de.kuschku.quasseldroid_ng.ui.chat.ChatActivity import de.kuschku.quasseldroid_ng.ui.setup.SetupActivity -import de.kuschku.quasseldroid_ng.util.helper.editCommit +import de.kuschku.quasseldroid_ng.util.helper.editApply class AccountSelectionActivity : SetupActivity() { companion object { @@ -23,7 +23,7 @@ class AccountSelectionActivity : SetupActivity() { private lateinit var statusPreferences: SharedPreferences override fun onDone(data: Bundle) { - statusPreferences.editCommit { + statusPreferences.editApply { putLong(Keys.Status.selectedAccount, data.getLong(Keys.Status.selectedAccount, -1)) putBoolean(Keys.Status.reconnect, true) } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionSlide.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionSlide.kt index a0198fb1a170477e261631d23d5526e75c8d1f4a..86b30513313eeac312f5dece8c2b0ac59ca9fd88 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionSlide.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionSlide.kt @@ -76,7 +76,7 @@ class AccountSelectionSlide : SlideFragment() { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQUEST_CREATE_FIRST && resultCode == Activity.RESULT_CANCELED) { - activity.finish() + activity?.finish() } } } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/AndroidThreeTenBackport.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/AndroidThreeTenBackport.kt new file mode 100644 index 0000000000000000000000000000000000000000..04019a0f0942c1c90ca1305b541570f15f22514e --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/AndroidThreeTenBackport.kt @@ -0,0 +1,38 @@ +package de.kuschku.quasseldroid_ng.util.backport + +import android.content.Context +import org.threeten.bp.zone.TzdbZoneRulesProvider +import org.threeten.bp.zone.ZoneRulesProvider +import java.io.IOException +import java.io.InputStream +import java.util.concurrent.atomic.AtomicBoolean + + +object AndroidThreeTenBackport { + private val initialized = AtomicBoolean() + + fun init(context: Context) { + if (initialized.getAndSet(true)) { + return + } + + val provider: TzdbZoneRulesProvider + var inputStream: InputStream? = null + try { + inputStream = context.assets.open("org/threeten/bp/TZDB.dat") + provider = TzdbZoneRulesProvider(inputStream) + } catch (e: IOException) { + throw IllegalStateException("TZDB.dat missing from assets.", e) + } finally { + if (inputStream != null) { + try { + inputStream.close() + } catch (ignored: IOException) { + } + + } + } + + ZoneRulesProvider.registerProvider(provider) + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/CRCUtils.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/CRCUtils.kt new file mode 100644 index 0000000000000000000000000000000000000000..9a734a320aa2e1e0965175e9bda5962ed5597ed1 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/CRCUtils.kt @@ -0,0 +1,44 @@ +package de.kuschku.quasseldroid_ng.util.quassel + +object CRCUtils { + fun qChecksum(data: ByteArray): Int { + var crc = 0xffff + val crcHighBitMask = 0x8000 + + for (b in data) { + val c = reflect(b.toInt(), 8) + var j = 0x80 + while (j > 0) { + var highBit = crc and crcHighBitMask + crc = crc shl 1 + if (c and j > 0) { + highBit = highBit xor crcHighBitMask + } + if (highBit > 0) { + crc = crc xor 0x1021 + } + j = j shr 1 + } + } + + crc = reflect(crc, 16) + crc = crc xor 0xffff + crc = crc and 0xffff + + return crc + } + + private fun reflect(crc: Int, n: Int): Int { + var j = 1 + var crcout = 0 + var i = 1 shl n - 1 + while (i > 0) { + if (crc and i > 0) { + crcout = crcout or j + } + j = j shl 1 + i = i shr 1 + } + return crcout + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/IrcUserUtils.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/IrcUserUtils.kt new file mode 100644 index 0000000000000000000000000000000000000000..f9a348d9bff80e07ebd5feaf2be9da92bcc0cc06 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/IrcUserUtils.kt @@ -0,0 +1,53 @@ +package de.kuschku.quasseldroid_ng.util.quassel + +import java.util.* + +object IrcUserUtils { + fun senderColor(nick: String): Int { + return 0xf and CRCUtils.qChecksum( + nick.trimEnd('_').toLowerCase(Locale.US).toByteArray(Charsets.ISO_8859_1) + ) + } + + fun nick(hostmask: String): String { + return hostmask.substring( + 0, + hostmask.lastIndex('!', hostmask.lastIndex('@')) ?: hostmask.length + ) + } + + fun user(hostmask: String): String { + return hostmask.substring( + hostmask.lastIndex('!', hostmask.lastIndex('@')) ?: 0, + hostmask.lastIndex('@') ?: hostmask.length + ) + } + + fun host(hostmask: String): String { + return hostmask.substring( + hostmask.lastIndex('@') ?: 0 + ) + } + + fun mask(hostmask: String): String { + return hostmask.substring( + hostmask.lastIndex('!', hostmask.lastIndex('@')) ?: 0 + ) + } + + private fun String.firstIndex(char: Char, startIndex: Int? = null, ignoreCase: Boolean = false): Int? { + val lastIndex = indexOf(char, startIndex ?: 0, ignoreCase) + if (lastIndex < 0) + return null + else + return lastIndex + } + + private fun String.lastIndex(char: Char, startIndex: Int? = null, ignoreCase: Boolean = false): Int? { + val lastIndex = lastIndexOf(char, startIndex ?: lastIndex, ignoreCase) + if (lastIndex < 0) + return null + else + return lastIndex + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/BackendServiceConnection.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/BackendServiceConnection.kt new file mode 100644 index 0000000000000000000000000000000000000000..6dff17f6a0658cc7a35a67884aae5800da4913fb --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/BackendServiceConnection.kt @@ -0,0 +1,52 @@ +package de.kuschku.quasseldroid_ng.util.service + +import android.arch.lifecycle.MutableLiveData +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder +import de.kuschku.libquassel.session.Backend +import de.kuschku.quasseldroid_ng.service.QuasselService + +class BackendServiceConnection : ServiceConnection { + var bound = false + val backend = MutableLiveData<Backend?>() + + var context: Context? = null + + override fun onServiceDisconnected(component: ComponentName?) { + bound = false + when (component) { + ComponentName(context, QuasselService::class.java) -> { + backend.value = null + } + } + } + + override fun onServiceConnected(component: ComponentName?, binder: IBinder?) { + bound = true + when (component) { + ComponentName(context, QuasselService::class.java) -> + if (binder is QuasselService.QuasselBinder) { + backend.value = binder.backend + } + } + } + + fun start(intent: Intent = Intent(context, QuasselService::class.java)) { + context?.startService(intent) + } + + fun bind(intent: Intent = Intent(context, QuasselService::class.java), flags: Int = 0) { + context?.bindService(intent, this, flags) + } + + fun stop(intent: Intent = Intent(context, QuasselService::class.java)) { + context?.stopService(intent) + } + + fun unbind() { + if (bound) context?.unbindService(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt index 9c8598786de164fedea30630a279ef0864e30b46..ef9518e587f9c76478494ed742ebefb0943da03d 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt @@ -1,49 +1,30 @@ package de.kuschku.quasseldroid_ng.util.service -import android.arch.lifecycle.MutableLiveData -import android.content.ComponentName -import android.content.Intent -import android.content.ServiceConnection +import android.arch.lifecycle.LiveData import android.os.Bundle -import android.os.IBinder import android.support.annotation.ColorRes import android.support.annotation.DrawableRes import android.support.v7.app.AppCompatActivity import de.kuschku.libquassel.session.Backend import de.kuschku.quasseldroid_ng.R -import de.kuschku.quasseldroid_ng.service.QuasselService import de.kuschku.quasseldroid_ng.util.helper.updateRecentsHeaderIfExisting abstract class ServiceBoundActivity : AppCompatActivity() { - protected val backend = MutableLiveData<Backend?>() @DrawableRes protected val icon: Int = R.mipmap.ic_launcher @ColorRes protected val recentsHeaderColor: Int = R.color.colorPrimaryDark - private val connection = object : ServiceConnection { - override fun onServiceDisconnected(component: ComponentName?) { - when (component) { - ComponentName(application, QuasselService::class.java) -> { - backend.value = null - } - } - } + private val connection = BackendServiceConnection() - override fun onServiceConnected(component: ComponentName?, binder: IBinder?) { - when (component) { - ComponentName(application, QuasselService::class.java) -> - if (binder is QuasselService.QuasselBinder) { - backend.value = binder.backend - } - } - } - } + val backend: LiveData<Backend?> + get() = connection.backend override fun onCreate(savedInstanceState: Bundle?) { + connection.context = this setTheme(R.style.Theme_ChatTheme_Quassel_Light) super.onCreate(savedInstanceState) - startService(Intent(this, QuasselService::class.java)) + connection.start() updateRecentsHeader() } @@ -56,17 +37,17 @@ abstract class ServiceBoundActivity : AppCompatActivity() { } override fun onStart() { - bindService(Intent(this, QuasselService::class.java), connection, 0) + connection.bind() super.onStart() } override fun onStop() { super.onStop() - unbindService(connection) + connection.unbind() } protected fun stopService() { - unbindService(connection) - stopService(Intent(this, QuasselService::class.java)) + connection.unbind() + connection.stop() } } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundFragment.kt index 87c260f11ad0bbbb6047a1306d7c26acc1bb1269..6d42d72272571339f6295c978227b2800fd4263a 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundFragment.kt @@ -1,49 +1,29 @@ package de.kuschku.quasseldroid_ng.util.service -import android.arch.lifecycle.MutableLiveData -import android.content.ComponentName -import android.content.Intent -import android.content.ServiceConnection +import android.arch.lifecycle.LiveData import android.os.Bundle -import android.os.IBinder import android.support.v4.app.Fragment import de.kuschku.libquassel.session.Backend -import de.kuschku.quasseldroid_ng.service.QuasselService abstract class ServiceBoundFragment : Fragment() { - protected val backend = MutableLiveData<Backend?>() + private var connection = BackendServiceConnection() - private val connection = object : ServiceConnection { - override fun onServiceDisconnected(component: ComponentName?) { - when (component) { - ComponentName(context.applicationContext, QuasselService::class.java) -> { - backend.value = null - } - } - } - - override fun onServiceConnected(component: ComponentName?, binder: IBinder?) { - when (component) { - ComponentName(context.applicationContext, QuasselService::class.java) -> - if (binder is QuasselService.QuasselBinder) { - backend.value = binder.backend - } - } - } - } + val backend: LiveData<Backend?> + get() = connection.backend override fun onCreate(savedInstanceState: Bundle?) { + connection.context = context super.onCreate(savedInstanceState) - context.startService(Intent(context, QuasselService::class.java)) + connection.start() } override fun onStart() { - context.bindService(Intent(context, QuasselService::class.java), connection, 0) + connection.bind() super.onStart() } override fun onStop() { super.onStop() - context.unbindService(connection) + connection.unbind() } } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/SpanFormatter.java b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/SpanFormatter.java new file mode 100644 index 0000000000000000000000000000000000000000..31f342ec75649868892b4b6cc928c25fe3a3e590 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/SpanFormatter.java @@ -0,0 +1,140 @@ +/* + * QuasselDroid - Quassel client for Android + * Copyright (C) 2016 Janne Koschinski + * Copyright (C) 2016 Ken Børge Viktil + * Copyright (C) 2016 Magnus Fjell + * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* +* Copyright © 2014 George T. Steel +* +* 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. +*/ + +package de.kuschku.quasseldroid_ng.util.ui; + +import android.support.annotation.NonNull; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.SpannedString; + +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Provides {@link String#format} style functions that work with {@link Spanned} strings and preserve formatting. + * + * @author George T. Steel + */ +public class SpanFormatter { + private static final Pattern FORMAT_SEQUENCE = Pattern.compile("%([0-9]+\\$|<?)([^a-zA-z%]*)([[a-zA-Z%]&&[^tT]]|[tT][a-zA-Z])"); + + private SpanFormatter() { + } + + /** + * Version of {@link String#format(String, Object...)} that works on {@link Spanned} strings to preserve rich text formatting. + * Both the {@code format} as well as any {@code %s args} can be Spanned and will have their formatting preserved. + * Due to the way {@link Spannable}s work, any argument's spans will can only be included <b>once</b> in the result. + * Any duplicates will appear as text only. + * + * @param format the format string (see {@link java.util.Formatter#format}) + * @param args the list of arguments passed to the formatter. If there are + * more arguments than required by {@code format}, + * additional arguments are ignored. + * @return the formatted string (with spans). + */ + @NonNull + public static SpannedString format(@NonNull CharSequence format, Object... args) { + return format(Locale.getDefault(), format, args); + } + + /** + * Version of {@link String#format(Locale, String, Object...)} that works on {@link Spanned} strings to preserve rich text formatting. + * Both the {@code format} as well as any {@code %s args} can be Spanned and will have their formatting preserved. + * Due to the way {@link Spannable}s work, any argument's spans will can only be included <b>once</b> in the result. + * Any duplicates will appear as text only. + * + * @param locale the locale to apply; {@code null} value means no localization. + * @param format the format string (see {@link java.util.Formatter#format}) + * @param args the list of arguments passed to the formatter. + * @return the formatted string (with spans). + * @see String#format(Locale, String, Object...) + */ + @NonNull + public static SpannedString format(@NonNull Locale locale, @NonNull CharSequence format, Object... args) { + SpannableStringBuilder out = new SpannableStringBuilder(format); + + int i = 0; + int argAt = -1; + + while (i < out.length()) { + Matcher m = FORMAT_SEQUENCE.matcher(out); + if (!m.find(i)) break; + i = m.start(); + int exprEnd = m.end(); + + String argTerm = m.group(1); + String modTerm = m.group(2); + String typeTerm = m.group(3); + + CharSequence cookedArg; + + if (typeTerm.equals("%")) { + cookedArg = "%"; + } else { + int argIdx; + switch (argTerm) { + case "": + argIdx = ++argAt; + break; + case "<": + argIdx = argAt; + break; + default: + argIdx = Integer.parseInt(argTerm.substring(0, argTerm.length() - 1)) - 1; + break; + } + + Object argItem = args[argIdx]; + + if (typeTerm.equals("s") && argItem instanceof Spanned) { + cookedArg = (Spanned) argItem; + } else { + cookedArg = String.format(locale, "%" + modTerm + typeTerm, argItem); + } + } + + out.replace(i, exprEnd, cookedArg); + i += cookedArg.length(); + } + + return new SpannedString(out); + } +} diff --git a/app/src/main/res/layout/widget_chatmessage_action.xml b/app/src/main/res/layout/widget_chatmessage_action.xml new file mode 100644 index 0000000000000000000000000000000000000000..b4271dd33221a05181e3973922f9022c1a81fab3 --- /dev/null +++ b/app/src/main/res/layout/widget_chatmessage_action.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ QuasselDroid - Quassel client for Android + ~ Copyright (C) 2016 Janne Koschinski + ~ Copyright (C) 2016 Ken Børge Viktil + ~ Copyright (C) 2016 Magnus Fjell + ~ Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org> + ~ + ~ This program is free software: you can redistribute it and/or modify it + ~ under the terms of the GNU General Public License as published by the Free + ~ Software Foundation, either version 3 of the License, or (at your option) + ~ any later version. + ~ + ~ This program is distributed in the hope that it will be useful, + ~ but WITHOUT ANY WARRANTY; without even the implied warranty of + ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ~ GNU General Public License for more details. + ~ + ~ You should have received a copy of the GNU General Public License along + ~ with this program. If not, see <http://www.gnu.org/licenses/>. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clickable="true" + android:focusable="true" + android:gravity="top" + android:orientation="horizontal" + android:paddingBottom="@dimen/message_vertical" + android:paddingEnd="@dimen/message_horizontal" + android:paddingLeft="@dimen/message_horizontal" + android:paddingRight="@dimen/message_horizontal" + android:paddingStart="@dimen/message_horizontal" + android:paddingTop="@dimen/message_vertical" + android:textAppearance="?android:attr/textAppearanceListItemSmall"> + + <TextView + android:id="@+id/time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/message_horizontal" + android:layout_marginRight="@dimen/message_horizontal" + android:textColor="?attr/colorForegroundSecondary" + android:typeface="monospace" /> + + <TextView + android:id="@+id/content" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="?attr/colorForegroundAction" + android:textIsSelectable="true" + android:textStyle="italic" /> +</LinearLayout> diff --git a/app/src/main/res/layout/widget_chatmessage_error.xml b/app/src/main/res/layout/widget_chatmessage_error.xml new file mode 100644 index 0000000000000000000000000000000000000000..44e42f1cdb0b6377b64c206663f679b84e05e92c --- /dev/null +++ b/app/src/main/res/layout/widget_chatmessage_error.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/colorBackgroundSecondary" + android:clickable="true" + android:focusable="true" + android:gravity="top" + android:orientation="horizontal" + android:paddingBottom="@dimen/message_vertical" + android:paddingEnd="@dimen/message_horizontal" + android:paddingLeft="@dimen/message_horizontal" + android:paddingRight="@dimen/message_horizontal" + android:paddingStart="@dimen/message_horizontal" + android:paddingTop="@dimen/message_vertical" + android:textAppearance="?android:attr/textAppearanceListItemSmall"> + + <TextView + android:id="@+id/time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/message_horizontal" + android:layout_marginRight="@dimen/message_horizontal" + android:textColor="?attr/colorForegroundSecondary" + android:typeface="monospace" /> + + <TextView + android:id="@+id/content" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="?attr/colorForegroundError" + android:textIsSelectable="true" + android:textStyle="italic" /> +</LinearLayout> diff --git a/app/src/main/res/layout/widget_chatmessage_plain.xml b/app/src/main/res/layout/widget_chatmessage_plain.xml new file mode 100644 index 0000000000000000000000000000000000000000..0e16b66a13b3b8023fdc9bffba49babe9d03308c --- /dev/null +++ b/app/src/main/res/layout/widget_chatmessage_plain.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clickable="true" + android:focusable="true" + android:gravity="top" + android:orientation="horizontal" + android:paddingBottom="@dimen/message_vertical" + android:paddingEnd="@dimen/message_horizontal" + android:paddingLeft="@dimen/message_horizontal" + android:paddingRight="@dimen/message_horizontal" + android:paddingStart="@dimen/message_horizontal" + android:paddingTop="@dimen/message_vertical" + android:textAppearance="?android:attr/textAppearanceListItemSmall"> + + <TextView + android:id="@+id/time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/message_horizontal" + android:layout_marginRight="@dimen/message_horizontal" + android:textColor="?attr/colorForegroundSecondary" + android:typeface="monospace" /> + + <TextView + android:id="@+id/content" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="?attr/colorForeground" + android:textIsSelectable="true" /> +</LinearLayout> diff --git a/app/src/main/res/layout/widget_chatmessage_server.xml b/app/src/main/res/layout/widget_chatmessage_server.xml new file mode 100644 index 0000000000000000000000000000000000000000..40613e00c91fb0cb192e2d0ea4c613ad70c6ed30 --- /dev/null +++ b/app/src/main/res/layout/widget_chatmessage_server.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/colorBackgroundSecondary" + android:clickable="true" + android:focusable="true" + android:gravity="top" + android:orientation="horizontal" + android:paddingBottom="@dimen/message_vertical" + android:paddingEnd="@dimen/message_horizontal" + android:paddingLeft="@dimen/message_horizontal" + android:paddingRight="@dimen/message_horizontal" + android:paddingStart="@dimen/message_horizontal" + android:paddingTop="@dimen/message_vertical" + android:textAppearance="?android:attr/textAppearanceListItemSmall"> + + <TextView + android:id="@+id/time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/message_horizontal" + android:layout_marginRight="@dimen/message_horizontal" + android:textColor="?attr/colorForegroundSecondary" + android:typeface="monospace" /> + + <TextView + android:id="@+id/content" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="?attr/colorForegroundSecondary" + android:textIsSelectable="true" + android:textStyle="italic" /> +</LinearLayout> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 4b085309263b5803199bd1e9b8e414b5185a313c..dd9f8a6b1b62f1f62373afc32a44a902a4490c33 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,3 +1,6 @@ <resources> - <dimen name="navigation_drawer_max_width">320dp</dimen> + <dimen name="navigation_drawer_max_width">320dp</dimen> + + <dimen name="message_horizontal">8dp</dimen> + <dimen name="message_vertical">2dp</dimen> </resources> diff --git a/build.gradle.kts b/build.gradle.kts index 98bb71717474b50f7acc652588459e641a24d567..b5ff130acd1899c464feb09dd105c80c449b321a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,8 +5,8 @@ buildscript { } dependencies { classpath("com.android.tools.build:gradle:3.0.1") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.61") - classpath("org.jetbrains.kotlin:kotlin-android-extensions:1.1.61") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.0") + classpath("org.jetbrains.kotlin:kotlin-android-extensions:1.2.0") } } diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index c39ec3973c9563cc4c82e70b456fcdc9b98a4b42..0161971e9748fe1809634f4e8fcea0e19b7466e4 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -11,10 +11,10 @@ plugins { val appCompatVersion = "26.1.0" dependencies { - implementation(kotlin("stdlib", "1.1.61")) + implementation(kotlin("stdlib", "1.2.0")) implementation(appCompat("support-annotations")) - implementation("org.threeten:threetenbp:1.3.6") + implementation("org.threeten", "threetenbp", "1.3.6") implementation("io.reactivex.rxjava2:rxjava:2.1.3") implementation(project(":invokerannotations")) diff --git a/malheur/build.gradle.kts b/malheur/build.gradle.kts index d1bdc445064a7639f85e74e2460bca97167d728f..38e8818bd602e17a811c4cdebdfd25ca911beaab 100644 --- a/malheur/build.gradle.kts +++ b/malheur/build.gradle.kts @@ -1,7 +1,3 @@ -import org.gradle.kotlin.dsl.apply -import org.gradle.kotlin.dsl.dependencies -import org.gradle.kotlin.dsl.kotlin - plugins { id("com.android.library") kotlin("android") @@ -10,7 +6,7 @@ plugins { android { compileSdkVersion(26) - buildToolsVersion("26.0.2") + buildToolsVersion("27.0.2") defaultConfig { minSdkVersion(9) @@ -21,7 +17,7 @@ android { } dependencies { - implementation(kotlin("stdlib", "1.1.61")) + implementation(kotlin("stdlib", "1.2.0")) - implementation("com.google.code.gson:gson:2.2.4") + implementation("com.google.code.gson", "gson", "2.2.4") }