diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/MatrixPatterns.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/MatrixPatterns.kt index 9557434c..19dc37e6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/MatrixPatterns.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/MatrixPatterns.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.api -import java.util.* import java.util.regex.Pattern /** @@ -25,53 +24,53 @@ import java.util.regex.Pattern object MatrixPatterns { // Note: TLD is not mandatory (localhost, IP address...) - private val DOMAIN_REGEX = ":[A-Z0-9.-]+(:[0-9]{2,5})?" + private const val DOMAIN_REGEX = ":[A-Z0-9.-]+(:[0-9]{2,5})?" // regex pattern to find matrix user ids in a string. // See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids - private val MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+$DOMAIN_REGEX" - val PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = Pattern.compile(MATRIX_USER_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE) + private const val MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+$DOMAIN_REGEX" + private val PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = Pattern.compile(MATRIX_USER_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE) // regex pattern to find room ids in a string. - private val MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+$DOMAIN_REGEX" - val PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = Pattern.compile(MATRIX_ROOM_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE) + private const val MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+$DOMAIN_REGEX" + private val PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = Pattern.compile(MATRIX_ROOM_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE) // regex pattern to find room aliases in a string. - private val MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+$DOMAIN_REGEX" - val PATTERN_CONTAIN_MATRIX_ALIAS = Pattern.compile(MATRIX_ROOM_ALIAS_REGEX, Pattern.CASE_INSENSITIVE) + private const val MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+$DOMAIN_REGEX" + private val PATTERN_CONTAIN_MATRIX_ALIAS = Pattern.compile(MATRIX_ROOM_ALIAS_REGEX, Pattern.CASE_INSENSITIVE) // regex pattern to find message ids in a string. - private val MATRIX_EVENT_IDENTIFIER_REGEX = "\\$[A-Z0-9]+$DOMAIN_REGEX" - val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER = Pattern.compile(MATRIX_EVENT_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE) + private const val MATRIX_EVENT_IDENTIFIER_REGEX = "\\$[A-Z0-9]+$DOMAIN_REGEX" + private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER = Pattern.compile(MATRIX_EVENT_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE) // regex pattern to find message ids in a string. - private val MATRIX_EVENT_IDENTIFIER_V3_REGEX = "\\$[A-Z0-9/+]+" - val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 = Pattern.compile(MATRIX_EVENT_IDENTIFIER_V3_REGEX, Pattern.CASE_INSENSITIVE) + private const val MATRIX_EVENT_IDENTIFIER_V3_REGEX = "\\$[A-Z0-9/+]+" + private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 = Pattern.compile(MATRIX_EVENT_IDENTIFIER_V3_REGEX, Pattern.CASE_INSENSITIVE) // regex pattern to find group ids in a string. - private val MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+$DOMAIN_REGEX" - val PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = Pattern.compile(MATRIX_GROUP_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE) + private const val MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+$DOMAIN_REGEX" + private val PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = Pattern.compile(MATRIX_GROUP_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE) // regex pattern to find permalink with message id. // Android does not support in URL so extract it. - private val PERMALINK_BASE_REGEX = "https://matrix\\.to/#/" - private val APP_BASE_REGEX = "https://[A-Z0-9.-]+\\.[A-Z]{2,}/[A-Z]{3,}/#/room/" - val SEP_REGEX = "/" + private const val PERMALINK_BASE_REGEX = "https://matrix\\.to/#/" + private const val APP_BASE_REGEX = "https://[A-Z0-9.-]+\\.[A-Z]{2,}/[A-Z]{3,}/#/room/" + const val SEP_REGEX = "/" - private val LINK_TO_ROOM_ID_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX - val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE) + private const val LINK_TO_ROOM_ID_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX + private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE) - private val LINK_TO_ROOM_ALIAS_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX - val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE) + private const val LINK_TO_ROOM_ALIAS_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX + private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE) - private val LINK_TO_APP_ROOM_ID_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX - val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_APP_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE) + private const val LINK_TO_APP_ROOM_ID_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX + private val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_APP_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE) - private val LINK_TO_APP_ROOM_ALIAS_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX - val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_APP_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE) + private const val LINK_TO_APP_ROOM_ALIAS_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX + private val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_APP_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE) // list of patterns to find some matrix item. - val MATRIX_PATTERNS = Arrays.asList( + val MATRIX_PATTERNS = listOf( PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID, PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS, PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID, @@ -133,4 +132,4 @@ object MatrixPatterns { fun isGroupId(str: String?): Boolean { return str != null && PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER.matcher(str).matches() } -}// Cannot be instantiated +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageType.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageType.kt index 0b239f6c..7db33018 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageType.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageType.kt @@ -18,16 +18,16 @@ package im.vector.matrix.android.api.session.room.model.message object MessageType { - val MSGTYPE_TEXT = "m.text" - val MSGTYPE_EMOTE = "m.emote" - val MSGTYPE_NOTICE = "m.notice" - val MSGTYPE_IMAGE = "m.image" - val MSGTYPE_AUDIO = "m.audio" - val MSGTYPE_VIDEO = "m.video" - val MSGTYPE_LOCATION = "m.location" - val MSGTYPE_FILE = "m.file" - val FORMAT_MATRIX_HTML = "org.matrix.custom.html" + const val MSGTYPE_TEXT = "m.text" + const val MSGTYPE_EMOTE = "m.emote" + const val MSGTYPE_NOTICE = "m.notice" + const val MSGTYPE_IMAGE = "m.image" + const val MSGTYPE_AUDIO = "m.audio" + const val MSGTYPE_VIDEO = "m.video" + const val MSGTYPE_LOCATION = "m.location" + const val MSGTYPE_FILE = "m.file" + const val FORMAT_MATRIX_HTML = "org.matrix.custom.html" // Add, in local, a fake message type in order to StickerMessage can inherit Message class // Because sticker isn't a message type but a event type without msgtype field - val MSGTYPE_STICKER_LOCAL = "org.matrix.android.sdk.sticker" + const val MSGTYPE_STICKER_LOCAL = "org.matrix.android.sdk.sticker" } \ No newline at end of file diff --git a/vector/src/debug/AndroidManifest.xml b/vector/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..debb2987 --- /dev/null +++ b/vector/src/debug/AndroidManifest.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/vector/src/debug/java/im/vector/riotredesign/features/debug/DebugMaterialThemeActivity.kt b/vector/src/debug/java/im/vector/riotredesign/features/debug/DebugMaterialThemeActivity.kt new file mode 100644 index 00000000..475427fe --- /dev/null +++ b/vector/src/debug/java/im/vector/riotredesign/features/debug/DebugMaterialThemeActivity.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2019 New Vector 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. + */ + +package im.vector.riotredesign.features.debug + +import android.os.Bundle +import android.view.Menu +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.google.android.material.snackbar.Snackbar +import im.vector.riotredesign.R +import im.vector.riotredesign.core.utils.toast +import kotlinx.android.synthetic.debug.activity_test_material_theme.* + +// Rendering is not the same with VectorBaseActivity +abstract class DebugMaterialThemeActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_test_material_theme) + + debugShowSnackbar.setOnClickListener { + Snackbar.make(debugMaterialCoordinator, "Snackbar!", Snackbar.LENGTH_SHORT) + .setAction("Action") { } + .show() + } + + debugShowToast.setOnClickListener { + toast("Toast") + } + + debugShowDialog.setOnClickListener { + AlertDialog.Builder(this) + .setMessage("Dialog content") + .setIcon(R.drawable.ic_settings_x) + .setPositiveButton("Positive", null) + .setNegativeButton("Negative", null) + .setNeutralButton("Neutral", null) + .show() + } + + debugShowBottomSheet.setOnClickListener { + BottomSheetDialogFragment().show(supportFragmentManager, "TAG") + } + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.vector_home, menu) + return true + } +} diff --git a/vector/src/debug/java/im/vector/riotredesign/features/debug/DebugMaterialThemeDarkActivity.kt b/vector/src/debug/java/im/vector/riotredesign/features/debug/DebugMaterialThemeDarkActivity.kt new file mode 100644 index 00000000..bab21417 --- /dev/null +++ b/vector/src/debug/java/im/vector/riotredesign/features/debug/DebugMaterialThemeDarkActivity.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2019 New Vector 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. + */ + +package im.vector.riotredesign.features.debug + +class DebugMaterialThemeDarkActivity : DebugMaterialThemeActivity() \ No newline at end of file diff --git a/vector/src/debug/java/im/vector/riotredesign/features/debug/DebugMaterialThemeLightActivity.kt b/vector/src/debug/java/im/vector/riotredesign/features/debug/DebugMaterialThemeLightActivity.kt new file mode 100644 index 00000000..039d7c07 --- /dev/null +++ b/vector/src/debug/java/im/vector/riotredesign/features/debug/DebugMaterialThemeLightActivity.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2019 New Vector 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. + */ + +package im.vector.riotredesign.features.debug + +class DebugMaterialThemeLightActivity : DebugMaterialThemeActivity() \ No newline at end of file diff --git a/vector/src/debug/java/im/vector/riotredesign/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/riotredesign/features/debug/DebugMenuActivity.kt new file mode 100644 index 00000000..add4e2da --- /dev/null +++ b/vector/src/debug/java/im/vector/riotredesign/features/debug/DebugMenuActivity.kt @@ -0,0 +1,137 @@ +/* + * Copyright 2019 New Vector 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. + */ + +package im.vector.riotredesign.features.debug + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.content.Context +import android.content.Intent +import android.os.Build +import androidx.core.app.NotificationCompat +import androidx.core.app.Person +import butterknife.OnClick +import im.vector.riotredesign.R +import im.vector.riotredesign.core.platform.VectorBaseActivity + + +class DebugMenuActivity : VectorBaseActivity() { + + override fun getLayoutRes() = R.layout.activity_debug_menu + + @OnClick(R.id.debug_test_text_view_link) + fun testTextViewLink() { + startActivity(Intent(this, TestLinkifyActivity::class.java)) + } + + @OnClick(R.id.debug_test_notification) + fun testNotification() { + val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + // Create channel first + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = + NotificationChannel( + "CHAN", + "Channel name", + NotificationManager.IMPORTANCE_DEFAULT + ) + + channel.description = "Channel description" + (getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel) + + val channel2 = + NotificationChannel( + "CHAN2", + "Channel name 2", + NotificationManager.IMPORTANCE_DEFAULT + ) + + channel2.description = "Channel description 2" + (getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel2) + } + + + val builder = NotificationCompat.Builder(this, "CHAN") + .setWhen(System.currentTimeMillis()) + .setContentTitle("Title") + .setContentText("Content") + // No effect because it's a group summary notif + .setNumber(33) + .setSmallIcon(R.drawable.logo_transparent) + // This provocate the badge issue: no badge for group notification + .setGroup("GroupKey") + .setGroupSummary(true) + + val messagingStyle1 = NotificationCompat.MessagingStyle( + Person.Builder() + .setName("User name") + .build() + ) + .addMessage("Message 1 - 1", System.currentTimeMillis(), Person.Builder().setName("user 1-1").build()) + .addMessage("Message 1 - 2", System.currentTimeMillis(), Person.Builder().setName("user 1-2").build()) + + val messagingStyle2 = NotificationCompat.MessagingStyle( + Person.Builder() + .setName("User name 2") + .build() + ) + .addMessage("Message 2 - 1", System.currentTimeMillis(), Person.Builder().setName("user 1-1").build()) + .addMessage("Message 2 - 2", System.currentTimeMillis(), Person.Builder().setName("user 1-2").build()) + + + notificationManager.notify(10, builder.build()) + + notificationManager.notify( + 11, + NotificationCompat.Builder(this, "CHAN") + .setChannelId("CHAN") + .setWhen(System.currentTimeMillis()) + .setContentTitle("Title 1") + .setContentText("Content 1") + // For shortcut on long press on launcher icon + .setBadgeIconType(NotificationCompat.BADGE_ICON_NONE) + .setStyle(messagingStyle1) + .setSmallIcon(R.drawable.logo_transparent) + .setGroup("GroupKey") + .build() + ) + + notificationManager.notify( + 12, + NotificationCompat.Builder(this, "CHAN2") + .setWhen(System.currentTimeMillis()) + .setContentTitle("Title 2") + .setContentText("Content 2") + .setStyle(messagingStyle2) + .setSmallIcon(R.drawable.logo_transparent) + .setGroup("GroupKey") + .build() + ) + } + + @OnClick(R.id.debug_test_material_theme_light) + fun testMaterialThemeLight() { + startActivity(Intent(this, DebugMaterialThemeLightActivity::class.java)) + } + + @OnClick(R.id.debug_test_material_theme_dark) + fun testMaterialThemeDark() { + startActivity(Intent(this, DebugMaterialThemeDarkActivity::class.java)) + } + +} + diff --git a/vector/src/debug/java/im/vector/riotredesign/features/debug/TestLinkifyActivity.kt b/vector/src/debug/java/im/vector/riotredesign/features/debug/TestLinkifyActivity.kt new file mode 100644 index 00000000..7e37c319 --- /dev/null +++ b/vector/src/debug/java/im/vector/riotredesign/features/debug/TestLinkifyActivity.kt @@ -0,0 +1,133 @@ +/* + * Copyright 2019 New Vector 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. + */ + +package im.vector.riotredesign.features.debug + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.coordinatorlayout.widget.CoordinatorLayout +import butterknife.BindView +import butterknife.ButterKnife +import im.vector.riotredesign.R + + +class TestLinkifyActivity : AppCompatActivity() { + + @BindView(R.id.test_linkify_content_view) + lateinit var scrollContent: LinearLayout + + @BindView(R.id.test_linkify_coordinator) + lateinit var coordinatorLayout: CoordinatorLayout + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_test_linkify) + ButterKnife.bind(this) + + scrollContent.removeAllViews() + + listOf( + "https://www.html5rocks.com/en/tutorials/webrtc/basics/ |", + "https://www.html5rocks.com/en/tutorials/webrtc/basics/", + "mailto mailto:test@toto.com test@toto.com", + "Here is the link.www.test.com/foo/?23=35 you got it?", + "www.lemonde.fr", + " /www.lemonde.fr", + "://www.lemonde.fr", + "file:///dev/null ", + " ansible/xoxys.matrix#2c0b65eb", + "foo.ansible/xoxys.matrix#2c0b65eb", + "foo.ansible.fpo/xoxys.matrix#2c0b65eb", + "https://foo.ansible.fpo/xoxys.matrix#2c0b65eb", + "@vf:matrix.org", + "+44 207 123 1234", + "+33141437940", + "1234", + "3456.34,089", + "ksks9808", + "For example: geo:48.85828,2.29449?z=16 should be clickable", + "geo:37.786971,-122.399677;u=35", + "37.786971,-122.399677;u=35", + "48.107864,-1.712153", + "synchrone peut tenir la route la", + "that.is.some.sexy.link", + "test overlap 48.107864,0673728392 geo + pn?", + "test overlap 0673728392,48.107864 geo + pn?", + "If I add a link in brackets like (help for Riot: https://about.riot.im/help), the link is usable on Riot for Desktop", + "(help for Riot: https://about.riot.im/help)", + "http://example.com/test(1).html", + "http://example.com/test(1)", + "https://about.riot.im/help)", + "(http://example.com/test(1))", + "http://example.com/test1)", + "http://example.com/test1/, et ca", + "www.example.com/, et ca", + "foo.ansible.toplevel/xoxys.matrix#2c0b65eb", + "foo.ansible.ninja/xoxys.matrix#2c0b65eb", + "in brackets like (help for Riot: https://www.exemple/com/find(1)) , the link is usable ", + """ + In brackets like (help for Riot: https://about.riot.im/help) , the link is usable, + But you can call +44 207 123 1234 and come to 37.786971,-122.399677;u=35 then + see if this mail jhon@riot.im is active but this should not 12345 + """.trimIndent() + ) + .forEach { textContent -> + val item = LayoutInflater.from(this) + .inflate(R.layout.item_test_linkify, scrollContent, false) + + item.findViewById(R.id.test_linkify_auto_text) + ?.apply { + text = textContent + /* TODO Use BetterLinkMovementMethod when the other PR is merged + movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() { + override fun onURLClick(uri: Uri?) { + Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG) + .setAction("open") { + openUrlInExternalBrowser(this@TestLinkifyActivity, uri) + } + .show() + } + }) + */ + } + + item.findViewById(R.id.test_linkify_custom_text) + ?.apply { + text = textContent + /* TODO Use BetterLinkMovementMethod when the other PR is merged + movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() { + override fun onURLClick(uri: Uri?) { + Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG) + .setAction("open") { + openUrlInExternalBrowser(this@TestLinkifyActivity, uri) + } + .show() + } + }) + */ + + // TODO Call VectorLinkify.addLinks(text) + } + + scrollContent.addView(item, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)) + } + } +} diff --git a/vector/src/debug/res/drawable/linear_divider.xml b/vector/src/debug/res/drawable/linear_divider.xml new file mode 100644 index 00000000..95436029 --- /dev/null +++ b/vector/src/debug/res/drawable/linear_divider.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/vector/src/debug/res/layout/activity_debug_menu.xml b/vector/src/debug/res/layout/activity_debug_menu.xml new file mode 100644 index 00000000..d1e85019 --- /dev/null +++ b/vector/src/debug/res/layout/activity_debug_menu.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/vector/src/debug/res/layout/activity_test_linkify.xml b/vector/src/debug/res/layout/activity_test_linkify.xml new file mode 100644 index 00000000..2ccb2e5f --- /dev/null +++ b/vector/src/debug/res/layout/activity_test_linkify.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + diff --git a/vector/src/debug/res/layout/activity_test_material_theme.xml b/vector/src/debug/res/layout/activity_test_material_theme.xml new file mode 100644 index 00000000..198beefb --- /dev/null +++ b/vector/src/debug/res/layout/activity_test_material_theme.xml @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/debug/res/layout/demo_store_listing.xml b/vector/src/debug/res/layout/demo_store_listing.xml new file mode 100644 index 00000000..209a0589 --- /dev/null +++ b/vector/src/debug/res/layout/demo_store_listing.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/debug/res/layout/demo_theme_sample.xml b/vector/src/debug/res/layout/demo_theme_sample.xml new file mode 100644 index 00000000..b9102f1b --- /dev/null +++ b/vector/src/debug/res/layout/demo_theme_sample.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/debug/res/layout/demo_themes.xml b/vector/src/debug/res/layout/demo_themes.xml new file mode 100644 index 00000000..ac6bb409 --- /dev/null +++ b/vector/src/debug/res/layout/demo_themes.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/debug/res/layout/item_test_linkify.xml b/vector/src/debug/res/layout/item_test_linkify.xml new file mode 100644 index 00000000..19bebeaf --- /dev/null +++ b/vector/src/debug/res/layout/item_test_linkify.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/debug/res/values/styles.xml b/vector/src/debug/res/values/styles.xml new file mode 100644 index 00000000..063f652d --- /dev/null +++ b/vector/src/debug/res/values/styles.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 1c3e843b..4a03afbc 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + >() + val activityRestarter: LiveData> + get() = _activityRestarter + + + fun onActivityResumed() { + if (currentConfigurationValue == null) { + currentConfigurationValue = vectorConfiguration.getHash() + Timber.v("Configuration: init to $currentConfigurationValue") + } else { + val newHash = vectorConfiguration.getHash() + Timber.v("Configuration: newHash $newHash") + + if (newHash != currentConfigurationValue) { + Timber.v("Configuration: recreate the Activity") + currentConfigurationValue = newHash + + _activityRestarter.postValue(LiveEvent(Unit)) + } + } + } +} diff --git a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt index de1f0df0..30047836 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt @@ -16,6 +16,7 @@ package im.vector.riotredesign.core.platform +import android.content.Context import android.content.res.Configuration import android.os.Bundle import android.view.Menu @@ -24,6 +25,8 @@ import android.view.View import androidx.annotation.* import androidx.appcompat.widget.Toolbar import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders import butterknife.BindView import butterknife.ButterKnife import butterknife.Unbinder @@ -33,14 +36,16 @@ import com.google.android.material.snackbar.Snackbar import im.vector.riotredesign.BuildConfig import im.vector.riotredesign.R import im.vector.riotredesign.core.utils.toast +import im.vector.riotredesign.features.configuration.VectorConfiguration import im.vector.riotredesign.features.rageshake.BugReportActivity import im.vector.riotredesign.features.rageshake.BugReporter import im.vector.riotredesign.features.rageshake.RageShake import im.vector.riotredesign.features.themes.ThemeUtils import im.vector.riotredesign.receivers.DebugReceiver -import im.vector.ui.themes.ActivityOtherThemes +import im.vector.riotredesign.features.themes.ActivityOtherThemes import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable +import org.koin.android.ext.android.inject import timber.log.Timber @@ -58,6 +63,10 @@ abstract class VectorBaseActivity : BaseMvRxActivity() { * DATA * ========================================================================================== */ + private val vectorConfiguration: VectorConfiguration by inject() + + private lateinit var configurationViewModel: ConfigurationViewModel + private var unBinder: Unbinder? = null private var savedInstanceState: Bundle? = null @@ -70,6 +79,10 @@ abstract class VectorBaseActivity : BaseMvRxActivity() { private var rageShake: RageShake? = null + override fun attachBaseContext(base: Context) { + super.attachBaseContext(vectorConfiguration.getLocalisedContext(base)) + } + override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) restorables.forEach { it.onSaveInstanceState(outState) } @@ -95,6 +108,16 @@ abstract class VectorBaseActivity : BaseMvRxActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + configurationViewModel = ViewModelProviders.of(this).get(ConfigurationViewModel::class.java) + + configurationViewModel.activityRestarter.observe(this, Observer { + if (!it.hasBeenHandled) { + // Recreate the Activity because configuration has changed + startActivity(intent) + finish() + } + }) + // Shake detector rageShake = RageShake(this) @@ -136,6 +159,8 @@ abstract class VectorBaseActivity : BaseMvRxActivity() { Timber.d("onResume Activity ${this.javaClass.simpleName}") + configurationViewModel.onActivityResumed() + if (this !is BugReportActivity) { rageShake?.start() } diff --git a/vector/src/main/java/im/vector/riotredesign/features/configuration/VectorConfiguration.kt b/vector/src/main/java/im/vector/riotredesign/features/configuration/VectorConfiguration.kt new file mode 100644 index 00000000..8fff619d --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/configuration/VectorConfiguration.kt @@ -0,0 +1,146 @@ +/* + * Copyright 2019 New Vector 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. + */ + +package im.vector.riotredesign.features.configuration + +import android.annotation.SuppressLint +import android.content.Context +import android.content.res.Configuration +import android.os.Build +import im.vector.riotredesign.features.settings.FontScale +import im.vector.riotredesign.features.settings.VectorLocale +import im.vector.riotredesign.features.themes.ThemeUtils +import timber.log.Timber +import java.util.* + +/** + * Handle locale configuration change, such as theme, font size and locale chosen by the user + */ +class VectorConfiguration(private val context: Context) { + + // TODO Import mLanguageReceiver From Riot? + fun onConfigurationChanged(newConfig: Configuration?) { + if (Locale.getDefault().toString() != VectorLocale.applicationLocale.toString()) { + Timber.v("## onConfigurationChanged() : the locale has been updated to " + Locale.getDefault().toString() + + ", restore the expected value " + VectorLocale.applicationLocale.toString()) + updateApplicationSettings(VectorLocale.applicationLocale, + FontScale.getFontScalePrefValue(context), + ThemeUtils.getApplicationTheme(context)) + } + } + + + private fun updateApplicationSettings(locale: Locale, textSize: String, theme: String) { + VectorLocale.saveApplicationLocale(context, locale) + FontScale.saveFontScale(context, textSize) + Locale.setDefault(locale) + + val config = Configuration(context.resources.configuration) + config.locale = locale + config.fontScale = FontScale.getFontScale(context) + context.resources.updateConfiguration(config, context.resources.displayMetrics) + + ThemeUtils.setApplicationTheme(context, theme) + // TODO PhoneNumberUtils.onLocaleUpdate() + } + + /** + * Update the application theme + * + * @param theme the new theme + */ + fun updateApplicationTheme(theme: String) { + ThemeUtils.setApplicationTheme(context, theme) + updateApplicationSettings(VectorLocale.applicationLocale, + FontScale.getFontScalePrefValue(context), + theme) + } + + /** + * Init the configuration from the saved one + */ + fun initConfiguration() { + VectorLocale.init(context) + + val locale = VectorLocale.applicationLocale + val fontScale = FontScale.getFontScale(context) + val theme = ThemeUtils.getApplicationTheme(context) + + Locale.setDefault(locale) + val config = Configuration(context.resources.configuration) + config.locale = locale + config.fontScale = fontScale + context.resources.updateConfiguration(config, context.resources.displayMetrics) + + // init the theme + ThemeUtils.setApplicationTheme(context, theme) + } + + /** + * Update the application locale + * + * @param locale + */ + // TODO Call from LanguagePickerActivity + fun updateApplicationLocale(locale: Locale) { + updateApplicationSettings(locale, FontScale.getFontScalePrefValue(context), ThemeUtils.getApplicationTheme(context)) + } + + /** + * Compute a localised context + * + * @param context the context + * @return the localised context + */ + @SuppressLint("NewApi") + fun getLocalisedContext(context: Context): Context { + try { + val resources = context.resources + val locale = VectorLocale.applicationLocale + val configuration = resources.configuration + configuration.fontScale = FontScale.getFontScale(context) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + configuration.setLocale(locale) + configuration.setLayoutDirection(locale) + return context.createConfigurationContext(configuration) + } else { + configuration.locale = locale + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + configuration.setLayoutDirection(locale) + } + resources.updateConfiguration(configuration, resources.displayMetrics) + return context + } + } catch (e: Exception) { + Timber.e(e, "## getLocalisedContext() failed") + } + + return context + } + + /** + * Compute the locale status value + * @param activity the activity + * @return the local status value + */ + // TODO Create data class for this + fun getHash(): String { + return (VectorLocale.applicationLocale.toString() + + "_" + FontScale.getFontScalePrefValue(context) + + "_" + ThemeUtils.getApplicationTheme(context)) + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/AvatarRenderer.kt b/vector/src/main/java/im/vector/riotredesign/features/home/AvatarRenderer.kt index d86872a8..7975206f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/AvatarRenderer.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/AvatarRenderer.kt @@ -45,9 +45,9 @@ object AvatarRenderer { private const val THUMBNAIL_SIZE = 250 private val AVATAR_COLOR_LIST = listOf( - R.color.avatar_color_1, - R.color.avatar_color_2, - R.color.avatar_color_3 + R.color.riotx_avatar_fill_1, + R.color.riotx_avatar_fill_2, + R.color.riotx_avatar_fill_3 ) @UiThread @@ -118,33 +118,4 @@ object AvatarRenderer { .load(resolvedUrl) .apply(RequestOptions.circleCropTransform()) } - - - //Based on riot-web implementation - @ColorRes - fun getColorFromUserId(sender: String): Int { - var hash = 0 - var i = 0 - var chr: Char - if (sender.isEmpty()) { - return R.color.username_1 - } - while (i < sender.length) { - chr = sender[i] - hash = (hash shl 5) - hash + chr.toInt() - hash = hash or 0 - i++ - } - val cI = Math.abs(hash) % 8 + 1 - return when (cI) { - 1 -> R.color.username_1 - 2 -> R.color.username_2 - 3 -> R.color.username_3 - 4 -> R.color.username_4 - 5 -> R.color.username_5 - 6 -> R.color.username_6 - 7 -> R.color.username_7 - else -> R.color.username_8 - } - } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt index 0d63dd73..ff08720d 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt @@ -56,5 +56,10 @@ class HomeDrawerFragment : VectorBaseFragment() { homeDrawerHeaderSettingsView.setOnClickListener { navigator.openSettings() } + + // Debug menu + homeDrawerHeaderDebugView.setOnClickListener { + navigator.openDebug() + } } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/UserColor.kt b/vector/src/main/java/im/vector/riotredesign/features/home/UserColor.kt new file mode 100644 index 00000000..bd3f60f4 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/home/UserColor.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2019 New Vector 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. + */ + +package im.vector.riotredesign.features.home + +import androidx.annotation.ColorRes +import im.vector.riotredesign.R + + +@ColorRes +fun getColorFromUserId(userId: String?): Int { + if (userId.isNullOrBlank()) { + return R.color.riotx_username_1 + } + + var hash = 0 + var i = 0 + var chr: Char + + while (i < userId.length) { + chr = userId[i] + hash = (hash shl 5) - hash + chr.toInt() + i++ + } + + return when (Math.abs(hash) % 8 + 1) { + 1 -> R.color.riotx_username_1 + 2 -> R.color.riotx_username_2 + 3 -> R.color.riotx_username_3 + 4 -> R.color.riotx_username_4 + 5 -> R.color.riotx_username_5 + 6 -> R.color.riotx_username_6 + 7 -> R.color.riotx_username_7 + else -> R.color.riotx_username_8 + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt index 98d0325a..4653d751 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt @@ -75,6 +75,7 @@ import im.vector.riotredesign.features.command.Command import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.HomeModule import im.vector.riotredesign.features.home.HomePermalinkHandler +import im.vector.riotredesign.features.home.getColorFromUserId import im.vector.riotredesign.features.home.room.detail.composer.TextComposerActions import im.vector.riotredesign.features.home.room.detail.composer.TextComposerView import im.vector.riotredesign.features.home.room.detail.composer.TextComposerViewModel @@ -223,8 +224,7 @@ class RoomDetailFragment : //switch to expanded bar composerLayout.composerRelatedMessageTitle.apply { text = event.senderName - setTextColor(ContextCompat.getColor(requireContext(), AvatarRenderer.getColorFromUserId(event.root.sender - ?: ""))) + setTextColor(ContextCompat.getColor(requireContext(), getColorFromUserId(event.root.sender))) } //TODO this is used at several places, find way to refactor? diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/BaseMvRxBottomSheetDialog.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/BaseMvRxBottomSheetDialog.kt index a37a5eaf..c3a068be 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/BaseMvRxBottomSheetDialog.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/BaseMvRxBottomSheetDialog.kt @@ -16,6 +16,8 @@ package im.vector.riotredesign.features.home.room.detail.timeline.action import android.os.Bundle +import android.os.Parcelable +import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.MvRxView import com.airbnb.mvrx.MvRxViewModelStore import com.google.android.material.bottomsheet.BottomSheetDialogFragment @@ -51,6 +53,10 @@ abstract class BaseMvRxBottomSheetDialog : BottomSheetDialogFragment(), MvRxView // subscribe to a ViewModel. postInvalidate() } + + protected fun setArguments(args: Parcelable? = null) { + arguments = args?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } } + } } private const val PERSISTED_VIEW_ID_KEY = "mvrx:bottomsheet_persisted_view_id" \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt index 1d50d893..44a753af 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt @@ -144,15 +144,15 @@ class MessageActionsBottomSheet : BaseMvRxBottomSheetDialog() { companion object { fun newInstance(roomId: String, informationData: MessageInformationData): MessageActionsBottomSheet { - val args = Bundle() - val parcelableArgs = ParcelableArgs( - informationData.eventId, - roomId, - informationData - ) - args.putParcelable(MvRx.KEY_ARG, parcelableArgs) - return MessageActionsBottomSheet().apply { arguments = args } - + return MessageActionsBottomSheet().apply { + setArguments( + ParcelableArgs( + informationData.eventId, + roomId, + informationData + ) + ) + } } } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt index 4509b19e..d61848af 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -41,6 +41,7 @@ import im.vector.riotredesign.core.resources.ColorProvider import im.vector.riotredesign.core.resources.StringProvider import im.vector.riotredesign.core.utils.DebouncedClickListener import im.vector.riotredesign.features.home.AvatarRenderer +import im.vector.riotredesign.features.home.getColorFromUserId import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider @@ -79,7 +80,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider, val avatarUrl = event.senderAvatar val memberName = event.senderName ?: event.root.sender ?: "" val formattedMemberName = span(memberName) { - textColor = colorProvider.getColor(AvatarRenderer.getColorFromUserId(event.root.sender + textColor = colorProvider.getColor(getColorFromUserId(event.root.sender ?: "")) } val hasBeenEdited = event.annotations?.editSummary != null @@ -135,7 +136,8 @@ class MessageItemFactory(private val colorProvider: ColorProvider, } } - private fun buildAudioMessageItem(messageContent: MessageAudioContent, informationData: MessageInformationData, + private fun buildAudioMessageItem(messageContent: MessageAudioContent, + informationData: MessageInformationData, callback: TimelineEventController.Callback?): MessageFileItem? { return MessageFileItem_() .informationData(informationData) @@ -164,7 +166,8 @@ class MessageItemFactory(private val colorProvider: ColorProvider, } } - private fun buildFileMessageItem(messageContent: MessageFileContent, informationData: MessageInformationData, + private fun buildFileMessageItem(messageContent: MessageFileContent, + informationData: MessageInformationData, callback: TimelineEventController.Callback?): MessageFileItem? { return MessageFileItem_() .informationData(informationData) @@ -198,7 +201,8 @@ class MessageItemFactory(private val colorProvider: ColorProvider, return DefaultItem_().text(text) } - private fun buildImageMessageItem(messageContent: MessageImageContent, informationData: MessageInformationData, + private fun buildImageMessageItem(messageContent: MessageImageContent, + informationData: MessageInformationData, callback: TimelineEventController.Callback?): MessageImageVideoItem? { val (maxWidth, maxHeight) = timelineMediaSizeProvider.getMaxSize() @@ -233,14 +237,14 @@ class MessageItemFactory(private val colorProvider: ColorProvider, DebouncedClickListener(View.OnClickListener { view -> callback?.onEventCellClicked(informationData, messageContent, view) })) - .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) ?: false } } - private fun buildVideoMessageItem(messageContent: MessageVideoContent, informationData: MessageInformationData, + private fun buildVideoMessageItem(messageContent: MessageVideoContent, + informationData: MessageInformationData, callback: TimelineEventController.Callback?): MessageImageVideoItem? { val (maxWidth, maxHeight) = timelineMediaSizeProvider.getMaxSize() @@ -283,7 +287,8 @@ class MessageItemFactory(private val colorProvider: ColorProvider, } } - private fun buildTextMessageItem(sendState: SendState, messageContent: MessageTextContent, + private fun buildTextMessageItem(sendState: SendState, + messageContent: MessageTextContent, informationData: MessageInformationData, hasBeenEdited: Boolean, editSummary: EditAggregatedSummary?, @@ -335,6 +340,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider, editSummary: EditAggregatedSummary?): SpannableStringBuilder { val spannable = SpannableStringBuilder() spannable.append(linkifiedBody) + // TODO i18n val editedSuffix = "(edited)" spannable.append(" ").append(editedSuffix) val color = colorProvider.getColorFromAttribute(R.attr.vctr_list_header_secondary_text_color) @@ -362,13 +368,14 @@ class MessageItemFactory(private val colorProvider: ColorProvider, return spannable } - private fun buildNoticeMessageItem(messageContent: MessageNoticeContent, informationData: MessageInformationData, + private fun buildNoticeMessageItem(messageContent: MessageNoticeContent, + informationData: MessageInformationData, callback: TimelineEventController.Callback?): MessageTextItem? { val message = messageContent.body.let { val formattedBody = span { text = it - textColor = colorProvider.getColor(R.color.slate_grey) + textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary) textStyle = "italic" } linkifyBody(formattedBody, callback) @@ -395,7 +402,8 @@ class MessageItemFactory(private val colorProvider: ColorProvider, } } - private fun buildEmoteMessageItem(messageContent: MessageEmoteContent, informationData: MessageInformationData, + private fun buildEmoteMessageItem(messageContent: MessageEmoteContent, + informationData: MessageInformationData, hasBeenEdited: Boolean, editSummary: EditAggregatedSummary?, callback: TimelineEventController.Callback?): MessageTextItem? { @@ -433,7 +441,8 @@ class MessageItemFactory(private val colorProvider: ColorProvider, } } - private fun buildRedactedItem(informationData: MessageInformationData, callback: TimelineEventController.Callback?): RedactedMessageItem? { + private fun buildRedactedItem(informationData: MessageInformationData, + callback: TimelineEventController.Callback?): RedactedMessageItem? { return RedactedMessageItem_() .informationData(informationData) .avatarClickListener( @@ -456,32 +465,4 @@ class MessageItemFactory(private val colorProvider: ColorProvider, VectorLinkify.addLinks(spannable, true) return spannable } - - //Based on riot-web implementation - @ColorRes - private fun getColorFor(sender: String): Int { - var hash = 0 - var i = 0 - var chr: Char - if (sender.isEmpty()) { - return R.color.username_1 - } - while (i < sender.length) { - chr = sender[i] - hash = (hash shl 5) - hash + chr.toInt() - hash = hash or 0 - i++ - } - val cI = Math.abs(hash) % 8 + 1 - return when (cI) { - 1 -> R.color.username_1 - 2 -> R.color.username_2 - 3 -> R.color.username_3 - 4 -> R.color.username_4 - 5 -> R.color.username_5 - 6 -> R.color.username_6 - 7 -> R.color.username_7 - else -> R.color.username_8 - } - } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt index db5e3e54..022b7b0b 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt @@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotredesign.core.epoxy.EmptyItem_ import im.vector.riotredesign.core.epoxy.VectorEpoxyModel import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController +import timber.log.Timber class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, private val noticeItemFactory: NoticeItemFactory, @@ -32,8 +33,10 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, val computedModel = try { when (event.root.type) { + // Message EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, callback) + // State and call EventType.STATE_ROOM_NAME, EventType.STATE_ROOM_TOPIC, EventType.STATE_ROOM_MEMBER, @@ -42,12 +45,16 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, EventType.CALL_HANGUP, EventType.CALL_ANSWER -> noticeItemFactory.create(event) + // Unhandled event types (yet) EventType.ENCRYPTED, EventType.ENCRYPTION, EventType.STATE_ROOM_THIRD_PARTY_INVITE, EventType.STICKER, EventType.STATE_ROOM_CREATE -> defaultItemFactory.create(event) - else -> null + else -> { + Timber.w("Ignored event (type: ${event.root.type}") + null + } } } catch (e: Exception) { defaultItemFactory.create(event, e) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/DefaultItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/DefaultItem.kt index 3985e8c1..443290d3 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/DefaultItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/DefaultItem.kt @@ -40,6 +40,6 @@ abstract class DefaultItem : BaseEventItem() { } companion object { - private val STUB_ID = R.id.messageContentDefaultStub + private const val STUB_ID = R.id.messageContentDefaultStub } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt index dd06cb0c..dcb0bdf4 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt @@ -57,6 +57,6 @@ abstract class NoticeItem : BaseEventItem() { } companion object { - private val STUB_ID = R.id.messageContentNoticeStub + private const val STUB_ID = R.id.messageContentNoticeStub } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomCategoryItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomCategoryItem.kt index 5a837fd0..ef021938 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomCategoryItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomCategoryItem.kt @@ -25,6 +25,7 @@ import com.airbnb.epoxy.EpoxyModelClass import im.vector.riotredesign.R import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder import im.vector.riotredesign.core.epoxy.VectorEpoxyModel +import im.vector.riotredesign.features.themes.ThemeUtils @EpoxyModelClass(layout = R.layout.item_room_category) abstract class RoomCategoryItem : VectorEpoxyModel() { @@ -36,7 +37,7 @@ abstract class RoomCategoryItem : VectorEpoxyModel() { @EpoxyAttribute var listener: (() -> Unit)? = null override fun bind(holder: Holder) { - val tintColor = ContextCompat.getColor(holder.rootView.context, R.color.bluey_grey_two) + val tintColor = ThemeUtils.getColor(holder.rootView.context, R.attr.riotx_text_secondary) val expandedArrowDrawableRes = if (expanded) R.drawable.ic_expand_more_white else R.drawable.ic_expand_less_white val expandedArrowDrawable = ContextCompat.getDrawable(holder.rootView.context, expandedArrowDrawableRes)?.also { DrawableCompat.setTint(it, tintColor) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt index 19b031cf..247ab070 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt @@ -16,7 +16,6 @@ package im.vector.riotredesign.features.home.room.list -import android.animation.Animator import android.os.Bundle import android.os.Parcelable import androidx.annotation.StringRes @@ -25,18 +24,16 @@ import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.airbnb.mvrx.* -import com.google.android.material.floatingactionbutton.FloatingActionButton import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.riotredesign.R -import im.vector.riotredesign.core.animations.ANIMATION_DURATION_SHORT -import im.vector.riotredesign.core.animations.SimpleAnimatorListener import im.vector.riotredesign.core.epoxy.LayoutManagerStateRestorer import im.vector.riotredesign.core.extensions.observeEvent import im.vector.riotredesign.core.platform.OnBackPressed import im.vector.riotredesign.core.platform.StateView import im.vector.riotredesign.core.platform.VectorBaseFragment +import im.vector.riotredesign.features.home.room.list.widget.FabMenuView import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_room_list.* import org.koin.android.ext.android.inject @@ -47,11 +44,7 @@ data class RoomListParams( ) : Parcelable -class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback, OnBackPressed { - - lateinit var fabButton: FloatingActionButton - - private var isFabMenuOpened = false +class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback, OnBackPressed, FabMenuView.Listener { enum class DisplayMode(@StringRes val titleRes: Int) { HOME(R.string.bottom_action_home), @@ -82,21 +75,16 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback, O navigator.openRoom(it) } - isFabMenuOpened = false + createChatFabMenu.listener = this } private fun setupCreateRoomButton() { - fabButton = when (roomListParams.displayMode) { - DisplayMode.HOME -> createRoomButton - DisplayMode.PEOPLE -> createChatRoomButton - else -> createGroupRoomButton + when (roomListParams.displayMode) { + DisplayMode.HOME -> createChatFabMenu.isVisible = true + DisplayMode.PEOPLE -> createChatRoomButton.isVisible = true + else -> createGroupRoomButton.isVisible = true } - fabButton.isVisible = true - - createRoomButton.setOnClickListener { - toggleFabMenu() - } createChatRoomButton.setOnClickListener { createDirectChat() } @@ -104,93 +92,34 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback, O openRoomDirectory() } - createRoomItemChat.setOnClickListener { - toggleFabMenu() - createDirectChat() - } - createRoomItemGroup.setOnClickListener { - toggleFabMenu() - openRoomDirectory() - } - - createRoomTouchGuard.setOnClickListener { - toggleFabMenu() - } - - createRoomTouchGuard.isClickable = false - // Hide FAB when list is scrolling epoxyRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { - fabButton.removeCallbacks(showFabRunnable) + createChatFabMenu.removeCallbacks(showFabRunnable) when (newState) { RecyclerView.SCROLL_STATE_IDLE -> { - fabButton.postDelayed(showFabRunnable, 1000) + createChatFabMenu.postDelayed(showFabRunnable, 1000) } RecyclerView.SCROLL_STATE_DRAGGING, RecyclerView.SCROLL_STATE_SETTLING -> { - fabButton.hide() + when (roomListParams.displayMode) { + DisplayMode.HOME -> createChatFabMenu.hide() + DisplayMode.PEOPLE -> createChatRoomButton.hide() + else -> createGroupRoomButton.hide() + } } } } }) } - private fun toggleFabMenu() { - isFabMenuOpened = !isFabMenuOpened - if (isFabMenuOpened) { - createRoomItemChat.isVisible = true - createRoomItemGroup.isVisible = true - - createRoomButton.animate() - .setDuration(ANIMATION_DURATION_SHORT) - .rotation(135f) - createRoomItemChat.animate() - .setDuration(ANIMATION_DURATION_SHORT) - .translationY(-resources.getDimension(R.dimen.fab_menu_offset_1)) - createRoomItemGroup.animate() - .setDuration(ANIMATION_DURATION_SHORT) - .translationY(-resources.getDimension(R.dimen.fab_menu_offset_2)) - createRoomTouchGuard.animate() - .setDuration(ANIMATION_DURATION_SHORT) - .alpha(0.6f) - .setListener(null) - createRoomTouchGuard.isClickable = true - } else { - createRoomButton.animate() - .setDuration(ANIMATION_DURATION_SHORT) - .rotation(0f) - createRoomItemChat.animate() - .setDuration(ANIMATION_DURATION_SHORT) - .translationY(0f) - createRoomItemGroup.animate() - .setDuration(ANIMATION_DURATION_SHORT) - .translationY(0f) - createRoomTouchGuard.animate() - .setDuration(ANIMATION_DURATION_SHORT) - .alpha(0f) - .setListener(object : SimpleAnimatorListener() { - override fun onAnimationCancel(animation: Animator?) { - animation?.removeListener(this) - } - - override fun onAnimationEnd(animation: Animator?) { - // Use isFabMenuOpened because it may have been open meanwhile - createRoomItemChat.isVisible = isFabMenuOpened - createRoomItemGroup.isVisible = isFabMenuOpened - } - }) - createRoomTouchGuard.isClickable = false - } - } - - private fun openRoomDirectory() { + override fun openRoomDirectory() { navigator.openRoomDirectory() } - private fun createDirectChat() { + override fun createDirectChat() { vectorBaseActivity.notImplemented("creating direct chat") } @@ -206,7 +135,13 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback, O } private val showFabRunnable = Runnable { - fabButton.show() + if (isAdded) { + when (roomListParams.displayMode) { + DisplayMode.HOME -> createChatFabMenu.show() + DisplayMode.PEOPLE -> createChatRoomButton.show() + else -> createGroupRoomButton.show() + } + } } private fun renderState(state: RoomListViewState) { @@ -278,8 +213,7 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback, O } override fun onBackPressed(): Boolean { - if (isFabMenuOpened) { - toggleFabMenu() + if (createChatFabMenu.onBackPressed()) { return true } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/UnreadCounterBadgeView.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/UnreadCounterBadgeView.kt index 1f69a6a7..381fd0ec 100755 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/UnreadCounterBadgeView.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/UnreadCounterBadgeView.kt @@ -20,6 +20,7 @@ import android.util.AttributeSet import android.view.View import androidx.appcompat.widget.AppCompatTextView import im.vector.riotredesign.R +import im.vector.riotredesign.features.themes.ThemeUtils class UnreadCounterBadgeView : AppCompatTextView { @@ -37,7 +38,7 @@ class UnreadCounterBadgeView : AppCompatTextView { val bgRes = if (state.highlighted) { R.drawable.bg_unread_highlight } else { - R.drawable.bg_unread_notification + ThemeUtils.getResourceId(context, R.drawable.bg_unread_notification_light) } setBackgroundResource(bgRes) text = RoomSummaryFormatter.formatUnreadMessagesCounter(state.count) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/widget/FabMenuView.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/widget/FabMenuView.kt new file mode 100644 index 00000000..95b7179c --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/widget/FabMenuView.kt @@ -0,0 +1,166 @@ +/* + * Copyright 2019 New Vector 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. + */ + +package im.vector.riotredesign.features.home.room.list.widget + +import android.content.Context +import android.util.AttributeSet +import android.view.ViewGroup +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.constraintlayout.widget.ConstraintSet +import androidx.core.view.isVisible +import androidx.transition.ChangeTransform +import androidx.transition.Transition +import androidx.transition.TransitionManager +import im.vector.riotredesign.R +import im.vector.riotredesign.core.animations.ANIMATION_DURATION_SHORT +import im.vector.riotredesign.core.animations.SimpleTransitionListener +import im.vector.riotredesign.core.animations.VectorFullTransitionSet +import im.vector.riotredesign.features.themes.ThemeUtils +import kotlinx.android.synthetic.main.merge_fab_menu_view.view.* + +class FabMenuView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : ConstraintLayout(context, attrs, defStyleAttr) { + + var listener: Listener? = null + + private var isFabMenuOpened = false + + init { + inflate(context, R.layout.merge_fab_menu_view, this) + } + + override fun onFinishInflate() { + super.onFinishInflate() + + // Collapse + ConstraintSet().also { + it.clone(context, R.layout.constraint_set_fab_menu_close) + it.applyTo(this) + } + + createRoomItemChat.isVisible = false + createRoomItemChatLabel.isVisible = false + createRoomItemGroup.isVisible = false + createRoomItemGroupLabel.isVisible = false + // Collapse end + + // Tint label background + listOf(createRoomItemChatLabel, createRoomItemGroupLabel) + .forEach { + it.setBackgroundResource(ThemeUtils.getResourceId(context, R.drawable.vector_label_background_light)) + } + + createRoomButton.setOnClickListener { + toggleFabMenu() + } + + listOf(createRoomItemChat, createRoomItemChatLabel) + .forEach { + it.setOnClickListener { + closeFabMenu() + listener?.createDirectChat() + } + } + listOf(createRoomItemGroup, createRoomItemGroupLabel) + .forEach { + it.setOnClickListener { + closeFabMenu() + listener?.openRoomDirectory() + } + } + + createRoomTouchGuard.setOnClickListener { + closeFabMenu() + } + } + + fun show() { + createRoomButton.show() + } + + fun hide() { + createRoomButton.hide() + } + + private fun openFabMenu() { + if (isFabMenuOpened) { + return + } + + toggleFabMenu() + } + + private fun closeFabMenu() { + if (!isFabMenuOpened) { + return + } + + toggleFabMenu() + } + + private fun toggleFabMenu() { + isFabMenuOpened = !isFabMenuOpened + + TransitionManager.beginDelayedTransition(parent as? ViewGroup ?: this, + VectorFullTransitionSet().apply { + duration = ANIMATION_DURATION_SHORT + ChangeTransform() + addListener(object : SimpleTransitionListener() { + override fun onTransitionEnd(transition: Transition) { + // Hide the view after the transition for a better visual effect + createRoomItemChat.isVisible = isFabMenuOpened + createRoomItemChatLabel.isVisible = isFabMenuOpened + createRoomItemGroup.isVisible = isFabMenuOpened + createRoomItemGroupLabel.isVisible = isFabMenuOpened + } + }) + }) + + if (isFabMenuOpened) { + // Animate manually the rotation for a better effect + createRoomButton.animate().setDuration(ANIMATION_DURATION_SHORT).rotation(135f) + + + ConstraintSet().also { + it.clone(context, R.layout.constraint_set_fab_menu_open) + it.applyTo(this) + } + } else { + createRoomButton.animate().setDuration(ANIMATION_DURATION_SHORT).rotation(0f) + + ConstraintSet().also { + it.clone(context, R.layout.constraint_set_fab_menu_close) + it.applyTo(this) + } + } + } + + fun onBackPressed(): Boolean { + if (isFabMenuOpened) { + closeFabMenu() + return true + } + + return false + } + + interface Listener { + fun createDirectChat() + fun openRoomDirectory() + } + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/login/LoginActivity.kt index dc6f3aeb..ffadac11 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/login/LoginActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/login/LoginActivity.kt @@ -29,6 +29,7 @@ import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.sync.FilterService import im.vector.riotredesign.R +import im.vector.riotredesign.core.extensions.showPassword import im.vector.riotredesign.core.platform.VectorBaseActivity import im.vector.riotredesign.features.home.HomeActivity import io.reactivex.Observable @@ -44,14 +45,20 @@ class LoginActivity : VectorBaseActivity() { private val authenticator = Matrix.getInstance().authenticator() + private var passwordShown = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_login) setupAuthButton() + setupPasswordReveal() homeServerField.setText(DEFAULT_HOME_SERVER_URI) } private fun authenticate() { + passwordShown = false + renderPasswordField() + val login = loginField.text?.trim().toString() val password = passwordField.text?.trim().toString() buildHomeServerConnectionConfig().fold( @@ -105,6 +112,24 @@ class LoginActivity : VectorBaseActivity() { authenticateButton.setOnClickListener { authenticate() } } + private fun setupPasswordReveal() { + passwordShown = false + + passwordReveal.setOnClickListener { + passwordShown = !passwordShown + + renderPasswordField() + } + + renderPasswordField() + } + + private fun renderPasswordField() { + passwordField.showPassword(passwordShown) + + passwordReveal.setImageResource(if (passwordShown) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black) + } + private fun goToHome() { val intent = HomeActivity.newIntent(this) startActivity(intent) diff --git a/vector/src/main/java/im/vector/riotredesign/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/riotredesign/features/navigation/DefaultNavigator.kt index 34c774a3..307d4fe8 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/navigation/DefaultNavigator.kt @@ -20,6 +20,7 @@ import android.app.Activity import android.content.Intent import androidx.fragment.app.Fragment import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom +import im.vector.riotredesign.features.debug.DebugMenuActivity import im.vector.riotredesign.features.home.room.detail.RoomDetailActivity import im.vector.riotredesign.features.home.room.detail.RoomDetailArgs import im.vector.riotredesign.features.roomdirectory.RoomDirectoryActivity @@ -50,4 +51,8 @@ class DefaultNavigator(private val fraqment: Fragment) : Navigator { val intent = VectorSettingsActivity.getIntent(activity, "TODO") activity.startActivity(intent) } + + override fun openDebug() { + activity.startActivity(Intent(activity, DebugMenuActivity::class.java)) + } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/riotredesign/features/navigation/Navigator.kt index a47bbaa3..518e8de8 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/navigation/Navigator.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/navigation/Navigator.kt @@ -28,4 +28,6 @@ interface Navigator { fun openSettings() + fun openDebug() + } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsFragment.kt index 5ffae5bb..aae438b7 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsFragment.kt @@ -32,6 +32,7 @@ import im.vector.riotredesign.core.error.ErrorFormatter import im.vector.riotredesign.core.extensions.addFragmentToBackstack import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerFragment +import im.vector.riotredesign.features.themes.ThemeUtils import io.reactivex.rxkotlin.subscribeBy import kotlinx.android.synthetic.main.fragment_public_rooms.* import org.koin.android.ext.android.inject @@ -58,13 +59,15 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - vectorBaseActivity.setSupportActionBar(toolbar) + vectorBaseActivity.setSupportActionBar(publicRoomsToolbar) vectorBaseActivity.supportActionBar?.let { it.setDisplayShowHomeEnabled(true) it.setDisplayHomeAsUpEnabled(true) } + publicRoomsFilter.setBackgroundResource(ThemeUtils.getResourceId(requireContext(), R.drawable.bg_search_edit_text_light)) + RxTextView.textChanges(publicRoomsFilter) .debounce(500, TimeUnit.MILLISECONDS) .subscribeBy { diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt index 6365d39a..51369a91 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt @@ -28,7 +28,6 @@ import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule import im.vector.riotredesign.features.roomdirectory.RoomDirectoryViewModel -import kotlinx.android.synthetic.main.fragment_public_rooms.toolbar import kotlinx.android.synthetic.main.fragment_room_directory_picker.* import org.koin.android.ext.android.inject import org.koin.android.scope.ext.android.bindScope diff --git a/vector/src/main/java/im/vector/riotredesign/features/settings/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/settings/VectorSettingsPreferencesFragment.kt index d124af6b..c1c30658 100755 --- a/vector/src/main/java/im/vector/riotredesign/features/settings/VectorSettingsPreferencesFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/settings/VectorSettingsPreferencesFragment.kt @@ -54,6 +54,7 @@ import im.vector.riotredesign.core.preference.UserAvatarPreference import im.vector.riotredesign.core.preference.VectorPreference import im.vector.riotredesign.core.utils.* import im.vector.riotredesign.features.MainActivity +import im.vector.riotredesign.features.configuration.VectorConfiguration import im.vector.riotredesign.features.themes.ThemeUtils import org.koin.android.ext.android.inject import java.lang.ref.WeakReference @@ -99,6 +100,8 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref // used to avoid requesting to enter the password for each deletion private var mAccountPassword: String? = null + private val vectorConfiguration by inject() + // current publicised group list private var mPublicisedGroups: MutableSet? = null @@ -366,8 +369,10 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref findPreference(ThemeUtils.APPLICATION_THEME_KEY) .onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> if (newValue is String) { - // TODO VectorApp.updateApplicationTheme(newValue) + vectorConfiguration.updateApplicationTheme(newValue) + // Restart the Activity activity?.let { + // Note: recreate does not apply the color correctly it.startActivity(it.intent) it.finish() } @@ -1359,7 +1364,7 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref if (resultCode == Activity.RESULT_OK) { when (requestCode) { - REQUEST_CALL_RINGTONE -> { + REQUEST_CALL_RINGTONE -> { val callRingtoneUri: Uri? = data?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI) val thisActivity = activity if (callRingtoneUri != null && thisActivity != null) { @@ -1368,9 +1373,9 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref } } REQUEST_E2E_FILE_REQUEST_CODE -> importKeys(data) - REQUEST_NEW_PHONE_NUMBER -> refreshPhoneNumbersList() - REQUEST_PHONEBOOK_COUNTRY -> onPhonebookCountryUpdate(data) - REQUEST_LOCALE -> { + REQUEST_NEW_PHONE_NUMBER -> refreshPhoneNumbersList() + REQUEST_PHONEBOOK_COUNTRY -> onPhonebookCountryUpdate(data) + REQUEST_LOCALE -> { activity?.let { startActivity(it.intent) it.finish() diff --git a/vector/src/main/java/im/vector/riotredesign/features/themes/ActivityOtherThemes.kt b/vector/src/main/java/im/vector/riotredesign/features/themes/ActivityOtherThemes.kt index da17de49..159a4801 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/themes/ActivityOtherThemes.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/themes/ActivityOtherThemes.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.ui.themes +package im.vector.riotredesign.features.themes import androidx.annotation.StyleRes import im.vector.riotredesign.R @@ -33,45 +33,4 @@ sealed class ActivityOtherThemes(@StyleRes val dark: Int, R.style.AppTheme_Status ) - object NoActionBarFullscreen : ActivityOtherThemes( - R.style.AppTheme_NoActionBar_FullScreen_Dark, - R.style.AppTheme_NoActionBar_FullScreen_Black, - R.style.AppTheme_NoActionBar_FullScreen_Status - ) - - object Home : ActivityOtherThemes( - R.style.HomeActivityTheme_Dark, - R.style.HomeActivityTheme_Black, - R.style.HomeActivityTheme_Status - ) - - object Group : ActivityOtherThemes( - R.style.GroupAppTheme_Dark, - R.style.GroupAppTheme_Black, - R.style.GroupAppTheme_Status - ) - - object Picker : ActivityOtherThemes( - R.style.CountryPickerTheme_Dark, - R.style.CountryPickerTheme_Black, - R.style.CountryPickerTheme_Status - ) - - object Lock : ActivityOtherThemes( - R.style.Theme_Vector_Lock_Dark, - R.style.Theme_Vector_Lock_Light, - R.style.Theme_Vector_Lock_Status - ) - - object Search : ActivityOtherThemes( - R.style.SearchesAppTheme_Dark, - R.style.SearchesAppTheme_Black, - R.style.SearchesAppTheme_Status - ) - - object Call : ActivityOtherThemes( - R.style.CallActivityTheme_Dark, - R.style.CallActivityTheme_Black, - R.style.CallActivityTheme_Status - ) } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/themes/ThemeUtils.kt b/vector/src/main/java/im/vector/riotredesign/features/themes/ThemeUtils.kt index 8550c3c1..26a265df 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/themes/ThemeUtils.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/themes/ThemeUtils.kt @@ -20,7 +20,6 @@ package im.vector.riotredesign.features.themes import android.app.Activity import android.content.Context import android.graphics.drawable.Drawable -import android.text.TextUtils import android.util.TypedValue import android.view.Menu import androidx.annotation.AttrRes @@ -29,7 +28,6 @@ import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat import androidx.preference.PreferenceManager import im.vector.riotredesign.R -import im.vector.ui.themes.ActivityOtherThemes import timber.log.Timber import java.util.* @@ -56,7 +54,7 @@ object ThemeUtils { */ fun getApplicationTheme(context: Context): String { return PreferenceManager.getDefaultSharedPreferences(context) - .getString(APPLICATION_THEME_KEY, THEME_LIGHT_VALUE) + .getString(APPLICATION_THEME_KEY, THEME_LIGHT_VALUE)!! } /** @@ -65,20 +63,14 @@ object ThemeUtils { * @param aTheme the new theme */ fun setApplicationTheme(context: Context, aTheme: String) { - PreferenceManager.getDefaultSharedPreferences(context) - .edit() - .putString(APPLICATION_THEME_KEY, aTheme) - .apply() - - /* TODO when (aTheme) { - THEME_DARK_VALUE -> VectorApp.getInstance().setTheme(R.style.AppTheme_Dark) - THEME_BLACK_VALUE -> VectorApp.getInstance().setTheme(R.style.AppTheme_Black) - THEME_STATUS_VALUE -> VectorApp.getInstance().setTheme(R.style.AppTheme_Status) - else -> VectorApp.getInstance().setTheme(R.style.AppTheme_Light) + THEME_DARK_VALUE -> context.setTheme(R.style.AppTheme_Dark) + THEME_BLACK_VALUE -> context.setTheme(R.style.AppTheme_Black) + THEME_STATUS_VALUE -> context.setTheme(R.style.AppTheme_Status) + else -> context.setTheme(R.style.AppTheme_Light) } - */ + // Clear the cache mColorByAttr.clear() } @@ -89,8 +81,8 @@ object ThemeUtils { */ fun setActivityTheme(activity: Activity, otherThemes: ActivityOtherThemes) { when (getApplicationTheme(activity)) { - THEME_DARK_VALUE -> activity.setTheme(otherThemes.dark) - THEME_BLACK_VALUE -> activity.setTheme(otherThemes.black) + THEME_DARK_VALUE -> activity.setTheme(otherThemes.dark) + THEME_BLACK_VALUE -> activity.setTheme(otherThemes.black) THEME_STATUS_VALUE -> activity.setTheme(otherThemes.status) } @@ -164,7 +156,7 @@ object ThemeUtils { try { val typedValue = TypedValue() c.theme.resolveAttribute(attribute, typedValue, true) - return typedValue + return typedValue } catch (e: Exception) { Timber.e(e, "Unable to get color") } @@ -175,19 +167,41 @@ object ThemeUtils { * Get the resource Id applied to the current theme * * @param c the context - * @param resourceId the resource id + * @param resourceId the resource id in the light theme * @return the resource Id for the current theme */ fun getResourceId(c: Context, resourceId: Int): Int { - if (TextUtils.equals(getApplicationTheme(c), THEME_LIGHT_VALUE) - || TextUtils.equals(getApplicationTheme(c), THEME_STATUS_VALUE)) { - return when (resourceId) { - R.drawable.line_divider_dark -> R.drawable.line_divider_light - R.style.Floating_Actions_Menu -> R.style.Floating_Actions_Menu_Light - else -> resourceId + val theme = getApplicationTheme(c) + + return when (theme) { + THEME_LIGHT_VALUE -> resourceId + THEME_DARK_VALUE -> { + return when (resourceId) { + R.drawable.bg_search_edit_text_light -> R.drawable.bg_search_edit_text_dark + R.drawable.bg_unread_notification_light -> R.drawable.bg_unread_notification_dark + R.drawable.vector_label_background_light -> R.drawable.vector_label_background_dark + else -> { + Timber.w("Warning, missing case for wanted drawable in dark theme") + resourceId + } + } + } + THEME_BLACK_VALUE -> { + return when (resourceId) { + R.drawable.bg_search_edit_text_light -> R.drawable.bg_search_edit_text_black + R.drawable.bg_unread_notification_light -> R.drawable.bg_unread_notification_black + R.drawable.vector_label_background_light -> R.drawable.vector_label_background_black + else -> { + Timber.w("Warning, missing case for wanted drawable in black theme") + resourceId + } + } + } + else -> { + Timber.w("Warning, missing theme: $theme") + resourceId } } - return resourceId } /** diff --git a/vector/src/main/res/color/color_room_title.xml b/vector/src/main/res/color/color_room_title.xml deleted file mode 100644 index 1cda9bf6..00000000 --- a/vector/src/main/res/color/color_room_title.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/vector/src/main/res/drawable/bg_search_edit_text_black.xml b/vector/src/main/res/drawable/bg_search_edit_text_black.xml new file mode 100644 index 00000000..741e3c03 --- /dev/null +++ b/vector/src/main/res/drawable/bg_search_edit_text_black.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/vector/src/main/res/drawable/bg_search_edit_text.xml b/vector/src/main/res/drawable/bg_search_edit_text_dark.xml similarity index 67% rename from vector/src/main/res/drawable/bg_search_edit_text.xml rename to vector/src/main/res/drawable/bg_search_edit_text_dark.xml index bba3fa26..d65c331e 100644 --- a/vector/src/main/res/drawable/bg_search_edit_text.xml +++ b/vector/src/main/res/drawable/bg_search_edit_text_dark.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/vector/src/main/res/drawable/bg_search_edit_text_light.xml b/vector/src/main/res/drawable/bg_search_edit_text_light.xml new file mode 100644 index 00000000..ba0da296 --- /dev/null +++ b/vector/src/main/res/drawable/bg_search_edit_text_light.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/vector/src/main/res/drawable/bg_splash.xml b/vector/src/main/res/drawable/bg_splash.xml deleted file mode 100644 index 86e66697..00000000 --- a/vector/src/main/res/drawable/bg_splash.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vector/src/main/res/drawable/bg_unread_highlight.xml b/vector/src/main/res/drawable/bg_unread_highlight.xml index 87d7cae1..42a1e08b 100644 --- a/vector/src/main/res/drawable/bg_unread_highlight.xml +++ b/vector/src/main/res/drawable/bg_unread_highlight.xml @@ -4,5 +4,5 @@ - + \ No newline at end of file diff --git a/vector/src/main/res/drawable/bg_unread_notification_black.xml b/vector/src/main/res/drawable/bg_unread_notification_black.xml new file mode 100644 index 00000000..7059985f --- /dev/null +++ b/vector/src/main/res/drawable/bg_unread_notification_black.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/drawable/bg_unread_notification.xml b/vector/src/main/res/drawable/bg_unread_notification_dark.xml similarity index 73% rename from vector/src/main/res/drawable/bg_unread_notification.xml rename to vector/src/main/res/drawable/bg_unread_notification_dark.xml index 1f93e4dd..7f3669c5 100644 --- a/vector/src/main/res/drawable/bg_unread_notification.xml +++ b/vector/src/main/res/drawable/bg_unread_notification_dark.xml @@ -5,5 +5,5 @@ - + \ No newline at end of file diff --git a/vector/src/main/res/drawable/bg_unread_notification_light.xml b/vector/src/main/res/drawable/bg_unread_notification_light.xml new file mode 100644 index 00000000..944af91a --- /dev/null +++ b/vector/src/main/res/drawable/bg_unread_notification_light.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/drawable/circle.xml b/vector/src/main/res/drawable/circle.xml index 853d7c36..2c2d89ae 100644 --- a/vector/src/main/res/drawable/circle.xml +++ b/vector/src/main/res/drawable/circle.xml @@ -2,5 +2,5 @@ - + \ No newline at end of file diff --git a/vector/src/main/res/drawable/fg_group_item.xml b/vector/src/main/res/drawable/fg_group_item.xml deleted file mode 100644 index c6272163..00000000 --- a/vector/src/main/res/drawable/fg_group_item.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/vector/src/main/res/drawable/vector_label_background_black.xml b/vector/src/main/res/drawable/vector_label_background_black.xml new file mode 100644 index 00000000..dc85b060 --- /dev/null +++ b/vector/src/main/res/drawable/vector_label_background_black.xml @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/drawable/vector_label_background_dark.xml b/vector/src/main/res/drawable/vector_label_background_dark.xml new file mode 100644 index 00000000..1e375fbf --- /dev/null +++ b/vector/src/main/res/drawable/vector_label_background_dark.xml @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/drawable/vector_label_background_light.xml b/vector/src/main/res/drawable/vector_label_background_light.xml new file mode 100644 index 00000000..b09b0c7d --- /dev/null +++ b/vector/src/main/res/drawable/vector_label_background_light.xml @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/activity_bug_report.xml b/vector/src/main/res/layout/activity_bug_report.xml index 4d87ced7..2afeaa41 100644 --- a/vector/src/main/res/layout/activity_bug_report.xml +++ b/vector/src/main/res/layout/activity_bug_report.xml @@ -7,9 +7,9 @@ + android:layout_height="wrap_content" + android:elevation="4dp" /> + android:textColor="?riotx_text_primary" /> diff --git a/vector/src/main/res/layout/activity_emoji_reaction_picker.xml b/vector/src/main/res/layout/activity_emoji_reaction_picker.xml index 4744931b..38694933 100644 --- a/vector/src/main/res/layout/activity_emoji_reaction_picker.xml +++ b/vector/src/main/res/layout/activity_emoji_reaction_picker.xml @@ -26,8 +26,7 @@ android:elevation="4dp" android:minHeight="0dp" android:theme="@style/ThemeOverlay.AppCompat.ActionBar" - app:layout_scrollFlags="scroll|exitUntilCollapsed|snap|enterAlways" - app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> + app:layout_scrollFlags="scroll|exitUntilCollapsed|snap|enterAlways" /> + android:elevation="4dp" /> @@ -29,6 +30,7 @@ android:src="@drawable/logo_login" /> - - + android:orientation="horizontal"> - - + android:layout_marginTop="16dp" + android:hint="@string/auth_password_placeholder"> + + + + + + + + android:layout_height="wrap_content" + android:elevation="4dp" /> + android:elevation="4dp" /> + android:tint="?riotx_text_secondary" + tools:src="@drawable/ic_delete" /> diff --git a/vector/src/main/res/layout/adapter_item_action_quick_reaction.xml b/vector/src/main/res/layout/adapter_item_action_quick_reaction.xml index fef7b0ee..272f89a6 100644 --- a/vector/src/main/res/layout/adapter_item_action_quick_reaction.xml +++ b/vector/src/main/res/layout/adapter_item_action_quick_reaction.xml @@ -52,6 +52,7 @@ android:layout_marginTop="4dp" android:text="@string/reactions_agree" android:textAlignment="center" + android:textColor="?riotx_text_secondary" android:textStyle="bold" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/center_guideline" @@ -108,6 +109,7 @@ android:layout_height="wrap_content" android:text="@string/reactions_like" android:textAlignment="center" + android:textColor="?riotx_text_secondary" android:textStyle="bold" app:layout_constraintBottom_toBottomOf="@id/quick_react_agree_text" app:layout_constraintEnd_toEndOf="parent" diff --git a/vector/src/main/res/layout/bottom_sheet_logout_and_backup.xml b/vector/src/main/res/layout/bottom_sheet_logout_and_backup.xml index 6a86c0be..aeaa2fb9 100644 --- a/vector/src/main/res/layout/bottom_sheet_logout_and_backup.xml +++ b/vector/src/main/res/layout/bottom_sheet_logout_and_backup.xml @@ -16,6 +16,7 @@ android:layout_marginEnd="@dimen/layout_horizontal_margin" android:layout_marginBottom="8dp" android:text="@string/action_sign_out" + android:textColor="?riotx_text_primary" android:textSize="18sp" android:textStyle="bold" /> @@ -26,7 +27,7 @@ android:layout_marginStart="@dimen/layout_horizontal_margin" android:layout_marginEnd="@dimen/layout_horizontal_margin" android:layout_marginBottom="8dp" - android:textColor="?android:attr/textColorSecondary" + android:textColor="?riotx_text_secondary" tools:text="@string/sign_out_bottom_sheet_warning_no_backup" /> @@ -95,6 +97,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="@string/keys_backup_setup" + android:textColor="?riotx_text_secondary" android:textSize="17sp" /> @@ -128,6 +131,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" + android:textColor="?riotx_text_secondary" android:text="@string/keys_backup_activate" android:textSize="17sp" /> @@ -155,14 +159,14 @@ android:layout_marginRight="16dp" android:scaleType="fitCenter" android:src="@drawable/ic_material_leave" - android:tint="@color/vector_error_color" /> + android:tint="@color/riotx_notice" /> @@ -188,14 +192,14 @@ android:layout_marginEnd="16dp" android:layout_marginRight="16dp" android:src="@drawable/ic_material_exit_to_app" - android:tint="@color/vector_error_color" /> + android:tint="@color/riotx_notice" /> diff --git a/vector/src/main/res/layout/bottom_sheet_message_actions.xml b/vector/src/main/res/layout/bottom_sheet_message_actions.xml index 967bbe42..0de471bd 100644 --- a/vector/src/main/res/layout/bottom_sheet_message_actions.xml +++ b/vector/src/main/res/layout/bottom_sheet_message_actions.xml @@ -42,6 +42,7 @@ android:ellipsize="end" android:fontFamily="sans-serif-bold" android:singleLine="true" + android:textColor="?riotx_text_primary" android:textSize="14sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" @@ -49,8 +50,7 @@ app:layout_constraintTop_toTopOf="@id/bottom_sheet_message_preview_avatar" tools:text="@tools:sample/full_names" /> - + app:layout_constraintStart_toEndOf="parent" + tools:visibility="visible" /> - \ No newline at end of file diff --git a/vector/src/main/res/layout/constraint_set_composer_layout_expanded.xml b/vector/src/main/res/layout/constraint_set_composer_layout_expanded.xml index 48048e62..f71ccf5e 100644 --- a/vector/src/main/res/layout/constraint_set_composer_layout_expanded.xml +++ b/vector/src/main/res/layout/constraint_set_composer_layout_expanded.xml @@ -96,7 +96,7 @@ android:layout_marginRight="8dp" android:background="?android:attr/selectableItemBackground" android:src="@drawable/ic_close_round" - android:tint="@color/rosy_pink" + android:tint="@color/riotx_notice" app:layout_constraintBottom_toBottomOf="@id/composer_related_message_preview" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@id/composer_related_message_preview" /> diff --git a/vector/src/main/res/layout/constraint_set_fab_menu_close.xml b/vector/src/main/res/layout/constraint_set_fab_menu_close.xml new file mode 100644 index 00000000..4df0e8d0 --- /dev/null +++ b/vector/src/main/res/layout/constraint_set_fab_menu_close.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/constraint_set_fab_menu_open.xml b/vector/src/main/res/layout/constraint_set_fab_menu_open.xml new file mode 100644 index 00000000..fc47458e --- /dev/null +++ b/vector/src/main/res/layout/constraint_set_fab_menu_open.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/dialog_change_password.xml b/vector/src/main/res/layout/dialog_change_password.xml index 9fa28afd..925859bc 100644 --- a/vector/src/main/res/layout/dialog_change_password.xml +++ b/vector/src/main/res/layout/dialog_change_password.xml @@ -37,6 +37,7 @@ @@ -50,6 +51,7 @@ @@ -64,6 +66,7 @@ diff --git a/vector/src/main/res/layout/fragment_home_detail.xml b/vector/src/main/res/layout/fragment_home_detail.xml index fd39b751..a54fa61e 100644 --- a/vector/src/main/res/layout/fragment_home_detail.xml +++ b/vector/src/main/res/layout/fragment_home_detail.xml @@ -8,15 +8,12 @@ + app:layout_constraintTop_toTopOf="parent"> @@ -51,7 +48,7 @@ android:id="@+id/roomListContainer" android:layout_width="match_parent" android:layout_height="0dp" - android:background="#F3F8FD" + android:background="?riotx_header_panel_background" app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView" app:layout_constraintTop_toBottomOf="@+id/groupToolbar" /> @@ -59,10 +56,8 @@ android:id="@+id/bottomNavigationView" android:layout_width="0dp" android:layout_height="48dp" - android:background="#FFFFFF" + android:background="?riotx_background" app:itemIconSize="20dp" - app:itemIconTint="@color/home_bottom_nav_view_tint" - app:itemTextColor="@color/home_bottom_nav_view_tint" app:labelVisibilityMode="unlabeled" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/vector/src/main/res/layout/fragment_home_drawer.xml b/vector/src/main/res/layout/fragment_home_drawer.xml index 8bbd52c2..fd60368b 100644 --- a/vector/src/main/res/layout/fragment_home_drawer.xml +++ b/vector/src/main/res/layout/fragment_home_drawer.xml @@ -11,11 +11,22 @@ android:id="@+id/homeDrawerHeader" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?attr/colorPrimary" + android:background="?riotx_base" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> + + + android:background="?riotx_header_panel_background"> - - - + android:layout_height="match_parent"> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + -