mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-04-26 16:48:35 +00:00
Added plain text file viewer
This commit is contained in:
parent
de2f247c5f
commit
5d3d8eeedc
12 changed files with 122 additions and 35 deletions
|
|
@ -30,7 +30,6 @@ import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.webkit.MimeTypeMap
|
|
||||||
import androidx.annotation.AnyThread
|
import androidx.annotation.AnyThread
|
||||||
import androidx.annotation.MainThread
|
import androidx.annotation.MainThread
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
|
|
@ -749,7 +748,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
val filePath = contentUri.toString()
|
val filePath = contentUri.toString()
|
||||||
val extension = FileUtils.getExtensionFromFileName(filePath)
|
val extension = FileUtils.getExtensionFromFileName(filePath)
|
||||||
if (extension.isNotEmpty()) {
|
if (extension.isNotEmpty()) {
|
||||||
val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
|
val mime = FileUtils.getMimeTypeFromExtension(extension)
|
||||||
notifiableMessage.filePath = contentUri
|
notifiableMessage.filePath = contentUri
|
||||||
notifiableMessage.fileMime = mime
|
notifiableMessage.fileMime = mime
|
||||||
Log.i("$TAG Added file $contentUri with MIME $mime to notification")
|
Log.i("$TAG Added file $contentUri with MIME $mime to notification")
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.animation.Animation
|
import android.view.animation.Animation
|
||||||
import android.view.animation.AnimationUtils
|
import android.view.animation.AnimationUtils
|
||||||
import android.webkit.MimeTypeMap
|
|
||||||
import androidx.annotation.UiThread
|
import androidx.annotation.UiThread
|
||||||
import androidx.core.view.doOnPreDraw
|
import androidx.core.view.doOnPreDraw
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
|
@ -244,9 +243,9 @@ class ConversationsListFragment : AbstractTopBarFragment() {
|
||||||
if (findNavController().currentDestination?.id == R.id.conversationsListFragment) {
|
if (findNavController().currentDestination?.id == R.id.conversationsListFragment) {
|
||||||
Log.i("$TAG Navigating to file viewer fragment with path [$path]")
|
Log.i("$TAG Navigating to file viewer fragment with path [$path]")
|
||||||
val extension = FileUtils.getExtensionFromFileName(path)
|
val extension = FileUtils.getExtensionFromFileName(path)
|
||||||
val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
|
val mime = FileUtils.getMimeTypeFromExtension(extension)
|
||||||
when (FileUtils.getMimeType(mime)) {
|
when (FileUtils.getMimeType(mime)) {
|
||||||
FileUtils.MimeType.Image, FileUtils.MimeType.Video, FileUtils.MimeType.Pdf -> {
|
FileUtils.MimeType.Image, FileUtils.MimeType.Video, FileUtils.MimeType.Pdf, FileUtils.MimeType.PlainText -> {
|
||||||
val action =
|
val action =
|
||||||
FileViewerFragmentDirections.actionGlobalFileViewerFragment(path)
|
FileViewerFragmentDirections.actionGlobalFileViewerFragment(path)
|
||||||
findNavController().navigate(action)
|
findNavController().navigate(action)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package org.linphone.ui.main.chat.model
|
package org.linphone.ui.main.chat.model
|
||||||
|
|
||||||
import android.webkit.MimeTypeMap
|
|
||||||
import androidx.annotation.AnyThread
|
import androidx.annotation.AnyThread
|
||||||
import androidx.annotation.UiThread
|
import androidx.annotation.UiThread
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
|
@ -41,7 +40,7 @@ class FileModel @AnyThread constructor(
|
||||||
val extension = FileUtils.getExtensionFromFileName(file)
|
val extension = FileUtils.getExtensionFromFileName(file)
|
||||||
isPdf = extension == "pdf"
|
isPdf = extension == "pdf"
|
||||||
|
|
||||||
val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
|
val mime = FileUtils.getMimeTypeFromExtension(extension)
|
||||||
mimeType = FileUtils.getMimeType(mime)
|
mimeType = FileUtils.getMimeType(mime)
|
||||||
isImage = mimeType == FileUtils.MimeType.Image
|
isImage = mimeType == FileUtils.MimeType.Image
|
||||||
isVideoPreview = mimeType == FileUtils.MimeType.Video
|
isVideoPreview = mimeType == FileUtils.MimeType.Video
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ class FileViewerFragment : GenericFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
postponeEnterTransition()
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this)[FileViewModel::class.java]
|
viewModel = ViewModelProvider(this)[FileViewModel::class.java]
|
||||||
|
|
@ -75,6 +76,21 @@ class FileViewerFragment : GenericFragment() {
|
||||||
goBack()
|
goBack()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.fileReadyEvent.observe(viewLifecycleOwner) {
|
||||||
|
it.consume { done ->
|
||||||
|
if (done) {
|
||||||
|
(view.parent as? ViewGroup)?.doOnPreDraw {
|
||||||
|
startPostponedEnterTransition()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(view.parent as? ViewGroup)?.doOnPreDraw {
|
||||||
|
Log.e("$TAG Failed to open file, going back")
|
||||||
|
goBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.setShareClickListener {
|
binding.setShareClickListener {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val filePath = FileUtils.getProperFilePath(path)
|
val filePath = FileUtils.getProperFilePath(path)
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,17 @@ import android.net.Uri
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.os.ParcelFileDescriptor
|
import android.os.ParcelFileDescriptor
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.webkit.MimeTypeMap
|
import android.text.PrecomputedText
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.annotation.UiThread
|
import androidx.annotation.UiThread
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import java.io.BufferedReader
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.FileReader
|
||||||
import java.lang.IllegalStateException
|
import java.lang.IllegalStateException
|
||||||
|
import java.lang.StringBuilder
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
@ -50,6 +53,12 @@ class FileViewModel @UiThread constructor() : ViewModel() {
|
||||||
|
|
||||||
val isVideoPlaying = MutableLiveData<Boolean>()
|
val isVideoPlaying = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
val isText = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
val text = MutableLiveData<String>()
|
||||||
|
|
||||||
|
val fileReadyEvent = MutableLiveData<Event<Boolean>>()
|
||||||
|
|
||||||
val pdfRendererReadyEvent: MutableLiveData<Event<Boolean>> by lazy {
|
val pdfRendererReadyEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||||
MutableLiveData<Event<Boolean>>()
|
MutableLiveData<Event<Boolean>>()
|
||||||
}
|
}
|
||||||
|
|
@ -100,45 +109,34 @@ class FileViewModel @UiThread constructor() : ViewModel() {
|
||||||
fileName.value = name
|
fileName.value = name
|
||||||
|
|
||||||
val extension = FileUtils.getExtensionFromFileName(name)
|
val extension = FileUtils.getExtensionFromFileName(name)
|
||||||
val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
|
val mime = FileUtils.getMimeTypeFromExtension(extension)
|
||||||
when (FileUtils.getMimeType(mime)) {
|
when (FileUtils.getMimeType(mime)) {
|
||||||
FileUtils.MimeType.Pdf -> {
|
FileUtils.MimeType.Pdf -> {
|
||||||
Log.i("$TAG File [$file] seems to be a PDF")
|
Log.i("$TAG File [$file] seems to be a PDF")
|
||||||
isPdf.value = true
|
loadPdf()
|
||||||
|
|
||||||
viewModelScope.launch {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
val input = ParcelFileDescriptor.open(
|
|
||||||
File(file),
|
|
||||||
ParcelFileDescriptor.MODE_READ_ONLY
|
|
||||||
)
|
|
||||||
pdfRenderer = PdfRenderer(input)
|
|
||||||
val count = pdfRenderer.pageCount
|
|
||||||
Log.i("$TAG $count pages in file $file")
|
|
||||||
pdfPages.postValue(count.toString())
|
|
||||||
pdfCurrentPage.postValue("1")
|
|
||||||
pdfRendererReadyEvent.postValue(Event(true))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
FileUtils.MimeType.Image -> {
|
FileUtils.MimeType.Image -> {
|
||||||
Log.i("$TAG File [$file] seems to be an image")
|
Log.i("$TAG File [$file] seems to be an image")
|
||||||
isImage.value = true
|
isImage.value = true
|
||||||
path.value = file
|
path.value = file
|
||||||
|
fileReadyEvent.value = Event(true)
|
||||||
}
|
}
|
||||||
FileUtils.MimeType.Video -> {
|
FileUtils.MimeType.Video -> {
|
||||||
Log.i("$TAG File [$file] seems to be a video")
|
Log.i("$TAG File [$file] seems to be a video")
|
||||||
isVideo.value = true
|
isVideo.value = true
|
||||||
isVideoPlaying.value = false
|
isVideoPlaying.value = false
|
||||||
|
fileReadyEvent.value = Event(true)
|
||||||
}
|
}
|
||||||
FileUtils.MimeType.Audio -> {
|
FileUtils.MimeType.Audio -> {
|
||||||
// TODO: handle audio files
|
// TODO: handle audio files
|
||||||
|
fileReadyEvent.value = Event(true)
|
||||||
}
|
}
|
||||||
FileUtils.MimeType.PlainText -> {
|
FileUtils.MimeType.PlainText -> {
|
||||||
// TODO: handle plain text files
|
Log.i("$TAG File [$file] seems to be plain text")
|
||||||
|
loadPlainText()
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
// TODO: open native app for unsupported files
|
fileReadyEvent.value = Event(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -261,6 +259,51 @@ class FileViewModel @UiThread constructor() : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadPdf() {
|
||||||
|
isPdf.value = true
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val input = ParcelFileDescriptor.open(
|
||||||
|
File(filePath),
|
||||||
|
ParcelFileDescriptor.MODE_READ_ONLY
|
||||||
|
)
|
||||||
|
pdfRenderer = PdfRenderer(input)
|
||||||
|
val count = pdfRenderer.pageCount
|
||||||
|
Log.i("$TAG $count pages in file $filePath")
|
||||||
|
pdfPages.postValue(count.toString())
|
||||||
|
pdfCurrentPage.postValue("1")
|
||||||
|
pdfRendererReadyEvent.postValue(Event(true))
|
||||||
|
fileReadyEvent.postValue(Event(true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadPlainText() {
|
||||||
|
isText.value = true
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
val br = BufferedReader(FileReader(filePath))
|
||||||
|
var line: String?
|
||||||
|
val textBuilder = StringBuilder()
|
||||||
|
while (br.readLine().also { line = it } != null) {
|
||||||
|
textBuilder.append(line)
|
||||||
|
textBuilder.append('\n')
|
||||||
|
}
|
||||||
|
br.close()
|
||||||
|
text.postValue(textBuilder.toString())
|
||||||
|
Log.i("$TAG Finished reading file [$filePath]")
|
||||||
|
fileReadyEvent.postValue(Event(true))
|
||||||
|
// TODO FIXME : improve performances !
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("$TAG Exception trying to read file [$filePath] as text: $e")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private suspend fun addContentToMediaStore(
|
private suspend fun addContentToMediaStore(
|
||||||
path: String
|
path: String
|
||||||
|
|
@ -285,7 +328,7 @@ class FileViewModel @UiThread constructor() : ViewModel() {
|
||||||
val relativePath = "$directory/$appName"
|
val relativePath = "$directory/$appName"
|
||||||
val fileName = FileUtils.getNameFromFilePath(path)
|
val fileName = FileUtils.getNameFromFilePath(path)
|
||||||
val extension = FileUtils.getExtensionFromFileName(fileName)
|
val extension = FileUtils.getExtensionFromFileName(fileName)
|
||||||
val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
|
val mime = FileUtils.getMimeTypeFromExtension(extension)
|
||||||
|
|
||||||
val context = coreContext.context
|
val context = coreContext.context
|
||||||
val mediaStoreFilePath = when {
|
val mediaStoreFilePath = when {
|
||||||
|
|
|
||||||
|
|
@ -65,21 +65,21 @@ class FileUtils {
|
||||||
@AnyThread
|
@AnyThread
|
||||||
fun isExtensionImage(path: String): Boolean {
|
fun isExtensionImage(path: String): Boolean {
|
||||||
val extension = getExtensionFromFileName(path)
|
val extension = getExtensionFromFileName(path)
|
||||||
val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
|
val type = getMimeTypeFromExtension(extension)
|
||||||
return getMimeType(type) == MimeType.Image
|
return getMimeType(type) == MimeType.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
@AnyThread
|
@AnyThread
|
||||||
fun isExtensionVideo(path: String): Boolean {
|
fun isExtensionVideo(path: String): Boolean {
|
||||||
val extension = getExtensionFromFileName(path)
|
val extension = getExtensionFromFileName(path)
|
||||||
val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
|
val type = getMimeTypeFromExtension(extension)
|
||||||
return getMimeType(type) == MimeType.Video
|
return getMimeType(type) == MimeType.Video
|
||||||
}
|
}
|
||||||
|
|
||||||
@AnyThread
|
@AnyThread
|
||||||
fun isExtensionAudio(path: String): Boolean {
|
fun isExtensionAudio(path: String): Boolean {
|
||||||
val extension = getExtensionFromFileName(path)
|
val extension = getExtensionFromFileName(path)
|
||||||
val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
|
val type = getMimeTypeFromExtension(extension)
|
||||||
return getMimeType(type) == MimeType.Audio
|
return getMimeType(type) == MimeType.Audio
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,12 +96,18 @@ class FileUtils {
|
||||||
return extension.lowercase(Locale.getDefault())
|
return extension.lowercase(Locale.getDefault())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AnyThread
|
||||||
|
fun getMimeTypeFromExtension(extension: String): String {
|
||||||
|
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) ?: "file/$extension"
|
||||||
|
}
|
||||||
|
|
||||||
@AnyThread
|
@AnyThread
|
||||||
fun getMimeType(type: String?): MimeType {
|
fun getMimeType(type: String?): MimeType {
|
||||||
if (type.isNullOrEmpty()) return MimeType.Unknown
|
if (type.isNullOrEmpty()) return MimeType.Unknown
|
||||||
return when {
|
return when {
|
||||||
type.startsWith("image/") -> MimeType.Image
|
type.startsWith("image/") -> MimeType.Image
|
||||||
type.startsWith("text/plain") -> MimeType.PlainText
|
type.startsWith("text/") -> MimeType.PlainText
|
||||||
|
type.endsWith("/log") -> MimeType.PlainText
|
||||||
type.startsWith("video/") -> MimeType.Video
|
type.startsWith("video/") -> MimeType.Video
|
||||||
type.startsWith("audio/") -> MimeType.Audio
|
type.startsWith("audio/") -> MimeType.Audio
|
||||||
type.startsWith("application/pdf") -> MimeType.Pdf
|
type.startsWith("application/pdf") -> MimeType.Pdf
|
||||||
|
|
@ -220,7 +226,7 @@ class FileUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
val extension = getExtensionFromFileName(name)
|
val extension = getExtensionFromFileName(name)
|
||||||
val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
|
val type = getMimeTypeFromExtension(extension)
|
||||||
val isImage = getMimeType(type) == MimeType.Image
|
val isImage = getMimeType(type) == MimeType.Image
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@
|
||||||
android:layout_height="@dimen/chat_bubble_big_image_max_size"
|
android:layout_height="@dimen/chat_bubble_big_image_max_size"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
android:visibility="@{model.filesList.size() == 1 && model.firstImagePath.length() >= 0 ? View.VISIBLE : View.GONE, default=gone}"
|
android:visibility="@{model.filesList.size() == 1 && model.firstImagePath.length() > 0 ? View.VISIBLE : View.GONE, default=gone}"
|
||||||
coilBubble="@{model.firstImagePath}"/>
|
coilBubble="@{model.firstImagePath}"/>
|
||||||
|
|
||||||
<ViewStub
|
<ViewStub
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@
|
||||||
android:layout_height="@dimen/chat_bubble_big_image_max_size"
|
android:layout_height="@dimen/chat_bubble_big_image_max_size"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
android:visibility="@{model.filesList.size() == 1 && model.firstImagePath.length() >= 0 ? View.VISIBLE : View.GONE, default=gone}"
|
android:visibility="@{model.filesList.size() == 1 && model.firstImagePath.length() > 0 ? View.VISIBLE : View.GONE, default=gone}"
|
||||||
coilBubble="@{model.firstImagePath}"/>
|
coilBubble="@{model.firstImagePath}"/>
|
||||||
|
|
||||||
<ViewStub
|
<ViewStub
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,27 @@
|
||||||
coilFile="@{viewModel.path}"
|
coilFile="@{viewModel.path}"
|
||||||
android:visibility="@{viewModel.isImage ? View.VISIBLE : View.GONE, default=gone}" />
|
android:visibility="@{viewModel.isImage ? View.VISIBLE : View.GONE, default=gone}" />
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/text"
|
||||||
|
android:background="?attr/color_main2_000"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="@{viewModel.isText ? View.VISIBLE : View.GONE, default=gone}" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/default_text_style"
|
||||||
|
android:onClick="@{() -> viewModel.toggleFullScreen()}"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:singleLine="false"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textColor="?attr/color_main2_900"
|
||||||
|
android:text="@{viewModel.text}"/>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/back"
|
android:id="@+id/back"
|
||||||
android:onClick="@{backClickListener}"
|
android:onClick="@{backClickListener}"
|
||||||
|
|
@ -159,4 +180,5 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"/>
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
<item name="color_main2_600">@color/gray_main2_400</item>
|
<item name="color_main2_600">@color/gray_main2_400</item>
|
||||||
<item name="color_main2_700">@color/gray_main2_300</item>
|
<item name="color_main2_700">@color/gray_main2_300</item>
|
||||||
<item name="color_main2_800">@color/gray_main2_200</item>
|
<item name="color_main2_800">@color/gray_main2_200</item>
|
||||||
|
<item name="color_main2_900">@color/white</item>
|
||||||
|
|
||||||
<item name="color_grey_100">@color/gray_900</item>
|
<item name="color_grey_100">@color/gray_900</item>
|
||||||
<item name="color_grey_200">@color/gray_800</item>
|
<item name="color_grey_200">@color/gray_800</item>
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
<attr name="color_main2_600" format="color"/>
|
<attr name="color_main2_600" format="color"/>
|
||||||
<attr name="color_main2_700" format="color"/>
|
<attr name="color_main2_700" format="color"/>
|
||||||
<attr name="color_main2_800" format="color"/>
|
<attr name="color_main2_800" format="color"/>
|
||||||
|
<attr name="color_main2_900" format="color"/>
|
||||||
|
|
||||||
<attr name="color_grey_100" format="color"/>
|
<attr name="color_grey_100" format="color"/>
|
||||||
<attr name="color_grey_200" format="color"/>
|
<attr name="color_grey_200" format="color"/>
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
<item name="color_main2_600">@color/gray_main2_600</item>
|
<item name="color_main2_600">@color/gray_main2_600</item>
|
||||||
<item name="color_main2_700">@color/gray_main2_700</item>
|
<item name="color_main2_700">@color/gray_main2_700</item>
|
||||||
<item name="color_main2_800">@color/gray_main2_800</item>
|
<item name="color_main2_800">@color/gray_main2_800</item>
|
||||||
|
<item name="color_main2_900">@color/black</item>
|
||||||
|
|
||||||
<item name="color_grey_100">@color/gray_100</item>
|
<item name="color_grey_100">@color/gray_100</item>
|
||||||
<item name="color_grey_200">@color/gray_200</item>
|
<item name="color_grey_200">@color/gray_200</item>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue