Add rageskahe module
This commit is contained in:
parent
0644a5822f
commit
3f7a83c519
64 changed files with 3191 additions and 35 deletions
|
|
@ -1,2 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest />
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
</manifest>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package io.element.android.x.core.bitmap
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import java.io.File
|
||||
|
||||
fun File.writeBitmap(bitmap: Bitmap, format: Bitmap.CompressFormat, quality: Int) {
|
||||
outputStream().use { out ->
|
||||
bitmap.compress(format, quality, out)
|
||||
out.flush()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package io.element.android.x.core.bool
|
||||
|
||||
fun Boolean?.orTrue() = this ?: true
|
||||
|
||||
fun Boolean?.orFalse() = this ?: false
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package io.element.android.x.core.extensions
|
||||
|
||||
import android.util.Patterns
|
||||
|
||||
fun Boolean.toOnOff() = if (this) "ON" else "OFF"
|
||||
|
||||
inline fun <T> T.ooi(block: (T) -> Unit): T = also(block)
|
||||
|
||||
/**
|
||||
* Check if a CharSequence is an email.
|
||||
*/
|
||||
fun CharSequence.isEmail() = Patterns.EMAIL_ADDRESS.matcher(this).matches()
|
||||
|
||||
// fun CharSequence.isMatrixId() = MatrixPatterns.isUserId(this.toString())
|
||||
|
||||
/**
|
||||
* Return empty CharSequence if the CharSequence is null.
|
||||
*/
|
||||
fun CharSequence?.orEmpty() = this ?: ""
|
||||
|
||||
/**
|
||||
* Check if a CharSequence is a phone number.
|
||||
*/
|
||||
/*
|
||||
fun CharSequence.isMsisdn(): Boolean {
|
||||
return try {
|
||||
PhoneNumberUtil.getInstance().parse(ensurePrefix("+"), null)
|
||||
true
|
||||
} catch (e: NumberParseException) {
|
||||
false
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Useful to append a String at the end of a filename but before the extension if any
|
||||
* Ex:
|
||||
* - "file.txt".insertBeforeLast("_foo") will return "file_foo.txt"
|
||||
* - "file".insertBeforeLast("_foo") will return "file_foo"
|
||||
* - "fi.le.txt".insertBeforeLast("_foo") will return "fi.le_foo.txt"
|
||||
* - null.insertBeforeLast("_foo") will return "_foo".
|
||||
*/
|
||||
fun String?.insertBeforeLast(insert: String, delimiter: String = "."): String {
|
||||
if (this == null) return insert
|
||||
val idx = lastIndexOf(delimiter)
|
||||
return if (idx == -1) {
|
||||
this + insert
|
||||
} else {
|
||||
replaceRange(idx, idx, insert)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified R> Any?.takeAs(): R? {
|
||||
return takeIf { it is R } as R?
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package io.element.android.x.core.file
|
||||
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.util.zip.GZIPOutputStream
|
||||
|
||||
/**
|
||||
* GZip a file.
|
||||
*
|
||||
* @param file the input file
|
||||
* @return the gzipped file
|
||||
*/
|
||||
fun compressFile(file: File): File? {
|
||||
Timber.v("## compressFile() : compress ${file.name}")
|
||||
|
||||
val dstFile = file.resolveSibling(file.name + ".gz")
|
||||
|
||||
if (dstFile.exists()) {
|
||||
dstFile.delete()
|
||||
}
|
||||
|
||||
return try {
|
||||
GZIPOutputStream(dstFile.outputStream()).use { gos ->
|
||||
file.inputStream().use {
|
||||
it.copyTo(gos, 2048)
|
||||
}
|
||||
}
|
||||
|
||||
Timber.v("## compressFile() : ${file.length()} compressed to ${dstFile.length()} bytes")
|
||||
dstFile
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## compressFile() failed")
|
||||
null
|
||||
} catch (oom: OutOfMemoryError) {
|
||||
Timber.e(oom, "## compressFile() failed")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2020 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 io.element.android.x.core.hardware
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.VibrationEffect
|
||||
import android.os.Vibrator
|
||||
import androidx.core.content.getSystemService
|
||||
|
||||
fun Context.vibrate(durationMillis: Long = 100) {
|
||||
val vibrator = getSystemService<Vibrator>() ?: return
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
vibrator.vibrate(VibrationEffect.createOneShot(durationMillis, VibrationEffect.DEFAULT_AMPLITUDE))
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
vibrator.vibrate(durationMillis)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 io.element.android.x.core.mimetype
|
||||
|
||||
import io.element.android.x.core.bool.orFalse
|
||||
|
||||
// The Android SDK does not provide constant for mime type, add some of them here
|
||||
object MimeTypes {
|
||||
const val Any: String = "*/*"
|
||||
const val OctetStream = "application/octet-stream"
|
||||
const val Apk = "application/vnd.android.package-archive"
|
||||
|
||||
const val Images = "image/*"
|
||||
|
||||
const val Png = "image/png"
|
||||
const val BadJpg = "image/jpg"
|
||||
const val Jpeg = "image/jpeg"
|
||||
const val Gif = "image/gif"
|
||||
|
||||
const val Ogg = "audio/ogg"
|
||||
|
||||
const val PlainText = "text/plain"
|
||||
|
||||
fun String?.normalizeMimeType() = if (this == BadJpg) Jpeg else this
|
||||
|
||||
fun String?.isMimeTypeImage() = this?.startsWith("image/").orFalse()
|
||||
fun String?.isMimeTypeVideo() = this?.startsWith("video/").orFalse()
|
||||
fun String?.isMimeTypeAudio() = this?.startsWith("audio/").orFalse()
|
||||
fun String?.isMimeTypeApplication() = this?.startsWith("application/").orFalse()
|
||||
fun String?.isMimeTypeFile() = this?.startsWith("file/").orFalse()
|
||||
fun String?.isMimeTypeText() = this?.startsWith("text/").orFalse()
|
||||
fun String?.isMimeTypeAny() = this?.startsWith("*/").orFalse()
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package io.element.android.x.core.screenshot
|
||||
|
||||
import android.app.Activity
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.PixelCopy
|
||||
import android.view.View
|
||||
|
||||
fun View.screenshot(bitmapCallback: (ImageResult) -> Unit) {
|
||||
try {
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
val bitmap = Bitmap.createBitmap(
|
||||
width,
|
||||
height,
|
||||
Bitmap.Config.ARGB_8888,
|
||||
)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
PixelCopy.request(
|
||||
(this.context as Activity).window,
|
||||
clipBounds,
|
||||
bitmap,
|
||||
{
|
||||
when (it) {
|
||||
PixelCopy.SUCCESS -> {
|
||||
bitmapCallback.invoke(ImageResult.Success(bitmap))
|
||||
}
|
||||
else -> {
|
||||
bitmapCallback.invoke(ImageResult.Error(Exception(it.toString())))
|
||||
}
|
||||
}
|
||||
},
|
||||
handler
|
||||
)
|
||||
} else {
|
||||
handler.post {
|
||||
val canvas = Canvas(bitmap)
|
||||
.apply {
|
||||
translate(-clipBounds.left.toFloat(), -clipBounds.top.toFloat())
|
||||
}
|
||||
this.draw(canvas)
|
||||
canvas.setBitmap(null)
|
||||
bitmapCallback.invoke(ImageResult.Success(bitmap))
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
bitmapCallback.invoke(ImageResult.Error(e))
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface ImageResult {
|
||||
data class Error(val exception: Exception) : ImageResult
|
||||
data class Success(val data: Bitmap) : ImageResult
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue