Cleanup dagger setup (#2300)

* cleanup dagger setup

* fix tests

* fix ktlint

* cleanup FragmentBuildersModule
This commit is contained in:
Konrad Pozniak 2022-01-23 20:24:55 +01:00 committed by GitHub
parent 0b70f52ad2
commit e29567c9ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 44 additions and 159 deletions

View File

@ -2,21 +2,19 @@ package com.keylesspalace.tusky.appstore
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.subjects.PublishSubject
import javax.inject.Inject
import javax.inject.Singleton
interface Event
interface Dispatchable : Event
interface EventHub {
val events: Observable<Event>
fun dispatch(event: Dispatchable)
}
object EventHubImpl : EventHub {
@Singleton
class EventHub @Inject constructor() {
private val eventsSubject = PublishSubject.create<Event>()
override val events: Observable<Event> = eventsSubject
val events: Observable<Event> = eventsSubject
override fun dispatch(event: Dispatchable) {
fun dispatch(event: Dispatchable) {
eventsSubject.onNext(event)
}
}

View File

@ -41,6 +41,7 @@ import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.Date
import javax.inject.Inject
sealed class UploadEvent {
data class ProgressEvent(val percentage: Int) : UploadEvent()
@ -61,21 +62,16 @@ fun createNewImageFile(context: Context): File {
data class PreparedMedia(val type: QueuedMedia.Type, val uri: Uri, val size: Long)
interface MediaUploader {
fun prepareMedia(inUri: Uri): Single<PreparedMedia>
fun uploadMedia(media: QueuedMedia): Observable<UploadEvent>
}
class AudioSizeException : Exception()
class VideoSizeException : Exception()
class MediaTypeException : Exception()
class CouldNotOpenFileException : Exception()
class MediaUploaderImpl(
class MediaUploader @Inject constructor(
private val context: Context,
private val mastodonApi: MastodonApi
) : MediaUploader {
override fun uploadMedia(media: QueuedMedia): Observable<UploadEvent> {
) {
fun uploadMedia(media: QueuedMedia): Observable<UploadEvent> {
return Observable
.fromCallable {
if (shouldResizeMedia(media)) {
@ -86,7 +82,7 @@ class MediaUploaderImpl(
.subscribeOn(Schedulers.io())
}
override fun prepareMedia(inUri: Uri): Single<PreparedMedia> {
fun prepareMedia(inUri: Uri): Single<PreparedMedia> {
return Single.fromCallable {
var mediaSize = getMediaSize(contentResolver, inUri)
var uri = inUri

View File

@ -1,5 +1,6 @@
package com.keylesspalace.tusky.components.notifications
import android.content.Context
import android.util.Log
import com.keylesspalace.tusky.db.AccountEntity
import com.keylesspalace.tusky.db.AccountManager
@ -12,7 +13,7 @@ import javax.inject.Inject
class NotificationFetcher @Inject constructor(
private val mastodonApi: MastodonApi,
private val accountManager: AccountManager,
private val notifier: Notifier
private val context: Context
) {
fun fetchAndShow() {
for (account in accountManager.getAllAccountsOrderedByActive()) {
@ -20,7 +21,7 @@ class NotificationFetcher @Inject constructor(
try {
val notifications = fetchNotifications(account)
notifications.forEachIndexed { index, notification ->
notifier.show(notification, account, index == 0)
NotificationHelper.make(context, notification, account, index == 0)
}
accountManager.saveAccount(account)
} catch (e: Exception) {

View File

@ -1,20 +0,0 @@
package com.keylesspalace.tusky.components.notifications
import android.content.Context
import com.keylesspalace.tusky.db.AccountEntity
import com.keylesspalace.tusky.entity.Notification
/**
* Shows notifications.
*/
interface Notifier {
fun show(notification: Notification, account: AccountEntity, isFirstInBatch: Boolean)
}
class SystemNotifier(
private val context: Context
) : Notifier {
override fun show(notification: Notification, account: AccountEntity, isFirstInBatch: Boolean) {
NotificationHelper.make(context, notification, account, isFirstInBatch)
}
}

View File

@ -34,8 +34,7 @@ import javax.inject.Singleton
ActivitiesModule::class,
ServicesModule::class,
BroadcastReceiverModule::class,
ViewModelModule::class,
MediaUploaderModule::class
ViewModelModule::class
]
)
interface AppComponent {

View File

@ -18,19 +18,11 @@ package com.keylesspalace.tusky.di
import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
import androidx.room.Room
import com.keylesspalace.tusky.TuskyApplication
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.EventHubImpl
import com.keylesspalace.tusky.components.notifications.Notifier
import com.keylesspalace.tusky.components.notifications.SystemNotifier
import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.db.Converters
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.network.TimelineCases
import com.keylesspalace.tusky.network.TimelineCasesImpl
import dagger.Module
import dagger.Provides
import javax.inject.Singleton
@ -53,23 +45,6 @@ class AppModule {
return PreferenceManager.getDefaultSharedPreferences(app)
}
@Provides
fun providesBroadcastManager(app: Application): LocalBroadcastManager {
return LocalBroadcastManager.getInstance(app)
}
@Provides
fun providesTimelineUseCases(
api: MastodonApi,
eventHub: EventHub
): TimelineCases {
return TimelineCasesImpl(api, eventHub)
}
@Provides
@Singleton
fun providesEventHub(): EventHub = EventHubImpl
@Provides
@Singleton
fun providesDatabase(appContext: Context, converters: Converters): AppDatabase {
@ -90,8 +65,4 @@ class AppModule {
)
.build()
}
@Provides
@Singleton
fun notifier(context: Context): Notifier = SystemNotifier(context)
}

View File

@ -56,9 +56,6 @@ abstract class FragmentBuildersModule {
@ContributesAndroidInjector
abstract fun notificationsFragment(): NotificationsFragment
@ContributesAndroidInjector
abstract fun searchFragment(): SearchStatusesFragment
@ContributesAndroidInjector
abstract fun notificationPreferencesFragment(): NotificationPreferencesFragment
@ -66,7 +63,7 @@ abstract class FragmentBuildersModule {
abstract fun accountPreferencesFragment(): AccountPreferencesFragment
@ContributesAndroidInjector
abstract fun directMessagesPreferencesFragment(): ConversationsFragment
abstract fun conversationsFragment(): ConversationsFragment
@ContributesAndroidInjector
abstract fun accountInListsFragment(): AccountsInListFragment
@ -83,6 +80,9 @@ abstract class FragmentBuildersModule {
@ContributesAndroidInjector
abstract fun instanceListFragment(): InstanceListFragment
@ContributesAndroidInjector
abstract fun searchStatusesFragment(): SearchStatusesFragment
@ContributesAndroidInjector
abstract fun searchAccountFragment(): SearchAccountsFragment

View File

@ -1,30 +0,0 @@
/* Copyright 2019 Tusky Contributors
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.di
import android.content.Context
import com.keylesspalace.tusky.components.compose.MediaUploader
import com.keylesspalace.tusky.components.compose.MediaUploaderImpl
import com.keylesspalace.tusky.network.MastodonApi
import dagger.Module
import dagger.Provides
@Module
class MediaUploaderModule {
@Provides
fun providesMediaUploder(context: Context, mastodonApi: MastodonApi): MediaUploader =
MediaUploaderImpl(context, mastodonApi)
}

View File

@ -15,25 +15,12 @@
package com.keylesspalace.tusky.di
import android.content.Context
import com.keylesspalace.tusky.service.SendTootService
import com.keylesspalace.tusky.service.ServiceClient
import com.keylesspalace.tusky.service.ServiceClientImpl
import dagger.Module
import dagger.Provides
import dagger.android.ContributesAndroidInjector
@Module
abstract class ServicesModule {
@ContributesAndroidInjector
abstract fun contributesSendTootService(): SendTootService
@Module
companion object {
@Provides
@JvmStatic
fun providesServiceClient(context: Context): ServiceClient {
return ServiceClientImpl(context)
}
}
}

View File

@ -32,27 +32,16 @@ import com.keylesspalace.tusky.entity.Status
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.addTo
import javax.inject.Inject
/**
* Created by charlag on 3/24/18.
*/
interface TimelineCases {
fun reblog(statusId: String, reblog: Boolean): Single<Status>
fun favourite(statusId: String, favourite: Boolean): Single<Status>
fun bookmark(statusId: String, bookmark: Boolean): Single<Status>
fun mute(statusId: String, notifications: Boolean, duration: Int?)
fun block(statusId: String)
fun delete(statusId: String): Single<DeletedStatus>
fun pin(statusId: String, pin: Boolean): Single<Status>
fun voteInPoll(statusId: String, pollId: String, choices: List<Int>): Single<Poll>
fun muteConversation(statusId: String, mute: Boolean): Single<Status>
}
class TimelineCasesImpl(
class TimelineCases @Inject constructor(
private val mastodonApi: MastodonApi,
private val eventHub: EventHub
) : TimelineCases {
) {
/**
* Unused yet but can be use for cancellation later. It's always a good idea to save
@ -60,7 +49,7 @@ class TimelineCasesImpl(
*/
private val cancelDisposable = CompositeDisposable()
override fun reblog(statusId: String, reblog: Boolean): Single<Status> {
fun reblog(statusId: String, reblog: Boolean): Single<Status> {
val call = if (reblog) {
mastodonApi.reblogStatus(statusId)
} else {
@ -71,7 +60,7 @@ class TimelineCasesImpl(
}
}
override fun favourite(statusId: String, favourite: Boolean): Single<Status> {
fun favourite(statusId: String, favourite: Boolean): Single<Status> {
val call = if (favourite) {
mastodonApi.favouriteStatus(statusId)
} else {
@ -82,7 +71,7 @@ class TimelineCasesImpl(
}
}
override fun bookmark(statusId: String, bookmark: Boolean): Single<Status> {
fun bookmark(statusId: String, bookmark: Boolean): Single<Status> {
val call = if (bookmark) {
mastodonApi.bookmarkStatus(statusId)
} else {
@ -93,7 +82,7 @@ class TimelineCasesImpl(
}
}
override fun muteConversation(statusId: String, mute: Boolean): Single<Status> {
fun muteConversation(statusId: String, mute: Boolean): Single<Status> {
val call = if (mute) {
mastodonApi.muteConversation(statusId)
} else {
@ -104,7 +93,7 @@ class TimelineCasesImpl(
}
}
override fun mute(statusId: String, notifications: Boolean, duration: Int?) {
fun mute(statusId: String, notifications: Boolean, duration: Int?) {
mastodonApi.muteAccount(statusId, notifications, duration)
.subscribe(
{
@ -117,7 +106,7 @@ class TimelineCasesImpl(
.addTo(cancelDisposable)
}
override fun block(statusId: String) {
fun block(statusId: String) {
mastodonApi.blockAccount(statusId)
.subscribe(
{
@ -130,14 +119,14 @@ class TimelineCasesImpl(
.addTo(cancelDisposable)
}
override fun delete(statusId: String): Single<DeletedStatus> {
fun delete(statusId: String): Single<DeletedStatus> {
return mastodonApi.deleteStatus(statusId)
.doAfterSuccess {
eventHub.dispatch(StatusDeletedEvent(statusId))
}
}
override fun pin(statusId: String, pin: Boolean): Single<Status> {
fun pin(statusId: String, pin: Boolean): Single<Status> {
// Replace with extension method if we use RxKotlin
return (if (pin) mastodonApi.pinStatus(statusId) else mastodonApi.unpinStatus(statusId))
.doAfterSuccess {
@ -145,7 +134,7 @@ class TimelineCasesImpl(
}
}
override fun voteInPoll(statusId: String, pollId: String, choices: List<Int>): Single<Poll> {
fun voteInPoll(statusId: String, pollId: String, choices: List<Int>): Single<Poll> {
if (choices.isEmpty()) {
return Single.error(IllegalStateException())
}

View File

@ -16,19 +16,12 @@
package com.keylesspalace.tusky.service
import android.content.Context
import android.os.Build
import androidx.core.content.ContextCompat
import javax.inject.Inject
interface ServiceClient {
fun sendToot(tootToSend: TootToSend)
}
class ServiceClientImpl(private val context: Context) : ServiceClient {
override fun sendToot(tootToSend: TootToSend) {
class ServiceClient @Inject constructor(private val context: Context) {
fun sendToot(tootToSend: TootToSend) {
val intent = SendTootService.sendTootIntent(context, tootToSend)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
ContextCompat.startForegroundService(context, intent)
}
}

View File

@ -9,7 +9,7 @@ import androidx.room.Room
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.google.gson.Gson
import com.keylesspalace.tusky.appstore.EventHubImpl
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.components.timeline.TimelinePagingAdapter.Companion.TimelineDifferCallback
import com.keylesspalace.tusky.components.timeline.viewmodel.CachedTimelineViewModel
import com.keylesspalace.tusky.components.timeline.viewmodel.NetworkTimelineViewModel
@ -20,7 +20,7 @@ import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.db.Converters
import com.keylesspalace.tusky.network.FilterModel
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.network.TimelineCasesImpl
import com.keylesspalace.tusky.network.TimelineCases
import com.nhaarman.mockitokotlin2.doReturn
import com.nhaarman.mockitokotlin2.mock
import io.reactivex.rxjava3.core.Single
@ -66,6 +66,8 @@ class TimelineViewModelTest {
)
}
private val eventHub = EventHub()
private lateinit var db: AppDatabase
@Before
@ -115,9 +117,9 @@ class TimelineViewModelTest {
}
val viewModel = NetworkTimelineViewModel(
TimelineCasesImpl(api, EventHubImpl),
TimelineCases(api, eventHub),
api,
EventHubImpl,
eventHub,
accountManager,
mock(),
FilterModel()
@ -171,9 +173,9 @@ class TimelineViewModelTest {
}
val viewModel = CachedTimelineViewModel(
TimelineCasesImpl(api, EventHubImpl),
TimelineCases(api, eventHub),
api,
EventHubImpl,
eventHub,
accountManager,
mock(),
FilterModel(),
@ -189,7 +191,6 @@ class TimelineViewModelTest {
workerDispatcher = testDispatcher
)
var x = 1
viewModel.statuses.take(1000).collectLatest {
testScope.launch {
differ.submitData(it)