refactor(logging): introduce custom FastLogger and replace direct Android logging
This commit is contained in:
@@ -92,6 +92,7 @@ dependencies {
|
||||
implementation(projects.feature.photoviewer)
|
||||
implementation(projects.feature.createchat)
|
||||
|
||||
implementation(projects.core.logger)
|
||||
implementation(projects.core.common)
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.data)
|
||||
|
||||
@@ -2,7 +2,6 @@ package dev.meloda.fast
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.os.LocaleListCompat
|
||||
@@ -23,6 +22,7 @@ import dev.meloda.fast.datastore.AppSettings
|
||||
import dev.meloda.fast.datastore.UserSettings
|
||||
import dev.meloda.fast.domain.GetCurrentAccountUseCase
|
||||
import dev.meloda.fast.domain.LoadUserByIdUseCase
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import dev.meloda.fast.model.BaseError
|
||||
import dev.meloda.fast.model.api.domain.VkUser
|
||||
import dev.meloda.fast.navigation.Main
|
||||
@@ -67,7 +67,8 @@ class MainViewModelImpl(
|
||||
private val getCurrentAccountUseCase: GetCurrentAccountUseCase,
|
||||
private val loadUserByIdUseCase: LoadUserByIdUseCase,
|
||||
private val userSettings: UserSettings,
|
||||
private val longPollController: LongPollController
|
||||
private val longPollController: LongPollController,
|
||||
private val logger: FastLogger
|
||||
) : MainViewModel, ViewModel() {
|
||||
|
||||
override val startDestination = MutableStateFlow<Any?>(null)
|
||||
@@ -203,7 +204,10 @@ class MainViewModelImpl(
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val currentAccount = getCurrentAccountUseCase()
|
||||
|
||||
Log.d("MainViewModel", "currentAccount: $currentAccount")
|
||||
logger.debug(
|
||||
this@MainViewModelImpl::class,
|
||||
"loadAccounts(): currentAccount: $currentAccount"
|
||||
)
|
||||
|
||||
listenLongPollState()
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import com.skydoves.compose.stability.runtime.ComposeStabilityAnalyzer
|
||||
import dev.meloda.fast.auth.BuildConfig
|
||||
import dev.meloda.fast.common.di.applicationModule
|
||||
import dev.meloda.fast.datastore.AppSettings
|
||||
import dev.meloda.fast.logger.FastLogLevel
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import dev.meloda.fast.presentation.CrashActivity
|
||||
import org.koin.android.ext.android.get
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
@@ -30,6 +32,14 @@ class AppGlobal : Application(), ImageLoaderFactory {
|
||||
|
||||
initKoin()
|
||||
initCrashHandler()
|
||||
|
||||
val logLevel =
|
||||
if (BuildConfig.DEBUG) FastLogLevel.DEBUG
|
||||
else FastLogLevel.ERROR
|
||||
|
||||
get<FastLogger>()
|
||||
.apply { setLogLevel(logLevel) }
|
||||
.also { FastLogger.setInstance(it) }
|
||||
}
|
||||
|
||||
override fun newImageLoader(): ImageLoader = get()
|
||||
|
||||
@@ -19,6 +19,7 @@ import dev.meloda.fast.convos.di.createChatModule
|
||||
import dev.meloda.fast.domain.di.domainModule
|
||||
import dev.meloda.fast.friends.di.friendsModule
|
||||
import dev.meloda.fast.languagepicker.di.languagePickerModule
|
||||
import dev.meloda.fast.logger.loggerModule
|
||||
import dev.meloda.fast.messageshistory.di.messagesHistoryModule
|
||||
import dev.meloda.fast.photoviewer.di.photoViewModule
|
||||
import dev.meloda.fast.profile.di.profileModule
|
||||
@@ -49,6 +50,8 @@ val applicationModule = module {
|
||||
createChatModule
|
||||
)
|
||||
|
||||
includes(loggerModule)
|
||||
|
||||
// TODO: 14/05/2024, Danil Nikolaev: extract all operations with preferences to standalone class
|
||||
singleOf(PreferenceManager::getDefaultSharedPreferences)
|
||||
single<Resources> { androidContext().resources }
|
||||
|
||||
@@ -9,12 +9,11 @@ import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import androidx.activity.SystemBarStyle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.core.content.ContextCompat
|
||||
@@ -24,10 +23,13 @@ import dev.meloda.fast.MainViewModel
|
||||
import dev.meloda.fast.MainViewModelImpl
|
||||
import dev.meloda.fast.common.AppConstants
|
||||
import dev.meloda.fast.datastore.AppSettings
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import dev.meloda.fast.service.OnlineService
|
||||
import dev.meloda.fast.service.longpolling.LongPollingService
|
||||
import dev.meloda.fast.ui.R
|
||||
import dev.meloda.fast.ui.common.LocalLogger
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
@@ -64,25 +66,26 @@ class MainActivity : AppCompatActivity() {
|
||||
requestNotificationPermissions()
|
||||
|
||||
setContent {
|
||||
val viewModel: MainViewModel = koinViewModel<MainViewModelImpl>()
|
||||
LaunchedEffect(viewModel) {
|
||||
Log.d("VM_CREATE", "onCreate: viewModel: $viewModel")
|
||||
}
|
||||
val logger: FastLogger = koinInject()
|
||||
|
||||
val viewModel: MainViewModel = koinViewModel<MainViewModelImpl>()
|
||||
LifecycleResumeEffect(true) {
|
||||
viewModel.onAppResumed(intent)
|
||||
onPauseOrDispose {}
|
||||
}
|
||||
|
||||
RootScreen(
|
||||
toggleLongPollService = { enable, inBackground ->
|
||||
toggleLongPollService(
|
||||
enable = enable,
|
||||
inBackground = inBackground ?: AppSettings.Experimental.longPollInBackground
|
||||
)
|
||||
},
|
||||
toggleOnlineService = ::toggleOnlineService
|
||||
)
|
||||
CompositionLocalProvider(LocalLogger provides logger) {
|
||||
RootScreen(
|
||||
toggleLongPollService = { enable, inBackground ->
|
||||
toggleLongPollService(
|
||||
enable = enable,
|
||||
inBackground = inBackground
|
||||
?: AppSettings.Experimental.longPollInBackground
|
||||
)
|
||||
},
|
||||
toggleOnlineService = ::toggleOnlineService
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import androidx.activity.compose.LocalActivity
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
@@ -63,6 +62,7 @@ import dev.meloda.fast.photoviewer.presentation.PhotoViewDialog
|
||||
import dev.meloda.fast.settings.navigation.navigateToSettings
|
||||
import dev.meloda.fast.settings.navigation.settingsScreen
|
||||
import dev.meloda.fast.ui.R
|
||||
import dev.meloda.fast.ui.common.LocalLogger
|
||||
import dev.meloda.fast.ui.common.LocalSizeConfig
|
||||
import dev.meloda.fast.ui.model.DeviceSize
|
||||
import dev.meloda.fast.ui.model.SizeConfig
|
||||
@@ -83,6 +83,7 @@ fun RootScreen(
|
||||
toggleLongPollService: (enable: Boolean, inBackground: Boolean?) -> Unit,
|
||||
toggleOnlineService: (enable: Boolean) -> Unit
|
||||
) {
|
||||
val logger = LocalLogger.current
|
||||
val resources = LocalResources.current
|
||||
|
||||
val userSettings: UserSettings = koinInject()
|
||||
@@ -92,10 +93,6 @@ fun RootScreen(
|
||||
val longPollStateToApply by longPollController.stateToApply.collectAsStateWithLifecycle()
|
||||
|
||||
val viewModel: MainViewModel = koinViewModel<MainViewModelImpl>()
|
||||
LaunchedEffect(viewModel) {
|
||||
Log.d("VM_CREATE", "RootScreen(): viewModel: $viewModel")
|
||||
}
|
||||
|
||||
val currentUser: VkUser? by viewModel.currentUser.collectAsStateWithLifecycle()
|
||||
|
||||
val permissionState =
|
||||
@@ -126,13 +123,12 @@ fun RootScreen(
|
||||
}
|
||||
|
||||
LifecycleResumeEffect(longPollStateToApply) {
|
||||
Log.d("LongPollMainActivity", "longPollStateToApply: $longPollStateToApply")
|
||||
logger.debug("RootScreen", "longPollStateToApply: $longPollStateToApply")
|
||||
if (longPollStateToApply != LongPollState.Background) {
|
||||
if (longPollStateToApply.isLaunched() && longPollCurrentState.isLaunched()
|
||||
&& longPollCurrentState != longPollStateToApply
|
||||
) {
|
||||
toggleLongPollService(false, null)
|
||||
Log.d("LongPoll", "recreate()")
|
||||
}
|
||||
|
||||
toggleLongPollService(
|
||||
|
||||
@@ -6,8 +6,9 @@ import android.os.IBinder
|
||||
import android.util.Log
|
||||
import dev.meloda.fast.common.extensions.createTimerFlow
|
||||
import dev.meloda.fast.data.UserConfig
|
||||
import dev.meloda.fast.domain.AccountUseCase
|
||||
import dev.meloda.fast.data.processState
|
||||
import dev.meloda.fast.domain.AccountUseCase
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -24,11 +25,12 @@ import kotlin.time.Duration.Companion.minutes
|
||||
|
||||
class OnlineService : Service() {
|
||||
|
||||
private val logger: FastLogger by inject()
|
||||
|
||||
private val job = SupervisorJob()
|
||||
|
||||
private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
|
||||
Log.d(TAG, "error: $throwable")
|
||||
throwable.printStackTrace()
|
||||
logger.error(this::class.java, "CoroutineException", throwable)
|
||||
}
|
||||
|
||||
private val coroutineContext: CoroutineContext
|
||||
@@ -42,17 +44,20 @@ class OnlineService : Service() {
|
||||
private var onlineJob: Job? = null
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
Log.d(STATE_TAG, "onBind: intent: $intent")
|
||||
logger.debug(this::class, "STATE: onBind(): intent: $intent")
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
if (startId > 1) return START_STICKY
|
||||
|
||||
Log.d(STATE_TAG, "onStartCommand: flags: $flags; startId: $startId\ninstance: $this")
|
||||
logger.debug(
|
||||
this::class,
|
||||
"STATE: onStartCommand(): flags: %s; startId: %s;\ninstance: %s"
|
||||
.format("$flags", "$startId", "$this")
|
||||
)
|
||||
|
||||
createTimer()
|
||||
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
@@ -68,13 +73,13 @@ class OnlineService : Service() {
|
||||
private fun setOnline() {
|
||||
if (onlineJob != null) return
|
||||
|
||||
Log.d(TAG, "setOnline()")
|
||||
logger.debug(this::class, "setOnline()")
|
||||
|
||||
onlineJob = coroutineScope.launch {
|
||||
val token = UserConfig.fastToken ?: UserConfig.accessToken
|
||||
|
||||
if (token.isBlank()) {
|
||||
Log.d(TAG, "setOnline: token is empty")
|
||||
logger.debug(this::class, "setOnline(): token is empty")
|
||||
return@launch
|
||||
}
|
||||
|
||||
@@ -84,10 +89,10 @@ class OnlineService : Service() {
|
||||
).onEach { state ->
|
||||
state.processState(
|
||||
error = { error ->
|
||||
Log.w(TAG, "setOnline(): error: $error")
|
||||
logger.error(this@OnlineService::class, "setOnline(): ERROR: $error")
|
||||
},
|
||||
success = { response ->
|
||||
Log.d(TAG, "setOnline(): success: $response")
|
||||
logger.debug(this@OnlineService::class, "setOnline(): response: $response")
|
||||
}
|
||||
)
|
||||
}.collect()
|
||||
@@ -96,7 +101,7 @@ class OnlineService : Service() {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
Log.d(STATE_TAG, "onDestroy")
|
||||
logger.debug(this::class, "onDestroy()")
|
||||
|
||||
timerJob?.cancel("OnlineService destroyed")
|
||||
onlineJob?.cancel("OnlineService destroyed")
|
||||
|
||||
@@ -7,7 +7,6 @@ import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.ServiceCompat
|
||||
import com.conena.nanokt.android.app.stopForegroundCompat
|
||||
@@ -22,6 +21,7 @@ import dev.meloda.fast.datastore.AppSettings
|
||||
import dev.meloda.fast.domain.LongPollEventsHandler
|
||||
import dev.meloda.fast.domain.LongPollUpdatesParser
|
||||
import dev.meloda.fast.domain.LongPollUseCase
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import dev.meloda.fast.model.api.data.LongPollUpdates
|
||||
import dev.meloda.fast.model.api.data.VkLongPollData
|
||||
import dev.meloda.fast.ui.R
|
||||
@@ -41,6 +41,8 @@ import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class LongPollingService : Service() {
|
||||
|
||||
private val logger: FastLogger by inject()
|
||||
|
||||
private val longPollController: LongPollController by inject()
|
||||
|
||||
private val job = SupervisorJob()
|
||||
@@ -65,20 +67,21 @@ class LongPollingService : Service() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
Log.d(STATE_TAG, "onCreate()")
|
||||
logger.debug(this::class, "STATE: onCreate()")
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
Log.d(STATE_TAG, "onBind: intent: $intent")
|
||||
logger.debug(this::class, "STATE: onBind(): intent: $intent")
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
if (startId > 1) return START_STICKY
|
||||
|
||||
Log.d(
|
||||
STATE_TAG,
|
||||
"onStartCommand: asForeground: $inBackground; flags: $flags; startId: $startId;\ninstance: $this"
|
||||
logger.debug(
|
||||
this::class,
|
||||
"STATE: onStartCommand(): asForeground: %s; flags: %s; startId: %s;\ninstance: %s"
|
||||
.format("$inBackground", "$flags", "$startId", "$this")
|
||||
)
|
||||
|
||||
startJob()
|
||||
@@ -133,11 +136,15 @@ class LongPollingService : Service() {
|
||||
|
||||
private fun startPolling(): Job {
|
||||
if (job.isCompleted || job.isCancelled) {
|
||||
Log.d(STATE_TAG, "Job is completed or cancelled")
|
||||
logger.debug(
|
||||
this::class,
|
||||
"startPolling(): Job is already done. isCompleted: %s; isCancelled: %s"
|
||||
.format("${job.isCompleted}", "${job.isCancelled}")
|
||||
)
|
||||
throw Exception("Job is over")
|
||||
}
|
||||
|
||||
Log.d(STATE_TAG, "Starting job...")
|
||||
logger.debug(this::class, "startPolling(): Starting job.")
|
||||
|
||||
return coroutineScope.launch(coroutineContext) {
|
||||
longPollController.updateCurrentState(
|
||||
@@ -213,11 +220,11 @@ class LongPollingService : Service() {
|
||||
).listenValue(coroutineScope) { state ->
|
||||
state.processState(
|
||||
success = { response ->
|
||||
Log.d(TAG, "getServerInfo: serverInfoResponse: $response")
|
||||
logger.debug(this::class, "getServerInfo(): response: $response")
|
||||
it.resume(response)
|
||||
},
|
||||
error = { error ->
|
||||
Log.e(TAG, "getServerInfo: $error")
|
||||
logger.error(this::class, "getServerInfo(): ERROR: $error")
|
||||
it.resume(null)
|
||||
}
|
||||
)
|
||||
@@ -237,11 +244,11 @@ class LongPollingService : Service() {
|
||||
).listenValue(coroutineScope) { state ->
|
||||
state.processState(
|
||||
success = { response ->
|
||||
Log.d(TAG, "lastUpdateResponse: $response")
|
||||
logger.debug(this::class, "getUpdatesResponse(): response: $response")
|
||||
it.resume(response)
|
||||
},
|
||||
error = { error ->
|
||||
Log.d(TAG, "getUpdatesResponse: error: $error")
|
||||
logger.debug(this::class, "getUpdatesResponse(): error: $error")
|
||||
it.resume(null)
|
||||
}
|
||||
)
|
||||
@@ -254,7 +261,7 @@ class LongPollingService : Service() {
|
||||
}
|
||||
|
||||
private fun handleError(throwable: Throwable) {
|
||||
Log.e(TAG, "error: $throwable")
|
||||
logger.error(this::class, "CoroutineException", throwable)
|
||||
|
||||
if (throwable !is NoAccessTokenException) {
|
||||
throwable.printStackTrace()
|
||||
@@ -269,7 +276,7 @@ class LongPollingService : Service() {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
Log.d(STATE_TAG, "onDestroy")
|
||||
logger.debug(this::class, "STATE: onDestroy()")
|
||||
longPollController.updateCurrentState(LongPollState.Stopped)
|
||||
try {
|
||||
AppSettings.edit { putBoolean(KEY_LONG_POLL_WAS_DESTROYED, true) }
|
||||
@@ -281,7 +288,7 @@ class LongPollingService : Service() {
|
||||
}
|
||||
|
||||
override fun onTrimMemory(level: Int) {
|
||||
Log.d(STATE_TAG, "onTrimMemory. Level: $level")
|
||||
logger.debug(this::class, "STATE: onTrimMemory(): Level: $level")
|
||||
super.onTrimMemory(level)
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,13 +1,13 @@
|
||||
package dev.meloda.fast.common.model
|
||||
|
||||
enum class LogLevel(val value: Int) {
|
||||
enum class NetworkLogLevel(val value: Int) {
|
||||
NONE(0),
|
||||
BASIC(1),
|
||||
HEADERS(2),
|
||||
BODY(3);
|
||||
|
||||
companion object {
|
||||
fun parse(value: Int): LogLevel = entries.firstOrNull { it.value == value }
|
||||
fun parse(value: Int): NetworkLogLevel = entries.firstOrNull { it.value == value }
|
||||
?: throw IllegalArgumentException("Unknown log level with value: $value")
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package dev.meloda.fast.datastore
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import dev.meloda.fast.common.model.DarkMode
|
||||
import dev.meloda.fast.common.model.LogLevel
|
||||
import dev.meloda.fast.common.model.NetworkLogLevel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
@@ -238,11 +238,11 @@ object AppSettings {
|
||||
)
|
||||
set(value) = put(SettingsKeys.KEY_DEBUG_SHOW_CRASH_ALERT, value)
|
||||
|
||||
var networkLogLevel: LogLevel
|
||||
var networkLogLevel: NetworkLogLevel
|
||||
get() = get(
|
||||
SettingsKeys.KEY_DEBUG_NETWORK_LOG_LEVEL,
|
||||
SettingsKeys.DEFAULT_NETWORK_LOG_LEVEL
|
||||
).let(LogLevel::parse)
|
||||
).let(NetworkLogLevel::parse)
|
||||
set(level) = put(SettingsKeys.KEY_DEBUG_NETWORK_LOG_LEVEL, level.value)
|
||||
|
||||
var showDebugCategory: Boolean
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package dev.meloda.fast.domain
|
||||
|
||||
import android.util.Log
|
||||
import dev.meloda.fast.database.dao.ConvoDao
|
||||
import dev.meloda.fast.database.dao.MessageDao
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import dev.meloda.fast.model.LongPollParsedEvent
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -11,6 +11,7 @@ import kotlinx.coroutines.SupervisorJob
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class LongPollEventsHandler(
|
||||
private val logger: FastLogger,
|
||||
private val convoUseCase: ConvoUseCase,
|
||||
private val messagesUseCase: MessagesUseCase,
|
||||
private val convoDao: ConvoDao,
|
||||
@@ -20,8 +21,7 @@ class LongPollEventsHandler(
|
||||
|
||||
private val exceptionHandler =
|
||||
CoroutineExceptionHandler { _, throwable ->
|
||||
Log.e("LongPollUpdatesParser", "error: $throwable")
|
||||
throwable.printStackTrace()
|
||||
logger.error(this::class, "CoroutineException", throwable)
|
||||
}
|
||||
|
||||
private val coroutineContext: CoroutineContext
|
||||
@@ -45,8 +45,8 @@ class LongPollEventsHandler(
|
||||
isArchived = event.convo.isArchived
|
||||
)
|
||||
|
||||
Log.d(
|
||||
"LongPollEventsHandler",
|
||||
logger.debug(
|
||||
this::class,
|
||||
"isArchived ${event.convo.isArchived}: updated $affectedRows rows."
|
||||
)
|
||||
}
|
||||
@@ -57,7 +57,10 @@ class LongPollEventsHandler(
|
||||
cmId = event.toCmId
|
||||
)
|
||||
|
||||
Log.d("LongPollEventsHandler", "updateLastCmId: updated $affectedRows rows.")
|
||||
logger.debug(
|
||||
this::class,
|
||||
"updateLastCmId: updated $affectedRows rows."
|
||||
)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.ChatMajorChanged -> {
|
||||
@@ -66,7 +69,10 @@ class LongPollEventsHandler(
|
||||
majorId = event.majorId
|
||||
)
|
||||
|
||||
Log.d("LongPollEventsHandler", "updateMajorId: updated $affectedRows rows.")
|
||||
logger.debug(
|
||||
this::class,
|
||||
"updateMajorId: updated $affectedRows rows."
|
||||
)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.ChatMinorChanged -> {
|
||||
@@ -75,7 +81,10 @@ class LongPollEventsHandler(
|
||||
minorId = event.minorId
|
||||
)
|
||||
|
||||
Log.d("LongPollEventsHandler", "updateMinorId: updated $affectedRows rows.")
|
||||
logger.debug(
|
||||
this::class,
|
||||
"updateMinorId: updated $affectedRows rows."
|
||||
)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.Interaction -> {
|
||||
@@ -93,7 +102,10 @@ class LongPollEventsHandler(
|
||||
isDeleted = true
|
||||
)
|
||||
|
||||
Log.d("LongPollEventsHandler", "markDeleted: updated $affectedRows rows.")
|
||||
logger.debug(
|
||||
this::class,
|
||||
"markDeleted: updated $affectedRows rows."
|
||||
)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.MessageEdited -> {
|
||||
@@ -107,7 +119,10 @@ class LongPollEventsHandler(
|
||||
isImportant = event.marked
|
||||
)
|
||||
|
||||
Log.d("LongPollEventsHandler", "markImportant: updated $affectedRows rows.")
|
||||
logger.debug(
|
||||
this::class,
|
||||
"markImportant: updated $affectedRows rows."
|
||||
)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.MessageMarkedAsNotSpam -> {
|
||||
@@ -121,7 +136,10 @@ class LongPollEventsHandler(
|
||||
isSpam = true
|
||||
)
|
||||
|
||||
Log.d("LongPollEventsHandler", "markSpam: updated $affectedRows rows.")
|
||||
logger.debug(
|
||||
this::class,
|
||||
"markSpam: updated $affectedRows rows."
|
||||
)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.MessageRestored -> {
|
||||
@@ -143,7 +161,10 @@ class LongPollEventsHandler(
|
||||
unreadCount = event.unreadCount
|
||||
)
|
||||
|
||||
Log.d("LongPollEventsHandler", "inMessageRead: updated $affectedRows rows.")
|
||||
logger.debug(
|
||||
this::class,
|
||||
"inMessageRead: updated $affectedRows rows."
|
||||
)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.OutgoingMessageRead -> {
|
||||
@@ -153,7 +174,10 @@ class LongPollEventsHandler(
|
||||
unreadCount = event.unreadCount
|
||||
)
|
||||
|
||||
Log.d("LongPollEventsHandler", "outMessageRead: updated $affectedRows rows.")
|
||||
logger.debug(
|
||||
this::class,
|
||||
"outMessageRead: updated $affectedRows rows."
|
||||
)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.UnreadCounter -> {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package dev.meloda.fast.domain
|
||||
|
||||
import android.util.Log
|
||||
import dev.meloda.fast.common.VkConstants
|
||||
import dev.meloda.fast.common.extensions.asInt
|
||||
import dev.meloda.fast.common.extensions.asLong
|
||||
@@ -8,6 +7,7 @@ import dev.meloda.fast.common.extensions.listenValue
|
||||
import dev.meloda.fast.common.extensions.toList
|
||||
import dev.meloda.fast.data.UserConfig
|
||||
import dev.meloda.fast.data.processState
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import dev.meloda.fast.model.ApiEvent
|
||||
import dev.meloda.fast.model.ConvoFlags
|
||||
import dev.meloda.fast.model.InteractionType
|
||||
@@ -27,6 +27,7 @@ import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
class LongPollUpdatesParser(
|
||||
private val logger: FastLogger,
|
||||
private val convoUseCase: ConvoUseCase,
|
||||
private val messagesUseCase: MessagesUseCase
|
||||
) {
|
||||
@@ -34,8 +35,7 @@ class LongPollUpdatesParser(
|
||||
|
||||
private val exceptionHandler =
|
||||
CoroutineExceptionHandler { _, throwable ->
|
||||
Log.e("LongPollUpdatesParser", "error: $throwable")
|
||||
throwable.printStackTrace()
|
||||
logger.error(this::class, "CoroutineException", throwable)
|
||||
}
|
||||
|
||||
private val coroutineContext: CoroutineContext
|
||||
@@ -51,7 +51,7 @@ class LongPollUpdatesParser(
|
||||
|
||||
return when (val eventType = ApiEvent.parseOrNull(eventId)) {
|
||||
null -> {
|
||||
Log.d("LongPollUpdatesParser", "parseNextUpdate: unknownEvent: $event")
|
||||
logger.debug(this::class, "parseNextUpdate(): unknownEvent: $event")
|
||||
emptyList()
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
logger.debug(this::class, "parseMessageSetFlags(): $eventType: $event")
|
||||
|
||||
val cmId = event[1].asLong()
|
||||
val flags = event[2].asInt()
|
||||
@@ -171,7 +171,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> = suspendCancellableCoroutine { continuation ->
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
logger.debug(this::class, "parseMessageClearFlags(): $eventType: $event")
|
||||
|
||||
val cmId = event[1].asLong()
|
||||
val flags = event[2].asInt()
|
||||
@@ -246,7 +246,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> = suspendCancellableCoroutine { continuation ->
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
logger.debug(this::class, "parseMessageNew(): $eventType: $event")
|
||||
|
||||
val cmId = event[1].asLong()
|
||||
val peerId = event[4].asLong()
|
||||
@@ -284,7 +284,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> = suspendCancellableCoroutine { continuation ->
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
logger.debug(this::class, "parseMessageEdit(): $eventType: $event")
|
||||
|
||||
val cmId = event[1].asLong()
|
||||
val peerId = event[3].asLong()
|
||||
@@ -305,7 +305,8 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
logger.debug(this::class, "parseMessageReadIncoming(): $eventType: $event")
|
||||
|
||||
val peerId = event[1].asLong()
|
||||
val cmId = event[2].asLong()
|
||||
val unreadCount = event[3].asInt()
|
||||
@@ -323,7 +324,8 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
logger.debug(this::class, "parseMessageReadOutgoing(): $eventType: $event")
|
||||
|
||||
val peerId = event[1].asLong()
|
||||
val cmId = event[2].asLong()
|
||||
val unreadCount = event[3].asInt()
|
||||
@@ -342,7 +344,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> = suspendCancellableCoroutine { continuation ->
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
logger.debug(this::class, "parseChatClearFlags(): $eventType: $event")
|
||||
|
||||
val peerId = event[1].asLong()
|
||||
val flags = event[2].asInt()
|
||||
@@ -402,7 +404,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> = suspendCancellableCoroutine { continuation ->
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
logger.debug(this::class, "parseChatSetFlags(): $eventType: $event")
|
||||
|
||||
val peerId = event[1].asLong()
|
||||
val flags = event[2].asInt()
|
||||
@@ -462,7 +464,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
logger.debug(this::class, "parseMessagesDeleted(): $eventType: $event")
|
||||
|
||||
val peerId = event[1].asLong()
|
||||
val cmId = event[2].asLong()
|
||||
@@ -479,7 +481,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
logger.debug(this::class, "parseChatMajorChanged(): $eventType: $event")
|
||||
|
||||
val peerId = event[1].asLong()
|
||||
val majorId = event[2].asInt()
|
||||
@@ -496,7 +498,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
logger.debug(this::class, "parseChatMinorChanged(): $eventType: $event")
|
||||
|
||||
val peerId = event[1].asLong()
|
||||
val minorId = event[2].asInt()
|
||||
@@ -513,7 +515,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
logger.debug(this::class, "parseInteraction(): $eventType: $event")
|
||||
|
||||
val interactionType = when (eventType) {
|
||||
ApiEvent.TYPING -> InteractionType.Typing
|
||||
@@ -556,7 +558,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> {
|
||||
Log.d("LongPollUpdatesParser", "$eventType $event")
|
||||
logger.debug(this::class, "parseUnreadCounterUpdate(): $eventType: $event")
|
||||
|
||||
val unreadCount = event[1].asInt()
|
||||
val unreadUnmutedCount = event[2].asInt()
|
||||
@@ -583,7 +585,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> = suspendCancellableCoroutine { continuation ->
|
||||
Log.d("LongPollUpdatesParser", "$eventType $event")
|
||||
logger.debug(this::class, "parseMessageUpdated(): $eventType: $event")
|
||||
|
||||
val cmId = event[1].asLong()
|
||||
val peerId = event[4].asLong()
|
||||
@@ -605,7 +607,7 @@ class LongPollUpdatesParser(
|
||||
eventType: ApiEvent,
|
||||
event: List<Any>
|
||||
): List<LongPollParsedEvent> = suspendCancellableCoroutine { continuation ->
|
||||
Log.d("LongPollUpdatesParser", "$eventType $event")
|
||||
logger.debug(this::class, "parseMessageCacheClear(): $eventType: $event")
|
||||
|
||||
val messageId = event[1].asLong()
|
||||
|
||||
@@ -639,7 +641,7 @@ class LongPollUpdatesParser(
|
||||
).listenValue(this) { state ->
|
||||
state.processState(
|
||||
error = { error ->
|
||||
Log.e("LongPollUpdatesParser", "loadMessage: error: $error")
|
||||
logger.error(this::class, "loadMessage(): ERROR: $error")
|
||||
continuation.resume(null)
|
||||
},
|
||||
success = { response ->
|
||||
@@ -668,7 +670,7 @@ class LongPollUpdatesParser(
|
||||
).listenValue(coroutineScope) { state ->
|
||||
state.processState(
|
||||
error = { error ->
|
||||
Log.e("LongPollUpdatesParser", "loadConvo: error: $error")
|
||||
logger.error(this::class, "loadConvo(): ERROR: $error")
|
||||
continuation.resume(null)
|
||||
},
|
||||
success = { response ->
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,11 @@
|
||||
plugins {
|
||||
alias(libs.plugins.fast.android.library)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "dev.meloda.fast.logger"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.koin.android)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package dev.meloda.fast.logger;
|
||||
|
||||
enum class FastLogLevel {
|
||||
VERBOSE,
|
||||
DEBUG,
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR,
|
||||
ASSERT;
|
||||
|
||||
companion object {
|
||||
fun parse(value: Int): FastLogLevel {
|
||||
if (value !in 0..5) throw IllegalArgumentException("Unknown LogLevel value $value")
|
||||
return entries.first { it.ordinal == value }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package dev.meloda.fast.logger
|
||||
|
||||
import android.util.Log
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class FastLogger {
|
||||
companion object {
|
||||
|
||||
@Volatile
|
||||
private lateinit var instance: FastLogger
|
||||
|
||||
fun setInstance(logger: FastLogger) {
|
||||
if (::instance.isInitialized) {
|
||||
throw IllegalStateException("FastLogger has already been initialized.")
|
||||
}
|
||||
|
||||
instance = logger
|
||||
}
|
||||
|
||||
fun getInstance(): FastLogger {
|
||||
if (!::instance.isInitialized) {
|
||||
throw UninitializedPropertyAccessException("FastLogger is not initialized.")
|
||||
}
|
||||
return instance
|
||||
}
|
||||
}
|
||||
|
||||
private var logLevel: FastLogLevel = FastLogLevel.ERROR
|
||||
|
||||
fun setLogLevel(logLevel: FastLogLevel) {
|
||||
Log.v(this::class.java.simpleName, "Set LogLevel from ${this.logLevel} to $logLevel")
|
||||
this.logLevel = logLevel
|
||||
}
|
||||
|
||||
fun verbose(clazz: Class<*>, message: String, throwable: Throwable? = null) {
|
||||
verbose(clazz.simpleName, message, throwable)
|
||||
}
|
||||
|
||||
fun verbose(tag: String, message: String, throwable: Throwable? = null) {
|
||||
if (shouldLog(FastLogLevel.VERBOSE)) {
|
||||
Log.v(tag, message, throwable)
|
||||
}
|
||||
}
|
||||
|
||||
fun debug(clazz: KClass<*>, message: String, throwable: Throwable? = null) {
|
||||
debug(clazz.java, message, throwable)
|
||||
}
|
||||
|
||||
fun debug(clazz: Class<*>, message: String, throwable: Throwable? = null) {
|
||||
debug(clazz.simpleName, message, throwable)
|
||||
}
|
||||
|
||||
fun debug(tag: String, message: String, throwable: Throwable? = null) {
|
||||
if (shouldLog(FastLogLevel.DEBUG)) {
|
||||
Log.d(tag, message, throwable)
|
||||
}
|
||||
}
|
||||
|
||||
fun info(clazz: KClass<*>, message: String, throwable: Throwable? = null) {
|
||||
info(clazz.java, message, throwable)
|
||||
}
|
||||
|
||||
fun info(clazz: Class<*>, message: String, throwable: Throwable? = null) {
|
||||
info(clazz.simpleName, message, throwable)
|
||||
}
|
||||
|
||||
fun info(tag: String, message: String, throwable: Throwable? = null) {
|
||||
if (shouldLog(FastLogLevel.INFO)) {
|
||||
Log.i(tag, message, throwable)
|
||||
}
|
||||
}
|
||||
|
||||
fun warning(clazz: Class<*>, message: String, throwable: Throwable? = null) {
|
||||
warning(clazz.simpleName, message, throwable)
|
||||
}
|
||||
|
||||
fun warning(tag: String, message: String, throwable: Throwable? = null) {
|
||||
if (shouldLog(FastLogLevel.WARNING)) {
|
||||
Log.w(tag, message, throwable)
|
||||
}
|
||||
}
|
||||
|
||||
fun error(clazz: KClass<*>, message: String, throwable: Throwable? = null) {
|
||||
error(clazz.java, message, throwable)
|
||||
}
|
||||
|
||||
fun error(clazz: Class<*>, message: String, throwable: Throwable? = null) {
|
||||
error(clazz.simpleName, message, throwable)
|
||||
}
|
||||
|
||||
fun error(tag: String, message: String, throwable: Throwable? = null) {
|
||||
if (shouldLog(FastLogLevel.ERROR)) {
|
||||
Log.e(tag, message, throwable)
|
||||
}
|
||||
}
|
||||
|
||||
fun assert(clazz: Class<*>, message: String, throwable: Throwable? = null) {
|
||||
assert(clazz.simpleName, message, throwable)
|
||||
}
|
||||
|
||||
fun assert(tag: String, message: String, throwable: Throwable? = null) {
|
||||
if (shouldLog(FastLogLevel.ASSERT)) {
|
||||
Log.wtf(tag, message, throwable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldLog(level: FastLogLevel): Boolean = level.ordinal >= logLevel.ordinal
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package dev.meloda.fast.logger
|
||||
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.module
|
||||
|
||||
val loggerModule = module {
|
||||
singleOf(::FastLogger)
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package dev.meloda.fast.model.api.data
|
||||
|
||||
import android.util.Log
|
||||
|
||||
enum class AttachmentType(var value: String) {
|
||||
UNKNOWN("unknown"),
|
||||
PHOTO("photo"),
|
||||
@@ -42,10 +40,6 @@ enum class AttachmentType(var value: String) {
|
||||
it.value == value
|
||||
} ?: UNKNOWN
|
||||
|
||||
if (parsedValue == UNKNOWN) {
|
||||
Log.e("AttachmentType", "Unknown attachment type: $value")
|
||||
}
|
||||
|
||||
return parsedValue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ dependencies {
|
||||
api(projects.core.common)
|
||||
api(projects.core.model)
|
||||
api(projects.core.datastore)
|
||||
api(projects.core.logger)
|
||||
|
||||
implementation(libs.moshi.kotlin)
|
||||
implementation(libs.koin.android)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package dev.meloda.fast.network
|
||||
|
||||
import android.util.Log
|
||||
import com.slack.eithernet.ApiException
|
||||
import com.slack.eithernet.errorType
|
||||
import com.slack.eithernet.toType
|
||||
import com.squareup.moshi.JsonDataException
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.Converter
|
||||
import retrofit2.Retrofit
|
||||
@@ -16,7 +16,10 @@ import java.lang.reflect.Type
|
||||
*
|
||||
* допускает Unit как SuccessType в случае невозможности каста ответа в ErrorType
|
||||
*/
|
||||
class ResponseConverterFactory(private val converter: JsonConverter) : Converter.Factory() {
|
||||
class ResponseConverterFactory(
|
||||
private val converter: JsonConverter,
|
||||
private val logger: FastLogger
|
||||
) : Converter.Factory() {
|
||||
|
||||
override fun responseBodyConverter(
|
||||
type: Type,
|
||||
@@ -29,6 +32,7 @@ class ResponseConverterFactory(private val converter: JsonConverter) : Converter
|
||||
successType = type,
|
||||
errorRaw = errorRaw,
|
||||
converter = converter,
|
||||
logger = logger
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,6 +40,7 @@ class ResponseConverterFactory(private val converter: JsonConverter) : Converter
|
||||
private val successType: Type,
|
||||
private val errorRaw: Class<*>,
|
||||
private val converter: JsonConverter,
|
||||
private val logger: FastLogger
|
||||
) : Converter<ResponseBody, Any?> {
|
||||
override fun convert(value: ResponseBody): Any? {
|
||||
val string = value.string()
|
||||
@@ -53,7 +58,7 @@ class ResponseConverterFactory(private val converter: JsonConverter) : Converter
|
||||
},
|
||||
onFailure = { failure ->
|
||||
if (failure is JsonDataException) {
|
||||
Log.d("ResponseBodyConverter", "convertJsonDataException: $failure")
|
||||
logger.error(this::class, "convert(): ERROR", failure)
|
||||
throw ApiException(
|
||||
RestApiError(
|
||||
errorCode = -1,
|
||||
@@ -68,10 +73,11 @@ class ResponseConverterFactory(private val converter: JsonConverter) : Converter
|
||||
converter.fromJson(errorRaw, string)
|
||||
}.fold(
|
||||
onSuccess = { errorModel ->
|
||||
Log.d("ResponseBodyConverter", "convert: $errorModel")
|
||||
logger.debug(this::class, "convert(): errorModel: $errorModel")
|
||||
throw ApiException(errorModel)
|
||||
},
|
||||
onFailure = { exception ->
|
||||
logger.error(this::class, "convert(): INNER: ERROR", exception)
|
||||
if (!isUnit) {
|
||||
throw exception
|
||||
} else {
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.slack.eithernet.integration.retrofit.ApiResultConverterFactory
|
||||
import com.squareup.moshi.Moshi
|
||||
import dev.meloda.fast.common.AppConstants
|
||||
import dev.meloda.fast.datastore.AppSettings
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import dev.meloda.fast.network.JsonConverter
|
||||
import dev.meloda.fast.network.MoshiConverter
|
||||
import dev.meloda.fast.network.OAuthResultCallFactory
|
||||
@@ -123,7 +124,12 @@ private fun Scope.buildRetrofit(client: OkHttpClient): Retrofit {
|
||||
.baseUrl("${AppConstants.URL_API}/")
|
||||
.addConverterFactory(ApiResultConverterFactory)
|
||||
.addCallAdapterFactory(ApiResultCallAdapterFactory)
|
||||
.addConverterFactory(ResponseConverterFactory(get<JsonConverter>()))
|
||||
.addConverterFactory(
|
||||
ResponseConverterFactory(
|
||||
get<JsonConverter>(),
|
||||
get<FastLogger>()
|
||||
)
|
||||
)
|
||||
.addConverterFactory(MoshiConverterFactory.create(get()))
|
||||
.client(client)
|
||||
.build()
|
||||
|
||||
+11
-13
@@ -1,9 +1,9 @@
|
||||
package dev.meloda.fast.network.interceptor
|
||||
|
||||
import android.util.Log
|
||||
import dev.meloda.fast.common.extensions.listenValue
|
||||
import dev.meloda.fast.datastore.AppSettings
|
||||
import dev.meloda.fast.datastore.CaptchaTokenResult
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -14,11 +14,7 @@ import org.json.JSONObject
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
class Error14HandlingInterceptor(
|
||||
// private val domains: Set<String> = emptySet(),
|
||||
) : Interceptor {
|
||||
|
||||
private val cookie = AtomicReference<String?>(null)
|
||||
class Error14HandlingInterceptor(private val logger: FastLogger) : Interceptor {
|
||||
|
||||
private companion object {
|
||||
private const val CAPTCHA_ERROR_CODE = 14
|
||||
@@ -26,6 +22,8 @@ class Error14HandlingInterceptor(
|
||||
private val executor = Executors.newSingleThreadExecutor()
|
||||
}
|
||||
|
||||
private val cookie = AtomicReference<String?>(null)
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request().withCookie()
|
||||
val response = chain.proceed(request)
|
||||
@@ -41,23 +39,23 @@ class Error14HandlingInterceptor(
|
||||
|
||||
executor.submit {
|
||||
AppSettings.setCaptchaRedirectUri(redirectUri)
|
||||
Log.d("Error14Interceptor", "passCaptchaAndGetToken: $redirectUri")
|
||||
logger.debug(this::class, "passCaptchaAndGetToken: $redirectUri")
|
||||
|
||||
var job: Job? = null
|
||||
job = AppSettings.getCaptchaResultFlow()
|
||||
.listenValue(CoroutineScope(Dispatchers.IO)) {
|
||||
Log.d("Error14Interceptor", "passCaptchaAndGetToken: $it")
|
||||
logger.debug(this::class, "passCaptchaAndGetToken: $it")
|
||||
if (it != CaptchaTokenResult.Initial) {
|
||||
synchronized(tokenResult) {
|
||||
Log.d(
|
||||
"Error14Interceptor",
|
||||
logger.debug(
|
||||
this::class,
|
||||
"passCaptchaAndGetToken: SYNCHRONIZED: $it"
|
||||
)
|
||||
tokenResult.set(wrapResult(it))
|
||||
tokenResult.notifyAll()
|
||||
job?.cancel()
|
||||
Log.d(
|
||||
"Error14Interceptor",
|
||||
logger.debug(
|
||||
this::class,
|
||||
"passCaptchaAndGetToken: NULL RESULT"
|
||||
)
|
||||
AppSettings.setCaptchaResult(CaptchaTokenResult.Initial)
|
||||
@@ -71,7 +69,7 @@ class Error14HandlingInterceptor(
|
||||
tokenResult.wait()
|
||||
}
|
||||
|
||||
Log.d("Error14Interceptor", "passCaptchaAndGetToken: GET VALUE")
|
||||
logger.debug(this::class, "passCaptchaAndGetToken: GET VALUE")
|
||||
tokenResult.get().getOrThrow()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ android {
|
||||
dependencies {
|
||||
api(projects.core.common)
|
||||
api(projects.core.model)
|
||||
api(projects.core.logger)
|
||||
implementation(projects.core.presentation)
|
||||
|
||||
implementation(libs.haze)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package dev.meloda.fast.ui.common
|
||||
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
|
||||
val LocalLogger = compositionLocalOf { FastLogger.getInstance() }
|
||||
+14
-8
@@ -1,7 +1,6 @@
|
||||
package dev.meloda.fast.auth.captcha.presentation
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.util.Log
|
||||
import android.webkit.JavascriptInterface
|
||||
import android.webkit.WebResourceRequest
|
||||
import android.webkit.WebView
|
||||
@@ -32,7 +31,9 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import dev.meloda.fast.ui.R
|
||||
import dev.meloda.fast.ui.common.LocalLogger
|
||||
import dev.meloda.fast.ui.components.ActionInvokeDismiss
|
||||
import dev.meloda.fast.ui.components.FullScreenDialog
|
||||
import dev.meloda.fast.ui.components.MaterialDialog
|
||||
@@ -46,6 +47,8 @@ fun CaptchaScreen(
|
||||
onBack: () -> Unit = {},
|
||||
onResult: (String) -> Unit = {}
|
||||
) {
|
||||
val logger = LocalLogger.current
|
||||
|
||||
if (captchaRedirectUri != null) {
|
||||
val focusManager = LocalFocusManager.current
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
@@ -114,7 +117,10 @@ fun CaptchaScreen(
|
||||
view: WebView?,
|
||||
request: WebResourceRequest?
|
||||
): Boolean {
|
||||
Log.i(TAG, "shouldOverrideUrlLoading: $request")
|
||||
logger.info(
|
||||
"CaptchaScreen",
|
||||
"WebViewClient(): shouldOverrideUrlLoading(): request: $request"
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -148,7 +154,8 @@ fun CaptchaScreen(
|
||||
// TODO: 03/05/2026, Danil Nikolaev: show error
|
||||
}
|
||||
},
|
||||
onCloseRequested = { showExitAlert = true }
|
||||
onCloseRequested = { showExitAlert = true },
|
||||
logger = logger
|
||||
),
|
||||
"AndroidBridge"
|
||||
)
|
||||
@@ -176,19 +183,18 @@ fun CaptchaScreen(
|
||||
|
||||
class WebCaptchaListener(
|
||||
private val onSuccessTokenReceived: (String) -> Unit,
|
||||
private val onCloseRequested: (String) -> Unit
|
||||
private val onCloseRequested: (String) -> Unit,
|
||||
private val logger: FastLogger
|
||||
) {
|
||||
private val tag = "WebCaptchaListener"
|
||||
|
||||
@JavascriptInterface
|
||||
fun VKCaptchaGetResult(arg: String) {
|
||||
onSuccessTokenReceived(arg)
|
||||
Log.i(tag, "VKCaptchaGetResult($arg)")
|
||||
logger.info(this::class, "VKCaptchaGetResult(): arg: $arg")
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun VKCaptchaCloseCaptcha(arg: String) {
|
||||
onCloseRequested(arg)
|
||||
Log.i(tag, "VKCaptchaCloseCaptcha($arg)")
|
||||
logger.info(this::class, "VKCaptchaCloseCaptcha(): arg: $arg")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package dev.meloda.fast.auth.login
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dev.meloda.fast.auth.login.model.CaptchaArguments
|
||||
@@ -28,6 +27,7 @@ import dev.meloda.fast.datastore.AppSettings
|
||||
import dev.meloda.fast.datastore.UserSettings
|
||||
import dev.meloda.fast.domain.LoadUserByIdUseCase
|
||||
import dev.meloda.fast.domain.OAuthUseCase
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import dev.meloda.fast.model.database.AccountEntity
|
||||
import dev.meloda.fast.network.OAuthErrorDomain
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
@@ -48,7 +48,8 @@ class LoginViewModel(
|
||||
private val accountsRepository: AccountsRepository,
|
||||
private val loginValidator: LoginValidator,
|
||||
private val longPollController: LongPollController,
|
||||
private val userSettings: UserSettings
|
||||
private val userSettings: UserSettings,
|
||||
private val logger: FastLogger
|
||||
) : ViewModel() {
|
||||
private val _screenState = MutableStateFlow(LoginScreenState.EMPTY)
|
||||
val screenState = _screenState.asStateFlow()
|
||||
@@ -189,7 +190,7 @@ class LoginViewModel(
|
||||
).listenValue(viewModelScope) { state ->
|
||||
state.processState(
|
||||
error = { error ->
|
||||
Log.d("LoginViewModelImpl", "login: error: $error")
|
||||
logger.error(this::class, "getSilentToken(): ERROR: $error")
|
||||
|
||||
_screenState.updateValue { copy(isLoading = false) }
|
||||
|
||||
|
||||
+1
-5
@@ -1,6 +1,5 @@
|
||||
package dev.meloda.fast.chatmaterials.util
|
||||
|
||||
import android.util.Log
|
||||
import dev.meloda.fast.chatmaterials.model.UiChatMaterial
|
||||
import dev.meloda.fast.common.util.AndroidUtils
|
||||
import dev.meloda.fast.model.api.data.AttachmentType
|
||||
@@ -135,8 +134,5 @@ fun VkAttachmentHistoryMessage.asPresentation(): UiChatMaterial? =
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
Log.w("ChatMaterialMapper", "Unsupported type: $type")
|
||||
null
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
-11
@@ -6,7 +6,6 @@ import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
@@ -685,8 +684,6 @@ class MessagesHistoryViewModelImpl(
|
||||
private fun handleNewMessage(event: LongPollParsedEvent.NewMessage) {
|
||||
val message = event.message
|
||||
|
||||
Log.d("MessagesHistoryViewModel", "handleNewMessage: $message")
|
||||
|
||||
if (message.peerId != screenState.value.convoId) return
|
||||
if (messages.value.indexOfFirstOrNull { it.id == message.id } != null) return
|
||||
|
||||
@@ -835,8 +832,6 @@ class MessagesHistoryViewModelImpl(
|
||||
}
|
||||
|
||||
private fun loadConvo() {
|
||||
Log.d("MessagesHistoryViewModelImpl", "loadConvo()")
|
||||
|
||||
loadConvosByIdUseCase(
|
||||
peerIds = listOf(screenState.value.convoId),
|
||||
extended = true,
|
||||
@@ -904,8 +899,6 @@ class MessagesHistoryViewModelImpl(
|
||||
}
|
||||
|
||||
private fun loadMessagesHistory(offset: Int = currentOffset.value) {
|
||||
Log.d("MessagesHistoryViewModel", "loadMessagesHistory: $offset")
|
||||
|
||||
messagesUseCase.getMessagesHistory(
|
||||
convoId = screenState.value.convoId,
|
||||
count = MESSAGES_LOAD_COUNT,
|
||||
@@ -1079,8 +1072,6 @@ class MessagesHistoryViewModelImpl(
|
||||
state.processState(
|
||||
any = { sendingMessages.remove(newMessage) },
|
||||
error = { error ->
|
||||
Log.d("MessagesHistoryViewModelImpl", "sendMessage: ERROR: $error")
|
||||
|
||||
val failedId = -500_000L - failedMessages.size
|
||||
val newFailedMessage = newMessage.copy(id = failedId)
|
||||
failedMessages += newFailedMessage
|
||||
@@ -1144,8 +1135,6 @@ class MessagesHistoryViewModelImpl(
|
||||
) ?: return
|
||||
|
||||
// TODO: 13/03/2026, Danil Nikolaev: check if message is exact same, then do not edit
|
||||
|
||||
Log.d("MessagesHistoryViewModelImpl", "editMessage: $newMessage")
|
||||
}
|
||||
|
||||
private fun markAsImportant(
|
||||
|
||||
-2
@@ -1,7 +1,6 @@
|
||||
package dev.meloda.fast.messageshistory.presentation
|
||||
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import android.view.HapticFeedbackConstants
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
@@ -129,7 +128,6 @@ fun MessagesList(
|
||||
when (attachment) {
|
||||
is VkPhotoDomain -> {
|
||||
val maxSize = attachment.getMaxSize()
|
||||
Log.d("MessagesList", "onPhotoLongClicked. Max size: ${maxSize?.url}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -64,7 +64,6 @@ fun DynamicPreviewGrid(
|
||||
val spacingPx = with(LocalDensity.current) { spacing.toPx() }
|
||||
|
||||
val rows = previews.chunked(3)
|
||||
Log.d("ROWS", "DynamicPreviewGrid: ${rows.size}")
|
||||
|
||||
Column(verticalArrangement = Arrangement.spacedBy(spacing)) {
|
||||
rows.forEachIndexed { outerIndex, row ->
|
||||
|
||||
@@ -12,7 +12,7 @@ import dev.meloda.fast.common.extensions.findWithIndex
|
||||
import dev.meloda.fast.common.extensions.listenValue
|
||||
import dev.meloda.fast.common.extensions.setValue
|
||||
import dev.meloda.fast.common.model.DarkMode
|
||||
import dev.meloda.fast.common.model.LogLevel
|
||||
import dev.meloda.fast.common.model.NetworkLogLevel
|
||||
import dev.meloda.fast.common.model.LongPollState
|
||||
import dev.meloda.fast.common.model.UiText
|
||||
import dev.meloda.fast.common.model.parseString
|
||||
@@ -497,10 +497,10 @@ class SettingsViewModel(
|
||||
)
|
||||
|
||||
val logLevelValues = listOf(
|
||||
LogLevel.NONE to UiText.Simple("None"),
|
||||
LogLevel.BASIC to UiText.Simple("Basic"),
|
||||
LogLevel.HEADERS to UiText.Simple("Headers"),
|
||||
LogLevel.BODY to UiText.Simple("Body")
|
||||
NetworkLogLevel.NONE to UiText.Simple("None"),
|
||||
NetworkLogLevel.BASIC to UiText.Simple("Basic"),
|
||||
NetworkLogLevel.HEADERS to UiText.Simple("Headers"),
|
||||
NetworkLogLevel.BODY to UiText.Simple("Body")
|
||||
).toMap()
|
||||
|
||||
val debugNetworkLogLevel = SettingsItem.ListItem(
|
||||
@@ -509,10 +509,10 @@ class SettingsViewModel(
|
||||
valueClass = Int::class,
|
||||
defaultValue = SettingsKeys.DEFAULT_NETWORK_LOG_LEVEL,
|
||||
titles = logLevelValues.values.toList(),
|
||||
values = logLevelValues.keys.toList().map(LogLevel::value)
|
||||
values = logLevelValues.keys.toList().map(NetworkLogLevel::value)
|
||||
).apply {
|
||||
textProvider = TextProvider { item ->
|
||||
val textValue = logLevelValues[LogLevel.parse(item.value)].parseString(resources)
|
||||
val textValue = logLevelValues[NetworkLogLevel.parse(item.value)].parseString(resources)
|
||||
|
||||
UiText.Simple("Current value: $textValue")
|
||||
}
|
||||
|
||||
@@ -55,3 +55,4 @@ include(":feature:friends")
|
||||
include(":feature:profile")
|
||||
include(":feature:createchat")
|
||||
include(":core:presentation")
|
||||
include(":core:logger")
|
||||
|
||||
Reference in New Issue
Block a user