diff --git a/app/src/main/java/com/keylesspalace/tusky/appstore/EventsHub.kt b/app/src/main/java/com/keylesspalace/tusky/appstore/EventsHub.kt index 31697493..7fb1f05b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/appstore/EventsHub.kt +++ b/app/src/main/java/com/keylesspalace/tusky/appstore/EventsHub.kt @@ -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 - fun dispatch(event: Dispatchable) -} - -object EventHubImpl : EventHub { +@Singleton +class EventHub @Inject constructor() { private val eventsSubject = PublishSubject.create() - override val events: Observable = eventsSubject + val events: Observable = eventsSubject - override fun dispatch(event: Dispatchable) { + fun dispatch(event: Dispatchable) { eventsSubject.onNext(event) } } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt index 6ff361a9..44d1e8ed 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt @@ -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 - fun uploadMedia(media: QueuedMedia): Observable -} - 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 { +) { + fun uploadMedia(media: QueuedMedia): Observable { return Observable .fromCallable { if (shouldResizeMedia(media)) { @@ -86,7 +82,7 @@ class MediaUploaderImpl( .subscribeOn(Schedulers.io()) } - override fun prepareMedia(inUri: Uri): Single { + fun prepareMedia(inUri: Uri): Single { return Single.fromCallable { var mediaSize = getMediaSize(contentResolver, inUri) var uri = inUri diff --git a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationFetcher.kt b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationFetcher.kt index fe48a16b..1af9b3d7 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationFetcher.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationFetcher.kt @@ -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) { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/notifications/Notifier.kt b/app/src/main/java/com/keylesspalace/tusky/components/notifications/Notifier.kt deleted file mode 100644 index 5092530b..00000000 --- a/app/src/main/java/com/keylesspalace/tusky/components/notifications/Notifier.kt +++ /dev/null @@ -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) - } -} diff --git a/app/src/main/java/com/keylesspalace/tusky/di/AppComponent.kt b/app/src/main/java/com/keylesspalace/tusky/di/AppComponent.kt index c360be36..2cf48046 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/AppComponent.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/AppComponent.kt @@ -34,8 +34,7 @@ import javax.inject.Singleton ActivitiesModule::class, ServicesModule::class, BroadcastReceiverModule::class, - ViewModelModule::class, - MediaUploaderModule::class + ViewModelModule::class ] ) interface AppComponent { diff --git a/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt index b98d2c70..7699ba69 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt @@ -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) } diff --git a/app/src/main/java/com/keylesspalace/tusky/di/FragmentBuildersModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/FragmentBuildersModule.kt index 21f37bb9..b3c5eaf8 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/FragmentBuildersModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/FragmentBuildersModule.kt @@ -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 diff --git a/app/src/main/java/com/keylesspalace/tusky/di/MediaUploaderModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/MediaUploaderModule.kt deleted file mode 100644 index 00ec1b73..00000000 --- a/app/src/main/java/com/keylesspalace/tusky/di/MediaUploaderModule.kt +++ /dev/null @@ -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 . */ - -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) -} diff --git a/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt index f34dc075..156020f6 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt @@ -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) - } - } } diff --git a/app/src/main/java/com/keylesspalace/tusky/network/TimelineCases.kt b/app/src/main/java/com/keylesspalace/tusky/network/TimelineCases.kt index ea51d8c3..86148e51 100644 --- a/app/src/main/java/com/keylesspalace/tusky/network/TimelineCases.kt +++ b/app/src/main/java/com/keylesspalace/tusky/network/TimelineCases.kt @@ -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 - fun favourite(statusId: String, favourite: Boolean): Single - fun bookmark(statusId: String, bookmark: Boolean): Single - fun mute(statusId: String, notifications: Boolean, duration: Int?) - fun block(statusId: String) - fun delete(statusId: String): Single - fun pin(statusId: String, pin: Boolean): Single - fun voteInPoll(statusId: String, pollId: String, choices: List): Single - fun muteConversation(statusId: String, mute: Boolean): Single -} - -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 { + fun reblog(statusId: String, reblog: Boolean): Single { val call = if (reblog) { mastodonApi.reblogStatus(statusId) } else { @@ -71,7 +60,7 @@ class TimelineCasesImpl( } } - override fun favourite(statusId: String, favourite: Boolean): Single { + fun favourite(statusId: String, favourite: Boolean): Single { val call = if (favourite) { mastodonApi.favouriteStatus(statusId) } else { @@ -82,7 +71,7 @@ class TimelineCasesImpl( } } - override fun bookmark(statusId: String, bookmark: Boolean): Single { + fun bookmark(statusId: String, bookmark: Boolean): Single { val call = if (bookmark) { mastodonApi.bookmarkStatus(statusId) } else { @@ -93,7 +82,7 @@ class TimelineCasesImpl( } } - override fun muteConversation(statusId: String, mute: Boolean): Single { + fun muteConversation(statusId: String, mute: Boolean): Single { 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 { + fun delete(statusId: String): Single { return mastodonApi.deleteStatus(statusId) .doAfterSuccess { eventHub.dispatch(StatusDeletedEvent(statusId)) } } - override fun pin(statusId: String, pin: Boolean): Single { + fun pin(statusId: String, pin: Boolean): Single { // 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): Single { + fun voteInPoll(statusId: String, pollId: String, choices: List): Single { if (choices.isEmpty()) { return Single.error(IllegalStateException()) } diff --git a/app/src/main/java/com/keylesspalace/tusky/service/ServiceClient.kt b/app/src/main/java/com/keylesspalace/tusky/service/ServiceClient.kt index 5b9e3298..9ac5adac 100644 --- a/app/src/main/java/com/keylesspalace/tusky/service/ServiceClient.kt +++ b/app/src/main/java/com/keylesspalace/tusky/service/ServiceClient.kt @@ -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) } } diff --git a/app/src/test/java/com/keylesspalace/tusky/components/timeline/TimelineViewModelTest.kt b/app/src/test/java/com/keylesspalace/tusky/components/timeline/TimelineViewModelTest.kt index 5269ebe6..e99cb14a 100644 --- a/app/src/test/java/com/keylesspalace/tusky/components/timeline/TimelineViewModelTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/components/timeline/TimelineViewModelTest.kt @@ -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)