change: Improve logging calls to Timber (#430)

- Use format strings so any overhead of building the string is only
incurred if the message is actually logged

- Pass throwables as the first parameter so they are logged with the
stacktrace
This commit is contained in:
Nik Clayton 2024-02-09 17:33:01 +01:00 committed by GitHub
parent 9b0f1118f9
commit 96474a9ac3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
64 changed files with 161 additions and 156 deletions

View File

@ -320,7 +320,7 @@ class EditProfileActivity : BaseActivity() {
}
private fun onPickFailure(throwable: Throwable?) {
Timber.w("failed to pick media", throwable)
Timber.w(throwable, "failed to pick media")
Snackbar.make(binding.avatarButton, R.string.error_media_upload_sending, Snackbar.LENGTH_LONG).show()
}

View File

@ -459,12 +459,12 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
if (frequency == UpdateNotificationFrequency.ONCE_PER_VERSION) {
val ignoredVersion = sharedPreferencesRepository.getInt(PrefKeys.UPDATE_NOTIFICATION_VERSIONCODE, -1)
if (latestVersionCode == ignoredVersion) {
Timber.d("Ignoring update to $latestVersionCode")
Timber.d("Ignoring update to %d", latestVersionCode)
return@launch
}
}
Timber.d("New version is: $latestVersionCode")
Timber.d("New version is: %d", latestVersionCode)
when (showUpdateDialog()) {
AlertDialog.BUTTON_POSITIVE -> {
startActivity(updateCheck.updateIntent)
@ -776,7 +776,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
"Reset janky animation warning flag",
),
) { _, which ->
Timber.d("Developer tools: $which")
Timber.d("Developer tools: %d", which)
when (which) {
0 -> {
Timber.d("Clearing home timeline cache")
@ -993,7 +993,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
onFetchUserInfoSuccess(userInfo)
},
{ throwable ->
Timber.e("Failed to fetch user info. " + throwable.message)
Timber.e(throwable, "Failed to fetch user info.")
},
)
}
@ -1126,7 +1126,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
updateAnnouncementsBadge()
},
{ throwable ->
Timber.w("Failed to fetch announcements.", throwable)
Timber.w(throwable, "Failed to fetch announcements.")
},
)
}

View File

@ -129,7 +129,7 @@ class PachliApplication : Application() {
}
private fun upgradeSharedPreferences(oldVersion: Int, newVersion: Int) {
Timber.d("Upgrading shared preferences: $oldVersion -> $newVersion")
Timber.d("Upgrading shared preferences: %d -> %d", oldVersion, newVersion)
val editor = sharedPreferencesRepository.edit()
if (oldVersion != NEW_INSTALL_SCHEMA_VERSION) {

View File

@ -167,7 +167,7 @@ class StatusListActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButton
updateMuteTagMenuItems()
},
{
Timber.w("Failed to query tag #$tag", it)
Timber.w(it, "Failed to query tag #%s", tag)
},
)
}
@ -187,7 +187,7 @@ class StatusListActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButton
},
{
Snackbar.make(binding.root, getString(R.string.error_following_hashtag_format, tag), Snackbar.LENGTH_SHORT).show()
Timber.e("Failed to follow #$tag", it)
Timber.e(it, "Failed to follow #%s", tag)
},
)
}
@ -207,7 +207,7 @@ class StatusListActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButton
},
{
Snackbar.make(binding.root, getString(R.string.error_unfollowing_hashtag_format, tag), Snackbar.LENGTH_SHORT).show()
Timber.e("Failed to unfollow #$tag", it)
Timber.e(it, "Failed to unfollow #%s", tag)
},
)
}
@ -259,11 +259,11 @@ class StatusListActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButton
updateTagMuteState(mutedFilterV1 != null)
},
{ throwable ->
Timber.e("Error getting filters: $throwable")
Timber.e(throwable, "Error getting filters")
},
)
} else {
Timber.e("Error getting filters: $throwable")
Timber.e(throwable, "Error getting filters")
}
},
)
@ -300,7 +300,7 @@ class StatusListActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButton
Snackbar.make(binding.root, getString(R.string.confirmation_hashtag_muted, hashtag), Snackbar.LENGTH_SHORT).show()
} else {
Snackbar.make(binding.root, getString(R.string.error_muting_hashtag_format, hashtag), Snackbar.LENGTH_SHORT).show()
Timber.e("Failed to mute $tagWithHash")
Timber.e("Failed to mute %s", tagWithHash)
}
},
{ throwable ->
@ -320,12 +320,12 @@ class StatusListActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButton
},
{ throwable ->
Snackbar.make(binding.root, getString(R.string.error_muting_hashtag_format, hashtag), Snackbar.LENGTH_SHORT).show()
Timber.e("Failed to mute $tagWithHash", throwable)
Timber.e(throwable, "Failed to mute %s", tagWithHash)
},
)
} else {
Snackbar.make(binding.root, getString(R.string.error_muting_hashtag_format, hashtag), Snackbar.LENGTH_SHORT).show()
Timber.e("Failed to mute $tagWithHash", throwable)
Timber.e(throwable, "Failed to mute %s", tagWithHash)
}
},
)
@ -379,7 +379,7 @@ class StatusListActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButton
},
{ throwable ->
Snackbar.make(binding.root, getString(R.string.error_unmuting_hashtag_format, hashtag), Snackbar.LENGTH_SHORT).show()
Timber.e("Failed to unmute $tagWithHash", throwable)
Timber.e(throwable, "Failed to unmute %s", tagWithHash)
},
)
}

View File

@ -314,7 +314,7 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
.autoDispose(AndroidLifecycleScopeProvider.from(this, Lifecycle.Event.ON_DESTROY))
.subscribe(
{ result ->
Timber.d("Download image result: $result")
Timber.d("Download image result: %s", result)
isCreating = false
invalidateOptionsMenu()
binding.progressBarShare.visibility = View.GONE
@ -326,7 +326,7 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
isCreating = false
invalidateOptionsMenu()
binding.progressBarShare.visibility = View.GONE
Timber.e("Failed to download image", error)
Timber.e(error, "Failed to download image")
},
)
}

View File

@ -81,7 +81,7 @@ class AccountViewModel @Inject constructor(
isFromOwnDomain = domain == activeAccount.domain
},
{ t ->
Timber.w("failed obtaining account", t)
Timber.w(t, "failed obtaining account")
accountData.postValue(Error(cause = t))
isDataLoading = false
isRefreshing.postValue(false)
@ -102,7 +102,7 @@ class AccountViewModel @Inject constructor(
relationshipData.postValue(if (relationships.isNotEmpty()) Success(relationships[0]) else Error())
},
{ t ->
Timber.w("failed obtaining relationships", t)
Timber.w(t, "failed obtaining relationships")
relationshipData.postValue(Error(cause = t))
},
)
@ -155,7 +155,7 @@ class AccountViewModel @Inject constructor(
relationshipData.postValue(Success(relation.copy(blockingDomain = true)))
}
}, { e ->
Timber.e("Error muting $instance", e)
Timber.e(e, "Error muting %s", instance)
})
}
}
@ -168,7 +168,7 @@ class AccountViewModel @Inject constructor(
relationshipData.postValue(Success(relation.copy(blockingDomain = false)))
}
}, { e ->
Timber.e("Error unmuting $instance", e)
Timber.e(e, "Error unmuting %s", instance)
})
}
}
@ -269,7 +269,7 @@ class AccountViewModel @Inject constructor(
}
},
{ t ->
Timber.w("failed loading relationship", t)
Timber.w(t, "failed loading relationship")
relationshipData.postValue(Error(relation, cause = t))
},
)
@ -288,7 +288,7 @@ class AccountViewModel @Inject constructor(
noteSaved.postValue(false)
},
{ t ->
Timber.w("Error updating note", t)
Timber.w(t, "Error updating note")
},
)
}

View File

@ -215,7 +215,7 @@ class AccountListFragment :
} else {
"unmute"
}
Timber.e("Failed to $verb account id $accountId")
Timber.e("Failed to %s account id %s", verb, accountId)
}
override fun onBlock(block: Boolean, id: String, position: Int) {
@ -255,7 +255,7 @@ class AccountListFragment :
} else {
"unblock"
}
Timber.e("Failed to $verb account accountId $accountId: $throwable")
Timber.e(throwable, "Failed to %s account accountId %s", verb, accountId)
}
override fun onRespondToFollowRequest(
@ -278,7 +278,7 @@ class AccountListFragment :
} else {
"reject"
}
Timber.e("Failed to $verb account id $accountId.", throwable)
Timber.e(throwable, "Failed to %s accountId %s", verb, accountId)
},
)
}
@ -390,7 +390,7 @@ class AccountListFragment :
lifecycleScope.launch {
api.relationships(ids)
.fold(::onFetchRelationshipsSuccess) { throwable ->
Timber.e("Fetch failure for relationships of accounts: $ids", throwable)
Timber.e(throwable, "Fetch failure for relationships of accounts: %s", ids)
}
}
}
@ -405,7 +405,7 @@ class AccountListFragment :
private fun onFetchAccountsFailure(throwable: Throwable) {
fetching = false
binding.swipeRefreshLayout.isRefreshing = false
Timber.e("Fetch failure", throwable)
Timber.e(throwable, "Fetch failure")
if (adapter.itemCount == 0) {
binding.messageView.show()

View File

@ -129,7 +129,7 @@ class AnnouncementsViewModel @Inject constructor(
)
},
{
Timber.w("Failed to add reaction to the announcement.", it)
Timber.w(it, "Failed to add reaction to the announcement.")
},
)
}
@ -168,7 +168,7 @@ class AnnouncementsViewModel @Inject constructor(
)
},
{
Timber.w("Failed to remove reaction from the announcement.", it)
Timber.w(it, "Failed to remove reaction from the announcement.")
},
)
}

View File

@ -196,7 +196,7 @@ class ComposeActivity :
} else if (result == CropImage.CancelledResult) {
Timber.w("Edit image cancelled by user")
} else {
Timber.w("Edit image failed: " + result.error)
Timber.w(result.error, "Edit image failed")
displayTransientMessage(R.string.error_image_edit_failed)
}
viewModel.cropImageItemOld = null

View File

@ -385,7 +385,7 @@ class ComposeViewModel @Inject constructor(
.fold({ accounts ->
accounts.map { AutocompleteResult.AccountResult(it) }
}, { e ->
Timber.e("Autocomplete search for $token failed.", e)
Timber.e(e, "Autocomplete search for %s failed.", token)
emptyList()
})
}
@ -394,7 +394,7 @@ class ComposeViewModel @Inject constructor(
.fold({ searchResult ->
searchResult.hashtags.map { AutocompleteResult.HashtagResult(it.name) }
}, { e ->
Timber.e("Autocomplete search for $token failed.", e)
Timber.e(e, "Autocomplete search for %s failed.", token)
emptyList()
})
}
@ -411,7 +411,7 @@ class ComposeViewModel @Inject constructor(
}
}
else -> {
Timber.w("Unexpected autocompletion token: $token")
Timber.w("Unexpected autocompletion token: %s", token)
return emptyList()
}
}

View File

@ -189,7 +189,7 @@ class MediaUploader @Inject constructor(
ContentResolver.SCHEME_FILE -> {
val path = uri.path
if (path == null) {
Timber.w("empty uri path $uri")
Timber.w("empty uri path %s", uri)
throw CouldNotOpenFileException()
}
val inputFile = File(path)
@ -209,7 +209,7 @@ class MediaUploader @Inject constructor(
}
}
else -> {
Timber.w("Unknown uri scheme $uri")
Timber.w("Unknown uri scheme %s", uri)
throw CouldNotOpenFileException()
}
}

View File

@ -83,7 +83,7 @@ class ConversationsViewModel @Inject constructor(
favourite,
)
}, { e ->
Timber.w("failed to favourite status", e)
Timber.w(e, "failed to favourite status")
})
}
}
@ -100,7 +100,7 @@ class ConversationsViewModel @Inject constructor(
bookmark,
)
}, { e ->
Timber.w("failed to bookmark status", e)
Timber.w(e, "failed to bookmark status")
})
}
}
@ -118,7 +118,7 @@ class ConversationsViewModel @Inject constructor(
converters.pollToJson(poll)!!,
)
}, { e ->
Timber.w("failed to vote in poll", e)
Timber.w(e, "failed to vote in poll")
})
}
}
@ -163,7 +163,7 @@ class ConversationsViewModel @Inject constructor(
accountId = accountManager.activeAccount!!.id,
)
} catch (e: Exception) {
Timber.w("failed to delete conversation", e)
Timber.w(e, "failed to delete conversation")
}
}
}
@ -179,7 +179,7 @@ class ConversationsViewModel @Inject constructor(
muted,
)
} catch (e: Exception) {
Timber.w("failed to mute conversation", e)
Timber.w(e, "failed to mute conversation")
}
}
}

View File

@ -153,7 +153,7 @@ class DraftHelper @Inject constructor(
suspend fun deleteAttachments(draft: DraftEntity) = withContext(Dispatchers.IO) {
draft.attachments.forEach { attachment ->
if (context.contentResolver.delete(attachment.uri, null, null) == 0) {
Timber.e("Did not delete file ${attachment.uriString}")
Timber.e("Did not delete file %s", attachment.uriString)
}
}
}
@ -193,7 +193,7 @@ class DraftHelper @Inject constructor(
}
}
} catch (ex: IOException) {
Timber.w("failed to save media", ex)
Timber.w(ex, "failed to save media")
return null
}
} else {

View File

@ -130,7 +130,7 @@ class DraftsActivity : BaseActivity(), DraftActionListener {
{ throwable ->
bottomSheet.state = BottomSheetBehavior.STATE_HIDDEN
Timber.w("failed loading reply information", throwable)
Timber.w(throwable, "failed loading reply information")
if (throwable is HttpException && throwable.code() == 404) {
// the original status to which a reply was drafted has been deleted

View File

@ -104,7 +104,7 @@ class FollowedTagsActivity :
binding.followedTagsMessageView.show()
val errorState = loadState.refresh as LoadState.Error
binding.followedTagsMessageView.setup(errorState.error) { retry() }
Timber.w("error loading followed hashtags", errorState.error)
Timber.w(errorState.error, "error loading followed hashtags")
} else {
binding.followedTagsView.show()
binding.followedTagsMessageView.hide()

View File

@ -41,7 +41,7 @@ class FollowedTagsViewModel @Inject constructor(
.fold({ searchResult ->
searchResult.hashtags.map { ComposeAutoCompleteAdapter.AutocompleteResult.HashtagResult(it.name) }
}, { e ->
Timber.e("Autocomplete search for $token failed.", e)
Timber.e(e, "Autocomplete search for %s failed.", token)
emptyList()
})
}

View File

@ -70,7 +70,7 @@ class InstanceListFragment :
api.blockDomain(instance).fold({
adapter.addItem(instance)
}, { e ->
Timber.e("Error muting domain $instance", e)
Timber.e(e, "Error muting domain %s", instance)
})
} else {
api.unblockDomain(instance).fold({
@ -81,7 +81,7 @@ class InstanceListFragment :
}
.show()
}, { e ->
Timber.e("Error unmuting domain $instance", e)
Timber.e(e, "Error unmuting domain %s", instance)
})
}
}
@ -136,7 +136,7 @@ class InstanceListFragment :
private fun onFetchInstancesFailure(throwable: Throwable) {
fetching = false
binding.instanceProgressBar.hide()
Timber.e("Fetch failure", throwable)
Timber.e(throwable, "Fetch failure")
if (adapter.itemCount == 0) {
binding.messageView.show()

View File

@ -110,7 +110,7 @@ class NotificationFetcher @Inject constructor(
accountManager.saveAccount(account)
} catch (e: Exception) {
Timber.e("Error while fetching notifications", e)
Timber.e(e, "Error while fetching notifications")
}
}
}
@ -142,18 +142,18 @@ class NotificationFetcher @Inject constructor(
// - The Mastodon marker API (if the server supports it)
// - account.notificationMarkerId
// - account.lastNotificationId
Timber.d("getting notification marker for ${account.fullName}")
Timber.d("getting notification marker for %s", account.fullName)
val remoteMarkerId = fetchMarker(authHeader, account)?.lastReadId ?: "0"
val localMarkerId = account.notificationMarkerId
val markerId = if (remoteMarkerId.isLessThan(localMarkerId)) localMarkerId else remoteMarkerId
val readingPosition = account.lastNotificationId
var minId: String? = if (readingPosition.isLessThan(markerId)) markerId else readingPosition
Timber.d(" remoteMarkerId: $remoteMarkerId")
Timber.d(" localMarkerId: $localMarkerId")
Timber.d(" readingPosition: $readingPosition")
Timber.d(" remoteMarkerId: %s", remoteMarkerId)
Timber.d(" localMarkerId: %s", localMarkerId)
Timber.d(" readingPosition: %s", readingPosition)
Timber.d("getting Notifications for ${account.fullName}, min_id: $minId")
Timber.d("getting Notifications for %s, min_id: %s", account.fullName, minId)
// Fetch all outstanding notifications
val notifications = buildList {
@ -181,7 +181,7 @@ class NotificationFetcher @Inject constructor(
// Save the newest notification ID in the marker.
notifications.firstOrNull()?.let {
val newMarkerId = notifications.first().id
Timber.d("updating notification marker for ${account.fullName} to: $newMarkerId")
Timber.d("updating notification marker for %s to: %s", account.fullName, newMarkerId)
mastodonApi.updateMarkersWithAuth(
auth = authHeader,
domain = account.domain,
@ -202,10 +202,10 @@ class NotificationFetcher @Inject constructor(
listOf("notifications"),
)
val notificationMarker = allMarkers["notifications"]
Timber.d("Fetched marker for ${account.fullName}: $notificationMarker")
Timber.d("Fetched marker for %s: %s", account.fullName, notificationMarker)
notificationMarker
} catch (e: Exception) {
Timber.e("Failed to fetch marker", e)
Timber.e(e, "Failed to fetch marker")
null
}
}

View File

@ -602,7 +602,7 @@ fun enablePullNotifications(context: Context) {
.setInitialDelay(5, TimeUnit.MINUTES)
.build()
workManager.enqueue(workRequest)
Timber.d("enabled notification checks with " + PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS + "ms interval")
Timber.d("enabled notification checks with %d ms interval", PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS)
}
fun disablePullNotifications(context: Context) {

View File

@ -216,12 +216,12 @@ class NotificationsFragment :
// - With a "Retry" option if the error included a UiAction to retry.
launch {
viewModel.uiError.collect { error ->
Timber.d(error.toString())
val message = getString(
error.message,
error.throwable.localizedMessage
?: getString(R.string.ui_error_unknown),
)
Timber.d(error.throwable, message)
val snackbar = Snackbar.make(
// Without this the FAB will not move out of the way
(activity as ActionButtonActivity).actionButton ?: binding.root,

View File

@ -43,7 +43,7 @@ class NotificationsPagingSource @Inject constructor(
) : PagingSource<String, Notification>() {
@OptIn(ExperimentalStdlibApi::class)
override suspend fun load(params: LoadParams<String>): LoadResult<String, Notification> {
Timber.d("load() with ${params.javaClass.simpleName} for key: ${params.key}")
Timber.d("load() with %s for key: %s", params.javaClass.simpleName, params.key)
try {
val response = when (params) {
@ -203,7 +203,7 @@ class NotificationsPagingSource @Inject constructor(
override fun getRefreshKey(state: PagingState<String, Notification>): String? {
return state.anchorPosition?.let { anchorPosition ->
val id = state.closestItemToPosition(anchorPosition)?.id
Timber.d(" getRefreshKey returning $id")
Timber.d(" getRefreshKey returning %s", id)
return id
}
}

View File

@ -50,7 +50,7 @@ class NotificationsRepository @Inject constructor(
pageSize: Int = PAGE_SIZE,
initialKey: String? = null,
): Flow<PagingData<Notification>> {
Timber.d("getNotificationsStream(), filtering: $filter")
Timber.d("getNotificationsStream(), filtering: %s", filter)
factory = InvalidatingPagingSourceFactory {
NotificationsPagingSource(mastodonApi, moshi, filter)

View File

@ -358,7 +358,7 @@ class NotificationsViewModel @Inject constructor(
.distinctUntilChanged()
// Save each change back to the active account
.onEach { action ->
Timber.d("notificationFilter: $action")
Timber.d("notificationFilter: %s", action)
account.notificationsFilter = serialize(action.filter)
accountManager.saveAccount(account)
}
@ -389,7 +389,7 @@ class NotificationsViewModel @Inject constructor(
.filterIsInstance<InfallibleUiAction.SaveVisibleId>()
.distinctUntilChanged()
.collectLatest { action ->
Timber.d("Saving visible ID: ${action.visibleId}, active account = ${account.id}")
Timber.d("Saving visible ID: %s, active account = %d", action.visibleId, account.id)
account.lastNotificationId = action.visibleId
accountManager.saveAccount(account)
}
@ -515,7 +515,7 @@ class NotificationsViewModel @Inject constructor(
filters: Set<Notification.Type>,
initialKey: String? = null,
): Flow<PagingData<NotificationViewData>> {
Timber.d("getNotifications: $initialKey")
Timber.d("getNotifications: %s", initialKey)
return repository.getNotificationsStream(filter = filters, initialKey = initialKey)
.map { pagingData ->
pagingData.map { notification ->
@ -553,7 +553,7 @@ class NotificationsViewModel @Inject constructor(
"0" -> null
else -> id
}
Timber.d("Restoring at $initialKey")
Timber.d("Restoring at %s", initialKey)
return initialKey
}

View File

@ -192,10 +192,10 @@ suspend fun registerUnifiedPushEndpoint(
auth,
buildSubscriptionData(context, account),
).onFailure { throwable ->
Timber.w("Error setting push endpoint for account ${account.id}", throwable)
Timber.w(throwable, "Error setting push endpoint for account %d", account.id)
disableUnifiedPushNotificationsForAccount(context, account)
}.onSuccess {
Timber.d("UnifiedPush registration succeeded for account ${account.id}")
Timber.d("UnifiedPush registration succeeded for account %d", account.id)
account.pushPubKey = keyPair.pubkey
account.pushPrivKey = keyPair.privKey
@ -214,7 +214,7 @@ suspend fun updateUnifiedPushSubscription(context: Context, api: MastodonApi, ac
account.domain,
buildSubscriptionData(context, account),
).onSuccess {
Timber.d("UnifiedPush subscription updated for account ${account.id}")
Timber.d("UnifiedPush subscription updated for account %d", account.id)
account.pushServerKey = it.serverKey
accountManager.saveAccount(account)
@ -226,10 +226,10 @@ suspend fun unregisterUnifiedPushEndpoint(api: MastodonApi, accountManager: Acco
withContext(Dispatchers.IO) {
api.unsubscribePushNotifications("Bearer ${account.accessToken}", account.domain)
.onFailure { throwable ->
Timber.w("Error unregistering push endpoint for account " + account.id, throwable)
Timber.w(throwable, "Error unregistering push endpoint for account %d", account.id)
}
.onSuccess {
Timber.d("UnifiedPush unregistration succeeded for account " + account.id)
Timber.d("UnifiedPush unregistration succeeded for account %d", account.id)
// Clear the URL in database
account.unifiedPushUrl = ""
account.pushServerKey = ""

View File

@ -329,7 +329,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat() {
}
override fun onFailure(call: Call<Account>, t: Throwable) {
Timber.e("failed updating settings on server", t)
Timber.e(t, "failed updating settings on server")
showErrorSnackbar(visibility, sensitive)
}
},

View File

@ -69,7 +69,7 @@ class StatusesPagingSource(
nextKey = result.lastOrNull()?.id,
)
} catch (e: Exception) {
Timber.w("failed to load statuses", e)
Timber.w(e, "failed to load statuses")
return LoadResult.Error(e)
}
}

View File

@ -51,7 +51,7 @@ class ScheduledStatusViewModel @Inject constructor(
pagingSourceFactory.remove(status)
},
{ throwable ->
Timber.w("Error deleting scheduled status: $throwable")
Timber.w(throwable, "Error deleting scheduled status")
},
)
}

View File

@ -127,7 +127,7 @@ class SearchViewModel @Inject constructor(
),
)
}, { t ->
Timber.d("Failed to reblog status ${statusViewData.id}", t)
Timber.d(t, "Failed to reblog status %s", statusViewData.id)
})
}
}
@ -145,7 +145,7 @@ class SearchViewModel @Inject constructor(
updateStatus(statusViewData.status.copy(poll = votedPoll))
viewModelScope.launch {
timelineCases.voteInPoll(statusViewData.id, votedPoll.id, choices)
.onFailure { t -> Timber.d("Failed to vote in poll: ${statusViewData.id}", t) }
.onFailure { t -> Timber.d(t, "Failed to vote in poll: %s", statusViewData.id) }
}
}

View File

@ -445,7 +445,7 @@ class SearchStatusesFragment : SearchFragment<StatusViewData>(), StatusActionLis
startActivity(intent)
},
{ error ->
Timber.w("error deleting status", error)
Timber.w(error, "error deleting status")
Toast.makeText(context, R.string.error_generic, Toast.LENGTH_SHORT).show()
},
)

View File

@ -80,7 +80,7 @@ class CachedTimelineRepository @Inject constructor(
pageSize: Int = PAGE_SIZE,
initialKey: String? = null,
): Flow<PagingData<TimelineStatusWithAccount>> {
Timber.d("getStatusStream(): key: $initialKey")
Timber.d("getStatusStream(): key: %s", initialKey)
return accountManager.activeAccountFlow.flatMapLatest {
activeAccount = it
@ -101,7 +101,7 @@ class CachedTimelineRepository @Inject constructor(
}
}
Timber.d("initialKey: $initialKey is row: $row")
Timber.d("initialKey: %s is row: %d", initialKey, row)
Pager(
config = PagingConfig(

View File

@ -85,7 +85,7 @@ class NetworkTimelineRepository @Inject constructor(
pageSize: Int = PAGE_SIZE,
initialKey: String? = null,
): Flow<PagingData<Status>> {
Timber.d("getStatusStream(): key: $initialKey")
Timber.d("getStatusStream(): key: %s", initialKey)
factory = InvalidatingPagingSourceFactory {
NetworkTimelinePagingSource(pageCache)

View File

@ -236,12 +236,12 @@ class TimelineFragment :
// TODO: Very similar to same code in NotificationsFragment
launch {
viewModel.uiError.collect { error ->
Timber.d(error.toString())
val message = getString(
error.message,
error.throwable.localizedMessage
?: getString(R.string.ui_error_unknown),
)
Timber.d(error.throwable, message)
snackbar = Snackbar.make(
// Without this the FAB will not move out of the way
(activity as? ActionButtonActivity)?.actionButton ?: binding.root,
@ -518,7 +518,7 @@ class TimelineFragment :
?.let { adapter.snapshot().getOrNull(it)?.id }
id?.let {
Timber.d("Saving ID: $it")
Timber.d("Saving ID: %s", it)
viewModel.accept(InfallibleUiAction.SaveVisibleId(visibleId = it))
}
}
@ -726,7 +726,7 @@ class TimelineFragment :
val wasEnabled = talkBackWasEnabled
talkBackWasEnabled = a11yManager?.isEnabled == true
Timber.d("talkback was enabled: $wasEnabled, now $talkBackWasEnabled")
Timber.d("talkback was enabled: %s, now %s", wasEnabled, talkBackWasEnabled)
if (talkBackWasEnabled && !wasEnabled) {
adapter.notifyItemRangeChanged(0, adapter.itemCount)
}

View File

@ -66,7 +66,7 @@ class CachedTimelineRemoteMediator(
return MediatorResult.Success(endOfPaginationReached = true)
}
Timber.d("load(), LoadType = $loadType")
Timber.d("load(), LoadType = %s", loadType)
return try {
val response = when (loadType) {
@ -75,7 +75,7 @@ class CachedTimelineRemoteMediator(
state.closestItemToPosition(maxOf(0, it - (state.config.pageSize / 2)))
}?.status?.serverId
val statusId = closestItem ?: initialKey
Timber.d("Loading from item: $statusId")
Timber.d("Loading from item: %s", statusId)
getInitialPage(statusId, state.config.pageSize)
}
LoadType.APPEND -> {
@ -84,7 +84,7 @@ class CachedTimelineRemoteMediator(
TIMELINE_ID,
RemoteKeyKind.NEXT,
) ?: return MediatorResult.Success(endOfPaginationReached = true)
Timber.d("Loading from remoteKey: $rke")
Timber.d("Loading from remoteKey: %s", rke)
api.homeTimeline(maxId = rke.key, limit = state.config.pageSize)
}
LoadType.PREPEND -> {
@ -93,7 +93,7 @@ class CachedTimelineRemoteMediator(
TIMELINE_ID,
RemoteKeyKind.PREV,
) ?: return MediatorResult.Success(endOfPaginationReached = true)
Timber.d("Loading from remoteKey: $rke")
Timber.d("Loading from remoteKey: %s", rke)
api.homeTimeline(minId = rke.key, limit = state.config.pageSize)
}
}
@ -103,7 +103,7 @@ class CachedTimelineRemoteMediator(
return MediatorResult.Error(HttpException(response))
}
Timber.d("${statuses.size} - # statuses loaded")
Timber.d("%d - # statuses loaded", statuses.size)
// This request succeeded with no new data, and pagination ends (unless this is a
// REFRESH, which must always set endOfPaginationReached to false).
@ -112,7 +112,7 @@ class CachedTimelineRemoteMediator(
return MediatorResult.Success(endOfPaginationReached = loadType != LoadType.REFRESH)
}
Timber.d(" ${statuses.first().id}..${statuses.last().id}")
Timber.d(" %s..%s", statuses.first().id, statuses.last().id)
val links = Links.from(response.headers()["link"])

View File

@ -86,7 +86,7 @@ class CachedTimelineViewModel @Inject constructor(
private fun getStatuses(
initialKey: String? = null,
): Flow<PagingData<StatusViewData>> {
Timber.d("getStatuses: kind: $timelineKind, initialKey: $initialKey")
Timber.d("getStatuses: kind: %s, initialKey: %s", timelineKind, initialKey)
return repository.getStatusStream(kind = timelineKind, initialKey = initialKey)
.map { pagingData ->
pagingData

View File

@ -32,7 +32,7 @@ class NetworkTimelinePagingSource @Inject constructor(
) : PagingSource<String, Status>() {
override suspend fun load(params: LoadParams<String>): LoadResult<String, Status> {
Timber.d("- load(), type = ${params.javaClass.simpleName}, key = ${params.key}")
Timber.d("- load(), type = %s, key = %s", params.javaClass.simpleName, params.key)
pageCache.debug()
val page = synchronized(pageCache) {
@ -106,7 +106,7 @@ class NetworkTimelinePagingSource @Inject constructor(
Timber.d(" Returning empty page")
} else {
Timber.d(" Returning full page:")
Timber.d(" $page")
Timber.d(" %s", page)
}
// Bail if this paging source has already been invalidated. If you do not do this there
@ -150,7 +150,7 @@ class NetworkTimelinePagingSource @Inject constructor(
it.getOrNull(it.size / 2)?.id
}
Timber.d("- getRefreshKey(), state.anchorPosition = ${state.anchorPosition}, return $refreshKey")
Timber.d("- getRefreshKey(), state.anchorPosition = %d, return %s", state.anchorPosition, refreshKey)
return refreshKey
}
}

View File

@ -100,7 +100,7 @@ class NetworkTimelineRemoteMediator(
}
}
Timber.d("- load(), type = $loadType, key = $key")
Timber.d("- load(), type = %s, key = %s", loadType, key)
val response = fetchStatusPageByKind(loadType, key, state.config.initialLoadSize)
val page = Page.tryFrom(response).getOrElse { return MediatorResult.Error(it) }
@ -113,7 +113,12 @@ class NetworkTimelineRemoteMediator(
}
pageCache.upsert(page)
Timber.d(" Page $loadType complete for $timelineKind, now got ${pageCache.size} pages")
Timber.d(
" Page %s complete for %s, now got %d pages",
loadType,
timelineKind,
pageCache.size,
)
pageCache.debug()
}
Timber.d(" Invalidating paging source")

View File

@ -84,7 +84,7 @@ class NetworkTimelineViewModel @Inject constructor(
private fun getStatuses(
initialKey: String? = null,
): Flow<PagingData<StatusViewData>> {
Timber.d("getStatuses: kind: $timelineKind, initialKey: $initialKey")
Timber.d("getStatuses: kind: %s, initialKey: %s", timelineKind, initialKey)
return repository.getStatusStream(viewModelScope, kind = timelineKind, initialKey = initialKey)
.map { pagingData ->
pagingData.map {
@ -122,8 +122,8 @@ class NetworkTimelineViewModel @Inject constructor(
}
override fun changeContentCollapsed(isCollapsed: Boolean, status: StatusViewData) {
Timber.d("changeContentCollapsed: $isCollapsed")
Timber.d(" " + status.content)
Timber.d("changeContentCollapsed: %s", isCollapsed)
Timber.d(" %s", status.content)
modifiedViewData[status.id] = status.copy(
isCollapsed = isCollapsed,
)

View File

@ -99,8 +99,8 @@ data class Page(
}
val links = Links.from(response.headers()["link"])
Timber.d(" link: " + response.headers()["link"])
Timber.d(" ${statuses.size} - # statuses loaded")
Timber.d(" link: %s", response.headers()["link"])
Timber.d(" %d - # statuses loaded", statuses.size)
return success(
Page(
@ -135,7 +135,7 @@ class PageCache : TreeMap<String, Page>(compareBy({ it.length }, { it })) {
val key = page.data.last().id
Timber.d("Inserting new page:")
Timber.d(" $page")
Timber.d(" %s", page)
this[key] = page
@ -161,7 +161,7 @@ class PageCache : TreeMap<String, Page>(compareBy({ it.length }, { it })) {
Timber.d(" ** empty **")
} else {
this.onEachIndexed { index, entry ->
Timber.d(" $index: ${entry.value}")
Timber.d(" %d: %s", index, entry.value)
}
}
}

View File

@ -413,7 +413,7 @@ abstract class TimelineViewModel(
.filterIsInstance<InfallibleUiAction.SaveVisibleId>()
.distinctUntilChanged()
.collectLatest { action ->
Timber.d("Saving Home timeline position at: ${action.visibleId}")
Timber.d("Saving Home timeline position at: %s", action.visibleId)
activeAccount.lastVisibleHomeTimelineStatusId = action.visibleId
accountManager.saveAccount(activeAccount)
readingPositionId = action.visibleId
@ -538,7 +538,7 @@ abstract class TimelineViewModel(
is FilterKind.V2 -> FilterModel(filterKind)
}
} catch (throwable: Throwable) {
Timber.d("updateFilter(): Error fetching filters: ${throwable.message}")
Timber.d(throwable, "updateFilter(): Error fetching filters")
_uiErrorChannel.send(UiError.GetFilters(throwable))
}
}

View File

@ -221,7 +221,7 @@ class TrendingLinksFragment :
val wasEnabled = talkBackWasEnabled
talkBackWasEnabled = a11yManager?.isEnabled == true
Timber.d("talkback was enabled: $wasEnabled, now $talkBackWasEnabled")
Timber.d("talkback was enabled: %s, now %s", wasEnabled, talkBackWasEnabled)
if (talkBackWasEnabled && !wasEnabled) {
adapter.notifyItemRangeChanged(0, adapter.itemCount)
}

View File

@ -264,7 +264,7 @@ class TrendingTagsFragment :
val wasEnabled = talkBackWasEnabled
talkBackWasEnabled = a11yManager?.isEnabled == true
Timber.d("talkback was enabled: $wasEnabled, now $talkBackWasEnabled")
Timber.d("talkback was enabled: %s, now %s", wasEnabled, talkBackWasEnabled)
if (talkBackWasEnabled && !wasEnabled) {
adapter.notifyItemRangeChanged(0, adapter.itemCount)
}

View File

@ -112,7 +112,7 @@ class TrendingTagsViewModel @Inject constructor(
}
},
{ error ->
Timber.w("failed loading trending tags", error)
Timber.w(error, "failed loading trending tags")
if (error is IOException) {
_uiState.value = TrendingTagsUiState(emptyList(), LoadingState.ERROR_NETWORK)
} else {

View File

@ -169,7 +169,7 @@ class ViewThreadFragment :
binding.statusView.hide()
}
is ThreadUiState.Error -> {
Timber.w("failed to load status", uiState.throwable)
Timber.w(uiState.throwable, "failed to load status")
initialProgressBar.cancel()
threadProgressBar.cancel()
@ -217,7 +217,7 @@ class ViewThreadFragment :
lifecycleScope.launch {
viewModel.errors.collect { throwable ->
Timber.w("failed to load status context", throwable)
Timber.w(throwable, "failed to load status context")
val msg = view.context.getString(R.string.error_generic_fmt, throwable)
Snackbar.make(binding.root, msg, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.action_retry) {

View File

@ -127,7 +127,7 @@ class ViewThreadViewModel @Inject constructor(
_uiState.value = ThreadUiState.Loading
viewModelScope.launch {
Timber.d("Finding status with: $id")
Timber.d("Finding status with: %s", id)
val contextCall = async { api.statusContext(id) }
val timelineStatusWithAccount = timelineDao.getStatus(id)
@ -265,7 +265,7 @@ class ViewThreadViewModel @Inject constructor(
timelineCases.reblog(status.actionableId, reblog).getOrThrow()
} catch (t: Exception) {
ifExpected(t) {
Timber.d("Failed to reblog status " + status.actionableId, t)
Timber.d(t, "Failed to reblog status: %s", status.actionableId)
}
}
}
@ -275,7 +275,7 @@ class ViewThreadViewModel @Inject constructor(
timelineCases.favourite(status.actionableId, favorite).getOrThrow()
} catch (t: Exception) {
ifExpected(t) {
Timber.d("Failed to favourite status " + status.actionableId, t)
Timber.d(t, "Failed to favourite status: %s ", status.actionableId)
}
}
}
@ -285,7 +285,7 @@ class ViewThreadViewModel @Inject constructor(
timelineCases.bookmark(status.actionableId, bookmark).getOrThrow()
} catch (t: Exception) {
ifExpected(t) {
Timber.d("Failed to bookmark status " + status.actionableId, t)
Timber.d(t, "Failed to bookmark status: %s", status.actionableId)
}
}
}
@ -300,7 +300,7 @@ class ViewThreadViewModel @Inject constructor(
timelineCases.voteInPoll(status.actionableId, poll.id, choices).getOrThrow()
} catch (t: Exception) {
ifExpected(t) {
Timber.d("Failed to vote in poll: " + status.actionableId, t)
Timber.d(t, "Failed to vote in poll: %s", status.actionableId)
}
}
}

View File

@ -103,7 +103,7 @@ class ViewEditsFragment :
}
EditsUiState.Refreshing -> {}
is EditsUiState.Error -> {
Timber.w("failed to load edits", uiState.throwable)
Timber.w(uiState.throwable, "failed to load edits")
binding.swipeRefreshLayout.isRefreshing = false
binding.recyclerView.hide()

View File

@ -56,7 +56,7 @@ class DraftsAlert @Inject constructor(private val draftDao: DraftDao) {
// at init, at next onResume, or immediately if the context is resumed already.
if (showAlert) {
draftsNeedUserAlert.observe(context) { count ->
Timber.d("User id $activeAccountId changed: Notification-worthy draft count $count")
Timber.d("User id %d changed: Notification-worthy draft count %d", activeAccountId, count)
if (count > 0) {
AlertDialog.Builder(context)
.setTitle(R.string.action_post_failed)
@ -77,7 +77,7 @@ class DraftsAlert @Inject constructor(private val draftDao: DraftDao) {
}
} else {
draftsNeedUserAlert.observe(context) {
Timber.d("User id $activeAccountId: Clean out notification-worthy drafts")
Timber.d("User id %d: Clean out notification-worthy drafts", activeAccountId)
clearDraftsAlert(coroutineScope, activeAccountId)
}
}

View File

@ -425,7 +425,7 @@ abstract class SFragment<T : IStatusViewData> : Fragment(), StatusActionListener
lifecycleScope.launch {
val result = timelineCases.delete(viewData.status.id).exceptionOrNull()
if (result != null) {
Timber.w("error deleting status", result)
Timber.w(result, "error deleting status")
Toast.makeText(context, R.string.error_generic, Toast.LENGTH_SHORT).show()
}
// XXX: Removes the item even if there was an error. This is probably not

View File

@ -100,7 +100,7 @@ class ServerRepository @Inject constructor(
val nodeInfoUrl = nodeInfoUrlResult.bind()
Timber.d("Loading node info from $nodeInfoUrl")
Timber.d("Loading node info from %s", nodeInfoUrl)
val nodeInfo = nodeInfoApi.nodeInfo(nodeInfoUrl).fold(
{ NodeInfo.from(it).mapError { ValidateNodeInfo(nodeInfoUrl, it) } },
{ Err(GetNodeInfo(nodeInfoUrl, it)) },

View File

@ -42,14 +42,14 @@ class UnifiedPushBroadcastReceiver : MessagingReceiver() {
lateinit var mastodonApi: MastodonApi
override fun onMessage(context: Context, message: ByteArray, instance: String) {
Timber.d("New message received for account $instance")
Timber.d("New message received for account %s", instance)
val workManager = WorkManager.getInstance(context)
val request = OneTimeWorkRequest.from(NotificationWorker::class.java)
workManager.enqueue(request)
}
override fun onNewEndpoint(context: Context, endpoint: String, instance: String) {
Timber.d("Endpoint available for account $instance: $endpoint")
Timber.d("Endpoint available for account %s: %s", instance, endpoint)
accountManager.getAccountById(instance.toLong())?.let {
// Launch the coroutine in global scope -- it is short and we don't want to lose the registration event
// and there is no saner way to use structured concurrency in a receiver
@ -60,7 +60,7 @@ class UnifiedPushBroadcastReceiver : MessagingReceiver() {
override fun onRegistrationFailed(context: Context, instance: String) = Unit
override fun onUnregistered(context: Context, instance: String) {
Timber.d("Endpoint unregistered for account $instance")
Timber.d("Endpoint unregistered for account %s", instance)
accountManager.getAccountById(instance.toLong())?.let {
// It's fine if the account does not exist anymore -- that means it has been logged out
GlobalScope.launch { unregisterUnifiedPushEndpoint(mastodonApi, accountManager, it) }

View File

@ -147,7 +147,7 @@ class SendStatusService : Service() {
when (val uploadState = mediaUploader.getMediaUploadState(mediaItem.localId)) {
is UploadEvent.FinishedEvent -> mediaItem.copy(id = uploadState.mediaId, processed = uploadState.processed)
is UploadEvent.ErrorEvent -> {
Timber.w("failed uploading media", uploadState.error)
Timber.w(uploadState.error, "failed uploading media")
failSending(statusId)
stopSelfWhenDone()
return@launch
@ -179,7 +179,7 @@ class SendStatusService : Service() {
mediaCheckRetries++
}
} catch (e: Exception) {
Timber.w("failed getting media status", e)
Timber.w(e, "failed getting media status")
retrySending(statusId)
return@launch
}
@ -192,7 +192,7 @@ class SendStatusService : Service() {
mastodonApi.updateMedia(mediaItem.id!!, mediaItem.description, mediaItem.focus?.toMastodonApiString())
.fold({
}, { throwable ->
Timber.w("failed to update media on status send", throwable)
Timber.w(throwable, "failed to update media on status send")
failOrRetry(throwable, statusId)
return@launch
@ -269,7 +269,7 @@ class SendStatusService : Service() {
notificationManager.cancel(statusId)
}, { throwable ->
Timber.w("failed sending status: $throwable")
Timber.w(throwable, "failed sending status")
failOrRetry(throwable, statusId)
})
stopSelfWhenDone()

View File

@ -93,7 +93,7 @@ class TimelineCases @Inject constructor(
mastodonApi.muteAccount(statusId, notifications, duration)
eventHub.dispatch(MuteEvent(statusId))
} catch (t: Throwable) {
Timber.w("Failed to mute account", t)
Timber.w(t, "Failed to mute account")
}
}
@ -102,14 +102,14 @@ class TimelineCases @Inject constructor(
mastodonApi.blockAccount(statusId)
eventHub.dispatch(BlockEvent(statusId))
} catch (t: Throwable) {
Timber.w("Failed to block account", t)
Timber.w(t, "Failed to block account")
}
}
suspend fun delete(statusId: String): NetworkResult<DeletedStatus> {
return mastodonApi.deleteStatus(statusId)
.onSuccess { eventHub.dispatch(StatusDeletedEvent(statusId)) }
.onFailure { Timber.w("Failed to delete status", it) }
.onFailure { Timber.w(it, "Failed to delete status") }
}
suspend fun pin(statusId: String, pin: Boolean): NetworkResult<Status> {
@ -121,7 +121,7 @@ class TimelineCases @Inject constructor(
eventHub.dispatch(PinEvent(statusId, pin))
NetworkResult.success(status)
}, { e ->
Timber.w("Failed to change pin state", e)
Timber.w(e, "Failed to change pin state")
NetworkResult.failure(TimelineError(e.getServerErrorMessage()))
})
}

View File

@ -166,7 +166,7 @@ fun Flow<CombinedLoadStates>.asRefreshState(): Flow<UserRefreshState> {
if (BuildConfig.DEBUG) {
previousLoadState?.let {
val loadStateDiff = loadState.diff(previousLoadState)
Timber.d("Current state: $refresh $prepend")
Timber.d("Current state: %s %s", refresh, prepend)
if (loadStateDiff.isNotEmpty()) Timber.d(loadStateDiff)
}
previousLoadState = loadState

View File

@ -46,7 +46,7 @@ private fun ensureLanguagesAreFirst(locales: MutableList<Locale>, languages: Lis
// - Your per-account posting language is set to one android doesn't know (e.g. toki pona)
// - Replying to a post in a language android doesn't know
locales.add(0, Locale(language))
Timber.w("Attempting to use unknown language tag '$language'")
Timber.w("Attempting to use unknown language tag '%s'", language)
continue
}
}

View File

@ -42,7 +42,7 @@ class PruneCacheWorker(
override suspend fun doWork(): Result {
for (account in accountManager.accounts) {
Timber.d("Pruning database using account ID: ${account.id}")
Timber.d("Pruning database using account ID: %d", account.id)
timelineDao.cleanup(account.id, MAX_STATUSES_IN_CACHE)
}
return Result.success()

View File

@ -56,7 +56,7 @@ class WorkerFactory @Inject constructor(
// Class might be missing if it was renamed / moved to a different package, as
// periodic work requests from before the rename might still exist. Catch and
// return null, which should stop future requests.
Timber.d("Invalid class: $workerClassName", e)
Timber.d(e, "Invalid class: %s", workerClassName)
null
}
workerFactories[key]?.let {

View File

@ -89,7 +89,7 @@ class AccountManager @Inject constructor(
) {
activeAccount?.let {
it.isActive = false
Timber.d("addAccount: saving account with id " + it.id)
Timber.d("addAccount: saving account with id %d", it.id)
accountDao.insertOrReplace(it)
}
@ -131,7 +131,7 @@ class AccountManager @Inject constructor(
*/
fun saveAccount(account: AccountEntity) {
if (account.id != 0L) {
Timber.d("saveAccount: saving account with id " + account.id)
Timber.d("saveAccount: saving account with id %d", account.id)
accountDao.insertOrReplace(account)
}
}
@ -152,7 +152,7 @@ class AccountManager @Inject constructor(
if (accounts.size > 0) {
accounts[0].isActive = true
activeAccount = accounts[0]
Timber.d("logActiveAccountOut: saving account with id " + accounts[0].id)
Timber.d("logActiveAccountOut: saving account with id %d", accounts[0].id)
accountDao.insertOrReplace(accounts[0])
} else {
activeAccount = null
@ -178,7 +178,7 @@ class AccountManager @Inject constructor(
it.emojis = account.emojis.orEmpty()
it.locked = account.locked
Timber.d("updateActiveAccount: saving account with id " + it.id)
Timber.d("updateActiveAccount: saving account with id %d", it.id)
accountDao.insertOrReplace(it)
}
}
@ -193,7 +193,7 @@ class AccountManager @Inject constructor(
} ?: return // invalid accountId passed, do nothing
activeAccount?.let {
Timber.d("setActiveAccount: saving account with id " + it.id)
Timber.d("setActiveAccount: saving account with id %d", it.id)
it.isActive = false
saveAccount(it)
}

View File

@ -54,7 +54,7 @@ fun openLinkInCustomTab(uri: Uri, context: Context) {
try {
customTabsIntent.launchUrl(context, uri)
} catch (e: ActivityNotFoundException) {
Timber.w("Activity was not found for intent $customTabsIntent")
Timber.w(e, "Activity was not found for intent %s", customTabsIntent)
openLinkInBrowser(uri, context)
}
}
@ -70,7 +70,7 @@ private fun openLinkInBrowser(uri: Uri?, context: Context) {
try {
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
Timber.w("Activity was not found for intent, $intent")
Timber.w(e, "Activity was not found for intent, %s", intent)
}
}

View File

@ -48,7 +48,7 @@ class InstanceInfoRepository @Inject constructor(
api.getCustomEmojis()
.onSuccess { emojiList -> instanceDao.upsert(EmojisEntity(instanceName, emojiList)) }
.getOrElse { throwable ->
Timber.w("failed to load custom emojis, falling back to cache", throwable)
Timber.w(throwable, "failed to load custom emojis, falling back to cache")
instanceDao.getEmojiInfo(instanceName)?.emojiList.orEmpty()
}
}
@ -85,7 +85,7 @@ class InstanceInfoRepository @Inject constructor(
instanceEntity
},
{ throwable ->
Timber.w("failed to instance, falling back to cache and default values", throwable)
Timber.w(throwable, "failed to instance, falling back to cache and default values")
try {
instanceDao.getInstanceInfo(instanceName)
} catch (_: Exception) {

View File

@ -100,7 +100,7 @@ object NetworkModule {
ProxyConfiguration.create(httpServer, httpPort)?.also { conf ->
val address = InetSocketAddress.createUnresolved(IDN.toASCII(conf.hostname), conf.port)
builder.proxy(Proxy(Proxy.Type.HTTP, address))
} ?: Timber.w("Invalid proxy configuration: ($httpServer, $httpPort)")
} ?: Timber.w("Invalid proxy configuration: (%s, %d)", httpServer, httpPort)
}
return builder

View File

@ -65,7 +65,7 @@ class InstanceSwitchAuthInterceptor @Inject constructor() : Interceptor {
val newRequest: Request = builder.build()
if (MastodonApi.PLACEHOLDER_DOMAIN == newRequest.url.host) {
Timber.w("no user logged in or no domain header specified - can't make request to " + newRequest.url)
Timber.w("no user logged in or no domain header specified - can't make request to %s", newRequest.url)
return Response.Builder()
.code(400)
.message("Bad Request")

View File

@ -215,7 +215,7 @@ class ClickableSpanTextView @JvmOverloads constructor(
for ((rect, span) in spanRects) {
if (!rect.contains(x, y)) continue
clickedSpan = span
Timber.v("span click: ${(clickedSpan as URLSpan).url}")
Timber.v("span click: %s", (clickedSpan as URLSpan).url)
return super.onTouchEvent(event)
}
@ -230,13 +230,13 @@ class ClickableSpanTextView @JvmOverloads constructor(
activeEntry = entry
continue
}
Timber.v("Overlap: ${(entry.value as URLSpan).url} ${(activeEntry.value as URLSpan).url}")
Timber.v("Overlap: %s %s", (entry.value as URLSpan).url, (activeEntry.value as URLSpan).url)
if (isClickOnFirst(entry.key, activeEntry.key, x, y)) {
activeEntry = entry
}
}
clickedSpan = activeEntry?.value
clickedSpan?.let { Timber.v("padding click: ${(clickedSpan as URLSpan).url}") }
clickedSpan?.let { Timber.v("padding click: %s", (clickedSpan as URLSpan).url) }
return super.onTouchEvent(event)
}
ACTION_UP -> {
@ -334,7 +334,7 @@ class ClickableSpanTextView @JvmOverloads constructor(
* @return true if the click was closer to the first rectangle than the second
*/
private fun isClickOnFirst(first: RectF, second: RectF, x: Float, y: Float): Boolean {
Timber.v("first: $first second: $second click: $x $y")
Timber.v("first: %s second: %s click: %f %f", first, second, x, y)
val (firstDiff, secondDiff) = if (first.top == second.top) {
Timber.v("left/right overlap")
Pair(abs(first.centerX() - x), abs(second.centerX() - x))
@ -342,7 +342,7 @@ class ClickableSpanTextView @JvmOverloads constructor(
Timber.v("top/bottom overlap")
Pair(abs(first.centerY() - y), abs(second.centerY() - y))
}
Timber.d("firstDiff: $firstDiff secondDiff: $secondDiff")
Timber.d("firstDiff: %f secondDiff: %f", firstDiff, secondDiff)
return firstDiff < secondDiff
}

View File

@ -297,7 +297,7 @@ class LoginActivity : BaseActivity() {
setLoading(false)
binding.domainTextInputLayout.error =
getString(R.string.error_retrieving_oauth_token)
Timber.e(getString(R.string.error_retrieving_oauth_token), e)
Timber.e(e, getString(R.string.error_retrieving_oauth_token))
},
)
}
@ -330,7 +330,7 @@ class LoginActivity : BaseActivity() {
setLoading(false)
binding.domainTextInputLayout.error =
getString(R.string.error_loading_account_details)
Timber.e(getString(R.string.error_loading_account_details), e)
Timber.e(e, getString(R.string.error_loading_account_details))
})
}

View File

@ -149,7 +149,7 @@ class LoginWebViewActivity : BaseActivity() {
request: WebResourceRequest,
error: WebResourceError,
) {
Timber.d("Failed to load ${data.url}: $error")
Timber.d("Failed to load %s: %s", data.url, error)
sendResult(LoginResult.Err(getString(R.string.error_could_not_load_login_page)))
}

View File

@ -43,7 +43,7 @@ class LoginWebViewViewModel @Inject constructor(
api.getInstanceV1(domain).fold({ instance ->
instanceRules.value = instance.rules?.map { rule -> rule.text }.orEmpty()
}, { throwable ->
Timber.w("failed to load instance info", throwable)
Timber.w(throwable, "failed to load instance info")
})
}
}