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

First version of channel and user info screen

parent 56a43b7e
Branches
Tags
No related merge requests found
Showing
with 601 additions and 77 deletions
{
"data": [
{
"name": "Nickname",
"value": "justJanne"
},
{
"name": "Ident",
"value": "~justJanne"
},
{
"name": "host",
"value": "lithium.kuschku.de"
},
{
"name": "Real Name",
"value": "Janne Koschinski https://kuschku.de/"
},
{
"name": "Account",
"value": "justJanne"
}
]
}
\ No newline at end of file
{
"data": [
{
"id": 0,
"name": "User"
},
{
"id": 1,
"name": "Away"
}
]
}
\ No newline at end of file
......@@ -33,6 +33,12 @@
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:name=".ui.chat.detailinfo.InfoActivity"
android:exported="false"
android:label="@string/label_details"
android:parentActivityName=".ui.chat.ChatActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".ui.setup.accounts.setup.AccountSetupActivity"
......
......@@ -6,6 +6,7 @@ import de.kuschku.quasseldroid.service.QuasselService
import de.kuschku.quasseldroid.ui.chat.ChatActivity
import de.kuschku.quasseldroid.ui.chat.ChatActivityModule
import de.kuschku.quasseldroid.ui.chat.ChatFragmentProvider
import de.kuschku.quasseldroid.ui.chat.detailinfo.InfoActivity
import de.kuschku.quasseldroid.ui.settings.about.AboutSettingsActivity
import de.kuschku.quasseldroid.ui.settings.about.AboutSettingsFragmentProvider
import de.kuschku.quasseldroid.ui.settings.app.AppSettingsActivity
......@@ -25,6 +26,9 @@ abstract class ActivityModule {
@ContributesAndroidInjector(modules = [ChatActivityModule::class, ChatFragmentProvider::class])
abstract fun bindChatActivity(): ChatActivity
@ContributesAndroidInjector
abstract fun bindInfoActivity(): InfoActivity
@ContributesAndroidInjector(modules = [AppSettingsFragmentProvider::class])
abstract fun bindAppSettingsActivity(): AppSettingsActivity
......
......@@ -7,8 +7,6 @@ import android.net.ConnectivityManager
import android.os.Binder
import de.kuschku.libquassel.protocol.*
import de.kuschku.libquassel.session.*
import de.kuschku.libquassel.util.compatibility.LoggingHandler
import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
import de.kuschku.quasseldroid.BuildConfig
import de.kuschku.quasseldroid.Keys
import de.kuschku.quasseldroid.R
......@@ -270,7 +268,6 @@ class QuasselService : DaggerLifecycleService(),
)
sessionManager.connectionProgress.toLiveData().observe(this, Observer {
log(LoggingHandler.LogLevel.ERROR, "DEBUG", "progress: $it")
if (this.progress.first != it?.first && it?.first == ConnectionState.CONNECTED) {
handlerService.backend {
database.message().clearMessages()
......
......@@ -3,6 +3,7 @@ package de.kuschku.quasseldroid.ui.chat
import android.arch.lifecycle.Observer
import android.arch.lifecycle.ViewModelProviders
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
......@@ -11,9 +12,14 @@ import android.widget.TextView
import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.libquassel.protocol.Buffer_Type
import de.kuschku.libquassel.quassel.BufferInfo
import de.kuschku.libquassel.util.hasFlag
import de.kuschku.libquassel.util.helpers.value
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.settings.AppearanceSettings
import de.kuschku.quasseldroid.ui.chat.detailinfo.InfoActivity
import de.kuschku.quasseldroid.ui.chat.detailinfo.InfoDescriptor
import de.kuschku.quasseldroid.ui.chat.detailinfo.InfoType
import de.kuschku.quasseldroid.util.helper.combineLatest
import de.kuschku.quasseldroid.util.helper.toLiveData
import de.kuschku.quasseldroid.util.helper.visibleIf
......@@ -30,6 +36,9 @@ class ToolbarFragment : ServiceBoundFragment() {
@BindView(R.id.toolbar_subtitle)
lateinit var toolbarSubtitle: TextView
@BindView(R.id.toolbar_action_area)
lateinit var actionArea: View
@Inject
lateinit var ircFormatDeserializer: IrcFormatDeserializer
......@@ -72,7 +81,7 @@ class ToolbarFragment : ServiceBoundFragment() {
if (it != null) {
val (data, isSecure, lag) = it
if (data?.info?.type?.hasFlag(Buffer_Type.StatusBuffer) == true) {
this.title = data.network?.networkName
this.title = data.network?.networkName()
} else {
this.title = data?.info?.bufferName
}
......@@ -92,8 +101,33 @@ class ToolbarFragment : ServiceBoundFragment() {
}
}
}
}
})
actionArea.setOnClickListener {
viewModel.bufferData.value?.info?.let { info ->
when (info.type.toInt()) {
BufferInfo.Type.QueryBuffer.toInt() -> InfoDescriptor(
type = InfoType.User,
nick = info.bufferName,
network = info.networkId
)
BufferInfo.Type.ChannelBuffer.toInt() -> InfoDescriptor(
type = InfoType.Channel,
channel = info.bufferName,
network = info.networkId
)
BufferInfo.Type.StatusBuffer.toInt() -> InfoDescriptor(
type = InfoType.Network,
network = info.networkId
)
else -> null
}
}?.let { infoDescriptor ->
val intent = Intent(requireContext(), InfoActivity::class.java)
intent.putExtra("info", infoDescriptor)
startActivity(intent)
}
}
return view
}
......
package de.kuschku.quasseldroid.ui.chat.detailinfo
import android.arch.lifecycle.Observer
import android.arch.lifecycle.ViewModelProviders
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.Toolbar
import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.libquassel.util.Optional
import de.kuschku.libquassel.util.compatibility.LoggingHandler
import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.util.helper.toLiveData
import de.kuschku.quasseldroid.util.irc.format.ContentFormatter
import de.kuschku.quasseldroid.util.service.ServiceBoundActivity
import de.kuschku.quasseldroid.viewmodel.QuasselViewModel
import de.kuschku.quasseldroid.viewmodel.data.InfoGroup
import de.kuschku.quasseldroid.viewmodel.data.InfoProperty
import io.reactivex.Observable
import javax.inject.Inject
class InfoActivity : ServiceBoundActivity() {
@BindView(R.id.toolbar)
lateinit var toolbar: Toolbar
@BindView(R.id.groups)
lateinit var groups: RecyclerView
@Inject
lateinit var contentFormatter: ContentFormatter
private lateinit var viewModel: QuasselViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_info)
ButterKnife.bind(this)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
viewModel = ViewModelProviders.of(this)[QuasselViewModel::class.java]
viewModel.backendWrapper.onNext(this.backend)
val adapter = InfoGroupAdapter()
groups.layoutManager = LinearLayoutManager(this)
groups.adapter = adapter
val info = intent.getSerializableExtra("info") as? InfoDescriptor
viewModel.session.switchMap { sessionOptional ->
val network = sessionOptional.orNull()?.networks?.get(info?.network)
if (info == null || network == null) {
Observable.just(Optional.empty())
} else {
when (info.type) {
InfoType.User -> {
network.liveIrcUser(info.nick).switchMap {
it.updates().map { user ->
Optional.of(InfoData(
type = info.type,
user = user,
network = network,
properties = listOf(
InfoGroup(
name = "Identity",
properties = listOf(
InfoProperty(
name = "Nickname",
value = user.nick()
),
InfoProperty(
name = "Ident",
value = user.user()
),
InfoProperty(
name = "Host",
value = user.host()
),
InfoProperty(
name = "Real Name",
value = contentFormatter.format(this, user.realName())
),
InfoProperty(
name = "Account",
value = user.account()
)
)
)
)
))
}
}
}
InfoType.Channel -> {
network.liveIrcChannel(info.channel).map { channel ->
Optional.of(InfoData(
type = info.type,
channel = channel,
network = network,
properties = listOf(
InfoGroup(
properties = listOf(
InfoProperty(
name = "Topic",
value = contentFormatter.format(this, channel.topic())
)
)
)
)
))
}
}
InfoType.Network -> {
network.live_connectionState.map {
Optional.of(InfoData(
type = info.type,
network = network
))
}
}
}
}
}.toLiveData().observe(this, Observer {
log(LoggingHandler.LogLevel.ERROR, "DEBUG", "data: $it")
adapter.submitList(it?.orNull()?.properties.orEmpty())
})
viewModel.buffer.onNext(intent.getIntExtra("buffer", -1))
}
}
\ No newline at end of file
package de.kuschku.quasseldroid.ui.chat.detailinfo
import de.kuschku.libquassel.quassel.syncables.IrcChannel
import de.kuschku.libquassel.quassel.syncables.IrcUser
import de.kuschku.libquassel.quassel.syncables.Network
import de.kuschku.quasseldroid.viewmodel.data.InfoGroup
data class InfoData(
val type: InfoType,
val user: IrcUser? = null,
val channel: IrcChannel? = null,
val network: Network,
val properties: List<InfoGroup> = emptyList()
)
\ No newline at end of file
package de.kuschku.quasseldroid.ui.chat.detailinfo
import java.io.Serializable
data class InfoDescriptor(
val type: InfoType,
val nick: String? = null,
val channel: String? = null,
val network: Int
) : Serializable
\ No newline at end of file
package de.kuschku.quasseldroid.ui.chat.detailinfo
import android.support.v7.recyclerview.extensions.ListAdapter
import android.support.v7.util.DiffUtil
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.quasseldroid.R
import de.kuschku.quasseldroid.util.helper.visibleIf
import de.kuschku.quasseldroid.viewmodel.data.InfoGroup
class InfoGroupAdapter :
ListAdapter<InfoGroup, InfoGroupAdapter.InfoGroupViewHolder>(
object : DiffUtil.ItemCallback<InfoGroup>() {
override fun areItemsTheSame(oldItem: InfoGroup, newItem: InfoGroup) =
oldItem.name == newItem.name
override fun areContentsTheSame(oldItem: InfoGroup, newItem: InfoGroup) =
oldItem == newItem
}
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = InfoGroupViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.widget_userinfo_group, parent, false)
)
override fun onBindViewHolder(holder: InfoGroupViewHolder, position: Int) =
holder.bind(getItem(position))
class InfoGroupViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
@BindView(R.id.title_container)
lateinit var titleContainer: View
@BindView(R.id.title)
lateinit var title: TextView
@BindView(R.id.properties)
lateinit var properties: RecyclerView
private val adapter: InfoPropertyAdapter
init {
ButterKnife.bind(this, itemView)
adapter = InfoPropertyAdapter()
properties.layoutManager = LinearLayoutManager(itemView.context)
properties.adapter = adapter
}
fun bind(item: InfoGroup) {
title.text = item.name
titleContainer.visibleIf(item.name != null)
adapter.submitList(item.properties)
}
}
}
\ No newline at end of file
package de.kuschku.quasseldroid.ui.chat.detailinfo
import android.support.v7.recyclerview.extensions.ListAdapter
import android.support.v7.util.DiffUtil
import android.support.v7.widget.AppCompatImageView
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.quasseldroid.R
import de.kuschku.quasseldroid.util.helper.visibleIf
import de.kuschku.quasseldroid.viewmodel.data.InfoProperty
import me.saket.bettermovementmethod.BetterLinkMovementMethod
class InfoPropertyAdapter :
ListAdapter<InfoProperty, InfoPropertyAdapter.InfoPropertyViewHolder>(
object : DiffUtil.ItemCallback<InfoProperty>() {
override fun areItemsTheSame(oldItem: InfoProperty, newItem: InfoProperty) =
oldItem.name == newItem.name
override fun areContentsTheSame(oldItem: InfoProperty, newItem: InfoProperty) =
oldItem == newItem
}
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = InfoPropertyViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.widget_userinfo, parent, false)
)
override fun onBindViewHolder(holder: InfoPropertyViewHolder, position: Int) =
holder.bind(getItem(position))
class InfoPropertyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
@BindView(R.id.icon)
lateinit var icon: AppCompatImageView
@BindView(R.id.name)
lateinit var name: TextView
@BindView(R.id.value)
lateinit var value: TextView
init {
ButterKnife.bind(this, itemView)
value.movementMethod = BetterLinkMovementMethod.getInstance()
}
fun bind(item: InfoProperty) {
item.icon?.let(icon::setImageResource)
name.text = item.name
value.text = item.value
icon.visibleIf(item.icon != null)
}
}
}
\ No newline at end of file
package de.kuschku.quasseldroid.ui.chat.detailinfo
enum class InfoType {
User,
Channel,
Network
}
\ No newline at end of file
......@@ -5,11 +5,8 @@ import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.LayerDrawable
import android.text.SpannableString
import android.text.Spanned
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
......@@ -21,11 +18,10 @@ import de.kuschku.quasseldroid.settings.AppearanceSettings
import de.kuschku.quasseldroid.settings.AppearanceSettings.ColorizeNicknamesMode
import de.kuschku.quasseldroid.settings.AppearanceSettings.ShowPrefixMode
import de.kuschku.quasseldroid.util.helper.styledAttributes
import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer
import de.kuschku.quasseldroid.util.irc.format.ContentFormatter
import de.kuschku.quasseldroid.util.quassel.IrcUserUtils
import de.kuschku.quasseldroid.util.ui.SpanFormatter
import de.kuschku.quasseldroid.viewmodel.data.FormattedMessage
import org.intellij.lang.annotations.Language
import org.threeten.bp.ZoneId
import org.threeten.bp.format.DateTimeFormatter
import org.threeten.bp.format.FormatStyle
......@@ -33,7 +29,7 @@ import javax.inject.Inject
class QuasselMessageRenderer @Inject constructor(
private val appearanceSettings: AppearanceSettings,
private val ircFormatDeserializer: IrcFormatDeserializer
private val contentFormatter: ContentFormatter
) : MessageRenderer {
private val timeFormatter = DateTimeFormatter.ofPattern(
timePattern(appearanceSettings.showSeconds, appearanceSettings.use24hClock)
......@@ -128,7 +124,7 @@ class QuasselMessageRenderer @Inject constructor(
context.getString(R.string.message_format_plain),
formatPrefix(message.content.senderPrefixes, highlight),
formatNick(message.content.sender, self, highlight, false),
formatContent(context, message.content.content, highlight)
contentFormatter.format(context, message.content.content, highlight)
),
isMarkerLine = message.isMarkerLine,
isExpanded = message.isExpanded,
......@@ -141,7 +137,7 @@ class QuasselMessageRenderer @Inject constructor(
context.getString(R.string.message_format_action),
formatPrefix(message.content.senderPrefixes, highlight),
formatNick(message.content.sender, self, highlight, false),
formatContent(context, message.content.content, highlight)
contentFormatter.format(context, message.content.content, highlight)
),
isMarkerLine = message.isMarkerLine,
isExpanded = message.isExpanded,
......@@ -154,7 +150,7 @@ class QuasselMessageRenderer @Inject constructor(
context.getString(R.string.message_format_notice),
formatPrefix(message.content.senderPrefixes, highlight),
formatNick(message.content.sender, self, highlight, false),
formatContent(context, message.content.content, highlight)
contentFormatter.format(context, message.content.content, highlight)
),
isMarkerLine = message.isMarkerLine,
isExpanded = message.isExpanded,
......@@ -225,7 +221,7 @@ class QuasselMessageRenderer @Inject constructor(
context.getString(R.string.message_format_part_2),
formatPrefix(message.content.senderPrefixes, highlight),
formatNick(message.content.sender, self, highlight, true),
formatContent(context, message.content.content, highlight)
contentFormatter.format(context, message.content.content, highlight)
)
},
isMarkerLine = message.isMarkerLine,
......@@ -246,7 +242,7 @@ class QuasselMessageRenderer @Inject constructor(
context.getString(R.string.message_format_quit_2),
formatPrefix(message.content.senderPrefixes, highlight),
formatNick(message.content.sender, self, highlight, true),
formatContent(context, message.content.content, highlight)
contentFormatter.format(context, message.content.content, highlight)
)
},
isMarkerLine = message.isMarkerLine,
......@@ -271,7 +267,7 @@ class QuasselMessageRenderer @Inject constructor(
formatNick(user, false, highlight, false),
formatPrefix(message.content.senderPrefixes, highlight),
formatNick(message.content.sender, self, highlight, true),
formatContent(context, reason, highlight)
contentFormatter.format(context, reason, highlight)
)
},
isMarkerLine = message.isMarkerLine,
......@@ -297,7 +293,7 @@ class QuasselMessageRenderer @Inject constructor(
formatNick(user, false, highlight, false),
formatPrefix(message.content.senderPrefixes, highlight),
formatNick(message.content.sender, self, highlight, true),
formatContent(context, reason, highlight)
contentFormatter.format(context, reason, highlight)
)
},
isMarkerLine = message.isMarkerLine,
......@@ -340,7 +336,7 @@ class QuasselMessageRenderer @Inject constructor(
Message_Type.Error -> FormattedMessage(
message.content.messageId,
timeFormatter.format(message.content.time.atZone(zoneId)),
formatContent(context, message.content.content, highlight),
contentFormatter.format(context, message.content.content, highlight),
isMarkerLine = message.isMarkerLine,
isExpanded = message.isExpanded,
isSelected = message.isSelected
......@@ -348,7 +344,7 @@ class QuasselMessageRenderer @Inject constructor(
Message_Type.Topic -> FormattedMessage(
message.content.messageId,
timeFormatter.format(message.content.time.atZone(zoneId)),
formatContent(context, message.content.content, highlight),
contentFormatter.format(context, message.content.content, highlight),
isMarkerLine = message.isMarkerLine,
isExpanded = message.isExpanded,
isSelected = message.isSelected
......@@ -378,59 +374,6 @@ class QuasselMessageRenderer @Inject constructor(
}
}
@Language("RegExp")
private val scheme = "(?:(?:mailto:|magnet:|(?:[+.-]?\\w)+://)|www(?=\\.\\S+\\.))"
@Language("RegExp")
private val authority = "(?:(?:[,.;@:]?[-\\w]+)+\\.?|\\[[0-9a-f:.]+])?(?::\\d+)?"
@Language("RegExp")
private val urlChars = "(?:[,.;:]*[\\w~@/?&=+$()!%#*-])"
@Language("RegExp")
private val urlEnd = "((?:>|[,.;:\"]*\\s|\\b|$))"
private val urlPattern = Regex(
"\\b($scheme$authority(?:$urlChars*)?)$urlEnd",
RegexOption.IGNORE_CASE
)
private val channelPattern = Regex(
"((?:#|![A-Z0-9]{5})[^,:\\s]+(?::[^,:\\s]+)?)\\b",
RegexOption.IGNORE_CASE
)
private fun formatContent(context: Context, content: String, highlight: Boolean): CharSequence {
val formattedText = ircFormatDeserializer.formatString(
context, content, appearanceSettings.colorizeMirc
)
val text = SpannableString(formattedText)
for (result in urlPattern.findAll(formattedText)) {
val group = result.groups[1]
if (group != null) {
text.setSpan(
QuasselURLSpan(group.value, highlight), group.range.start,
group.range.start + group.value.length,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
}
}
/*
for (result in channelPattern.findAll(content)) {
text.setSpan(URLSpan(result.value), result.range.start, result.range.endInclusive, Spanned.SPAN_INCLUSIVE_INCLUSIVE)}
*/
return text
}
class QuasselURLSpan(text: String, private val highlight: Boolean) : URLSpan(text) {
override fun updateDrawState(ds: TextPaint?) {
if (ds != null) {
if (!highlight)
ds.color = ds.linkColor
ds.isUnderlineText = true
}
}
}
private fun formatNickNickImpl(nick: String, colorize: Boolean): CharSequence {
val spannableString = SpannableString(nick)
if (colorize) {
......
......@@ -2,6 +2,7 @@ package de.kuschku.quasseldroid.ui.chat.nicks
import android.arch.lifecycle.Observer
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
......@@ -11,9 +12,14 @@ import android.view.View
import android.view.ViewGroup
import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.libquassel.quassel.BufferInfo
import de.kuschku.libquassel.util.helpers.value
import de.kuschku.libquassel.util.irc.IrcCaseMappers
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.settings.AppearanceSettings
import de.kuschku.quasseldroid.ui.chat.detailinfo.InfoActivity
import de.kuschku.quasseldroid.ui.chat.detailinfo.InfoDescriptor
import de.kuschku.quasseldroid.ui.chat.detailinfo.InfoType
import de.kuschku.quasseldroid.util.helper.toLiveData
import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer
import de.kuschku.quasseldroid.util.service.ServiceBoundFragment
......@@ -72,7 +78,15 @@ class NickListFragment : ServiceBoundFragment() {
return view
}
private val clickListener: ((String) -> Unit)? = {
// TODO
private val clickListener: ((String) -> Unit)? = { nick ->
viewModel.bufferData.value?.info?.let(BufferInfo::networkId)?.let { networkId ->
val intent = Intent(requireContext(), InfoActivity::class.java)
intent.putExtra("info", InfoDescriptor(
type = InfoType.User,
nick = nick,
network = networkId
))
startActivity(intent)
}
}
}
\ No newline at end of file
package de.kuschku.quasseldroid.util.irc.format
import android.content.Context
import android.text.SpannableString
import android.text.Spanned
import android.text.TextPaint
import android.text.style.URLSpan
import de.kuschku.quasseldroid.settings.AppearanceSettings
import org.intellij.lang.annotations.Language
import javax.inject.Inject
class ContentFormatter @Inject constructor(
private val ircFormatDeserializer: IrcFormatDeserializer,
private val appearanceSettings: AppearanceSettings
) {
@Language("RegExp")
private val scheme = "(?:(?:mailto:|magnet:|(?:[+.-]?\\w)+://)|www(?=\\.\\S+\\.))"
@Language("RegExp")
private val authority = "(?:(?:[,.;@:]?[-\\w]+)+\\.?|\\[[0-9a-f:.]+])?(?::\\d+)?"
@Language("RegExp")
private val urlChars = "(?:[,.;:]*[\\w~@/?&=+$()!%#*-])"
@Language("RegExp")
private val urlEnd = "((?:>|[,.;:\"]*\\s|\\b|$))"
private val urlPattern = Regex(
"\\b($scheme$authority(?:$urlChars*)?)$urlEnd",
RegexOption.IGNORE_CASE
)
private val channelPattern = Regex(
"((?:#|![A-Z0-9]{5})[^,:\\s]+(?::[^,:\\s]+)?)\\b",
RegexOption.IGNORE_CASE
)
class QuasselURLSpan(text: String, private val highlight: Boolean) : URLSpan(text) {
override fun updateDrawState(ds: TextPaint?) {
if (ds != null) {
if (!highlight)
ds.color = ds.linkColor
ds.isUnderlineText = true
}
}
}
fun format(context: Context, content: String, highlight: Boolean = false): CharSequence {
val formattedText = ircFormatDeserializer.formatString(
context, content, appearanceSettings.colorizeMirc
)
val text = SpannableString(formattedText)
for (result in urlPattern.findAll(formattedText)) {
val group = result.groups[1]
if (group != null) {
text.setSpan(
QuasselURLSpan(group.value, highlight), group.range.start,
group.range.start + group.value.length,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
}
}
/*
for (result in channelPattern.findAll(content)) {
text.setSpan(URLSpan(result.value), result.range.start, result.range.endInclusive, Spanned.SPAN_INCLUSIVE_INCLUSIVE)}
*/
return text
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 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:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:contentInsetStartWithNavigation="0dp"
app:popupTheme="?attr/actionBarPopupTheme" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/groups"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="12dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listitem="@layout/widget_userinfo_group" />
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
\ No newline at end of file
......@@ -4,8 +4,7 @@
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
......
<?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="72dp"
android:orientation="horizontal">
<android.support.v7.widget.AppCompatImageView
android:id="@+id/icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_account"
app:tint="?colorAccent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="12dp"
android:layout_marginStart="12dp"
android:orientation="vertical">
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="@sample/userinfo_basic.json/data/name" />
<TextView
android:id="@+id/value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?colorTextPrimary"
tools:text="@sample/userinfo_basic.json/data/value" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/title_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:ellipsize="end"
android:paddingBottom="20dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="20dp"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?colorAccent"
tools:text="@sample/userinfo_groups.json/data/name" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="?colorDivider" />
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/properties"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:itemCount="3"
tools:listitem="@layout/widget_userinfo" />
</LinearLayout>
</android.support.v7.widget.CardView>
\ No newline at end of file
......@@ -17,6 +17,7 @@
<string name="label_crashes">Absturzberichte</string>
<string name="label_delete">Löschen</string>
<string name="label_delete_all">Alle Löschen</string>
<string name="label_details">Details</string>
<string name="label_disconnect">Verbindung trennen</string>
<string name="label_filter_messages">Nachrichten filtern</string>
<string name="label_github">GitHub</string>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment