Files
rider-pro-android-app/app/src/main/java/com/aiosman/ravenow/utils/Utils.kt
AllenTom a215d79ce8 Feat: Add News tab and related functionality
- Added a "News" tab to the main index screen.
- Implemented API parameters for fetching news-specific posts: `imageTag`, `search`, `advancedSearch`, `newsFilter`, `onlyNews`, `newsSource`, `newsLanguage`, `newsCategory`, `requireImageCache`.
- Updated `Moment` data class and `MomentEntity` to include news-related fields like `isNews`, `newsTitle`, `newsUrl`, etc.
- Created `News.kt` composable and `NewsViewModel.kt` to display and manage news items.
- Updated `MomentLoader` to include a `newsOnly` parameter for fetching only news items.
- Added Japanese translations for new index tab strings: "Worldwide", "Dynamic", "Following", "Hot", and "News".
- Adjusted tab count and layout based on guest/logged-in user status to accommodate the new "News" tab.
2025-09-16 14:08:50 +08:00

110 lines
3.8 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.aiosman.ravenow.utils
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import coil.ImageLoader
import coil.request.CachePolicy
import com.aiosman.ravenow.data.api.AuthInterceptor
import com.aiosman.ravenow.data.api.getSafeOkHttpClient
import java.io.File
import java.io.FileOutputStream
import java.util.Date
import java.util.Locale
import java.util.UUID
import java.util.concurrent.TimeUnit
object Utils {
// 全局共享的 ImageLoader避免每次创建导致内存缓存不共享
private var sharedImageLoader: ImageLoader? = null
fun generateRandomString(length: Int): String {
val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9')
return (1..length)
.map { allowedChars.random() }
.joinToString("")
}
fun getImageLoader(context: Context): ImageLoader {
val appContext = context.applicationContext
val existing = sharedImageLoader
if (existing != null) return existing
val okHttpClient = getSafeOkHttpClient(authInterceptor = AuthInterceptor())
val loader = ImageLoader.Builder(appContext)
.okHttpClient(okHttpClient)
.memoryCachePolicy(CachePolicy.ENABLED)
.diskCachePolicy(CachePolicy.ENABLED)
.build()
sharedImageLoader = loader
return loader
}
fun getTimeAgo(date: Date): String {
val now = Date()
val diffInMillis = now.time - date.time
val seconds = TimeUnit.MILLISECONDS.toSeconds(diffInMillis)
val minutes = TimeUnit.MILLISECONDS.toMinutes(diffInMillis)
val hours = TimeUnit.MILLISECONDS.toHours(diffInMillis)
val days = TimeUnit.MILLISECONDS.toDays(diffInMillis)
val years = days / 365
return when {
seconds < 60 -> "$seconds seconds ago"
minutes < 60 -> "$minutes minutes ago"
hours < 24 -> "$hours hours ago"
days < 365 -> "$days days ago"
else -> "$years years ago"
}
}
fun getCurrentLanguage(): String {
return Locale.getDefault().language
}
/**
* 获取当前系统语言的完整标签,包含国家/地区代码
* 返回格式en, ja, zh-CN, zh-TW 等
*/
fun getCurrentLanguageTag(): String {
val locale = Locale.getDefault()
val language = locale.language
val country = locale.country
return when {
// 中文需要区分简体和繁体
language == "zh" && country.isNotEmpty() -> "$language-$country"
// 其他语言通常只需要语言代码
else -> language
}
}
fun compressImage(context: Context, uri: Uri, maxSize: Int = 512, quality: Int = 85): File {
val inputStream = context.contentResolver.openInputStream(uri)
val originalBitmap = BitmapFactory.decodeStream(inputStream)
val (width, height) = originalBitmap.width to originalBitmap.height
val (newWidth, newHeight) = if (width > height) {
maxSize to (height * maxSize / width)
} else {
(width * maxSize / height) to maxSize
}
val scaledBitmap = Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, true)
val uuidImageName = UUID.randomUUID().toString().let { "$it.jpg" }
val compressedFile = File(context.cacheDir, uuidImageName)
val outputStream = FileOutputStream(compressedFile)
if (quality > 100) {
throw IllegalArgumentException("Quality must be less than 100")
}
if (quality < 0) {
throw IllegalArgumentException("Quality must be greater than 0")
}
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream)
outputStream.flush()
outputStream.close()
return compressedFile
}
}